Most of this is fairly straight forward. Add handling for min/max via existing matcher utility and ConstantRange routines. Add handling for clamp by exploiting condition constraints on inputs. Note that I'm only handling two constant ranges at this point. It would be reasonable to consider treating overdefined as a full range if the instruction is typed as an integer, but that should be a separate change. Differential Revision: http://reviews.llvm.org/D17184 llvm-svn: 262085
395 lines
7.7 KiB
LLVM
395 lines
7.7 KiB
LLVM
; RUN: opt < %s -correlated-propagation -S | FileCheck %s
|
|
; PR2581
|
|
|
|
; CHECK-LABEL: @test1(
|
|
define i32 @test1(i1 %C) nounwind {
|
|
br i1 %C, label %exit, label %body
|
|
|
|
body: ; preds = %0
|
|
; CHECK-NOT: select
|
|
%A = select i1 %C, i32 10, i32 11 ; <i32> [#uses=1]
|
|
; CHECK: ret i32 11
|
|
ret i32 %A
|
|
|
|
exit: ; preds = %0
|
|
; CHECK: ret i32 10
|
|
ret i32 10
|
|
}
|
|
|
|
; PR4420
|
|
declare i1 @ext()
|
|
; CHECK-LABEL: @test2(
|
|
define i1 @test2() {
|
|
entry:
|
|
%cond = tail call i1 @ext() ; <i1> [#uses=2]
|
|
br i1 %cond, label %bb1, label %bb2
|
|
|
|
bb1: ; preds = %entry
|
|
%cond2 = tail call i1 @ext() ; <i1> [#uses=1]
|
|
br i1 %cond2, label %bb3, label %bb2
|
|
|
|
bb2: ; preds = %bb1, %entry
|
|
; CHECK-NOT: phi i1
|
|
%cond_merge = phi i1 [ %cond, %entry ], [ false, %bb1 ] ; <i1> [#uses=1]
|
|
; CHECK: ret i1 false
|
|
ret i1 %cond_merge
|
|
|
|
bb3: ; preds = %bb1
|
|
%res = tail call i1 @ext() ; <i1> [#uses=1]
|
|
; CHECK: ret i1 %res
|
|
ret i1 %res
|
|
}
|
|
|
|
; PR4855
|
|
@gv = internal constant i8 7
|
|
; CHECK-LABEL: @test3(
|
|
define i8 @test3(i8* %a) nounwind {
|
|
entry:
|
|
%cond = icmp eq i8* %a, @gv
|
|
br i1 %cond, label %bb2, label %bb
|
|
|
|
bb: ; preds = %entry
|
|
ret i8 0
|
|
|
|
bb2: ; preds = %entry
|
|
; CHECK: %should_be_const = load i8, i8* @gv
|
|
%should_be_const = load i8, i8* %a
|
|
ret i8 %should_be_const
|
|
}
|
|
|
|
; PR1757
|
|
; CHECK-LABEL: @test4(
|
|
define i32 @test4(i32) {
|
|
EntryBlock:
|
|
; CHECK: icmp sgt i32 %0, 2
|
|
%.demorgan = icmp sgt i32 %0, 2
|
|
br i1 %.demorgan, label %GreaterThanTwo, label %LessThanOrEqualToTwo
|
|
|
|
GreaterThanTwo:
|
|
; CHECK-NOT: icmp eq i32 %0, 2
|
|
icmp eq i32 %0, 2
|
|
; CHECK: br i1 false
|
|
br i1 %1, label %Impossible, label %NotTwoAndGreaterThanTwo
|
|
|
|
NotTwoAndGreaterThanTwo:
|
|
ret i32 2
|
|
|
|
Impossible:
|
|
ret i32 1
|
|
|
|
LessThanOrEqualToTwo:
|
|
ret i32 0
|
|
}
|
|
|
|
declare i32* @f(i32*)
|
|
define void @test5(i32* %x, i32* %y) {
|
|
; CHECK-LABEL: @test5(
|
|
entry:
|
|
%pre = icmp eq i32* %x, null
|
|
br i1 %pre, label %return, label %loop
|
|
|
|
loop:
|
|
%phi = phi i32* [ %sel, %loop ], [ %x, %entry ]
|
|
; CHECK: %phi = phi i32* [ %f, %loop ], [ %x, %entry ]
|
|
%f = tail call i32* @f(i32* %phi)
|
|
%cmp1 = icmp ne i32* %f, %y
|
|
%sel = select i1 %cmp1, i32* %f, i32* null
|
|
%cmp2 = icmp eq i32* %sel, null
|
|
br i1 %cmp2, label %return, label %loop
|
|
|
|
return:
|
|
ret void
|
|
}
|
|
|
|
define i32 @switch1(i32 %s) {
|
|
; CHECK-LABEL: @switch1(
|
|
entry:
|
|
%cmp = icmp slt i32 %s, 0
|
|
br i1 %cmp, label %negative, label %out
|
|
|
|
negative:
|
|
switch i32 %s, label %out [
|
|
; CHECK: switch i32 %s, label %out
|
|
i32 0, label %out
|
|
; CHECK-NOT: i32 0
|
|
i32 1, label %out
|
|
; CHECK-NOT: i32 1
|
|
i32 -1, label %next
|
|
; CHECK: i32 -1, label %next
|
|
i32 -2, label %next
|
|
; CHECK: i32 -2, label %next
|
|
i32 2, label %out
|
|
; CHECK-NOT: i32 2
|
|
i32 3, label %out
|
|
; CHECK-NOT: i32 3
|
|
]
|
|
|
|
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(
|
|
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
|
|
]
|
|
; CHECK: br label %out
|
|
|
|
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(
|
|
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
|
|
]
|
|
; CHECK: br label %out
|
|
|
|
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(
|
|
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
|
|
]
|
|
; CHECK: br label %next
|
|
|
|
out:
|
|
ret void
|
|
|
|
next:
|
|
ret void
|
|
}
|
|
|
|
define i1 @umin(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @umin(
|
|
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
|
|
br label %next
|
|
next:
|
|
; CHECK: next:
|
|
; CHECK: ret i1 false
|
|
ret i1 %res
|
|
out:
|
|
ret i1 false
|
|
}
|
|
|
|
define i1 @smin(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @smin(
|
|
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
|
|
br label %next
|
|
next:
|
|
; CHECK: next:
|
|
; CHECK: ret i1 false
|
|
ret i1 %res
|
|
out:
|
|
ret i1 false
|
|
}
|
|
|
|
define i1 @smax(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @smax(
|
|
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
|
|
br label %next
|
|
next:
|
|
; CHECK: next:
|
|
; CHECK: ret i1 false
|
|
ret i1 %res
|
|
out:
|
|
ret i1 false
|
|
}
|
|
|
|
define i1 @umax(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @umax(
|
|
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
|
|
br label %next
|
|
next:
|
|
; CHECK: next:
|
|
; CHECK: ret i1 false
|
|
ret i1 %res
|
|
out:
|
|
ret i1 false
|
|
}
|
|
|
|
define i1 @clamp_low1(i32 %a) {
|
|
; CHECK-LABEL: @clamp_low1(
|
|
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 %a
|
|
%res = icmp eq i32 %sel, 4
|
|
br label %next
|
|
next:
|
|
; CHECK: next:
|
|
; CHECK: ret i1 false
|
|
ret i1 %res
|
|
out:
|
|
ret i1 false
|
|
}
|
|
|
|
define i1 @clamp_low2(i32 %a) {
|
|
; CHECK-LABEL: @clamp_low2(
|
|
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 %a, i32 5
|
|
%res = icmp eq i32 %sel, 4
|
|
br label %next
|
|
next:
|
|
; CHECK: next:
|
|
; CHECK: ret i1 false
|
|
ret i1 %res
|
|
out:
|
|
ret i1 false
|
|
}
|
|
|
|
define i1 @clamp_high1(i32 %a) {
|
|
; CHECK-LABEL: @clamp_high1(
|
|
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 %a
|
|
%res = icmp eq i32 %sel, 6
|
|
br label %next
|
|
next:
|
|
; CHECK: next:
|
|
; CHECK: ret i1 false
|
|
ret i1 %res
|
|
out:
|
|
ret i1 false
|
|
}
|
|
|
|
define i1 @clamp_high2(i32 %a) {
|
|
; CHECK-LABEL: @clamp_high2(
|
|
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 %a, i32 5
|
|
%res = icmp eq i32 %sel, 6
|
|
br label %next
|
|
next:
|
|
; CHECK: next:
|
|
; CHECK: ret i1 false
|
|
ret i1 %res
|
|
out:
|
|
ret i1 false
|
|
}
|
|
|
|
; Just showing arbitrary constants work, not really a clamp
|
|
define i1 @clamp_high3(i32 %a) {
|
|
; CHECK-LABEL: @clamp_high3(
|
|
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 %a, i32 5
|
|
%res = icmp eq i32 %sel, 105
|
|
br label %next
|
|
next:
|
|
; CHECK: next:
|
|
; CHECK: ret i1 false
|
|
ret i1 %res
|
|
out:
|
|
ret i1 false
|
|
}
|