|  | ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py | 
|  | ; RUN: opt -S -guard-widening < %s        | FileCheck %s | 
|  | ; RUN: opt -S -passes=guard-widening < %s | FileCheck %s | 
|  |  | 
|  | declare void @llvm.experimental.guard(i1,...) | 
|  |  | 
|  | ; Basic test case: we wide the first check to check both the | 
|  | ; conditions. | 
|  | define void @f_0(i1 %cond_0, i1 %cond_1) { | 
|  | ; CHECK-LABEL: @f_0( | 
|  | ; CHECK-NEXT:  entry: | 
|  | ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]] | 
|  | ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] | 
|  | ; CHECK-NEXT:    ret void | 
|  | ; | 
|  | entry: | 
|  |  | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ] | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ] | 
|  | ret void | 
|  | } | 
|  |  | 
|  | ; Same as @f_0, but with using a more general notion of postdominance. | 
|  | define void @f_1(i1 %cond_0, i1 %cond_1) { | 
|  | ; CHECK-LABEL: @f_1( | 
|  | ; CHECK-NEXT:  entry: | 
|  | ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]] | 
|  | ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] | 
|  | ; CHECK-NEXT:    br i1 undef, label [[LEFT:%.*]], label [[RIGHT:%.*]] | 
|  | ; CHECK:       left: | 
|  | ; CHECK-NEXT:    br label [[MERGE:%.*]] | 
|  | ; CHECK:       right: | 
|  | ; CHECK-NEXT:    br label [[MERGE]] | 
|  | ; CHECK:       merge: | 
|  | ; CHECK-NEXT:    ret void | 
|  | ; | 
|  | entry: | 
|  |  | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ] | 
|  | br i1 undef, label %left, label %right | 
|  |  | 
|  | left: | 
|  | br label %merge | 
|  |  | 
|  | right: | 
|  | br label %merge | 
|  |  | 
|  | merge: | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ] | 
|  | ret void | 
|  | } | 
|  |  | 
|  | ; Like @f_1, but we have some code we need to hoist before we can | 
|  | ; widen a dominanting check. | 
|  | define void @f_2(i32 %a, i32 %b) { | 
|  | ; CHECK-LABEL: @f_2( | 
|  | ; CHECK-NEXT:  entry: | 
|  | ; CHECK-NEXT:    [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 10 | 
|  | ; CHECK-NEXT:    [[COND_1:%.*]] = icmp ult i32 [[B:%.*]], 10 | 
|  | ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0]], [[COND_1]] | 
|  | ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] | 
|  | ; CHECK-NEXT:    br i1 undef, label [[LEFT:%.*]], label [[RIGHT:%.*]] | 
|  | ; CHECK:       left: | 
|  | ; CHECK-NEXT:    br label [[MERGE:%.*]] | 
|  | ; CHECK:       right: | 
|  | ; CHECK-NEXT:    br label [[MERGE]] | 
|  | ; CHECK:       merge: | 
|  | ; CHECK-NEXT:    ret void | 
|  | ; | 
|  | entry: | 
|  |  | 
|  | %cond_0 = icmp ult i32 %a, 10 | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ] | 
|  | br i1 undef, label %left, label %right | 
|  |  | 
|  | left: | 
|  | br label %merge | 
|  |  | 
|  | right: | 
|  | br label %merge | 
|  |  | 
|  | merge: | 
|  | %cond_1 = icmp ult i32 %b, 10 | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ] | 
|  | ret void | 
|  | } | 
|  |  | 
|  | ; Negative test: don't hoist stuff out of control flow | 
|  | ; indiscriminately, since that can make us do more work than needed. | 
|  | define void @f_3(i32 %a, i32 %b) { | 
|  | ; CHECK-LABEL: @f_3( | 
|  | ; CHECK-NEXT:  entry: | 
|  | ; CHECK-NEXT:    [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 10 | 
|  | ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0]]) [ "deopt"() ] | 
|  | ; CHECK-NEXT:    br i1 undef, label [[LEFT:%.*]], label [[RIGHT:%.*]] | 
|  | ; CHECK:       left: | 
|  | ; CHECK-NEXT:    [[COND_1:%.*]] = icmp ult i32 [[B:%.*]], 10 | 
|  | ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND_1]]) [ "deopt"() ] | 
|  | ; CHECK-NEXT:    ret void | 
|  | ; CHECK:       right: | 
|  | ; CHECK-NEXT:    ret void | 
|  | ; | 
|  | entry: | 
|  |  | 
|  | %cond_0 = icmp ult i32 %a, 10 | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ] | 
|  | br i1 undef, label %left, label %right | 
|  |  | 
|  | left: | 
|  |  | 
|  | %cond_1 = icmp ult i32 %b, 10 | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ] | 
|  | ret void | 
|  |  | 
|  | right: | 
|  | ret void | 
|  | } | 
|  |  | 
|  | ; But hoisting out of control flow is fine if it makes a loop computed | 
|  | ; condition loop invariant.  This behavior may require some tuning in | 
|  | ; the future. | 
|  | define void @f_4(i32 %a, i32 %b) { | 
|  | ; CHECK-LABEL: @f_4( | 
|  | ; CHECK-NEXT:  entry: | 
|  | ; CHECK-NEXT:    [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 10 | 
|  | ; CHECK-NEXT:    [[COND_1:%.*]] = icmp ult i32 [[B:%.*]], 10 | 
|  | ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0]], [[COND_1]] | 
|  | ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] | 
|  | ; CHECK-NEXT:    br i1 undef, label [[LOOP:%.*]], label [[LEAVE:%.*]] | 
|  | ; CHECK:       loop: | 
|  | ; CHECK-NEXT:    br i1 undef, label [[LOOP]], label [[LEAVE]] | 
|  | ; CHECK:       leave: | 
|  | ; CHECK-NEXT:    ret void | 
|  | ; | 
|  | entry: | 
|  |  | 
|  | %cond_0 = icmp ult i32 %a, 10 | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ] | 
|  | br i1 undef, label %loop, label %leave | 
|  |  | 
|  | loop: | 
|  | %cond_1 = icmp ult i32 %b, 10 | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ] | 
|  | br i1 undef, label %loop, label %leave | 
|  |  | 
|  | leave: | 
|  | ret void | 
|  | } | 
|  |  | 
|  | ; Hoisting out of control flow is also fine if we can widen the | 
|  | ; dominating check without doing any extra work. | 
|  | define void @f_5(i32 %a) { | 
|  | ; CHECK-LABEL: @f_5( | 
|  | ; CHECK-NEXT:  entry: | 
|  | ; CHECK-NEXT:    [[COND_0:%.*]] = icmp ugt i32 [[A:%.*]], 7 | 
|  | ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = icmp uge i32 [[A]], 11 | 
|  | ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] | 
|  | ; CHECK-NEXT:    br i1 undef, label [[LEFT:%.*]], label [[RIGHT:%.*]] | 
|  | ; CHECK:       left: | 
|  | ; CHECK-NEXT:    [[COND_1:%.*]] = icmp ugt i32 [[A]], 10 | 
|  | ; CHECK-NEXT:    ret void | 
|  | ; CHECK:       right: | 
|  | ; CHECK-NEXT:    ret void | 
|  | ; | 
|  | entry: | 
|  |  | 
|  | %cond_0 = icmp ugt i32 %a, 7 | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ] | 
|  | br i1 undef, label %left, label %right | 
|  |  | 
|  | left: | 
|  | %cond_1 = icmp ugt i32 %a, 10 | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ] | 
|  | ret void | 
|  |  | 
|  | right: | 
|  | ret void | 
|  | } | 
|  |  | 
|  | ; Negative test: the load from %a can be safely speculated to before | 
|  | ; the first guard, but there is no guarantee that it will produce the | 
|  | ; same value. | 
|  | define void @f_6(i1* dereferenceable(32) %a, i1* %b, i1 %unknown) { | 
|  | ; CHECK-LABEL: @f_6( | 
|  | ; CHECK-NEXT:  entry: | 
|  | ; CHECK-NEXT:    [[COND_0:%.*]] = load i1, i1* [[A:%.*]], align 1 | 
|  | ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0]]) [ "deopt"() ] | 
|  | ; CHECK-NEXT:    store i1 [[UNKNOWN:%.*]], i1* [[B:%.*]], align 1 | 
|  | ; CHECK-NEXT:    [[COND_1:%.*]] = load i1, i1* [[A]], align 1 | 
|  | ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND_1]]) [ "deopt"() ] | 
|  | ; CHECK-NEXT:    ret void | 
|  | ; | 
|  | entry: | 
|  | %cond_0 = load i1, i1* %a | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ] | 
|  | store i1 %unknown, i1* %b | 
|  | %cond_1 = load i1, i1* %a | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ] | 
|  | ret void | 
|  | } | 
|  |  | 
|  | ; All else equal, we try to widen the earliest guard we can.  This | 
|  | ; heuristic can use some tuning. | 
|  | define void @f_7(i32 %a, i1* %cond_buf) { | 
|  | ; CHECK-LABEL: @f_7( | 
|  | ; CHECK-NEXT:  entry: | 
|  | ; CHECK-NEXT:    [[COND_1:%.*]] = load volatile i1, i1* [[COND_BUF:%.*]], align 1 | 
|  | ; CHECK-NEXT:    [[COND_3:%.*]] = icmp ult i32 [[A:%.*]], 7 | 
|  | ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_3]] | 
|  | ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] | 
|  | ; CHECK-NEXT:    [[COND_2:%.*]] = load volatile i1, i1* [[COND_BUF]], align 1 | 
|  | ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND_2]]) [ "deopt"() ] | 
|  | ; CHECK-NEXT:    br i1 undef, label [[LEFT:%.*]], label [[RIGHT:%.*]] | 
|  | ; CHECK:       left: | 
|  | ; CHECK-NEXT:    br label [[LEFT]] | 
|  | ; CHECK:       right: | 
|  | ; CHECK-NEXT:    ret void | 
|  | ; | 
|  | entry: | 
|  |  | 
|  | %cond_1 = load volatile i1, i1* %cond_buf | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ] | 
|  | %cond_2 = load volatile i1, i1* %cond_buf | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"() ] | 
|  | br i1 undef, label %left, label %right | 
|  |  | 
|  | left: | 
|  | %cond_3 = icmp ult i32 %a, 7 | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %cond_3) [ "deopt"() ] | 
|  | br label %left | 
|  |  | 
|  | right: | 
|  | ret void | 
|  | } | 
|  |  | 
|  | ; In this case the earliest dominating guard is in a loop, and we | 
|  | ; don't want to put extra work in there.  This heuristic can use some | 
|  | ; tuning. | 
|  | define void @f_8(i32 %a, i1 %cond_1, i1 %cond_2) { | 
|  | ; CHECK-LABEL: @f_8( | 
|  | ; CHECK-NEXT:  entry: | 
|  | ; CHECK-NEXT:    br label [[LOOP:%.*]] | 
|  | ; CHECK:       loop: | 
|  | ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND_1:%.*]]) [ "deopt"() ] | 
|  | ; CHECK-NEXT:    br i1 undef, label [[LOOP]], label [[LEAVE:%.*]] | 
|  | ; CHECK:       leave: | 
|  | ; CHECK-NEXT:    [[COND_3:%.*]] = icmp ult i32 [[A:%.*]], 7 | 
|  | ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_2:%.*]], [[COND_3]] | 
|  | ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] | 
|  | ; CHECK-NEXT:    br i1 undef, label [[LOOP2:%.*]], label [[LEAVE2:%.*]] | 
|  | ; CHECK:       loop2: | 
|  | ; CHECK-NEXT:    br label [[LOOP2]] | 
|  | ; CHECK:       leave2: | 
|  | ; CHECK-NEXT:    ret void | 
|  | ; | 
|  | entry: | 
|  | br label %loop | 
|  |  | 
|  | loop: | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ] | 
|  | br i1 undef, label %loop, label %leave | 
|  |  | 
|  | leave: | 
|  |  | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"() ] | 
|  | br i1 undef, label %loop2, label %leave2 | 
|  |  | 
|  | loop2: | 
|  | %cond_3 = icmp ult i32 %a, 7 | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %cond_3) [ "deopt"() ] | 
|  | br label %loop2 | 
|  |  | 
|  | leave2: | 
|  | ret void | 
|  | } | 
|  |  | 
|  | ; In cases like these where there isn't any "obviously profitable" | 
|  | ; widening sites, we refuse to do anything. | 
|  | define void @f_9(i32 %a, i1 %cond_0, i1 %cond_1) { | 
|  | ; CHECK-LABEL: @f_9( | 
|  | ; CHECK-NEXT:  entry: | 
|  | ; CHECK-NEXT:    br label [[FIRST_LOOP:%.*]] | 
|  | ; CHECK:       first_loop: | 
|  | ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0:%.*]]) [ "deopt"() ] | 
|  | ; CHECK-NEXT:    br i1 undef, label [[FIRST_LOOP]], label [[SECOND_LOOP:%.*]] | 
|  | ; CHECK:       second_loop: | 
|  | ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND_1:%.*]]) [ "deopt"() ] | 
|  | ; CHECK-NEXT:    br label [[SECOND_LOOP]] | 
|  | ; | 
|  | entry: | 
|  | br label %first_loop | 
|  |  | 
|  | first_loop: | 
|  |  | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ] | 
|  | br i1 undef, label %first_loop, label %second_loop | 
|  |  | 
|  | second_loop: | 
|  |  | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ] | 
|  | br label %second_loop | 
|  | } | 
|  |  | 
|  | ; Same situation as in @f_9: no "obviously profitable" widening sites, | 
|  | ; so we refuse to do anything. | 
|  | define void @f_10(i32 %a, i1 %cond_0, i1 %cond_1) { | 
|  | ; CHECK-LABEL: @f_10( | 
|  | ; CHECK-NEXT:  entry: | 
|  | ; CHECK-NEXT:    br label [[LOOP:%.*]] | 
|  | ; CHECK:       loop: | 
|  | ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0:%.*]]) [ "deopt"() ] | 
|  | ; CHECK-NEXT:    br i1 undef, label [[LOOP]], label [[NO_LOOP:%.*]] | 
|  | ; CHECK:       no_loop: | 
|  | ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND_1:%.*]]) [ "deopt"() ] | 
|  | ; CHECK-NEXT:    ret void | 
|  | ; | 
|  | entry: | 
|  | br label %loop | 
|  |  | 
|  | loop: | 
|  |  | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ] | 
|  | br i1 undef, label %loop, label %no_loop | 
|  |  | 
|  | no_loop: | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ] | 
|  | ret void | 
|  | } | 
|  |  | 
|  | ; With guards in loops, we're okay hoisting out the guard into the | 
|  | ; containing loop. | 
|  | define void @f_11(i32 %a, i1 %cond_0, i1 %cond_1) { | 
|  | ; CHECK-LABEL: @f_11( | 
|  | ; CHECK-NEXT:  entry: | 
|  | ; CHECK-NEXT:    br label [[INNER:%.*]] | 
|  | ; CHECK:       inner: | 
|  | ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]] | 
|  | ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] | 
|  | ; CHECK-NEXT:    br i1 undef, label [[INNER]], label [[OUTER:%.*]] | 
|  | ; CHECK:       outer: | 
|  | ; CHECK-NEXT:    br label [[INNER]] | 
|  | ; | 
|  | entry: | 
|  | br label %inner | 
|  |  | 
|  | inner: | 
|  |  | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ] | 
|  | br i1 undef, label %inner, label %outer | 
|  |  | 
|  | outer: | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ] | 
|  | br label %inner | 
|  | } | 
|  |  | 
|  | ; Checks that we are adequately guarded against exponential-time | 
|  | ; behavior when hoisting code. | 
|  | define void @f_12(i32 %a0) { | 
|  | ; CHECK-LABEL: @f_12( | 
|  | ; CHECK-NEXT:  entry: | 
|  | ; CHECK-NEXT:    [[A1:%.*]] = mul i32 [[A0:%.*]], [[A0]] | 
|  | ; CHECK-NEXT:    [[A2:%.*]] = mul i32 [[A1]], [[A1]] | 
|  | ; CHECK-NEXT:    [[A3:%.*]] = mul i32 [[A2]], [[A2]] | 
|  | ; CHECK-NEXT:    [[A4:%.*]] = mul i32 [[A3]], [[A3]] | 
|  | ; CHECK-NEXT:    [[A5:%.*]] = mul i32 [[A4]], [[A4]] | 
|  | ; CHECK-NEXT:    [[A6:%.*]] = mul i32 [[A5]], [[A5]] | 
|  | ; CHECK-NEXT:    [[A7:%.*]] = mul i32 [[A6]], [[A6]] | 
|  | ; CHECK-NEXT:    [[A8:%.*]] = mul i32 [[A7]], [[A7]] | 
|  | ; CHECK-NEXT:    [[A9:%.*]] = mul i32 [[A8]], [[A8]] | 
|  | ; CHECK-NEXT:    [[A10:%.*]] = mul i32 [[A9]], [[A9]] | 
|  | ; CHECK-NEXT:    [[A11:%.*]] = mul i32 [[A10]], [[A10]] | 
|  | ; CHECK-NEXT:    [[A12:%.*]] = mul i32 [[A11]], [[A11]] | 
|  | ; CHECK-NEXT:    [[A13:%.*]] = mul i32 [[A12]], [[A12]] | 
|  | ; CHECK-NEXT:    [[A14:%.*]] = mul i32 [[A13]], [[A13]] | 
|  | ; CHECK-NEXT:    [[A15:%.*]] = mul i32 [[A14]], [[A14]] | 
|  | ; CHECK-NEXT:    [[A16:%.*]] = mul i32 [[A15]], [[A15]] | 
|  | ; CHECK-NEXT:    [[A17:%.*]] = mul i32 [[A16]], [[A16]] | 
|  | ; CHECK-NEXT:    [[A18:%.*]] = mul i32 [[A17]], [[A17]] | 
|  | ; CHECK-NEXT:    [[A19:%.*]] = mul i32 [[A18]], [[A18]] | 
|  | ; CHECK-NEXT:    [[A20:%.*]] = mul i32 [[A19]], [[A19]] | 
|  | ; CHECK-NEXT:    [[A21:%.*]] = mul i32 [[A20]], [[A20]] | 
|  | ; CHECK-NEXT:    [[A22:%.*]] = mul i32 [[A21]], [[A21]] | 
|  | ; CHECK-NEXT:    [[A23:%.*]] = mul i32 [[A22]], [[A22]] | 
|  | ; CHECK-NEXT:    [[A24:%.*]] = mul i32 [[A23]], [[A23]] | 
|  | ; CHECK-NEXT:    [[A25:%.*]] = mul i32 [[A24]], [[A24]] | 
|  | ; CHECK-NEXT:    [[A26:%.*]] = mul i32 [[A25]], [[A25]] | 
|  | ; CHECK-NEXT:    [[A27:%.*]] = mul i32 [[A26]], [[A26]] | 
|  | ; CHECK-NEXT:    [[A28:%.*]] = mul i32 [[A27]], [[A27]] | 
|  | ; CHECK-NEXT:    [[A29:%.*]] = mul i32 [[A28]], [[A28]] | 
|  | ; CHECK-NEXT:    [[A30:%.*]] = mul i32 [[A29]], [[A29]] | 
|  | ; CHECK-NEXT:    [[COND:%.*]] = trunc i32 [[A30]] to i1 | 
|  | ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 true, [[COND]] | 
|  | ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] | 
|  | ; CHECK-NEXT:    ret void | 
|  | ; | 
|  |  | 
|  | ; Eliding the earlier 29 multiplications for brevity | 
|  |  | 
|  | entry: | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 true) [ "deopt"() ] | 
|  | %a1 = mul i32 %a0, %a0 | 
|  | %a2 = mul i32 %a1, %a1 | 
|  | %a3 = mul i32 %a2, %a2 | 
|  | %a4 = mul i32 %a3, %a3 | 
|  | %a5 = mul i32 %a4, %a4 | 
|  | %a6 = mul i32 %a5, %a5 | 
|  | %a7 = mul i32 %a6, %a6 | 
|  | %a8 = mul i32 %a7, %a7 | 
|  | %a9 = mul i32 %a8, %a8 | 
|  | %a10 = mul i32 %a9, %a9 | 
|  | %a11 = mul i32 %a10, %a10 | 
|  | %a12 = mul i32 %a11, %a11 | 
|  | %a13 = mul i32 %a12, %a12 | 
|  | %a14 = mul i32 %a13, %a13 | 
|  | %a15 = mul i32 %a14, %a14 | 
|  | %a16 = mul i32 %a15, %a15 | 
|  | %a17 = mul i32 %a16, %a16 | 
|  | %a18 = mul i32 %a17, %a17 | 
|  | %a19 = mul i32 %a18, %a18 | 
|  | %a20 = mul i32 %a19, %a19 | 
|  | %a21 = mul i32 %a20, %a20 | 
|  | %a22 = mul i32 %a21, %a21 | 
|  | %a23 = mul i32 %a22, %a22 | 
|  | %a24 = mul i32 %a23, %a23 | 
|  | %a25 = mul i32 %a24, %a24 | 
|  | %a26 = mul i32 %a25, %a25 | 
|  | %a27 = mul i32 %a26, %a26 | 
|  | %a28 = mul i32 %a27, %a27 | 
|  | %a29 = mul i32 %a28, %a28 | 
|  | %a30 = mul i32 %a29, %a29 | 
|  | %cond = trunc i32 %a30 to i1 | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %cond) [ "deopt"() ] | 
|  | ret void | 
|  | } | 
|  |  | 
|  | define void @f_13(i32 %a) { | 
|  | ; CHECK-LABEL: @f_13( | 
|  | ; CHECK-NEXT:  entry: | 
|  | ; CHECK-NEXT:    [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 14 | 
|  | ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = icmp ult i32 [[A]], 10 | 
|  | ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] | 
|  | ; CHECK-NEXT:    br i1 undef, label [[LEFT:%.*]], label [[RIGHT:%.*]] | 
|  | ; CHECK:       left: | 
|  | ; CHECK-NEXT:    [[COND_1:%.*]] = icmp slt i32 [[A]], 10 | 
|  | ; CHECK-NEXT:    ret void | 
|  | ; CHECK:       right: | 
|  | ; CHECK-NEXT:    ret void | 
|  | ; | 
|  | entry: | 
|  |  | 
|  | %cond_0 = icmp ult i32 %a, 14 | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ] | 
|  | br i1 undef, label %left, label %right | 
|  |  | 
|  | left: | 
|  | %cond_1 = icmp slt i32 %a, 10 | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ] | 
|  | ret void | 
|  |  | 
|  | right: | 
|  | ret void | 
|  | } | 
|  |  | 
|  | define void @f_14(i32 %a) { | 
|  | ; CHECK-LABEL: @f_14( | 
|  | ; CHECK-NEXT:  entry: | 
|  | ; CHECK-NEXT:    [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 14 | 
|  | ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0]]) [ "deopt"() ] | 
|  | ; CHECK-NEXT:    br i1 undef, label [[LEFT:%.*]], label [[RIGHT:%.*]] | 
|  | ; CHECK:       left: | 
|  | ; CHECK-NEXT:    [[COND_1:%.*]] = icmp sgt i32 [[A]], 10 | 
|  | ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND_1]]) [ "deopt"() ] | 
|  | ; CHECK-NEXT:    ret void | 
|  | ; CHECK:       right: | 
|  | ; CHECK-NEXT:    ret void | 
|  | ; | 
|  | entry: | 
|  |  | 
|  | %cond_0 = icmp ult i32 %a, 14 | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ] | 
|  | br i1 undef, label %left, label %right | 
|  |  | 
|  | left: | 
|  |  | 
|  | %cond_1 = icmp sgt i32 %a, 10 | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ] | 
|  | ret void | 
|  |  | 
|  | right: | 
|  | ret void | 
|  | } | 
|  |  | 
|  | ; Make sure we do not widen guard by trivial true conditions into something. | 
|  | define void @f_15(i1 %cond_0, i1 %cond_1) { | 
|  | ; CHECK-LABEL: @f_15( | 
|  | ; CHECK-NEXT:  entry: | 
|  | ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0:%.*]]) [ "deopt"() ] | 
|  | ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 true) [ "deopt"() ] | 
|  | ; CHECK-NEXT:    ret void | 
|  | ; | 
|  | entry: | 
|  |  | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ] | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 true) [ "deopt"() ] | 
|  | ret void | 
|  | } | 
|  |  | 
|  | ; Make sure we do not widen guard by trivial false conditions into something. | 
|  | define void @f_16(i1 %cond_0, i1 %cond_1) { | 
|  | ; CHECK-LABEL: @f_16( | 
|  | ; CHECK-NEXT:  entry: | 
|  | ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0:%.*]]) [ "deopt"() ] | 
|  | ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 false) [ "deopt"() ] | 
|  | ; CHECK-NEXT:    ret void | 
|  | ; | 
|  | entry: | 
|  |  | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ] | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 false) [ "deopt"() ] | 
|  | ret void | 
|  | } |