blob: be636bd77decf55c9fe484b2393163e2f66860c0 [file] [edit]
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
; RUN: llc -mtriple=thumbv7em-none-eabi %s -o - | FileCheck %s
; Tests for recovering SSAT from an "offset" clamp: a clamp(X, Lo, Hi) whose
; width Width = Hi - Lo + 1 is a power of two but whose bounds are not centered
; on zero. PerformMinMaxToSatCombine rewrites clamp(X, Lo, Hi) into
; ssat(X - Center) + Center, with Center = Lo + Width/2, guarded so that
; X - Center cannot signed-overflow.
; A bare clamp to [-224, 31] (width 256). X is range-limited by the ashr, so
; X + 96 cannot overflow: clamp[-224,31] -> ssat8(X + 96) - 96.
define i32 @offset_clamp_bare(i32 %x) {
; CHECK-LABEL: offset_clamp_bare:
; CHECK: @ %bb.0:
; CHECK-NEXT: movs r1, #96
; CHECK-NEXT: add.w r0, r1, r0, asr #8
; CHECK-NEXT: ssat r0, #8, r0
; CHECK-NEXT: subs r0, #96
; CHECK-NEXT: bx lr
%s = ashr i32 %x, 8
%lo = call i32 @llvm.smax.i32(i32 %s, i32 -224)
%hi = call i32 @llvm.smin.i32(i32 %lo, i32 31)
ret i32 %hi
}
; An already-symmetric clamp [-128, 127] is still a bare ssat.
define i32 @symmetric_clamp(i32 %x) {
; CHECK-LABEL: symmetric_clamp:
; CHECK: @ %bb.0:
; CHECK-NEXT: ssat r0, #8, r0
; CHECK-NEXT: bx lr
%lo = call i32 @llvm.smax.i32(i32 %x, i32 -128)
%hi = call i32 @llvm.smin.i32(i32 %lo, i32 127)
ret i32 %hi
}
; An unsigned clamp [0, 255] is still a usat.
define i32 @unsigned_clamp(i32 %x) {
; CHECK-LABEL: unsigned_clamp:
; CHECK: @ %bb.0:
; CHECK-NEXT: usat r0, #8, r0
; CHECK-NEXT: bx lr
%lo = call i32 @llvm.smax.i32(i32 %x, i32 0)
%hi = call i32 @llvm.smin.i32(i32 %lo, i32 255)
ret i32 %hi
}
; X is unconstrained, so X + 96 may signed-overflow and the rewrite is unsound.
; Must stay an explicit clamp (no ssat).
define i32 @offset_clamp_may_overflow(i32 %x) {
; CHECK-LABEL: offset_clamp_may_overflow:
; CHECK: @ %bb.0:
; CHECK-NEXT: cmn.w r0, #224
; CHECK-NEXT: it le
; CHECK-NEXT: mvnle r0, #223
; CHECK-NEXT: cmp r0, #31
; CHECK-NEXT: it ge
; CHECK-NEXT: movge r0, #31
; CHECK-NEXT: bx lr
%lo = call i32 @llvm.smax.i32(i32 %x, i32 -224)
%hi = call i32 @llvm.smin.i32(i32 %lo, i32 31)
ret i32 %hi
}
; Width 151 ([-100, 50]) is not a power of two. No fold.
define i32 @offset_clamp_non_pow2_width(i32 %x) {
; CHECK-LABEL: offset_clamp_non_pow2_width:
; CHECK: @ %bb.0:
; CHECK-NEXT: mvn r1, #99
; CHECK-NEXT: asrs r2, r0, #8
; CHECK-NEXT: cmn.w r2, #100
; CHECK-NEXT: it gt
; CHECK-NEXT: asrgt r1, r0, #8
; CHECK-NEXT: cmp r1, #50
; CHECK-NEXT: it ge
; CHECK-NEXT: movge r1, #50
; CHECK-NEXT: mov r0, r1
; CHECK-NEXT: bx lr
%s = ashr i32 %x, 8
%lo = call i32 @llvm.smax.i32(i32 %s, i32 -100)
%hi = call i32 @llvm.smin.i32(i32 %lo, i32 50)
ret i32 %hi
}
; Reversed bounds are a degenerate clamp. The modular APInt width would look
; like a power of two, but this must not become an offset ssat.
define i32 @offset_clamp_degenerate_bounds(i32 %x) {
; CHECK-LABEL: offset_clamp_degenerate_bounds:
; CHECK: @ %bb.0:
; CHECK-NEXT: mov.w r0, #-2147483648
; CHECK-NEXT: bx lr
%s = ashr i32 %x, 24
%lo = call i32 @llvm.smax.i32(i32 %s, i32 1)
%hi = call i32 @llvm.smin.i32(i32 %lo, i32 -2147483648)
ret i32 %hi
}