|  | ; RUN: opt -passes=jump-threading -S < %s | FileCheck %s | 
|  |  | 
|  | declare i32 @f1() | 
|  | declare i32 @f2() | 
|  | declare void @f3() | 
|  |  | 
|  | define i32 @test1(i1 %cond) { | 
|  | ; CHECK-LABEL: @test1( | 
|  |  | 
|  | br i1 %cond, label %T1, label %F1 | 
|  |  | 
|  | T1: | 
|  | %v1 = call i32 @f1() | 
|  | br label %Merge | 
|  |  | 
|  | F1: | 
|  | %v2 = call i32 @f2() | 
|  | br label %Merge | 
|  |  | 
|  | Merge: | 
|  | %A = phi i1 [true, %T1], [false, %F1] | 
|  | %B = phi i32 [%v1, %T1], [%v2, %F1] | 
|  | br i1 %A, label %T2, label %F2 | 
|  |  | 
|  | T2: | 
|  | ; CHECK: T2: | 
|  | ; CHECK: ret i32 %v1 | 
|  | call void @f3() | 
|  | ret i32 %B | 
|  |  | 
|  | F2: | 
|  | ; CHECK: F2: | 
|  | ; CHECK: ret i32 %v2 | 
|  | ret i32 %B | 
|  | } | 
|  |  | 
|  |  | 
|  | ;; cond is known false on Entry -> F1 edge! | 
|  | define i32 @test2(i1 %cond) { | 
|  | ; CHECK-LABEL: @test2( | 
|  | Entry: | 
|  | br i1 %cond, label %T1, label %F1 | 
|  |  | 
|  | T1: | 
|  | ; CHECK: %v1 = call i32 @f1() | 
|  | ; CHECK: ret i32 47 | 
|  | %v1 = call i32 @f1() | 
|  | br label %Merge | 
|  |  | 
|  | F1: | 
|  | br i1 %cond, label %Merge, label %F2 | 
|  |  | 
|  | Merge: | 
|  | %B = phi i32 [47, %T1], [192, %F1] | 
|  | ret i32 %B | 
|  |  | 
|  | F2: | 
|  | call void @f3() | 
|  | ret i32 12 | 
|  | } | 
|  |  | 
|  |  | 
|  | ; Undef handling. | 
|  | define i32 @test3(i1 %cond) { | 
|  | ; CHECK-LABEL: @test3( | 
|  | ; CHECK-NEXT: T1: | 
|  | ; CHECK-NEXT: ret i32 42 | 
|  | br i1 undef, label %T1, label %F1 | 
|  |  | 
|  | T1: | 
|  | ret i32 42 | 
|  |  | 
|  | F1: | 
|  | ret i32 17 | 
|  | } | 
|  |  | 
|  | define i32 @test4(i1 %cond, i1 %cond2) { | 
|  | ; CHECK-LABEL: @test4( | 
|  |  | 
|  | br i1 %cond, label %T1, label %F1 | 
|  |  | 
|  | T1: | 
|  | ; CHECK:   %v1 = call i32 @f1() | 
|  | ; CHECK-NEXT:   br label %T | 
|  |  | 
|  | %v1 = call i32 @f1() | 
|  | br label %Merge | 
|  |  | 
|  | F1: | 
|  | %v2 = call i32 @f2() | 
|  | ; CHECK:   %v2 = call i32 @f2() | 
|  | ; CHECK-NEXT:   br i1 %cond2, | 
|  | br label %Merge | 
|  |  | 
|  | Merge: | 
|  | %A = phi i1 [undef, %T1], [%cond2, %F1] | 
|  | %B = phi i32 [%v1, %T1], [%v2, %F1] | 
|  | br i1 %A, label %T2, label %F2 | 
|  |  | 
|  | T2: | 
|  | call void @f3() | 
|  | ret i32 %B | 
|  |  | 
|  | F2: | 
|  | ret i32 %B | 
|  | } | 
|  |  | 
|  |  | 
|  | ;; This tests that the branch in 'merge' can be cloned up into T1. | 
|  | define i32 @test5(i1 %cond, i1 %cond2) { | 
|  | ; CHECK-LABEL: @test5( | 
|  |  | 
|  | br i1 %cond, label %T1, label %F1 | 
|  |  | 
|  | T1: | 
|  | ; CHECK: T1: | 
|  | ; CHECK-NEXT:   %v1 = call i32 @f1() | 
|  | ; CHECK-NEXT:   %cond3 = icmp eq i32 %v1, 412 | 
|  | ; CHECK-NEXT:   br i1 %cond3, label %T2, label %F2 | 
|  |  | 
|  | %v1 = call i32 @f1() | 
|  | %cond3 = icmp eq i32 %v1, 412 | 
|  | br label %Merge | 
|  |  | 
|  | F1: | 
|  | %v2 = call i32 @f2() | 
|  | br label %Merge | 
|  |  | 
|  | Merge: | 
|  | %A = phi i1 [%cond3, %T1], [%cond2, %F1] | 
|  | %B = phi i32 [%v1, %T1], [%v2, %F1] | 
|  | br i1 %A, label %T2, label %F2 | 
|  |  | 
|  | T2: | 
|  | call void @f3() | 
|  | ret i32 %B | 
|  |  | 
|  | F2: | 
|  | ret i32 %B | 
|  | } | 
|  |  | 
|  |  | 
|  | ;; Lexically duplicated conditionals should be threaded. | 
|  |  | 
|  |  | 
|  | define i32 @test6(i32 %A) { | 
|  | ; CHECK-LABEL: @test6( | 
|  | %tmp455 = icmp eq i32 %A, 42 | 
|  | br i1 %tmp455, label %BB1, label %BB2 | 
|  |  | 
|  | ; CHECK: call i32 @f2() | 
|  | ; CHECK-NEXT: ret i32 3 | 
|  |  | 
|  | ; CHECK: call i32 @f1() | 
|  | ; CHECK-NOT: br | 
|  | ; CHECK: call void @f3() | 
|  | ; CHECK-NOT: br | 
|  | ; CHECK: ret i32 4 | 
|  |  | 
|  | BB2: | 
|  | call i32 @f1() | 
|  | br label %BB1 | 
|  |  | 
|  |  | 
|  | BB1: | 
|  | %tmp459 = icmp eq i32 %A, 42 | 
|  | br i1 %tmp459, label %BB3, label %BB4 | 
|  |  | 
|  | BB3: | 
|  | call i32 @f2() | 
|  | ret i32 3 | 
|  |  | 
|  | BB4: | 
|  | call void @f3() | 
|  | ret i32 4 | 
|  | } | 
|  |  | 
|  |  | 
|  | ;; This tests that the branch in 'merge' can be cloned up into T1. | 
|  | ;; rdar://7367025 | 
|  | define i32 @test7(i1 %cond, i1 %cond2) { | 
|  | Entry: | 
|  | ; CHECK-LABEL: @test7( | 
|  | %v1 = call i32 @f1() | 
|  | br i1 %cond, label %Merge, label %F1 | 
|  |  | 
|  | F1: | 
|  | %v2 = call i32 @f2() | 
|  | br label %Merge | 
|  |  | 
|  | Merge: | 
|  | %B = phi i32 [%v1, %Entry], [%v2, %F1] | 
|  | %M = icmp ne i32 %B, %v1 | 
|  | %N = icmp eq i32 %B, 47 | 
|  | %O = and i1 %M, %N | 
|  | br i1 %O, label %T2, label %F2 | 
|  |  | 
|  | ; CHECK: Merge: | 
|  | ; CHECK-NOT: phi | 
|  | ; CHECK-NEXT:   %v2 = call i32 @f2() | 
|  |  | 
|  | T2: | 
|  | call void @f3() | 
|  | ret i32 %B | 
|  |  | 
|  | F2: | 
|  | ret i32 %B | 
|  | ; CHECK: F2: | 
|  | ; CHECK-NEXT: phi i32 | 
|  | } | 
|  |  | 
|  |  | 
|  | declare i1 @test8a() | 
|  |  | 
|  | define i32 @test8b(i1 %cond, i1 %cond2) { | 
|  | ; CHECK-LABEL: @test8b( | 
|  | T0: | 
|  | %A = call i1 @test8a() | 
|  | br i1 %A, label %T1, label %F1 | 
|  |  | 
|  | ; CHECK: T0: | 
|  | ; CHECK-NEXT: call | 
|  | ; CHECK-NEXT: br i1 %A, label %T1, label %Y | 
|  |  | 
|  | T1: | 
|  | %B = call i1 @test8a() | 
|  | br i1 %B, label %T2, label %F1 | 
|  |  | 
|  | ; CHECK: T1: | 
|  | ; CHECK-NEXT: call | 
|  | ; CHECK-NEXT: br i1 %B, label %T2, label %Y | 
|  | T2: | 
|  | %C = call i1 @test8a() | 
|  | br i1 %cond, label %T3, label %F1 | 
|  |  | 
|  | ; CHECK: T2: | 
|  | ; CHECK-NEXT: call | 
|  | ; CHECK-NEXT: br i1 %cond, label %T3, label %Y | 
|  | T3: | 
|  | ret i32 0 | 
|  |  | 
|  | F1: | 
|  | %D = phi i32 [0, %T0], [0, %T1], [1, %T2] | 
|  | %E = icmp eq i32 %D, 1 | 
|  | %F = and i1 %E, %cond | 
|  | br i1 %F, label %X, label %Y | 
|  | X: | 
|  | call i1 @test8a() | 
|  | ret i32 1 | 
|  | Y: | 
|  | ret i32 2 | 
|  | } | 
|  |  | 
|  |  | 
|  | ;;; Verify that we can handle constraint propagation through "xor x, 1". | 
|  | define i32 @test9(i1 %cond, i1 %cond2) { | 
|  | Entry: | 
|  | ; CHECK-LABEL: @test9( | 
|  | %v1 = call i32 @f1() | 
|  | br i1 %cond, label %Merge, label %F1 | 
|  |  | 
|  | ; CHECK: Entry: | 
|  | ; CHECK-NEXT:  %v1 = call i32 @f1() | 
|  | ; CHECK-NEXT:  br i1 %cond, label %F2, label %Merge | 
|  |  | 
|  | F1: | 
|  | %v2 = call i32 @f2() | 
|  | br label %Merge | 
|  |  | 
|  | Merge: | 
|  | %B = phi i32 [%v1, %Entry], [%v2, %F1] | 
|  | %M = icmp eq i32 %B, %v1 | 
|  | %M1 = xor i1 %M, 1 | 
|  | %N = icmp eq i32 %B, 47 | 
|  | %O = and i1 %M1, %N | 
|  | br i1 %O, label %T2, label %F2 | 
|  |  | 
|  | ; CHECK: Merge: | 
|  | ; CHECK-NOT: phi | 
|  | ; CHECK-NEXT:   %v2 = call i32 @f2() | 
|  |  | 
|  | T2: | 
|  | %Q = zext i1 %M to i32 | 
|  | ret i32 %Q | 
|  |  | 
|  | F2: | 
|  | ret i32 %B | 
|  | ; CHECK: F2: | 
|  | ; CHECK-NEXT: phi i32 | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | ; CHECK: @test10 | 
|  | declare i32 @test10f1() | 
|  | declare i32 @test10f2() | 
|  | declare void @test10f3() | 
|  |  | 
|  | ;; Non-local condition threading. | 
|  | define i32 @test10g(i1 %cond) { | 
|  | ; CHECK-LABEL: @test10g( | 
|  | ; CHECK-NEXT:   br i1 %cond, label %T2, label %F2 | 
|  | br i1 %cond, label %T1, label %F1 | 
|  |  | 
|  | T1: | 
|  | %v1 = call i32 @test10f1() | 
|  | br label %Merge | 
|  |  | 
|  | ; CHECK: %v1 = call i32 @test10f1() | 
|  | ; CHECK-NEXT: call void @f3() | 
|  | ; CHECK-NEXT: ret i32 %v1 | 
|  |  | 
|  | F1: | 
|  | %v2 = call i32 @test10f2() | 
|  | br label %Merge | 
|  |  | 
|  | Merge: | 
|  | %B = phi i32 [%v1, %T1], [%v2, %F1] | 
|  | br i1 %cond, label %T2, label %F2 | 
|  |  | 
|  | T2: | 
|  | call void @f3() | 
|  | ret i32 %B | 
|  |  | 
|  | F2: | 
|  | ret i32 %B | 
|  | } | 
|  |  | 
|  |  | 
|  | ; Impossible conditional constraints should get threaded.  BB3 is dead here. | 
|  | define i32 @test11(i32 %A) { | 
|  | ; CHECK-LABEL: @test11( | 
|  | ; CHECK-NEXT: icmp | 
|  | ; CHECK-NEXT: br i1 %tmp455, label %BB4, label %BB2 | 
|  | %tmp455 = icmp eq i32 %A, 42 | 
|  | br i1 %tmp455, label %BB1, label %BB2 | 
|  |  | 
|  | BB2: | 
|  | ; CHECK: call i32 @f1() | 
|  | ; CHECK-NEXT: ret i32 %C | 
|  | %C = call i32 @f1() | 
|  | ret i32 %C | 
|  |  | 
|  |  | 
|  | BB1: | 
|  | %tmp459 = icmp eq i32 %A, 43 | 
|  | br i1 %tmp459, label %BB3, label %BB4 | 
|  |  | 
|  | BB3: | 
|  | call i32 @f2() | 
|  | ret i32 3 | 
|  |  | 
|  | BB4: | 
|  | call void @f3() | 
|  | ret i32 4 | 
|  | } | 
|  |  | 
|  | ;; Correlated value through boolean expression.  GCC PR18046. | 
|  | define void @test12(i32 %A) { | 
|  | ; CHECK-LABEL: @test12( | 
|  | entry: | 
|  | %cond = icmp eq i32 %A, 0 | 
|  | br i1 %cond, label %bb, label %bb1 | 
|  | ; Should branch to the return block instead of through BB1. | 
|  | ; CHECK: entry: | 
|  | ; CHECK-NEXT: %cond = icmp eq i32 %A, 0 | 
|  | ; CHECK-NEXT: br i1 %cond, label %bb1, label %return | 
|  |  | 
|  | bb: | 
|  | %B = call i32 @test10f2() | 
|  | br label %bb1 | 
|  |  | 
|  | bb1: | 
|  | %C = phi i32 [ %A, %entry ], [ %B, %bb ] | 
|  | %cond4 = icmp eq i32 %C, 0 | 
|  | br i1 %cond4, label %bb2, label %return | 
|  |  | 
|  | ; CHECK: bb1: | 
|  | ; CHECK-NEXT: %B = call i32 @test10f2() | 
|  | ; CHECK-NEXT: %cond4 = icmp eq i32 %B, 0 | 
|  | ; CHECK-NEXT: br i1 %cond4, label %bb2, label %return | 
|  |  | 
|  | bb2: | 
|  | %D = call i32 @test10f2() | 
|  | ret void | 
|  |  | 
|  | return: | 
|  | ret void | 
|  | } | 
|  |  | 
|  |  | 
|  | ;; Duplicate condition to avoid xor of cond. | 
|  | ;; rdar://7391699 | 
|  | define i32 @test13(i1 %cond, i1 %cond2) { | 
|  | Entry: | 
|  | ; CHECK-LABEL: @test13( | 
|  | %v1 = call i32 @f1() | 
|  | br i1 %cond, label %Merge, label %F1 | 
|  |  | 
|  | F1: | 
|  | br label %Merge | 
|  |  | 
|  | Merge: | 
|  | %B = phi i1 [true, %Entry], [%cond2, %F1] | 
|  | %C = phi i32 [192, %Entry], [%v1, %F1] | 
|  | %M = icmp eq i32 %C, 192 | 
|  | %N = xor i1 %B, %M | 
|  | br i1 %N, label %T2, label %F2 | 
|  |  | 
|  | T2: | 
|  | ret i32 123 | 
|  |  | 
|  | F2: | 
|  | ret i32 %v1 | 
|  |  | 
|  | ; CHECK:   br i1 %cond, label %F2, label %Merge | 
|  |  | 
|  | ; CHECK:      Merge: | 
|  | ; CHECK-NEXT:   %M = icmp eq i32 %v1, 192 | 
|  | ; CHECK-NEXT:   %N = xor i1 %cond2, %M | 
|  | ; CHECK-NEXT:   br i1 %N, label %T2, label %F2 | 
|  | } | 
|  |  | 
|  | ; CHECK-LABEL: @test14( | 
|  | define i32 @test14(i32 %in) { | 
|  | entry: | 
|  | %A = icmp eq i32 %in, 0 | 
|  | ; CHECK: br i1 %A, label %right_ret, label %merge | 
|  | br i1 %A, label %left, label %right | 
|  |  | 
|  | ; CHECK-NOT: left: | 
|  | left: | 
|  | br label %merge | 
|  |  | 
|  | ; CHECK-NOT: right: | 
|  | right: | 
|  | %B = call i32 @f1() | 
|  | br label %merge | 
|  |  | 
|  | merge: | 
|  | ; CHECK-NOT: %C = phi i32 [%in, %left], [%B, %right] | 
|  | %C = phi i32 [%in, %left], [%B, %right] | 
|  | %D = add i32 %C, 1 | 
|  | %E = icmp eq i32 %D, 2 | 
|  | br i1 %E, label %left_ret, label %right_ret | 
|  |  | 
|  | ; CHECK: left_ret: | 
|  | left_ret: | 
|  | ret i32 0 | 
|  |  | 
|  | right_ret: | 
|  | ret i32 1 | 
|  | } | 
|  |  | 
|  | ; PR5652 | 
|  | ; CHECK-LABEL: @test15( | 
|  | define i32 @test15(i32 %len) { | 
|  | entry: | 
|  | ; CHECK: icmp ult i32 %len, 13 | 
|  | %tmp = icmp ult i32 %len, 13 | 
|  | br i1 %tmp, label %check, label %exit0 | 
|  |  | 
|  | exit0: | 
|  | ret i32 0 | 
|  |  | 
|  | check: | 
|  | %tmp9 = icmp ult i32 %len, 21 | 
|  | br i1 %tmp9, label %exit1, label %exit2 | 
|  |  | 
|  | exit2: | 
|  | ; CHECK-NOT: ret i32 2 | 
|  | ret i32 2 | 
|  |  | 
|  | exit1: | 
|  | ret i32 1 | 
|  | ; CHECK: } | 
|  | } | 
|  |  | 
|  | ;;; Verify that we can handle constraint propagation through cast. | 
|  | define i32 @test16(i1 %cond) { | 
|  | Entry: | 
|  | ; CHECK-LABEL: @test16( | 
|  | br i1 %cond, label %Merge, label %F1 | 
|  |  | 
|  | ; CHECK: Entry: | 
|  | ; CHECK-NEXT:  br i1 %cond, label %F2, label %Merge | 
|  |  | 
|  | F1: | 
|  | %v1 = call i32 @f1() | 
|  | br label %Merge | 
|  |  | 
|  | Merge: | 
|  | %B = phi i32 [0, %Entry], [%v1, %F1] | 
|  | %M = icmp eq i32 %B, 0 | 
|  | %M1 = zext i1 %M to i32 | 
|  | %N = icmp eq i32 %M1, 0 | 
|  | br i1 %N, label %T2, label %F2 | 
|  |  | 
|  | ; CHECK: Merge: | 
|  | ; CHECK-NOT: phi | 
|  | ; CHECK-NEXT:   %v1 = call i32 @f1() | 
|  |  | 
|  | T2: | 
|  | %Q = call i32 @f2() | 
|  | ret i32 %Q | 
|  |  | 
|  | F2: | 
|  | ret i32 %B | 
|  | ; CHECK: F2: | 
|  | ; CHECK-NEXT: phi i32 | 
|  | } | 
|  |  | 
|  | ; In this test we check that block duplication is inhibited by the presence | 
|  | ; of a function with the 'noduplicate' attribute. | 
|  |  | 
|  | declare void @g() | 
|  | declare void @j() | 
|  | declare void @k() | 
|  |  | 
|  | ; CHECK-LABEL: define void @h(i32 %p) { | 
|  | define void @h(i32 %p) { | 
|  | %x = icmp ult i32 %p, 5 | 
|  | br i1 %x, label %l1, label %l2 | 
|  |  | 
|  | l1: | 
|  | call void @j() | 
|  | br label %l3 | 
|  |  | 
|  | l2: | 
|  | call void @k() | 
|  | br label %l3 | 
|  |  | 
|  | l3: | 
|  | ; CHECK: call void @g() [[$NOD:#[0-9]+]] | 
|  | ; CHECK-NOT: call void @g() [[$NOD]] | 
|  | call void @g() noduplicate | 
|  | %y = icmp ult i32 %p, 5 | 
|  | br i1 %y, label %l4, label %l5 | 
|  |  | 
|  | l4: | 
|  | call void @j() | 
|  | ret void | 
|  |  | 
|  | l5: | 
|  | call void @k() | 
|  | ret void | 
|  | ; CHECK: } | 
|  | } | 
|  |  | 
|  | define i1 @trunc_switch(i1 %arg) { | 
|  | ; CHECK-LABEL: @trunc_switch | 
|  | top: | 
|  | ; CHECK: br i1 %arg, label %exitA, label %exitB | 
|  | br i1 %arg, label %common, label %B | 
|  |  | 
|  | B: | 
|  | br label %common | 
|  |  | 
|  | common: | 
|  | %phi = phi i8 [ 2, %B ], [ 1, %top ] | 
|  | %trunc = trunc i8 %phi to i2 | 
|  | ; CHECK-NOT: switch | 
|  | switch i2 %trunc, label %unreach [ | 
|  | i2 1, label %exitA | 
|  | i2 -2, label %exitB | 
|  | ] | 
|  |  | 
|  | unreach: | 
|  | unreachable | 
|  |  | 
|  | exitA: | 
|  | ret i1 true | 
|  |  | 
|  | exitB: | 
|  | ret i1 false | 
|  | } | 
|  |  | 
|  | ; CHECK-LABEL: define void @h_con(i32 %p) { | 
|  | define void @h_con(i32 %p) { | 
|  | %x = icmp ult i32 %p, 5 | 
|  | br i1 %x, label %l1, label %l2 | 
|  |  | 
|  | l1: | 
|  | call void @j() | 
|  | br label %l3 | 
|  |  | 
|  | l2: | 
|  | call void @k() | 
|  | br label %l3 | 
|  |  | 
|  | l3: | 
|  | ; CHECK: call void @g() [[$CON:#[0-9]+]] | 
|  | ; CHECK-NOT: call void @g() [[$CON]] | 
|  | call void @g() convergent | 
|  | %y = icmp ult i32 %p, 5 | 
|  | br i1 %y, label %l4, label %l5 | 
|  |  | 
|  | l4: | 
|  | call void @j() | 
|  | ret void | 
|  |  | 
|  | l5: | 
|  | call void @k() | 
|  | ret void | 
|  | ; CHECK: } | 
|  | } | 
|  |  | 
|  |  | 
|  | ; CHECK: attributes [[$NOD]] = { noduplicate } | 
|  | ; CHECK: attributes [[$CON]] = { convergent } |