Please use GitHub pull requests for new patches. Avoid migrating existing patches. Phabricator shutdown timeline
Changeset View
Changeset View
Standalone View
Standalone View
llvm/trunk/test/Transforms/GVNSink/sink-common-code.ll
; RUN: opt < %s -gvn-sink -simplifycfg -simplifycfg-sink-common=false -S | FileCheck %s | |||||
define zeroext i1 @test1(i1 zeroext %flag, i32 %blksA, i32 %blksB, i32 %nblks) { | |||||
entry: | |||||
br i1 %flag, label %if.then, label %if.else | |||||
; CHECK-LABEL: test1 | |||||
; CHECK: add | |||||
; CHECK: select | |||||
; CHECK: icmp | |||||
; CHECK-NOT: br | |||||
if.then: | |||||
%cmp = icmp uge i32 %blksA, %nblks | |||||
%frombool1 = zext i1 %cmp to i8 | |||||
br label %if.end | |||||
if.else: | |||||
%add = add i32 %nblks, %blksB | |||||
%cmp2 = icmp ule i32 %add, %blksA | |||||
%frombool3 = zext i1 %cmp2 to i8 | |||||
br label %if.end | |||||
if.end: | |||||
%obeys.0 = phi i8 [ %frombool1, %if.then ], [ %frombool3, %if.else ] | |||||
%tobool4 = icmp ne i8 %obeys.0, 0 | |||||
ret i1 %tobool4 | |||||
} | |||||
define zeroext i1 @test2(i1 zeroext %flag, i32 %blksA, i32 %blksB, i32 %nblks) { | |||||
entry: | |||||
br i1 %flag, label %if.then, label %if.else | |||||
; CHECK-LABEL: test2 | |||||
; CHECK: add | |||||
; CHECK: select | |||||
; CHECK: icmp | |||||
; CHECK-NOT: br | |||||
if.then: | |||||
%cmp = icmp uge i32 %blksA, %nblks | |||||
%frombool1 = zext i1 %cmp to i8 | |||||
br label %if.end | |||||
if.else: | |||||
%add = add i32 %nblks, %blksB | |||||
%cmp2 = icmp uge i32 %blksA, %add | |||||
%frombool3 = zext i1 %cmp2 to i8 | |||||
br label %if.end | |||||
if.end: | |||||
%obeys.0 = phi i8 [ %frombool1, %if.then ], [ %frombool3, %if.else ] | |||||
%tobool4 = icmp ne i8 %obeys.0, 0 | |||||
ret i1 %tobool4 | |||||
} | |||||
declare i32 @foo(i32, i32) nounwind readnone | |||||
define i32 @test3(i1 zeroext %flag, i32 %x, i32 %y) { | |||||
entry: | |||||
br i1 %flag, label %if.then, label %if.else | |||||
if.then: | |||||
%x0 = call i32 @foo(i32 %x, i32 0) nounwind readnone | |||||
%y0 = call i32 @foo(i32 %x, i32 1) nounwind readnone | |||||
br label %if.end | |||||
if.else: | |||||
%x1 = call i32 @foo(i32 %y, i32 0) nounwind readnone | |||||
%y1 = call i32 @foo(i32 %y, i32 1) nounwind readnone | |||||
br label %if.end | |||||
if.end: | |||||
%xx = phi i32 [ %x0, %if.then ], [ %x1, %if.else ] | |||||
%yy = phi i32 [ %y0, %if.then ], [ %y1, %if.else ] | |||||
%ret = add i32 %xx, %yy | |||||
ret i32 %ret | |||||
} | |||||
; CHECK-LABEL: test3 | |||||
; CHECK: select | |||||
; CHECK: call | |||||
; CHECK: call | |||||
; CHECK: add | |||||
; CHECK-NOT: br | |||||
define i32 @test4(i1 zeroext %flag, i32 %x, i32* %y) { | |||||
entry: | |||||
br i1 %flag, label %if.then, label %if.else | |||||
if.then: | |||||
%a = add i32 %x, 5 | |||||
store i32 %a, i32* %y | |||||
br label %if.end | |||||
if.else: | |||||
%b = add i32 %x, 7 | |||||
store i32 %b, i32* %y | |||||
br label %if.end | |||||
if.end: | |||||
ret i32 1 | |||||
} | |||||
; CHECK-LABEL: test4 | |||||
; CHECK: select | |||||
; CHECK: store | |||||
; CHECK-NOT: store | |||||
define i32 @test5(i1 zeroext %flag, i32 %x, i32* %y) { | |||||
entry: | |||||
br i1 %flag, label %if.then, label %if.else | |||||
if.then: | |||||
%a = add i32 %x, 5 | |||||
store volatile i32 %a, i32* %y | |||||
br label %if.end | |||||
if.else: | |||||
%b = add i32 %x, 7 | |||||
store i32 %b, i32* %y | |||||
br label %if.end | |||||
if.end: | |||||
ret i32 1 | |||||
} | |||||
; CHECK-LABEL: test5 | |||||
; CHECK: store volatile | |||||
; CHECK: store | |||||
define i32 @test6(i1 zeroext %flag, i32 %x, i32* %y) { | |||||
entry: | |||||
br i1 %flag, label %if.then, label %if.else | |||||
if.then: | |||||
%a = add i32 %x, 5 | |||||
store volatile i32 %a, i32* %y | |||||
br label %if.end | |||||
if.else: | |||||
%b = add i32 %x, 7 | |||||
store volatile i32 %b, i32* %y | |||||
br label %if.end | |||||
if.end: | |||||
ret i32 1 | |||||
} | |||||
; CHECK-LABEL: test6 | |||||
; CHECK: select | |||||
; CHECK: store volatile | |||||
; CHECK-NOT: store | |||||
define i32 @test7(i1 zeroext %flag, i32 %x, i32* %y) { | |||||
entry: | |||||
br i1 %flag, label %if.then, label %if.else | |||||
if.then: | |||||
%z = load volatile i32, i32* %y | |||||
%a = add i32 %z, 5 | |||||
store volatile i32 %a, i32* %y | |||||
br label %if.end | |||||
if.else: | |||||
%w = load volatile i32, i32* %y | |||||
%b = add i32 %w, 7 | |||||
store volatile i32 %b, i32* %y | |||||
br label %if.end | |||||
if.end: | |||||
ret i32 1 | |||||
} | |||||
; CHECK-LABEL: test7 | |||||
; CHECK-DAG: select | |||||
; CHECK-DAG: load volatile | |||||
; CHECK: store volatile | |||||
; CHECK-NOT: load | |||||
; CHECK-NOT: store | |||||
; The extra store in %if.then means %z and %w are not equivalent. | |||||
define i32 @test9(i1 zeroext %flag, i32 %x, i32* %y, i32* %p) { | |||||
entry: | |||||
br i1 %flag, label %if.then, label %if.else | |||||
if.then: | |||||
store i32 7, i32* %p | |||||
%z = load volatile i32, i32* %y | |||||
store i32 6, i32* %p | |||||
%a = add i32 %z, 5 | |||||
store volatile i32 %a, i32* %y | |||||
br label %if.end | |||||
if.else: | |||||
%w = load volatile i32, i32* %y | |||||
%b = add i32 %w, 7 | |||||
store volatile i32 %b, i32* %y | |||||
br label %if.end | |||||
if.end: | |||||
ret i32 1 | |||||
} | |||||
; CHECK-LABEL: test9 | |||||
; CHECK: add | |||||
; CHECK: add | |||||
%struct.anon = type { i32, i32 } | |||||
; The GEP indexes a struct type so cannot have a variable last index. | |||||
define i32 @test10(i1 zeroext %flag, i32 %x, i32* %y, %struct.anon* %s) { | |||||
entry: | |||||
br i1 %flag, label %if.then, label %if.else | |||||
if.then: | |||||
%dummy = add i32 %x, 5 | |||||
%gepa = getelementptr inbounds %struct.anon, %struct.anon* %s, i32 0, i32 0 | |||||
store volatile i32 %x, i32* %gepa | |||||
br label %if.end | |||||
if.else: | |||||
%dummy1 = add i32 %x, 6 | |||||
%gepb = getelementptr inbounds %struct.anon, %struct.anon* %s, i32 0, i32 1 | |||||
store volatile i32 %x, i32* %gepb | |||||
br label %if.end | |||||
if.end: | |||||
ret i32 1 | |||||
} | |||||
; CHECK-LABEL: test10 | |||||
; CHECK: getelementptr | |||||
; CHECK: store volatile | |||||
; CHECK: getelementptr | |||||
; CHECK: store volatile | |||||
; The shufflevector's mask operand cannot be merged in a PHI. | |||||
define i32 @test11(i1 zeroext %flag, i32 %w, <2 x i32> %x, <2 x i32> %y) { | |||||
entry: | |||||
br i1 %flag, label %if.then, label %if.else | |||||
if.then: | |||||
%dummy = add i32 %w, 5 | |||||
%sv1 = shufflevector <2 x i32> %x, <2 x i32> %y, <2 x i32> <i32 0, i32 1> | |||||
br label %if.end | |||||
if.else: | |||||
%dummy1 = add i32 %w, 6 | |||||
%sv2 = shufflevector <2 x i32> %x, <2 x i32> %y, <2 x i32> <i32 1, i32 0> | |||||
br label %if.end | |||||
if.end: | |||||
%p = phi <2 x i32> [ %sv1, %if.then ], [ %sv2, %if.else ] | |||||
ret i32 1 | |||||
} | |||||
; CHECK-LABEL: test11 | |||||
; CHECK: shufflevector | |||||
; CHECK: shufflevector | |||||
; We can't common an intrinsic! | |||||
define i32 @test12(i1 zeroext %flag, i32 %w, i32 %x, i32 %y) { | |||||
entry: | |||||
br i1 %flag, label %if.then, label %if.else | |||||
if.then: | |||||
%dummy = add i32 %w, 5 | |||||
%sv1 = call i32 @llvm.ctlz.i32(i32 %x) | |||||
br label %if.end | |||||
if.else: | |||||
%dummy1 = add i32 %w, 6 | |||||
%sv2 = call i32 @llvm.cttz.i32(i32 %x) | |||||
br label %if.end | |||||
if.end: | |||||
%p = phi i32 [ %sv1, %if.then ], [ %sv2, %if.else ] | |||||
ret i32 1 | |||||
} | |||||
declare i32 @llvm.ctlz.i32(i32 %x) readnone | |||||
declare i32 @llvm.cttz.i32(i32 %x) readnone | |||||
; CHECK-LABEL: test12 | |||||
; CHECK: call i32 @llvm.ctlz | |||||
; CHECK: call i32 @llvm.cttz | |||||
; The TBAA metadata should be properly combined. | |||||
define i32 @test13(i1 zeroext %flag, i32 %x, i32* %y) { | |||||
entry: | |||||
br i1 %flag, label %if.then, label %if.else | |||||
if.then: | |||||
%z = load volatile i32, i32* %y | |||||
%a = add i32 %z, 5 | |||||
store volatile i32 %a, i32* %y, !tbaa !3 | |||||
br label %if.end | |||||
if.else: | |||||
%w = load volatile i32, i32* %y | |||||
%b = add i32 %w, 7 | |||||
store volatile i32 %b, i32* %y, !tbaa !4 | |||||
br label %if.end | |||||
if.end: | |||||
ret i32 1 | |||||
} | |||||
!0 = !{ !"an example type tree" } | |||||
!1 = !{ !"int", !0 } | |||||
!2 = !{ !"float", !0 } | |||||
!3 = !{ !"const float", !2, i64 0 } | |||||
!4 = !{ !"special float", !2, i64 1 } | |||||
; CHECK-LABEL: test13 | |||||
; CHECK-DAG: select | |||||
; CHECK-DAG: load volatile | |||||
; CHECK: store volatile {{.*}}, !tbaa !0 | |||||
; CHECK-NOT: load | |||||
; CHECK-NOT: store | |||||
; The call should be commoned. | |||||
define i32 @test13a(i1 zeroext %flag, i32 %w, i32 %x, i32 %y) { | |||||
entry: | |||||
br i1 %flag, label %if.then, label %if.else | |||||
if.then: | |||||
%sv1 = call i32 @bar(i32 %x) | |||||
br label %if.end | |||||
if.else: | |||||
%sv2 = call i32 @bar(i32 %y) | |||||
br label %if.end | |||||
if.end: | |||||
%p = phi i32 [ %sv1, %if.then ], [ %sv2, %if.else ] | |||||
ret i32 1 | |||||
} | |||||
declare i32 @bar(i32) | |||||
; CHECK-LABEL: test13a | |||||
; CHECK: %[[x:.*]] = select i1 %flag | |||||
; CHECK: call i32 @bar(i32 %[[x]]) | |||||
; The load should be commoned. | |||||
define i32 @test14(i1 zeroext %flag, i32 %w, i32 %x, i32 %y, %struct.anon* %s) { | |||||
entry: | |||||
br i1 %flag, label %if.then, label %if.else | |||||
if.then: | |||||
%dummy = add i32 %x, 1 | |||||
%gepa = getelementptr inbounds %struct.anon, %struct.anon* %s, i32 0, i32 1 | |||||
%sv1 = load i32, i32* %gepa | |||||
%cmp1 = icmp eq i32 %sv1, 56 | |||||
br label %if.end | |||||
if.else: | |||||
%dummy2 = add i32 %x, 4 | |||||
%gepb = getelementptr inbounds %struct.anon, %struct.anon* %s, i32 0, i32 1 | |||||
%sv2 = load i32, i32* %gepb | |||||
%cmp2 = icmp eq i32 %sv2, 57 | |||||
br label %if.end | |||||
if.end: | |||||
%p = phi i1 [ %cmp1, %if.then ], [ %cmp2, %if.else ] | |||||
ret i32 1 | |||||
} | |||||
; CHECK-LABEL: test14 | |||||
; CHECK: getelementptr | |||||
; CHECK: load | |||||
; CHECK-NOT: load | |||||
; The load should be commoned. | |||||
define i32 @test15(i1 zeroext %flag, i32 %w, i32 %x, i32 %y, %struct.anon* %s) { | |||||
entry: | |||||
br i1 %flag, label %if.then, label %if.else | |||||
if.then: | |||||
%dummy = add i32 %x, 1 | |||||
%gepa = getelementptr inbounds %struct.anon, %struct.anon* %s, i32 0, i32 0 | |||||
%sv1 = load i32, i32* %gepa | |||||
%ext1 = zext i32 %sv1 to i64 | |||||
%cmp1 = icmp eq i64 %ext1, 56 | |||||
br label %if.end | |||||
if.else: | |||||
%dummy2 = add i32 %x, 4 | |||||
%gepb = getelementptr inbounds %struct.anon, %struct.anon* %s, i32 0, i32 1 | |||||
%sv2 = load i32, i32* %gepb | |||||
%ext2 = zext i32 %sv2 to i64 | |||||
%cmp2 = icmp eq i64 %ext2, 56 | |||||
br label %if.end | |||||
if.end: | |||||
%p = phi i1 [ %cmp1, %if.then ], [ %cmp2, %if.else ] | |||||
ret i32 1 | |||||
} | |||||
; CHECK-LABEL: test15 | |||||
; CHECK: getelementptr | |||||
; CHECK: load | |||||
; CHECK-NOT: load | |||||
define zeroext i1 @test_crash(i1 zeroext %flag, i32* %i4, i32* %m, i32* %n) { | |||||
entry: | |||||
br i1 %flag, label %if.then, label %if.else | |||||
if.then: | |||||
%tmp1 = load i32, i32* %i4 | |||||
%tmp2 = add i32 %tmp1, -1 | |||||
store i32 %tmp2, i32* %i4 | |||||
br label %if.end | |||||
if.else: | |||||
%tmp3 = load i32, i32* %m | |||||
%tmp4 = load i32, i32* %n | |||||
%tmp5 = add i32 %tmp3, %tmp4 | |||||
store i32 %tmp5, i32* %i4 | |||||
br label %if.end | |||||
if.end: | |||||
ret i1 true | |||||
} | |||||
; CHECK-LABEL: test_crash | |||||
; No checks for test_crash - just ensure it doesn't crash! | |||||
define zeroext i1 @test16(i1 zeroext %flag, i1 zeroext %flag2, i32 %blksA, i32 %blksB, i32 %nblks) { | |||||
entry: | |||||
br i1 %flag, label %if.then, label %if.else | |||||
if.then: | |||||
%cmp = icmp uge i32 %blksA, %nblks | |||||
%frombool1 = zext i1 %cmp to i8 | |||||
br label %if.end | |||||
if.else: | |||||
br i1 %flag2, label %if.then2, label %if.end | |||||
if.then2: | |||||
%add = add i32 %nblks, %blksB | |||||
%cmp2 = icmp ule i32 %add, %blksA | |||||
%frombool3 = zext i1 %cmp2 to i8 | |||||
br label %if.end | |||||
if.end: | |||||
%obeys.0 = phi i8 [ %frombool1, %if.then ], [ %frombool3, %if.then2 ], [ 0, %if.else ] | |||||
%tobool4 = icmp ne i8 %obeys.0, 0 | |||||
ret i1 %tobool4 | |||||
} | |||||
; CHECK-LABEL: test16 | |||||
; CHECK: zext | |||||
; CHECK: zext | |||||
define zeroext i1 @test16a(i1 zeroext %flag, i1 zeroext %flag2, i32 %blksA, i32 %blksB, i32 %nblks, i8* %p) { | |||||
entry: | |||||
br i1 %flag, label %if.then, label %if.else | |||||
if.then: | |||||
%cmp = icmp uge i32 %blksA, %nblks | |||||
%frombool1 = zext i1 %cmp to i8 | |||||
%b1 = sext i8 %frombool1 to i32 | |||||
%b2 = trunc i32 %b1 to i8 | |||||
store i8 %b2, i8* %p | |||||
br label %if.end | |||||
if.else: | |||||
br i1 %flag2, label %if.then2, label %if.end | |||||
if.then2: | |||||
%add = add i32 %nblks, %blksB | |||||
%cmp2 = icmp ule i32 %add, %blksA | |||||
%frombool3 = zext i1 %cmp2 to i8 | |||||
%a1 = sext i8 %frombool3 to i32 | |||||
%a2 = trunc i32 %a1 to i8 | |||||
store i8 %a2, i8* %p | |||||
br label %if.end | |||||
if.end: | |||||
ret i1 true | |||||
} | |||||
; CHECK-LABEL: test16a | |||||
; CHECK: zext | |||||
; CHECK-NOT: zext | |||||
define zeroext i1 @test17(i32 %flag, i32 %blksA, i32 %blksB, i32 %nblks) { | |||||
entry: | |||||
switch i32 %flag, label %if.end [ | |||||
i32 0, label %if.then | |||||
i32 1, label %if.then2 | |||||
] | |||||
if.then: | |||||
%cmp = icmp uge i32 %blksA, %nblks | |||||
%frombool1 = call i8 @i1toi8(i1 %cmp) | |||||
%a1 = sext i8 %frombool1 to i32 | |||||
%a2 = trunc i32 %a1 to i8 | |||||
br label %if.end | |||||
if.then2: | |||||
%add = add i32 %nblks, %blksB | |||||
%cmp2 = icmp ule i32 %add, %blksA | |||||
%frombool3 = call i8 @i1toi8(i1 %cmp2) | |||||
%b1 = sext i8 %frombool3 to i32 | |||||
%b2 = trunc i32 %b1 to i8 | |||||
br label %if.end | |||||
if.end: | |||||
%obeys.0 = phi i8 [ %a2, %if.then ], [ %b2, %if.then2 ], [ 0, %entry ] | |||||
%tobool4 = icmp ne i8 %obeys.0, 0 | |||||
ret i1 %tobool4 | |||||
} | |||||
declare i8 @i1toi8(i1) | |||||
; FIXME: DISABLED - we don't consider this profitable. We should | |||||
; - Consider argument setup/return mov'ing for calls, like InlineCost does. | |||||
; - Consider the removal of the %obeys.0 PHI (zero PHI movement overall) | |||||
; DISABLED-CHECK-LABEL: test17 | |||||
; DISABLED-CHECK: if.then: | |||||
; DISABLED-CHECK-NEXT: icmp uge | |||||
; DISABLED-CHECK-NEXT: br label %[[x:.*]] | |||||
; DISABLED-CHECK: if.then2: | |||||
; DISABLED-CHECK-NEXT: add | |||||
; DISABLED-CHECK-NEXT: icmp ule | |||||
; DISABLED-CHECK-NEXT: br label %[[x]] | |||||
; DISABLED-CHECK: [[x]]: | |||||
; DISABLED-CHECK-NEXT: %[[y:.*]] = phi i1 [ %cmp | |||||
; DISABLED-CHECK-NEXT: %[[z:.*]] = call i8 @i1toi8(i1 %[[y]]) | |||||
; DISABLED-CHECK-NEXT: br label %if.end | |||||
; DISABLED-CHECK: if.end: | |||||
; DISABLED-CHECK-NEXT: phi i8 | |||||
; DISABLED-CHECK-DAG: [ %[[z]], %[[x]] ] | |||||
; DISABLED-CHECK-DAG: [ 0, %entry ] | |||||
define zeroext i1 @test18(i32 %flag, i32 %blksA, i32 %blksB, i32 %nblks) { | |||||
entry: | |||||
switch i32 %flag, label %if.then3 [ | |||||
i32 0, label %if.then | |||||
i32 1, label %if.then2 | |||||
] | |||||
if.then: | |||||
%cmp = icmp uge i32 %blksA, %nblks | |||||
%frombool1 = zext i1 %cmp to i8 | |||||
br label %if.end | |||||
if.then2: | |||||
%add = add i32 %nblks, %blksB | |||||
%cmp2 = icmp ule i32 %add, %blksA | |||||
%frombool3 = zext i1 %cmp2 to i8 | |||||
br label %if.end | |||||
if.then3: | |||||
%add2 = add i32 %nblks, %blksA | |||||
%cmp3 = icmp ule i32 %add2, %blksA | |||||
%frombool4 = zext i1 %cmp3 to i8 | |||||
br label %if.end | |||||
if.end: | |||||
%obeys.0 = phi i8 [ %frombool1, %if.then ], [ %frombool3, %if.then2 ], [ %frombool4, %if.then3 ] | |||||
%tobool4 = icmp ne i8 %obeys.0, 0 | |||||
ret i1 %tobool4 | |||||
} | |||||
; CHECK-LABEL: test18 | |||||
; CHECK: if.end: | |||||
; CHECK-NEXT: %[[x:.*]] = phi i1 | |||||
; CHECK-DAG: [ %cmp, %if.then ] | |||||
; CHECK-DAG: [ %cmp2, %if.then2 ] | |||||
; CHECK-DAG: [ %cmp3, %if.then3 ] | |||||
; CHECK-NEXT: zext i1 %[[x]] to i8 | |||||
; The phi is confusing - both add instructions are used by it, but | |||||
; not on their respective unconditional arcs. It should not be | |||||
; optimized. | |||||
define void @test_pr30292(i1 %cond, i1 %cond2, i32 %a, i32 %b) { | |||||
entry: | |||||
%add1 = add i32 %a, 1 | |||||
br label %succ | |||||
one: | |||||
br i1 %cond, label %two, label %succ | |||||
two: | |||||
call void @g() | |||||
%add2 = add i32 %a, 1 | |||||
br label %succ | |||||
succ: | |||||
%p = phi i32 [ 0, %entry ], [ %add1, %one ], [ %add2, %two ] | |||||
br label %one | |||||
} | |||||
declare void @g() | |||||
; CHECK-LABEL: test_pr30292 | |||||
; CHECK: phi i32 [ 0, %entry ], [ %add1, %succ ], [ %add2, %two ] | |||||
define zeroext i1 @test_pr30244(i1 zeroext %flag, i1 zeroext %flag2, i32 %blksA, i32 %blksB, i32 %nblks) { | |||||
entry: | |||||
%p = alloca i8 | |||||
br i1 %flag, label %if.then, label %if.else | |||||
if.then: | |||||
%cmp = icmp uge i32 %blksA, %nblks | |||||
%frombool1 = zext i1 %cmp to i8 | |||||
store i8 %frombool1, i8* %p | |||||
br label %if.end | |||||
if.else: | |||||
br i1 %flag2, label %if.then2, label %if.end | |||||
if.then2: | |||||
%add = add i32 %nblks, %blksB | |||||
%cmp2 = icmp ule i32 %add, %blksA | |||||
%frombool3 = zext i1 %cmp2 to i8 | |||||
store i8 %frombool3, i8* %p | |||||
br label %if.end | |||||
if.end: | |||||
ret i1 true | |||||
} | |||||
; CHECK-LABEL: @test_pr30244 | |||||
; CHECK: store | |||||
; CHECK-NOT: store | |||||
define i32 @test_pr30373a(i1 zeroext %flag, i32 %x, i32 %y) { | |||||
entry: | |||||
br i1 %flag, label %if.then, label %if.else | |||||
if.then: | |||||
%x0 = call i32 @foo(i32 %x, i32 0) nounwind readnone | |||||
%y0 = call i32 @foo(i32 %x, i32 1) nounwind readnone | |||||
%z0 = lshr i32 %y0, 8 | |||||
br label %if.end | |||||
if.else: | |||||
%x1 = call i32 @foo(i32 %y, i32 0) nounwind readnone | |||||
%y1 = call i32 @foo(i32 %y, i32 1) nounwind readnone | |||||
%z1 = lshr exact i32 %y1, 8 | |||||
br label %if.end | |||||
if.end: | |||||
%xx = phi i32 [ %x0, %if.then ], [ %x1, %if.else ] | |||||
%yy = phi i32 [ %z0, %if.then ], [ %z1, %if.else ] | |||||
%ret = add i32 %xx, %yy | |||||
ret i32 %ret | |||||
} | |||||
; CHECK-LABEL: test_pr30373a | |||||
; CHECK: lshr | |||||
; CHECK-NOT: exact | |||||
; CHECK: } | |||||
define i32 @test_pr30373b(i1 zeroext %flag, i32 %x, i32 %y) { | |||||
entry: | |||||
br i1 %flag, label %if.then, label %if.else | |||||
if.then: | |||||
%x0 = call i32 @foo(i32 %x, i32 0) nounwind readnone | |||||
%y0 = call i32 @foo(i32 %x, i32 1) nounwind readnone | |||||
%z0 = lshr exact i32 %y0, 8 | |||||
br label %if.end | |||||
if.else: | |||||
%x1 = call i32 @foo(i32 %y, i32 0) nounwind readnone | |||||
%y1 = call i32 @foo(i32 %y, i32 1) nounwind readnone | |||||
%z1 = lshr i32 %y1, 8 | |||||
br label %if.end | |||||
if.end: | |||||
%xx = phi i32 [ %x0, %if.then ], [ %x1, %if.else ] | |||||
%yy = phi i32 [ %z0, %if.then ], [ %z1, %if.else ] | |||||
%ret = add i32 %xx, %yy | |||||
ret i32 %ret | |||||
} | |||||
; CHECK-LABEL: test_pr30373b | |||||
; CHECK: lshr | |||||
; CHECK-NOT: exact | |||||
; CHECK: } | |||||
; CHECK: !0 = !{!1, !1, i64 0} | |||||
; CHECK: !1 = !{!"float", !2} | |||||
; CHECK: !2 = !{!"an example type tree"} |