Files
clang-p2996/llvm/test/Transforms/CorrelatedValuePropagation/basic.ll
Keno Fischer 1436a9232b [LVI] Look through negations when evaluating conditions
This teaches LVI (and thus CVP) to extract range information
from branches whose condition is negated using (`xor %c, true`).
On the implementation side, we switch the cache to additionally
track whether we're looking for the inverted value or not and
otherwise using the existing support for computing inverted
conditions.

I think the biggest question here is why this negation shows up
here at all. After all, it should always be possible for some
other pass to fold such a negation into a branch, comparison or
some other logical operation. Indeed, instcombine does just that.
However, these negations can be otherwise fairly persistent, e.g.
instsimplify is not able to exchange branch conditions from
negations. In addition, jumpthreading, which sits at the same
point in default pass pipeline also handles this pattern, which
adds further evidence that we might expect these negations to
not have been canonicalized away yet at this point in the pass
pipeline.

In the particular case I was looking at there was a bit of a
circular dependency where flags computed by cvp were needed
by instcombine, and incstombine's folding of the negation was
needed for cvp. Adding a second instombine pass would have
worked of course, but instcombine can be somewhat expensive,
so it appeared desirable to not require it to have run
before cvp (as is the case in the default pass pipeline).

Reviewed By: nikic

Differential Revision: https://reviews.llvm.org/D140933
2023-01-05 23:03:46 +00:00

