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
1918 lines
52 KiB
LLVM
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)
|