| ; RUN: opt < %s -passes=gvn-sink,simplifycfg -simplifycfg-require-and-preserve-domtree=1 -hoist-common-insts=true -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 |
| |
| ; FIXME: The test failes when the original order of the |
| ; candidates with the same cost is preserved. |
| ; |
| ;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, ptr %y) { |
| entry: |
| br i1 %flag, label %if.then, label %if.else |
| |
| if.then: |
| %a = add i32 %x, 5 |
| store i32 %a, ptr %y |
| br label %if.end |
| |
| if.else: |
| %b = add i32 %x, 7 |
| store i32 %b, ptr %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, ptr %y) { |
| entry: |
| br i1 %flag, label %if.then, label %if.else |
| |
| if.then: |
| %a = add i32 %x, 5 |
| store volatile i32 %a, ptr %y |
| br label %if.end |
| |
| if.else: |
| %b = add i32 %x, 7 |
| store i32 %b, ptr %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, ptr %y) { |
| entry: |
| br i1 %flag, label %if.then, label %if.else |
| |
| if.then: |
| %a = add i32 %x, 5 |
| store volatile i32 %a, ptr %y |
| br label %if.end |
| |
| if.else: |
| %b = add i32 %x, 7 |
| store volatile i32 %b, ptr %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, ptr %y) { |
| entry: |
| br i1 %flag, label %if.then, label %if.else |
| |
| if.then: |
| %z = load volatile i32, ptr %y |
| %a = add i32 %z, 5 |
| store volatile i32 %a, ptr %y |
| br label %if.end |
| |
| if.else: |
| %w = load volatile i32, ptr %y |
| %b = add i32 %w, 7 |
| store volatile i32 %b, ptr %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, ptr %y, ptr %p) { |
| entry: |
| br i1 %flag, label %if.then, label %if.else |
| |
| if.then: |
| store i32 7, ptr %p |
| %z = load volatile i32, ptr %y |
| store i32 6, ptr %p |
| %a = add i32 %z, 5 |
| store volatile i32 %a, ptr %y |
| br label %if.end |
| |
| if.else: |
| %w = load volatile i32, ptr %y |
| %b = add i32 %w, 7 |
| store volatile i32 %b, ptr %y |
| br label %if.end |
| |
| if.end: |
| ret i32 1 |
| } |
| |
| ; CHECK-LABEL: test9 |
| ; CHECK: add |
| ; CHECK: add |
| |
| %struct.anon = type { i32, i32, i32 } |
| |
| ; The GEP indexes a struct type so cannot have a variable last index. |
| define i32 @test10(i1 zeroext %flag, i32 %x, ptr %y, ptr %s) { |
| entry: |
| br i1 %flag, label %if.then, label %if.else |
| |
| if.then: |
| %dummy = add i32 %x, 5 |
| %gepa = getelementptr inbounds %struct.anon, ptr %s, i32 0, i32 1 |
| store volatile i32 %x, ptr %gepa |
| br label %if.end |
| |
| if.else: |
| %dummy1 = add i32 %x, 6 |
| %gepb = getelementptr inbounds %struct.anon, ptr %s, i32 0, i32 2 |
| store volatile i32 %x, ptr %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, ptr %y) { |
| entry: |
| br i1 %flag, label %if.then, label %if.else |
| |
| if.then: |
| %z = load volatile i32, ptr %y |
| %a = add i32 %z, 5 |
| store volatile i32 %a, ptr %y, !tbaa !3 |
| br label %if.end |
| |
| if.else: |
| %w = load volatile i32, ptr %y |
| %b = add i32 %w, 7 |
| store volatile i32 %b, ptr %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, ptr %s) { |
| entry: |
| br i1 %flag, label %if.then, label %if.else |
| |
| if.then: |
| %dummy = add i32 %x, 1 |
| %gepa = getelementptr inbounds %struct.anon, ptr %s, i32 0, i32 1 |
| %sv1 = load i32, ptr %gepa |
| %cmp1 = icmp eq i32 %sv1, 56 |
| br label %if.end |
| |
| if.else: |
| %dummy2 = add i32 %x, 4 |
| %gepb = getelementptr inbounds %struct.anon, ptr %s, i32 0, i32 1 |
| %sv2 = load i32, ptr %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, ptr %s) { |
| entry: |
| br i1 %flag, label %if.then, label %if.else |
| |
| if.then: |
| %dummy = add i32 %x, 1 |
| %gepa = getelementptr inbounds %struct.anon, ptr %s, i32 0, i32 0 |
| %sv1 = load i32, ptr %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, ptr %s, i32 0, i32 1 |
| %sv2 = load i32, ptr %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, ptr %i4, ptr %m, ptr %n) { |
| entry: |
| br i1 %flag, label %if.then, label %if.else |
| |
| if.then: |
| %tmp1 = load i32, ptr %i4 |
| %tmp2 = add i32 %tmp1, -1 |
| store i32 %tmp2, ptr %i4 |
| br label %if.end |
| |
| if.else: |
| %tmp3 = load i32, ptr %m |
| %tmp4 = load i32, ptr %n |
| %tmp5 = add i32 %tmp3, %tmp4 |
| store i32 %tmp5, ptr %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, ptr %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, ptr %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, ptr %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, ptr %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, ptr %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-LABEL: @common_bitcast( |
| ; CHECK: %. = select i1 %flag, float 2.000000e+00, float 1.000000e+00 |
| ; CHECK: %[[a1:.*]] = bitcast ptr %x to ptr |
| ; CHECK: store float %., ptr %[[a1]] |
| define i32 @common_bitcast(i1 zeroext %flag, ptr %x) { |
| entry: |
| br i1 %flag, label %if.then, label %if.else |
| |
| if.then: |
| %a = bitcast ptr %x to ptr |
| store float 2.0, ptr %a |
| br label %if.end |
| |
| if.else: |
| %b = bitcast ptr %x to ptr |
| store float 1.0, ptr %b |
| br label %if.end |
| |
| if.end: |
| ret i32 1 |
| } |
| |
| ; CHECK-LABEL: @common_addrspacecast( |
| ; CHECK: %. = select i1 %flag, i32 9, i32 10 |
| ; CHECK: %[[a2:.*]] = addrspacecast ptr %x to ptr addrspace(1) |
| ; CHECK: store i32 %., ptr addrspace(1) %[[a2]] |
| define i32 @common_addrspacecast(i1 zeroext %flag, ptr %x) { |
| entry: |
| br i1 %flag, label %if.then, label %if.else |
| |
| if.then: |
| %a = addrspacecast ptr %x to ptr addrspace(1) |
| store i32 9, ptr addrspace(1) %a |
| br label %if.end |
| |
| if.else: |
| %b = addrspacecast ptr %x to ptr addrspace(1) |
| store i32 10, ptr addrspace(1) %b |
| br label %if.end |
| |
| if.end: |
| ret i32 1 |
| } |
| |
| ; Don't merge different address spaces |
| ; CHECK-LABEL: @no_common_addrspacecast( |
| ; CHECK: addrspacecast ptr %x to ptr addrspace(1) |
| ; CHECK: addrspacecast ptr %x to ptr addrspace(3) |
| define i32 @no_common_addrspacecast(i1 zeroext %flag, ptr %x) { |
| entry: |
| br i1 %flag, label %if.then, label %if.else |
| |
| if.then: |
| %a = addrspacecast ptr %x to ptr addrspace(1) |
| store i32 9, ptr addrspace(1) %a |
| br label %if.end |
| |
| if.else: |
| %b = addrspacecast ptr %x to ptr addrspace(3) |
| store i32 10, ptr addrspace(3) %b |
| br label %if.end |
| |
| if.end: |
| ret i32 1 |
| } |
| |
| ; CHECK-LABEL: test_pr36954 |
| ; CHECK-NOT: xor |
| ; PR36954 reproducer containing self referencing instruction shouldn't crash GVNSink pass. |
| define void @test_pr36954() { |
| bb1: |
| %i2 = trunc i32 undef to i8 |
| br label %bb2 |
| |
| bb2: |
| br i1 undef, label %bb2, label %exit |
| |
| bb4.critedge: |
| %i6 = sub i8 %i2, undef |
| %i7 = zext i8 %i6 to i32 |
| %i8 = xor i32 %i8, %i7 |
| br i1 false, label %exit, label %bb4.critedge |
| |
| exit: |
| ret void |
| } |
| |
| ; CHECK: !0 = !{!1, !1, i64 0} |
| ; CHECK: !1 = !{!"float", !2} |
| ; CHECK: !2 = !{!"an example type tree"} |