1918 lines
52 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -passes=correlated-propagation -S | FileCheck %s
; PR2581
define i32 @test1(i1 %C) {
; CHECK-LABEL: @test1(
; CHECK-NEXT: br i1 [[C:%.*]], label [[EXIT:%.*]], label [[BODY:%.*]]
; CHECK: body:
; CHECK-NEXT: ret i32 11
; CHECK: exit:
; CHECK-NEXT: ret i32 10
;
br i1 %C, label %exit, label %body
body: ; preds = %0
%A = select i1 %C, i32 10, i32 11
ret i32 %A
exit: ; preds = %0
ret i32 10
}
; PR4420
declare i1 @ext()
define i1 @test2() {
; CHECK-LABEL: @test2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[COND:%.*]] = tail call i1 @ext()
; CHECK-NEXT: br i1 [[COND]], label [[BB1:%.*]], label [[BB2:%.*]]
; CHECK: bb1:
; CHECK-NEXT: [[COND2:%.*]] = tail call i1 @ext()
; CHECK-NEXT: br i1 [[COND2]], label [[BB3:%.*]], label [[BB2]]
; CHECK: bb2:
; CHECK-NEXT: ret i1 false
; CHECK: bb3:
; CHECK-NEXT: [[RES:%.*]] = tail call i1 @ext()
; CHECK-NEXT: ret i1 [[RES]]
;
entry:
%cond = tail call i1 @ext()
br i1 %cond, label %bb1, label %bb2
bb1:
%cond2 = tail call i1 @ext()
br i1 %cond2, label %bb3, label %bb2
bb2:
%cond_merge = phi i1 [ %cond, %entry ], [ false, %bb1 ]
ret i1 %cond_merge
bb3:
%res = tail call i1 @ext()
ret i1 %res
}
; PR4855
@gv = internal constant i8 7
define i8 @test3(ptr %a) nounwind {
; CHECK-LABEL: @test3(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[COND:%.*]] = icmp eq ptr [[A:%.*]], @gv
; CHECK-NEXT: br i1 [[COND]], label [[BB2:%.*]], label [[BB:%.*]]
; CHECK: bb:
; CHECK-NEXT: ret i8 0
; CHECK: bb2:
; CHECK-NEXT: [[SHOULD_BE_CONST:%.*]] = load i8, ptr @gv, align 1
; CHECK-NEXT: ret i8 [[SHOULD_BE_CONST]]
;
entry:
%cond = icmp eq ptr %a, @gv
br i1 %cond, label %bb2, label %bb
bb:
ret i8 0
bb2:
%should_be_const = load i8, ptr %a
ret i8 %should_be_const
}
; PR1757
define i32 @test4(i32) {
; CHECK-LABEL: @test4(
; CHECK-NEXT: EntryBlock:
; CHECK-NEXT: [[DOTDEMORGAN:%.*]] = icmp sgt i32 [[TMP0:%.*]], 2
; CHECK-NEXT: br i1 [[DOTDEMORGAN]], label [[GREATERTHANTWO:%.*]], label [[LESSTHANOREQUALTOTWO:%.*]]
; CHECK: GreaterThanTwo:
; CHECK-NEXT: br i1 false, label [[IMPOSSIBLE:%.*]], label [[NOTTWOANDGREATERTHANTWO:%.*]]
; CHECK: NotTwoAndGreaterThanTwo:
; CHECK-NEXT: ret i32 2
; CHECK: Impossible:
; CHECK-NEXT: ret i32 1
; CHECK: LessThanOrEqualToTwo:
; CHECK-NEXT: ret i32 0
;
EntryBlock:
%.demorgan = icmp sgt i32 %0, 2
br i1 %.demorgan, label %GreaterThanTwo, label %LessThanOrEqualToTwo
GreaterThanTwo:
icmp eq i32 %0, 2
br i1 %1, label %Impossible, label %NotTwoAndGreaterThanTwo
NotTwoAndGreaterThanTwo:
ret i32 2
Impossible:
ret i32 1
LessThanOrEqualToTwo:
ret i32 0
}
declare ptr @f(ptr)
define void @test5(ptr %x, ptr %y) {
; CHECK-LABEL: @test5(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[PRE:%.*]] = icmp eq ptr [[X:%.*]], null
; CHECK-NEXT: br i1 [[PRE]], label [[RETURN:%.*]], label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[PHI:%.*]] = phi ptr [ [[F:%.*]], [[LOOP]] ], [ [[X]], [[ENTRY:%.*]] ]
; CHECK-NEXT: [[F]] = tail call ptr @f(ptr [[PHI]])
; CHECK-NEXT: [[CMP1:%.*]] = icmp ne ptr [[F]], [[Y:%.*]]
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], ptr [[F]], ptr null
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq ptr [[SEL]], null
; CHECK-NEXT: br i1 [[CMP2]], label [[RETURN]], label [[LOOP]]
; CHECK: return:
; CHECK-NEXT: ret void
;
entry:
%pre = icmp eq ptr %x, null
br i1 %pre, label %return, label %loop
loop:
%phi = phi ptr [ %sel, %loop ], [ %x, %entry ]
%f = tail call ptr @f(ptr %phi)
%cmp1 = icmp ne ptr %f, %y
%sel = select i1 %cmp1, ptr %f, ptr null
%cmp2 = icmp eq ptr %sel, null
br i1 %cmp2, label %return, label %loop
return:
ret void
}
; "false" case for CorrelatedValuePropagation
define void @loop1(ptr %x, ptr %y) {
; CHECK-LABEL: @loop1(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[PHI:%.*]] = phi ptr [ [[F:%.*]], [[LOOP]] ], [ [[X:%.*]], [[ENTRY:%.*]] ]
; CHECK-NEXT: [[F]] = tail call ptr @f(ptr [[PHI]])
; CHECK-NEXT: [[CMP1:%.*]] = icmp ne ptr [[F]], [[Y:%.*]]
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], ptr [[F]], ptr null
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq ptr [[SEL]], null
; CHECK-NEXT: br i1 [[CMP2]], label [[RETURN:%.*]], label [[LOOP]]
; CHECK: return:
; CHECK-NEXT: ret void
;
entry:
br label %loop
loop:
%phi = phi ptr [ %sel, %loop ], [ %x, %entry ]
%f = tail call ptr @f(ptr %phi)
%cmp1 = icmp ne ptr %f, %y
%sel = select i1 %cmp1, ptr %f, ptr null
%cmp2 = icmp eq ptr %sel, null
br i1 %cmp2, label %return, label %loop
return:
ret void
}
; "true" case for CorrelatedValuePropagation
define void @loop2(ptr %x, ptr %y) {
; CHECK-LABEL: @loop2(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[PHI:%.*]] = phi ptr [ [[F:%.*]], [[LOOP]] ], [ [[X:%.*]], [[ENTRY:%.*]] ]
; CHECK-NEXT: [[F]] = tail call ptr @f(ptr [[PHI]])
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq ptr [[F]], [[Y:%.*]]
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], ptr null, ptr [[F]]
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq ptr [[SEL]], null
; CHECK-NEXT: br i1 [[CMP2]], label [[RETURN:%.*]], label [[LOOP]]
; CHECK: return:
; CHECK-NEXT: ret void
;
entry:
br label %loop
loop:
%phi = phi ptr [ %sel, %loop ], [ %x, %entry ]
%f = tail call ptr @f(ptr %phi)
%cmp1 = icmp eq ptr %f, %y
%sel = select i1 %cmp1, ptr null, ptr %f
%cmp2 = icmp eq ptr %sel, null
br i1 %cmp2, label %return, label %loop
return:
ret void
}
define i32 @switch1(i32 %s) {
; CHECK-LABEL: @switch1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[S:%.*]], 0
; CHECK-NEXT: br i1 [[CMP]], label [[NEGATIVE:%.*]], label [[OUT:%.*]]
; CHECK: negative:
; CHECK-NEXT: switch i32 [[S]], label [[OUT]] [
; CHECK-NEXT: i32 -2, label [[NEXT:%.*]]
; CHECK-NEXT: i32 -1, label [[NEXT]]
; CHECK-NEXT: ]
; CHECK: out:
; CHECK-NEXT: [[P:%.*]] = phi i32 [ 1, [[ENTRY:%.*]] ], [ -1, [[NEGATIVE]] ]
; CHECK-NEXT: ret i32 [[P]]
; CHECK: next:
; CHECK-NEXT: ret i32 0
;
entry:
%cmp = icmp slt i32 %s, 0
br i1 %cmp, label %negative, label %out
negative:
switch i32 %s, label %out [
i32 0, label %out
i32 1, label %out
i32 -1, label %next
i32 -2, label %next
i32 2, label %out
i32 3, label %out
]
out:
%p = phi i32 [ 1, %entry ], [ -1, %negative ], [ -1, %negative ], [ -1, %negative ], [ -1, %negative ], [ -1, %negative ]
ret i32 %p
next:
%q = phi i32 [ 0, %negative ], [ 0, %negative ]
ret i32 %q
}
define i32 @switch2(i32 %s) {
; CHECK-LABEL: @switch2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[S:%.*]], 0
; CHECK-NEXT: br i1 [[CMP]], label [[POSITIVE:%.*]], label [[OUT:%.*]]
; CHECK: positive:
; CHECK-NEXT: br label [[OUT]]
; CHECK: out:
; CHECK-NEXT: [[P:%.*]] = phi i32 [ -1, [[ENTRY:%.*]] ], [ 1, [[POSITIVE]] ]
; CHECK-NEXT: ret i32 [[P]]
; CHECK: next:
; CHECK-NEXT: ret i32 0
;
entry:
%cmp = icmp sgt i32 %s, 0
br i1 %cmp, label %positive, label %out
positive:
switch i32 %s, label %out [
i32 0, label %out
i32 -1, label %next
i32 -2, label %next
]
out:
%p = phi i32 [ -1, %entry ], [ 1, %positive ], [ 1, %positive ]
ret i32 %p
next:
%q = phi i32 [ 0, %positive ], [ 0, %positive ]
ret i32 %q
}
define i32 @switch3(i32 %s) {
; CHECK-LABEL: @switch3(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[S:%.*]], 0
; CHECK-NEXT: br i1 [[CMP]], label [[POSITIVE:%.*]], label [[OUT:%.*]]
; CHECK: positive:
; CHECK-NEXT: br label [[OUT]]
; CHECK: out:
; CHECK-NEXT: [[P:%.*]] = phi i32 [ -1, [[ENTRY:%.*]] ], [ 1, [[POSITIVE]] ]
; CHECK-NEXT: ret i32 [[P]]
; CHECK: next:
; CHECK-NEXT: ret i32 0
;
entry:
%cmp = icmp sgt i32 %s, 0
br i1 %cmp, label %positive, label %out
positive:
switch i32 %s, label %out [
i32 -1, label %out
i32 -2, label %next
i32 -3, label %next
]
out:
%p = phi i32 [ -1, %entry ], [ 1, %positive ], [ 1, %positive ]
ret i32 %p
next:
%q = phi i32 [ 0, %positive ], [ 0, %positive ]
ret i32 %q
}
define void @switch4(i32 %s) {
; CHECK-LABEL: @switch4(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[S:%.*]], 0
; CHECK-NEXT: br i1 [[CMP]], label [[ZERO:%.*]], label [[OUT:%.*]]
; CHECK: zero:
; CHECK-NEXT: br label [[NEXT:%.*]]
; CHECK: out:
; CHECK-NEXT: ret void
; CHECK: next:
; CHECK-NEXT: ret void
;
entry:
%cmp = icmp eq i32 %s, 0
br i1 %cmp, label %zero, label %out
zero:
switch i32 %s, label %out [
i32 0, label %next
i32 1, label %out
i32 -1, label %out
]
out:
ret void
next:
ret void
}
define void @switch_nonzero_zext(i8 %s) {
; CHECK-LABEL: @switch_nonzero_zext(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i8 [[S:%.*]], 0
; CHECK-NEXT: br i1 [[CMP]], label [[SWITCH:%.*]], label [[EXIT:%.*]]
; CHECK: switch:
; CHECK-NEXT: [[S_EXT:%.*]] = zext i8 [[S]] to i32
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: ret void
; CHECK: unreachable:
; CHECK-NEXT: ret void
;
entry:
%cmp = icmp ne i8 %s, 0
br i1 %cmp, label %switch, label %exit
switch:
%s.ext = zext i8 %s to i32
switch i32 %s.ext, label %exit [
i32 0, label %unreachable
i32 1, label %exit
i32 -1, label %exit
]
exit:
ret void
unreachable:
ret void
}
define void @switch_assume_nonzero(i32 %s) {
; CHECK-LABEL: @switch_assume_nonzero(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[S:%.*]], 0
; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]])
; CHECK-NEXT: br label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: ret void
; CHECK: unreachable:
; CHECK-NEXT: ret void
;
entry:
%cmp = icmp ne i32 %s, 0
call void @llvm.assume(i1 %cmp)
switch i32 %s, label %exit [
i32 0, label %unreachable
i32 1, label %exit
i32 -1, label %exit
]
exit:
ret void
unreachable:
ret void
}
define void @switch_nonzero_phi(i1 %cond) {
; CHECK-LABEL: @switch_nonzero_phi(
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
; CHECK: if:
; CHECK-NEXT: br label [[SWITCH:%.*]]
; CHECK: else:
; CHECK-NEXT: br label [[SWITCH]]
; CHECK: switch:
; CHECK-NEXT: [[S:%.*]] = phi i32 [ 1, [[IF]] ], [ -1, [[ELSE]] ]
; CHECK-NEXT: br label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: ret void
; CHECK: unreachable:
; CHECK-NEXT: ret void
;
entry:
br i1 %cond, label %if, label %else
if:
br label %switch
else:
br label %switch
switch:
%s = phi i32 [ 1, %if ], [ -1, %else ]
switch i32 %s, label %exit [
i32 0, label %unreachable
i32 1, label %exit
i32 -1, label %exit
]
exit:
ret void
unreachable:
ret void
}
define i32 @switch_range(i32 %cond) {
; CHECK-LABEL: @switch_range(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[S:%.*]] = urem i32 [[COND:%.*]], 3
; CHECK-NEXT: [[S1:%.*]] = add nuw nsw i32 [[S]], 1
; CHECK-NEXT: switch i32 [[S1]], label [[UNREACHABLE:%.*]] [
; CHECK-NEXT: i32 1, label [[EXIT1:%.*]]
; CHECK-NEXT: i32 2, label [[EXIT2:%.*]]
; CHECK-NEXT: i32 3, label [[EXIT1]]
; CHECK-NEXT: ]
; CHECK: exit1:
; CHECK-NEXT: ret i32 1
; CHECK: exit2:
; CHECK-NEXT: ret i32 2
; CHECK: unreachable:
; CHECK-NEXT: ret i32 0
;
entry:
%s = urem i32 %cond, 3
%s1 = add i32 %s, 1
switch i32 %s1, label %unreachable [
i32 1, label %exit1
i32 2, label %exit2
i32 3, label %exit1
]
exit1:
ret i32 1
exit2:
ret i32 2
unreachable:
ret i32 0
}
; If the cases do not cover the entire range of the
; switch condition, we should not change the default.
define i32 @switch_range_not_full(i32 %cond) {
; CHECK-LABEL: @switch_range_not_full(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[S:%.*]] = urem i32 [[COND:%.*]], 3
; CHECK-NEXT: [[S1:%.*]] = add nuw nsw i32 [[S]], 1
; CHECK-NEXT: switch i32 [[S1]], label [[UNREACHABLE:%.*]] [
; CHECK-NEXT: i32 1, label [[EXIT1:%.*]]
; CHECK-NEXT: i32 3, label [[EXIT2:%.*]]
; CHECK-NEXT: ]
; CHECK: exit1:
; CHECK-NEXT: ret i32 1
; CHECK: exit2:
; CHECK-NEXT: ret i32 2
; CHECK: unreachable:
; CHECK-NEXT: ret i32 0
;
entry:
%s = urem i32 %cond, 3
%s1 = add i32 %s, 1
switch i32 %s1, label %unreachable [
i32 1, label %exit1
i32 3, label %exit2
]
exit1:
ret i32 1
exit2:
ret i32 2
unreachable:
ret i32 0
}
; PR51531
define i8 @switch_defaultdest_multipleuse(i8 %t0) {
; CHECK-LABEL: @switch_defaultdest_multipleuse(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[O:%.*]] = or i8 [[T0:%.*]], 1
; CHECK-NEXT: [[R:%.*]] = srem i8 1, [[O]]
; CHECK-NEXT: switch i8 [[R]], label [[EXIT:%.*]] [
; CHECK-NEXT: i8 0, label [[EXIT]]
; CHECK-NEXT: i8 1, label [[EXIT]]
; CHECK-NEXT: ]
; CHECK: exit:
; CHECK-NEXT: ret i8 0
;
entry:
%o = or i8 %t0, 1
%r = srem i8 1, %o
switch i8 %r, label %exit [
i8 0, label %exit
i8 1, label %exit
]
exit:
ret i8 0
}
define i1 @arg_attribute(ptr nonnull %a) {
; CHECK-LABEL: @arg_attribute(
; CHECK-NEXT: ret i1 false
;
%cmp = icmp eq i8* %a, null
ret i1 %cmp
}
declare nonnull ptr @return_nonnull()
define i1 @call_attribute() {
; CHECK-LABEL: @call_attribute(
; CHECK-NEXT: [[A:%.*]] = call ptr @return_nonnull()
; CHECK-NEXT: ret i1 false
;
%a = call i8* @return_nonnull()
%cmp = icmp eq ptr %a, null
ret i1 %cmp
}
define i1 @umin(i32 %a, i32 %b) {
; CHECK-LABEL: @umin(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[A:%.*]], 5
; CHECK-NEXT: br i1 [[CMP]], label [[A_GUARD:%.*]], label [[OUT:%.*]]
; CHECK: a_guard:
; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 [[B:%.*]], 20
; CHECK-NEXT: br i1 [[CMP2]], label [[B_GUARD:%.*]], label [[OUT]]
; CHECK: b_guard:
; CHECK-NEXT: [[SEL_CMP:%.*]] = icmp ult i32 [[A]], [[B]]
; CHECK-NEXT: [[MIN:%.*]] = select i1 [[SEL_CMP]], i32 [[A]], i32 [[B]]
; CHECK-NEXT: ret i1 false
; CHECK: out:
; CHECK-NEXT: ret i1 false
;
entry:
%cmp = icmp ult i32 %a, 5
br i1 %cmp, label %a_guard, label %out
a_guard:
%cmp2 = icmp ult i32 %b, 20
br i1 %cmp2, label %b_guard, label %out
b_guard:
%sel_cmp = icmp ult i32 %a, %b
%min = select i1 %sel_cmp, i32 %a, i32 %b
%res = icmp eq i32 %min, 7
ret i1 %res
out:
ret i1 false
}
define i1 @smin(i32 %a, i32 %b) {
; CHECK-LABEL: @smin(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[A:%.*]], 5
; CHECK-NEXT: br i1 [[CMP]], label [[A_GUARD:%.*]], label [[OUT:%.*]]
; CHECK: a_guard:
; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 [[B:%.*]], 20
; CHECK-NEXT: br i1 [[CMP2]], label [[B_GUARD:%.*]], label [[OUT]]
; CHECK: b_guard:
; CHECK-NEXT: [[SEL_CMP:%.*]] = icmp ule i32 [[A]], [[B]]
; CHECK-NEXT: [[MIN:%.*]] = select i1 [[SEL_CMP]], i32 [[A]], i32 [[B]]
; CHECK-NEXT: ret i1 false
; CHECK: out:
; CHECK-NEXT: ret i1 false
;
entry:
%cmp = icmp ult i32 %a, 5
br i1 %cmp, label %a_guard, label %out
a_guard:
%cmp2 = icmp ult i32 %b, 20
br i1 %cmp2, label %b_guard, label %out
b_guard:
%sel_cmp = icmp sle i32 %a, %b
%min = select i1 %sel_cmp, i32 %a, i32 %b
%res = icmp eq i32 %min, 7
ret i1 %res
out:
ret i1 false
}
define i1 @smax(i32 %a, i32 %b) {
; CHECK-LABEL: @smax(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[A:%.*]], 5
; CHECK-NEXT: br i1 [[CMP]], label [[A_GUARD:%.*]], label [[OUT:%.*]]
; CHECK: a_guard:
; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i32 [[B:%.*]], 20
; CHECK-NEXT: br i1 [[CMP2]], label [[B_GUARD:%.*]], label [[OUT]]
; CHECK: b_guard:
; CHECK-NEXT: [[SEL_CMP:%.*]] = icmp uge i32 [[A]], [[B]]
; CHECK-NEXT: [[MAX:%.*]] = select i1 [[SEL_CMP]], i32 [[A]], i32 [[B]]
; CHECK-NEXT: ret i1 false
; CHECK: out:
; CHECK-NEXT: ret i1 false
;
entry:
%cmp = icmp sgt i32 %a, 5
br i1 %cmp, label %a_guard, label %out
a_guard:
%cmp2 = icmp sgt i32 %b, 20
br i1 %cmp2, label %b_guard, label %out
b_guard:
%sel_cmp = icmp sge i32 %a, %b
%max = select i1 %sel_cmp, i32 %a, i32 %b
%res = icmp eq i32 %max, 7
ret i1 %res
out:
ret i1 false
}
define i1 @umax(i32 %a, i32 %b) {
; CHECK-LABEL: @umax(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[A:%.*]], 5
; CHECK-NEXT: br i1 [[CMP]], label [[A_GUARD:%.*]], label [[OUT:%.*]]
; CHECK: a_guard:
; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i32 [[B:%.*]], 20
; CHECK-NEXT: br i1 [[CMP2]], label [[B_GUARD:%.*]], label [[OUT]]
; CHECK: b_guard:
; CHECK-NEXT: [[SEL_CMP:%.*]] = icmp uge i32 [[A]], [[B]]
; CHECK-NEXT: [[MAX:%.*]] = select i1 [[SEL_CMP]], i32 [[A]], i32 [[B]]
; CHECK-NEXT: ret i1 false
; CHECK: out:
; CHECK-NEXT: ret i1 false
;
entry:
%cmp = icmp sgt i32 %a, 5
br i1 %cmp, label %a_guard, label %out
a_guard:
%cmp2 = icmp sgt i32 %b, 20
br i1 %cmp2, label %b_guard, label %out
b_guard:
%sel_cmp = icmp uge i32 %a, %b
%max = select i1 %sel_cmp, i32 %a, i32 %b
%res = icmp eq i32 %max, 7
ret i1 %res
out:
ret i1 false
}
define i1 @umin_lhs_overdefined_rhs_const(i32 %a) {
; CHECK-LABEL: @umin_lhs_overdefined_rhs_const(
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[A:%.*]], 42
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 [[A]], i32 42
; CHECK-NEXT: ret i1 true
;
%cmp = icmp ult i32 %a, 42
%sel = select i1 %cmp, i32 %a, i32 42
%cmp2 = icmp ule i32 %sel, 42
ret i1 %cmp2
}
define i1 @umin_rhs_overdefined_lhs_const(i32 %a) {
; CHECK-LABEL: @umin_rhs_overdefined_lhs_const(
; CHECK-NEXT: [[CMP:%.*]] = icmp uge i32 [[A:%.*]], 42
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 42, i32 [[A]]
; CHECK-NEXT: ret i1 true
;
%cmp = icmp uge i32 %a, 42
%sel = select i1 %cmp, i32 42, i32 %a
%cmp2 = icmp ule i32 %sel, 42
ret i1 %cmp2
}
define i1 @umin_lhs_overdefined_rhs_range(i32 %a, i32 %b) {
; CHECK-LABEL: @umin_lhs_overdefined_rhs_range(
; CHECK-NEXT: [[ASSUME:%.*]] = icmp ult i32 [[B:%.*]], 42
; CHECK-NEXT: call void @llvm.assume(i1 [[ASSUME]])
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[A:%.*]], [[B]]
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 [[A]], i32 [[B]]
; CHECK-NEXT: ret i1 true
;
%assume = icmp ult i32 %b, 42
call void @llvm.assume(i1 %assume)
%cmp = icmp ult i32 %a, %b
%sel = select i1 %cmp, i32 %a, i32 %b
%cmp2 = icmp ult i32 %sel, 42
ret i1 %cmp2
}
define i1 @umin_rhs_overdefined_lhs_range(i32 %a, i32 %b) {
; CHECK-LABEL: @umin_rhs_overdefined_lhs_range(
; CHECK-NEXT: [[ASSUME:%.*]] = icmp ult i32 [[B:%.*]], 42
; CHECK-NEXT: call void @llvm.assume(i1 [[ASSUME]])
; CHECK-NEXT: [[CMP:%.*]] = icmp uge i32 [[A:%.*]], [[B]]
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 [[B]], i32 [[A]]
; CHECK-NEXT: ret i1 true
;
%assume = icmp ult i32 %b, 42
call void @llvm.assume(i1 %assume)
%cmp = icmp uge i32 %a, %b
%sel = select i1 %cmp, i32 %b, i32 %a
%cmp2 = icmp ult i32 %sel, 42
ret i1 %cmp2
}
define i1 @clamp_low1(i32 %a) {
; CHECK-LABEL: @clamp_low1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp sge i32 [[A:%.*]], 5
; CHECK-NEXT: br i1 [[CMP]], label [[A_GUARD:%.*]], label [[OUT:%.*]]
; CHECK: a_guard:
; CHECK-NEXT: [[SEL_CMP:%.*]] = icmp eq i32 [[A]], 5
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], -1
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[SEL_CMP]], i32 5, i32 [[ADD]]
; CHECK-NEXT: ret i1 false
; CHECK: out:
; CHECK-NEXT: ret i1 false
;
entry:
%cmp = icmp sge i32 %a, 5
br i1 %cmp, label %a_guard, label %out
a_guard:
%sel_cmp = icmp eq i32 %a, 5
%add = add i32 %a, -1
%sel = select i1 %sel_cmp, i32 5, i32 %add
%res = icmp eq i32 %sel, 4
ret i1 %res
out:
ret i1 false
}
define i1 @clamp_low2(i32 %a) {
; CHECK-LABEL: @clamp_low2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp sge i32 [[A:%.*]], 5
; CHECK-NEXT: br i1 [[CMP]], label [[A_GUARD:%.*]], label [[OUT:%.*]]
; CHECK: a_guard:
; CHECK-NEXT: [[SEL_CMP:%.*]] = icmp ne i32 [[A]], 5
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], -1
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[SEL_CMP]], i32 [[ADD]], i32 5
; CHECK-NEXT: ret i1 false
; CHECK: out:
; CHECK-NEXT: ret i1 false
;
entry:
%cmp = icmp sge i32 %a, 5
br i1 %cmp, label %a_guard, label %out
a_guard:
%sel_cmp = icmp ne i32 %a, 5
%add = add i32 %a, -1
%sel = select i1 %sel_cmp, i32 %add, i32 5
%res = icmp eq i32 %sel, 4
ret i1 %res
out:
ret i1 false
}
define i1 @clamp_low3(i32 %a) {
; CHECK-LABEL: @clamp_low3(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp sge i32 [[A:%.*]], 5
; CHECK-NEXT: br i1 [[CMP]], label [[A_GUARD:%.*]], label [[OUT:%.*]]
; CHECK: a_guard:
; CHECK-NEXT: [[SEL_CMP:%.*]] = icmp ugt i32 [[A]], 5
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], -1
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[SEL_CMP]], i32 [[ADD]], i32 5
; CHECK-NEXT: ret i1 false
; CHECK: out:
; CHECK-NEXT: ret i1 false
;
entry:
%cmp = icmp sge i32 %a, 5
br i1 %cmp, label %a_guard, label %out
a_guard:
%sel_cmp = icmp sgt i32 %a, 5
%add = add i32 %a, -1
%sel = select i1 %sel_cmp, i32 %add, i32 5
%res = icmp eq i32 %sel, 4
ret i1 %res
out:
ret i1 false
}
define i1 @clamp_low4(i32 %a) {
; CHECK-LABEL: @clamp_low4(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp sge i32 [[A:%.*]], 5
; CHECK-NEXT: br i1 [[CMP]], label [[A_GUARD:%.*]], label [[OUT:%.*]]
; CHECK: a_guard:
; CHECK-NEXT: [[SEL_CMP:%.*]] = icmp ule i32 [[A]], 5
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], -1
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[SEL_CMP]], i32 5, i32 [[ADD]]
; CHECK-NEXT: ret i1 false
; CHECK: out:
; CHECK-NEXT: ret i1 false
;
entry:
%cmp = icmp sge i32 %a, 5
br i1 %cmp, label %a_guard, label %out
a_guard:
%sel_cmp = icmp sle i32 %a, 5
%add = add i32 %a, -1
%sel = select i1 %sel_cmp, i32 5, i32 %add
%res = icmp eq i32 %sel, 4
ret i1 %res
out:
ret i1 false
}
define i1 @clamp_high1(i32 %a) {
; CHECK-LABEL: @clamp_high1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp sle i32 [[A:%.*]], 5
; CHECK-NEXT: br i1 [[CMP]], label [[A_GUARD:%.*]], label [[OUT:%.*]]
; CHECK: a_guard:
; CHECK-NEXT: [[SEL_CMP:%.*]] = icmp eq i32 [[A]], 5
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], 1
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[SEL_CMP]], i32 5, i32 [[ADD]]
; CHECK-NEXT: ret i1 false
; CHECK: out:
; CHECK-NEXT: ret i1 false
;
entry:
%cmp = icmp sle i32 %a, 5
br i1 %cmp, label %a_guard, label %out
a_guard:
%sel_cmp = icmp eq i32 %a, 5
%add = add i32 %a, 1
%sel = select i1 %sel_cmp, i32 5, i32 %add
%res = icmp eq i32 %sel, 6
ret i1 %res
out:
ret i1 false
}
define i1 @clamp_high2(i32 %a) {
; CHECK-LABEL: @clamp_high2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp sle i32 [[A:%.*]], 5
; CHECK-NEXT: br i1 [[CMP]], label [[A_GUARD:%.*]], label [[OUT:%.*]]
; CHECK: a_guard:
; CHECK-NEXT: [[SEL_CMP:%.*]] = icmp ne i32 [[A]], 5
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], 1
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[SEL_CMP]], i32 [[ADD]], i32 5
; CHECK-NEXT: ret i1 false
; CHECK: out:
; CHECK-NEXT: ret i1 false
;
entry:
%cmp = icmp sle i32 %a, 5
br i1 %cmp, label %a_guard, label %out
a_guard:
%sel_cmp = icmp ne i32 %a, 5
%add = add i32 %a, 1
%sel = select i1 %sel_cmp, i32 %add, i32 5
%res = icmp eq i32 %sel, 6
ret i1 %res
out:
ret i1 false
}
define i1 @clamp_high3(i32 %a) {
; CHECK-LABEL: @clamp_high3(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp sle i32 [[A:%.*]], 5
; CHECK-NEXT: br i1 [[CMP]], label [[A_GUARD:%.*]], label [[OUT:%.*]]
; CHECK: a_guard:
; CHECK-NEXT: [[SEL_CMP:%.*]] = icmp slt i32 [[A]], 5
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], 1
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[SEL_CMP]], i32 [[ADD]], i32 5
; CHECK-NEXT: ret i1 false
; CHECK: out:
; CHECK-NEXT: ret i1 false
;
entry:
%cmp = icmp sle i32 %a, 5
br i1 %cmp, label %a_guard, label %out
a_guard:
%sel_cmp = icmp slt i32 %a, 5
%add = add i32 %a, 1
%sel = select i1 %sel_cmp, i32 %add, i32 5
%res = icmp eq i32 %sel, 6
ret i1 %res
out:
ret i1 false
}
define i1 @clamp_high4(i32 %a) {
; CHECK-LABEL: @clamp_high4(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp sle i32 [[A:%.*]], 5
; CHECK-NEXT: br i1 [[CMP]], label [[A_GUARD:%.*]], label [[OUT:%.*]]
; CHECK: a_guard:
; CHECK-NEXT: [[SEL_CMP:%.*]] = icmp sge i32 [[A]], 5
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], 1
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[SEL_CMP]], i32 5, i32 [[ADD]]
; CHECK-NEXT: ret i1 false
; CHECK: out:
; CHECK-NEXT: ret i1 false
;
entry:
%cmp = icmp sle i32 %a, 5
br i1 %cmp, label %a_guard, label %out
a_guard:
%sel_cmp = icmp sge i32 %a, 5
%add = add i32 %a, 1
%sel = select i1 %sel_cmp, i32 5, i32 %add
%res = icmp eq i32 %sel, 6
ret i1 %res
out:
ret i1 false
}
; Just showing arbitrary constants work, not really a clamp
define i1 @not_clamp_high(i32 %a) {
; CHECK-LABEL: @not_clamp_high(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp sle i32 [[A:%.*]], 5
; CHECK-NEXT: br i1 [[CMP]], label [[A_GUARD:%.*]], label [[OUT:%.*]]
; CHECK: a_guard:
; CHECK-NEXT: [[SEL_CMP:%.*]] = icmp ne i32 [[A]], 5
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], 100
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[SEL_CMP]], i32 [[ADD]], i32 5
; CHECK-NEXT: ret i1 false
; CHECK: out:
; CHECK-NEXT: ret i1 false
;
entry:
%cmp = icmp sle i32 %a, 5
br i1 %cmp, label %a_guard, label %out
a_guard:
%sel_cmp = icmp ne i32 %a, 5
%add = add i32 %a, 100
%sel = select i1 %sel_cmp, i32 %add, i32 5
%res = icmp eq i32 %sel, 105
ret i1 %res
out:
ret i1 false
}
define void @abs1(i32 %a, ptr %p) {
; CHECK-LABEL: @abs1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[A:%.*]], 10
; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i32 [[A]], -20
; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
; CHECK-NEXT: br i1 [[AND]], label [[GUARD:%.*]], label [[EXIT:%.*]]
; CHECK: guard:
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 0, [[A]]
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[A]], 0
; CHECK-NEXT: [[ABS:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 [[A]]
; CHECK-NEXT: store i1 true, ptr [[P:%.*]], align 1
; CHECK-NEXT: [[C2:%.*]] = icmp ult i32 [[ABS]], 19
; CHECK-NEXT: store i1 [[C2]], ptr [[P]], align 1
; CHECK-NEXT: store i1 true, ptr [[P]], align 1
; CHECK-NEXT: [[C4:%.*]] = icmp uge i32 [[ABS]], 1
; CHECK-NEXT: store i1 [[C4]], ptr [[P]], align 1
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
%cmp1 = icmp slt i32 %a, 10
%cmp2 = icmp sgt i32 %a, -20
%and = and i1 %cmp1, %cmp2
br i1 %and, label %guard, label %exit
guard:
%sub = sub i32 0, %a
%cmp = icmp slt i32 %a, 0
%abs = select i1 %cmp, i32 %sub, i32 %a
%c1 = icmp slt i32 %abs, 20
store i1 %c1, ptr %p
%c2 = icmp slt i32 %abs, 19
store i1 %c2, ptr %p
%c3 = icmp sge i32 %abs, 0
store i1 %c3, ptr %p
%c4 = icmp sge i32 %abs, 1
store i1 %c4, ptr %p
br label %exit
exit:
ret void
}
define void @abs2(i32 %a, ptr %p) {
; CHECK-LABEL: @abs2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[A:%.*]], 10
; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i32 [[A]], -20
; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
; CHECK-NEXT: br i1 [[AND]], label [[GUARD:%.*]], label [[EXIT:%.*]]
; CHECK: guard:
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 0, [[A]]
; CHECK-NEXT: [[CMP:%.*]] = icmp sge i32 [[A]], 0
; CHECK-NEXT: [[ABS:%.*]] = select i1 [[CMP]], i32 [[A]], i32 [[SUB]]
; CHECK-NEXT: store i1 true, ptr [[P:%.*]], align 1
; CHECK-NEXT: [[C2:%.*]] = icmp ult i32 [[ABS]], 19
; CHECK-NEXT: store i1 [[C2]], ptr [[P]], align 1
; CHECK-NEXT: store i1 true, ptr [[P]], align 1
; CHECK-NEXT: [[C4:%.*]] = icmp uge i32 [[ABS]], 1
; CHECK-NEXT: store i1 [[C4]], ptr [[P]], align 1
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
%cmp1 = icmp slt i32 %a, 10
%cmp2 = icmp sgt i32 %a, -20
%and = and i1 %cmp1, %cmp2
br i1 %and, label %guard, label %exit
guard:
%sub = sub i32 0, %a
%cmp = icmp sge i32 %a, 0
%abs = select i1 %cmp, i32 %a, i32 %sub
%c1 = icmp slt i32 %abs, 20
store i1 %c1, ptr %p
%c2 = icmp slt i32 %abs, 19
store i1 %c2, ptr %p
%c3 = icmp sge i32 %abs, 0
store i1 %c3, ptr %p
%c4 = icmp sge i32 %abs, 1
store i1 %c4, ptr %p
br label %exit
exit:
ret void
}
define void @nabs1(i32 %a, ptr %p) {
; CHECK-LABEL: @nabs1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[A:%.*]], 10
; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i32 [[A]], -20
; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
; CHECK-NEXT: br i1 [[AND]], label [[GUARD:%.*]], label [[EXIT:%.*]]
; CHECK: guard:
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 0, [[A]]
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[A]], 0
; CHECK-NEXT: [[NABS:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 [[A]]
; CHECK-NEXT: store i1 true, ptr [[P:%.*]], align 1
; CHECK-NEXT: [[C2:%.*]] = icmp sgt i32 [[NABS]], -19
; CHECK-NEXT: store i1 [[C2]], ptr [[P]], align 1
; CHECK-NEXT: store i1 true, ptr [[P]], align 1
; CHECK-NEXT: [[C4:%.*]] = icmp sle i32 [[NABS]], -1
; CHECK-NEXT: store i1 [[C4]], ptr [[P]], align 1
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
%cmp1 = icmp slt i32 %a, 10
%cmp2 = icmp sgt i32 %a, -20
%and = and i1 %cmp1, %cmp2
br i1 %and, label %guard, label %exit
guard:
%sub = sub i32 0, %a
%cmp = icmp sgt i32 %a, 0
%nabs = select i1 %cmp, i32 %sub, i32 %a
%c1 = icmp sgt i32 %nabs, -20
store i1 %c1, ptr %p
%c2 = icmp sgt i32 %nabs, -19
store i1 %c2, ptr %p
%c3 = icmp sle i32 %nabs, 0
store i1 %c3, ptr %p
%c4 = icmp sle i32 %nabs, -1
store i1 %c4, ptr %p
br label %exit
exit:
ret void
}
define void @nabs2(i32 %a, ptr %p) {
; CHECK-LABEL: @nabs2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[A:%.*]], 10
; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i32 [[A]], -20
; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
; CHECK-NEXT: br i1 [[AND]], label [[GUARD:%.*]], label [[EXIT:%.*]]
; CHECK: guard:
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 0, [[A]]
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[A]], 0
; CHECK-NEXT: [[NABS:%.*]] = select i1 [[CMP]], i32 [[A]], i32 [[SUB]]
; CHECK-NEXT: store i1 true, ptr [[P:%.*]], align 1
; CHECK-NEXT: [[C2:%.*]] = icmp sgt i32 [[NABS]], -19
; CHECK-NEXT: store i1 [[C2]], ptr [[P]], align 1
; CHECK-NEXT: store i1 true, ptr [[P]], align 1
; CHECK-NEXT: [[C4:%.*]] = icmp sle i32 [[NABS]], -1
; CHECK-NEXT: store i1 [[C4]], ptr [[P]], align 1
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
%cmp1 = icmp slt i32 %a, 10
%cmp2 = icmp sgt i32 %a, -20
%and = and i1 %cmp1, %cmp2
br i1 %and, label %guard, label %exit
guard:
%sub = sub i32 0, %a
%cmp = icmp slt i32 %a, 0
%nabs = select i1 %cmp, i32 %a, i32 %sub
%c1 = icmp sgt i32 %nabs, -20
store i1 %c1, ptr %p
%c2 = icmp sgt i32 %nabs, -19
store i1 %c2, ptr %p
%c3 = icmp sle i32 %nabs, 0
store i1 %c3, ptr %p
%c4 = icmp sle i32 %nabs, -1
store i1 %c4, ptr %p
br label %exit
exit:
ret void
}
define i1 @zext_unknown(i8 %a) {
; CHECK-LABEL: @zext_unknown(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A32:%.*]] = zext i8 [[A:%.*]] to i32
; CHECK-NEXT: ret i1 true
;
entry:
%a32 = zext i8 %a to i32
%cmp = icmp sle i32 %a32, 256
ret i1 %cmp
}
define i1 @trunc_unknown(i32 %a) {
; CHECK-LABEL: @trunc_unknown(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A8:%.*]] = trunc i32 [[A:%.*]] to i8
; CHECK-NEXT: [[A32:%.*]] = sext i8 [[A8]] to i32
; CHECK-NEXT: ret i1 true
;
entry:
%a8 = trunc i32 %a to i8
%a32 = sext i8 %a8 to i32
%cmp = icmp sle i32 %a32, 128
ret i1 %cmp
}
define void @trunc_icmp_ule(i32 %x, ptr %p) {
; CHECK-LABEL: @trunc_icmp_ule(
; CHECK-NEXT: [[T:%.*]] = trunc i32 [[X:%.*]] to i8
; CHECK-NEXT: [[C:%.*]] = icmp uge i8 [[T]], 5
; CHECK-NEXT: br i1 [[C]], label [[TRUE:%.*]], label [[FALSE:%.*]]
; CHECK: true:
; CHECK-NEXT: store i1 true, ptr [[P:%.*]], align 1
; CHECK-NEXT: [[C2:%.*]] = icmp ugt i32 [[X]], 5
; CHECK-NEXT: store i1 [[C2]], ptr [[P]], align 1
; CHECK-NEXT: [[C3:%.*]] = icmp ule i32 [[X]], 5
; CHECK-NEXT: store i1 [[C3]], ptr [[P]], align 1
; CHECK-NEXT: store i1 false, ptr [[P]], align 1
; CHECK-NEXT: ret void
; CHECK: false:
; CHECK-NEXT: [[C1_2:%.*]] = icmp uge i32 [[X]], 5
; CHECK-NEXT: store i1 [[C1_2]], ptr [[P]], align 1
; CHECK-NEXT: [[C2_2:%.*]] = icmp ugt i32 [[X]], 5
; CHECK-NEXT: store i1 [[C2_2]], ptr [[P]], align 1
; CHECK-NEXT: [[C3_2:%.*]] = icmp ule i32 [[X]], 5
; CHECK-NEXT: store i1 [[C3_2]], ptr [[P]], align 1
; CHECK-NEXT: [[C4_2:%.*]] = icmp ult i32 [[X]], 5
; CHECK-NEXT: store i1 [[C4_2]], ptr [[P]], align 1
; CHECK-NEXT: ret void
;
%t = trunc i32 %x to i8
%c = icmp uge i8 %t, 5
br i1 %c, label %true, label %false
true:
%c1 = icmp uge i32 %x, 5
store i1 %c1, ptr %p
%c2 = icmp ugt i32 %x, 5
store i1 %c2, ptr %p
%c3 = icmp ule i32 %x, 5
store i1 %c3, ptr %p
%c4 = icmp ult i32 %x, 5
store i1 %c4, ptr %p
ret void
false:
%c1.2 = icmp uge i32 %x, 5
store i1 %c1.2, ptr %p
%c2.2 = icmp ugt i32 %x, 5
store i1 %c2.2, ptr %p
%c3.2 = icmp ule i32 %x, 5
store i1 %c3.2, ptr %p
%c4.2 = icmp ult i32 %x, 5
store i1 %c4.2, ptr %p
ret void
}
define void @trunc_icmp_eq(i32 %x, ptr %p) {
; CHECK-LABEL: @trunc_icmp_eq(
; CHECK-NEXT: [[T:%.*]] = trunc i32 [[X:%.*]] to i8
; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[T]], 5
; CHECK-NEXT: br i1 [[C]], label [[TRUE:%.*]], label [[FALSE:%.*]]
; CHECK: true:
; CHECK-NEXT: store i1 true, ptr [[P:%.*]], align 1
; CHECK-NEXT: [[C2:%.*]] = icmp ugt i32 [[X]], 5
; CHECK-NEXT: store i1 [[C2]], ptr [[P]], align 1
; CHECK-NEXT: [[C3:%.*]] = icmp ule i32 [[X]], 5
; CHECK-NEXT: store i1 [[C3]], ptr [[P]], align 1
; CHECK-NEXT: store i1 false, ptr [[P]], align 1
; CHECK-NEXT: ret void
; CHECK: false:
; CHECK-NEXT: [[C1_2:%.*]] = icmp uge i32 [[X]], 5
; CHECK-NEXT: store i1 [[C1_2]], ptr [[P]], align 1
; CHECK-NEXT: [[C2_2:%.*]] = icmp ugt i32 [[X]], 5
; CHECK-NEXT: store i1 [[C2_2]], ptr [[P]], align 1
; CHECK-NEXT: [[C3_2:%.*]] = icmp ule i32 [[X]], 5
; CHECK-NEXT: store i1 [[C3_2]], ptr [[P]], align 1
; CHECK-NEXT: [[C4_2:%.*]] = icmp ult i32 [[X]], 5
; CHECK-NEXT: store i1 [[C4_2]], ptr [[P]], align 1
; CHECK-NEXT: ret void
;
%t = trunc i32 %x to i8
%c = icmp eq i8 %t, 5
br i1 %c, label %true, label %false
true:
%c1 = icmp uge i32 %x, 5
store i1 %c1, ptr %p
%c2 = icmp ugt i32 %x, 5
store i1 %c2, ptr %p
%c3 = icmp ule i32 %x, 5
store i1 %c3, ptr %p
%c4 = icmp ult i32 %x, 5
store i1 %c4, ptr %p
ret void
false:
%c1.2 = icmp uge i32 %x, 5
store i1 %c1.2, ptr %p
%c2.2 = icmp ugt i32 %x, 5
store i1 %c2.2, ptr %p
%c3.2 = icmp ule i32 %x, 5
store i1 %c3.2, ptr %p
%c4.2 = icmp ult i32 %x, 5
store i1 %c4.2, ptr %p
ret void
}
; TODO: missed optimization
; Make sure we exercise non-integer inputs to unary operators (i.e. crash check).
define i1 @bitcast_unknown(float %a) {
; CHECK-LABEL: @bitcast_unknown(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A32:%.*]] = bitcast float [[A:%.*]] to i32
; CHECK-NEXT: [[CMP:%.*]] = icmp sle i32 [[A32]], 128
; CHECK-NEXT: ret i1 [[CMP]]
;
entry:
%a32 = bitcast float %a to i32
%cmp = icmp sle i32 %a32, 128
ret i1 %cmp
}
define i1 @bitcast_unknown2(ptr %p) {
; CHECK-LABEL: @bitcast_unknown2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[P64:%.*]] = ptrtoint ptr [[P:%.*]] to i64
; CHECK-NEXT: [[CMP:%.*]] = icmp sle i64 [[P64]], 128
; CHECK-NEXT: ret i1 [[CMP]]
;
entry:
%p64 = ptrtoint ptr %p to i64
%cmp = icmp sle i64 %p64, 128
ret i1 %cmp
}
define i1 @and_unknown(i32 %a) {
; CHECK-LABEL: @and_unknown(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[AND:%.*]] = and i32 [[A:%.*]], 128
; CHECK-NEXT: ret i1 true
;
entry:
%and = and i32 %a, 128
%cmp = icmp sle i32 %and, 128
ret i1 %cmp
}
define i1 @lshr_unknown(i32 %a) {
; CHECK-LABEL: @lshr_unknown(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[AND:%.*]] = lshr i32 [[A:%.*]], 30
; CHECK-NEXT: ret i1 true
;
entry:
%and = lshr i32 %a, 30
%cmp = icmp sle i32 %and, 128
ret i1 %cmp
}
define i1 @urem_unknown(i32 %a) {
; CHECK-LABEL: @urem_unknown(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[UREM:%.*]] = urem i32 [[A:%.*]], 30
; CHECK-NEXT: ret i1 true
;
entry:
%urem = urem i32 %a, 30
%cmp = icmp ult i32 %urem, 30
ret i1 %cmp
}
define i1 @srem_unknown(i32 %a) {
; CHECK-LABEL: @srem_unknown(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[SREM:%.*]] = srem i32 [[A:%.*]], 30
; CHECK-NEXT: br i1 undef, label [[EXIT1:%.*]], label [[EXIT2:%.*]]
; CHECK: exit1:
; CHECK-NEXT: ret i1 true
; CHECK: exit2:
; CHECK-NEXT: ret i1 true
;
entry:
%srem = srem i32 %a, 30
%cmp1 = icmp slt i32 %srem, 30
%cmp2 = icmp sgt i32 %srem, -30
br i1 undef, label %exit1, label %exit2
exit1:
ret i1 %cmp1
exit2:
ret i1 %cmp2
}
define i1 @sdiv_unknown(i32 %a) {
; CHECK-LABEL: @sdiv_unknown(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[SREM:%.*]] = sdiv i32 [[A:%.*]], 123
; CHECK-NEXT: br i1 undef, label [[EXIT1:%.*]], label [[EXIT2:%.*]]
; CHECK: exit1:
; CHECK-NEXT: ret i1 true
; CHECK: exit2:
; CHECK-NEXT: ret i1 true
;
entry:
%srem = sdiv i32 %a, 123
%cmp1 = icmp slt i32 %srem, 17459217
%cmp2 = icmp sgt i32 %srem, -17459217
br i1 undef, label %exit1, label %exit2
exit1:
ret i1 %cmp1
exit2:
ret i1 %cmp2
}
define i1 @uadd_sat_unknown(i32 %a) {
; CHECK-LABEL: @uadd_sat_unknown(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[VAL:%.*]] = call i32 @llvm.uadd.sat.i32(i32 [[A:%.*]], i32 100)
; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i32 [[VAL]], 100
; CHECK-NEXT: br i1 undef, label [[EXIT1:%.*]], label [[EXIT2:%.*]]
; CHECK: exit1:
; CHECK-NEXT: ret i1 true
; CHECK: exit2:
; CHECK-NEXT: ret i1 [[CMP2]]
;
entry:
%val = call i32 @llvm.uadd.sat.i32(i32 %a, i32 100)
%cmp1 = icmp uge i32 %val, 100
%cmp2 = icmp ugt i32 %val, 100
br i1 undef, label %exit1, label %exit2
exit1:
ret i1 %cmp1
exit2:
ret i1 %cmp2
}
define i1 @usub_sat_unknown(i32 %a) {
; CHECK-LABEL: @usub_sat_unknown(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[VAL:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[A:%.*]], i32 100)
; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 [[VAL]], -101
; CHECK-NEXT: br i1 undef, label [[EXIT1:%.*]], label [[EXIT2:%.*]]
; CHECK: exit1:
; CHECK-NEXT: ret i1 true
; CHECK: exit2:
; CHECK-NEXT: ret i1 [[CMP2]]
;
entry:
%val = call i32 @llvm.usub.sat.i32(i32 %a, i32 100)
%cmp1 = icmp ule i32 %val, 4294967195
%cmp2 = icmp ult i32 %val, 4294967195
br i1 undef, label %exit1, label %exit2
exit1:
ret i1 %cmp1
exit2:
ret i1 %cmp2
}
define i1 @sadd_sat_unknown(i32 %a) {
; CHECK-LABEL: @sadd_sat_unknown(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[VAL:%.*]] = call i32 @llvm.sadd.sat.i32(i32 [[A:%.*]], i32 100)
; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i32 [[VAL]], -2147483548
; CHECK-NEXT: br i1 undef, label [[EXIT1:%.*]], label [[EXIT2:%.*]]
; CHECK: exit1:
; CHECK-NEXT: ret i1 true
; CHECK: exit2:
; CHECK-NEXT: ret i1 [[CMP2]]
;
entry:
%val = call i32 @llvm.sadd.sat.i32(i32 %a, i32 100)
%cmp1 = icmp sge i32 %val, -2147483548
%cmp2 = icmp sgt i32 %val, -2147483548
br i1 undef, label %exit1, label %exit2
exit1:
ret i1 %cmp1
exit2:
ret i1 %cmp2
}
define i1 @ssub_sat_unknown(i32 %a) {
; CHECK-LABEL: @ssub_sat_unknown(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[VAL:%.*]] = call i32 @llvm.ssub.sat.i32(i32 [[A:%.*]], i32 100)
; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[VAL]], 2147483547
; CHECK-NEXT: br i1 undef, label [[EXIT1:%.*]], label [[EXIT2:%.*]]
; CHECK: exit1:
; CHECK-NEXT: ret i1 true
; CHECK: exit2:
; CHECK-NEXT: ret i1 [[CMP2]]
;
entry:
%val = call i32 @llvm.ssub.sat.i32(i32 %a, i32 100)
%cmp1 = icmp sle i32 %val, 2147483547
%cmp2 = icmp slt i32 %val, 2147483547
br i1 undef, label %exit1, label %exit2
exit1:
ret i1 %cmp1
exit2:
ret i1 %cmp2
}
define void @select_and(i32 %a, ptr %p) {
; CHECK-LABEL: @select_and(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[A:%.*]], -10
; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[A]], 10
; CHECK-NEXT: [[AND:%.*]] = select i1 [[CMP1]], i1 [[CMP2]], i1 false
; CHECK-NEXT: br i1 [[AND]], label [[GUARD:%.*]], label [[EXIT:%.*]]
; CHECK: guard:
; CHECK-NEXT: store i1 false, ptr [[P:%.*]], align 1
; CHECK-NEXT: store i1 false, ptr [[P]], align 1
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
%cmp1 = icmp sgt i32 %a, -10
%cmp2 = icmp slt i32 %a, 10
%and = select i1 %cmp1, i1 %cmp2, i1 false
br i1 %and, label %guard, label %exit
guard:
%c1 = icmp sgt i32 %a, 20
store i1 %c1, ptr %p
%c2 = icmp slt i32 %a, -20
store i1 %c2, ptr %p
br label %exit
exit:
ret void
}
define void @select_and_wrong_const(i32 %a, ptr %p) {
; CHECK-LABEL: @select_and_wrong_const(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[A:%.*]], -10
; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[A]], 10
; CHECK-NEXT: [[AND:%.*]] = select i1 [[CMP1]], i1 [[CMP2]], i1 true
; CHECK-NEXT: br i1 [[AND]], label [[GUARD:%.*]], label [[EXIT:%.*]]
; CHECK: guard:
; CHECK-NEXT: [[C1:%.*]] = icmp sgt i32 [[A]], 20
; CHECK-NEXT: store i1 [[C1]], ptr [[P:%.*]], align 1
; CHECK-NEXT: [[C2:%.*]] = icmp slt i32 [[A]], -20
; CHECK-NEXT: store i1 [[C2]], ptr [[P]], align 1
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
%cmp1 = icmp sgt i32 %a, -10
%cmp2 = icmp slt i32 %a, 10
%and = select i1 %cmp1, i1 %cmp2, i1 true
br i1 %and, label %guard, label %exit
guard:
%c1 = icmp sgt i32 %a, 20
store i1 %c1, ptr %p
%c2 = icmp slt i32 %a, -20
store i1 %c2, ptr %p
br label %exit
exit:
ret void
}
define void @select_and_wrong_operand(i32 %a, ptr %p) {
; CHECK-LABEL: @select_and_wrong_operand(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[A:%.*]], -10
; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[A]], 10
; CHECK-NEXT: [[AND:%.*]] = select i1 [[CMP1]], i1 false, i1 [[CMP2]]
; CHECK-NEXT: br i1 [[AND]], label [[GUARD:%.*]], label [[EXIT:%.*]]
; CHECK: guard:
; CHECK-NEXT: [[C1:%.*]] = icmp sgt i32 [[A]], 20
; CHECK-NEXT: store i1 [[C1]], ptr [[P:%.*]], align 1
; CHECK-NEXT: [[C2:%.*]] = icmp slt i32 [[A]], -20
; CHECK-NEXT: store i1 [[C2]], ptr [[P]], align 1
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
%cmp1 = icmp sgt i32 %a, -10
%cmp2 = icmp slt i32 %a, 10
%and = select i1 %cmp1, i1 false, i1 %cmp2
br i1 %and, label %guard, label %exit
guard:
%c1 = icmp sgt i32 %a, 20
store i1 %c1, ptr %p
%c2 = icmp slt i32 %a, -20
store i1 %c2, ptr %p
br label %exit
exit:
ret void
}
define void @select_or(i32 %a, ptr %p) {
; CHECK-LABEL: @select_or(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[A:%.*]], -10
; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i32 [[A]], 10
; CHECK-NEXT: [[OR:%.*]] = select i1 [[CMP1]], i1 true, i1 [[CMP2]]
; CHECK-NEXT: br i1 [[OR]], label [[EXIT:%.*]], label [[GUARD:%.*]]
; CHECK: guard:
; CHECK-NEXT: store i1 false, ptr [[P:%.*]], align 1
; CHECK-NEXT: store i1 false, ptr [[P]], align 1
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
%cmp1 = icmp slt i32 %a, -10
%cmp2 = icmp sgt i32 %a, 10
%or = select i1 %cmp1, i1 true, i1 %cmp2
br i1 %or, label %exit, label %guard
guard:
%c1 = icmp sgt i32 %a, 20
store i1 %c1, ptr %p
%c2 = icmp slt i32 %a, -20
store i1 %c2, ptr %p
br label %exit
exit:
ret void
}
define void @select_or_wrong_const(i32 %a, ptr %p) {
; CHECK-LABEL: @select_or_wrong_const(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[A:%.*]], -10
; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i32 [[A]], 10
; CHECK-NEXT: [[OR:%.*]] = select i1 [[CMP1]], i1 false, i1 [[CMP2]]
; CHECK-NEXT: br i1 [[OR]], label [[EXIT:%.*]], label [[GUARD:%.*]]
; CHECK: guard:
; CHECK-NEXT: [[C1:%.*]] = icmp sgt i32 [[A]], 20
; CHECK-NEXT: store i1 [[C1]], ptr [[P:%.*]], align 1
; CHECK-NEXT: [[C2:%.*]] = icmp slt i32 [[A]], -20
; CHECK-NEXT: store i1 [[C2]], ptr [[P]], align 1
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
%cmp1 = icmp slt i32 %a, -10
%cmp2 = icmp sgt i32 %a, 10
%or = select i1 %cmp1, i1 false, i1 %cmp2
br i1 %or, label %exit, label %guard
guard:
%c1 = icmp sgt i32 %a, 20
store i1 %c1, ptr %p
%c2 = icmp slt i32 %a, -20
store i1 %c2, ptr %p
br label %exit
exit:
ret void
}
define void @select_or_wrong_operand(i32 %a, ptr %p) {
; CHECK-LABEL: @select_or_wrong_operand(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[A:%.*]], -10
; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i32 [[A]], 10
; CHECK-NEXT: [[OR:%.*]] = select i1 [[CMP1]], i1 [[CMP2]], i1 true
; CHECK-NEXT: br i1 [[OR]], label [[EXIT:%.*]], label [[GUARD:%.*]]
; CHECK: guard:
; CHECK-NEXT: [[C1:%.*]] = icmp sgt i32 [[A]], 20
; CHECK-NEXT: store i1 [[C1]], ptr [[P:%.*]], align 1
; CHECK-NEXT: [[C2:%.*]] = icmp slt i32 [[A]], -20
; CHECK-NEXT: store i1 [[C2]], ptr [[P]], align 1
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
%cmp1 = icmp slt i32 %a, -10
%cmp2 = icmp sgt i32 %a, 10
%or = select i1 %cmp1, i1 %cmp2, i1 true
br i1 %or, label %exit, label %guard
guard:
%c1 = icmp sgt i32 %a, 20
store i1 %c1, ptr %p
%c2 = icmp slt i32 %a, -20
store i1 %c2, ptr %p
br label %exit
exit:
ret void
}
define void @or_union(i32 %a, ptr %p) {
; CHECK-LABEL: @or_union(
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[A:%.*]], 10
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[A]], 12
; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]]
; CHECK-NEXT: br i1 [[OR]], label [[GUARD:%.*]], label [[EXIT:%.*]]
; CHECK: guard:
; CHECK-NEXT: store i1 false, ptr [[P:%.*]], align 1
; CHECK-NEXT: [[C2:%.*]] = icmp eq i32 [[A]], 10
; CHECK-NEXT: store i1 [[C2]], ptr [[P]], align 1
; CHECK-NEXT: [[C3:%.*]] = icmp eq i32 [[A]], 11
; CHECK-NEXT: store i1 [[C3]], ptr [[P]], align 1
; CHECK-NEXT: [[C4:%.*]] = icmp eq i32 [[A]], 12
; CHECK-NEXT: store i1 [[C4]], ptr [[P]], align 1
; CHECK-NEXT: store i1 false, ptr [[P]], align 1
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
%cmp1 = icmp eq i32 %a, 10
%cmp2 = icmp eq i32 %a, 12
%or = or i1 %cmp1, %cmp2
br i1 %or, label %guard, label %exit
guard:
%c1 = icmp eq i32 %a, 9
store i1 %c1, ptr %p
%c2 = icmp eq i32 %a, 10
store i1 %c2, ptr %p
%c3 = icmp eq i32 %a, 11
store i1 %c3, ptr %p
%c4 = icmp eq i32 %a, 12
store i1 %c4, ptr %p
%c5 = icmp eq i32 %a, 13
store i1 %c5, ptr %p
br label %exit
exit:
ret void
}
define i1 @or_union_unknown_cond(i32 %a, i1 %c) {
; CHECK-LABEL: @or_union_unknown_cond(
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[A:%.*]], 10
; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[C:%.*]]
; CHECK-NEXT: br i1 [[OR]], label [[GUARD:%.*]], label [[EXIT:%.*]]
; CHECK: guard:
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[A]], 10
; CHECK-NEXT: ret i1 [[CMP2]]
; CHECK: exit:
; CHECK-NEXT: ret i1 false
;
%cmp1 = icmp eq i32 %a, 10
%or = or i1 %cmp1, %c
br i1 %or, label %guard, label %exit
guard:
%cmp2 = icmp eq i32 %a, 10
ret i1 %cmp2
exit:
ret i1 false
}
define void @and_union(i32 %a, ptr %p) {
; CHECK-LABEL: @and_union(
; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[A:%.*]], 10
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i32 [[A]], 12
; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
; CHECK-NEXT: br i1 [[AND]], label [[EXIT:%.*]], label [[GUARD:%.*]]
; CHECK: guard:
; CHECK-NEXT: store i1 false, ptr [[P:%.*]], align 1
; CHECK-NEXT: [[C2:%.*]] = icmp eq i32 [[A]], 10
; CHECK-NEXT: store i1 [[C2]], ptr [[P]], align 1
; CHECK-NEXT: [[C3:%.*]] = icmp eq i32 [[A]], 11
; CHECK-NEXT: store i1 [[C3]], ptr [[P]], align 1
; CHECK-NEXT: [[C4:%.*]] = icmp eq i32 [[A]], 12
; CHECK-NEXT: store i1 [[C4]], ptr [[P]], align 1
; CHECK-NEXT: store i1 false, ptr [[P]], align 1
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
%cmp1 = icmp ne i32 %a, 10
%cmp2 = icmp ne i32 %a, 12
%and = and i1 %cmp1, %cmp2
br i1 %and, label %exit, label %guard
guard:
%c1 = icmp eq i32 %a, 9
store i1 %c1, ptr %p
%c2 = icmp eq i32 %a, 10
store i1 %c2, ptr %p
%c3 = icmp eq i32 %a, 11
store i1 %c3, ptr %p
%c4 = icmp eq i32 %a, 12
store i1 %c4, ptr %p
%c5 = icmp eq i32 %a, 13
store i1 %c5, ptr %p
br label %exit
exit:
ret void
}
define i1 @and_union_unknown_cond(i32 %a, i1 %c) {
; CHECK-LABEL: @and_union_unknown_cond(
; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[A:%.*]], 10
; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[C:%.*]]
; CHECK-NEXT: br i1 [[AND]], label [[EXIT:%.*]], label [[GUARD:%.*]]
; CHECK: guard:
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[A]], 10
; CHECK-NEXT: ret i1 [[CMP2]]
; CHECK: exit:
; CHECK-NEXT: ret i1 false
;
%cmp1 = icmp ne i32 %a, 10
%and = and i1 %cmp1, %c
br i1 %and, label %exit, label %guard
guard:
%cmp2 = icmp eq i32 %a, 10
ret i1 %cmp2
exit:
ret i1 false
}
define void @select_assume(i32 %a, i32 %b, i1 %c, ptr %p) {
; CHECK-LABEL: @select_assume(
; CHECK-NEXT: [[C1:%.*]] = icmp ult i32 [[A:%.*]], 10
; CHECK-NEXT: call void @llvm.assume(i1 [[C1]])
; CHECK-NEXT: [[C2:%.*]] = icmp ult i32 [[B:%.*]], 20
; CHECK-NEXT: call void @llvm.assume(i1 [[C2]])
; CHECK-NEXT: [[S:%.*]] = select i1 [[C:%.*]], i32 [[A]], i32 [[B]]
; CHECK-NEXT: [[C3:%.*]] = icmp ult i32 [[S]], 19
; CHECK-NEXT: store i1 [[C3]], ptr [[P:%.*]], align 1
; CHECK-NEXT: store i1 true, ptr [[P]], align 1
; CHECK-NEXT: ret void
;
%c1 = icmp ult i32 %a, 10
call void @llvm.assume(i1 %c1)
%c2 = icmp ult i32 %b, 20
call void @llvm.assume(i1 %c2)
%s = select i1 %c, i32 %a, i32 %b
%c3 = icmp ult i32 %s, 19
store i1 %c3, ptr %p
%c4 = icmp ult i32 %s, 20
store i1 %c4, ptr %p
ret void
}
define void @xor(i8 %a, ptr %p) {
; CHECK-LABEL: @xor(
; CHECK-NEXT: [[A_MASK:%.*]] = and i8 [[A:%.*]], 15
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[A_MASK]], -86
; CHECK-NEXT: store i1 true, ptr [[P:%.*]], align 1
; CHECK-NEXT: [[C2:%.*]] = icmp ugt i8 [[XOR]], -96
; CHECK-NEXT: store i1 [[C2]], ptr [[P]], align 1
; CHECK-NEXT: store i1 true, ptr [[P]], align 1
; CHECK-NEXT: [[C4:%.*]] = icmp ult i8 [[XOR]], -81
; CHECK-NEXT: store i1 [[C4]], ptr [[P]], align 1
; CHECK-NEXT: ret void
;
%a.mask = and i8 %a, 15 ; 0b0000????
%xor = xor i8 %a.mask, 170 ; ^ 0b10101010 == 0b1010????
%c1 = icmp uge i8 %xor, 160
store i1 %c1, ptr %p
%c2 = icmp ugt i8 %xor, 160
store i1 %c2, ptr %p
%c3 = icmp ule i8 %xor, 175
store i1 %c3, ptr %p
%c4 = icmp ult i8 %xor, 175
store i1 %c4, ptr %p
ret void
}
define i1 @xor_neg_cond(i32 %a) {
; CHECK-LABEL: @xor_neg_cond(
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[A:%.*]], 10
; CHECK-NEXT: [[XOR:%.*]] = xor i1 [[CMP1]], true
; CHECK-NEXT: br i1 [[XOR]], label [[EXIT:%.*]], label [[GUARD:%.*]]
; CHECK: guard:
; CHECK-NEXT: ret i1 true
; CHECK: exit:
; CHECK-NEXT: ret i1 false
;
%cmp1 = icmp eq i32 %a, 10
%xor = xor i1 %cmp1, true
br i1 %xor, label %exit, label %guard
guard:
%cmp2 = icmp eq i32 %a, 10
ret i1 %cmp2
exit:
ret i1 false
}
define i1 @xor_approx(i32 %a) {
; CHECK-LABEL: @xor_approx(
; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i32 [[A:%.*]], 2
; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 [[A]], 5
; CHECK-NEXT: [[CMP3:%.*]] = icmp ugt i32 [[A]], 7
; CHECK-NEXT: [[CMP4:%.*]] = icmp ult i32 [[A]], 9
; CHECK-NEXT: [[AND1:%.*]] = and i1 [[CMP1]], [[CMP2]]
; CHECK-NEXT: [[AND2:%.*]] = and i1 [[CMP3]], [[CMP4]]
; CHECK-NEXT: [[OR:%.*]] = or i1 [[AND1]], [[AND2]]
; CHECK-NEXT: [[XOR:%.*]] = xor i1 [[OR]], true
; CHECK-NEXT: br i1 [[XOR]], label [[EXIT:%.*]], label [[GUARD:%.*]]
; CHECK: guard:
; CHECK-NEXT: [[CMP5:%.*]] = icmp eq i32 [[A]], 6
; CHECK-NEXT: ret i1 [[CMP5]]
; CHECK: exit:
; CHECK-NEXT: ret i1 false
;
%cmp1 = icmp ugt i32 %a, 2
%cmp2 = icmp ult i32 %a, 5
%cmp3 = icmp ugt i32 %a, 7
%cmp4 = icmp ult i32 %a, 9
%and1 = and i1 %cmp1, %cmp2
%and2 = and i1 %cmp3, %cmp4
%or = or i1 %and1, %and2
%xor = xor i1 %or, true
br i1 %xor, label %exit, label %guard
guard:
%cmp5 = icmp eq i32 %a, 6
ret i1 %cmp5
exit:
ret i1 false
}
declare i32 @llvm.uadd.sat.i32(i32, i32)
declare i32 @llvm.usub.sat.i32(i32, i32)
declare i32 @llvm.sadd.sat.i32(i32, i32)
declare i32 @llvm.ssub.sat.i32(i32, i32)
declare void @llvm.assume(i1)