|  | ; RUN: opt < %s -jump-threading -dce -S | FileCheck %s | 
|  |  | 
|  | declare void @llvm.experimental.guard(i1, ...) | 
|  |  | 
|  | declare i32 @f1() | 
|  | declare i32 @f2() | 
|  |  | 
|  | define i32 @branch_implies_guard(i32 %a) { | 
|  | ; CHECK-LABEL: @branch_implies_guard( | 
|  | %cond = icmp slt i32 %a, 10 | 
|  | br i1 %cond, label %T1, label %F1 | 
|  |  | 
|  | T1: | 
|  | ; CHECK:       T1.split | 
|  | ; CHECK:         %v1 = call i32 @f1() | 
|  | ; CHECK-NEXT:    %retVal | 
|  | ; CHECK-NEXT:    br label %Merge | 
|  | %v1 = call i32 @f1() | 
|  | br label %Merge | 
|  |  | 
|  | F1: | 
|  | ; CHECK:       F1.split | 
|  | ; CHECK:         %v2 = call i32 @f2() | 
|  | ; CHECK-NEXT:    %retVal | 
|  | ; CHECK-NEXT:    %condGuard | 
|  | ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 %condGuard | 
|  | ; CHECK-NEXT:    br label %Merge | 
|  | %v2 = call i32 @f2() | 
|  | br label %Merge | 
|  |  | 
|  | Merge: | 
|  | ; CHECK:       Merge | 
|  | ; CHECK-NOT:     call void(i1, ...) @llvm.experimental.guard( | 
|  | %retPhi = phi i32 [ %v1, %T1 ], [ %v2, %F1 ] | 
|  | %retVal = add i32 %retPhi, 10 | 
|  | %condGuard = icmp slt i32 %a, 20 | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ] | 
|  | ret i32 %retVal | 
|  | } | 
|  |  | 
|  | define i32 @not_branch_implies_guard(i32 %a) { | 
|  | ; CHECK-LABEL: @not_branch_implies_guard( | 
|  | %cond = icmp slt i32 %a, 20 | 
|  | br i1 %cond, label %T1, label %F1 | 
|  |  | 
|  | T1: | 
|  | ; CHECK:       T1.split: | 
|  | ; CHECK-NEXT:    %v1 = call i32 @f1() | 
|  | ; CHECK-NEXT:    %retVal | 
|  | ; CHECK-NEXT:    %condGuard | 
|  | ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 %condGuard | 
|  | ; CHECK-NEXT:    br label %Merge | 
|  | %v1 = call i32 @f1() | 
|  | br label %Merge | 
|  |  | 
|  | F1: | 
|  | ; CHECK:       F1.split: | 
|  | ; CHECK-NEXT:   %v2 = call i32 @f2() | 
|  | ; CHECK-NEXT:   %retVal | 
|  | ; CHECK-NEXT:   br label %Merge | 
|  | %v2 = call i32 @f2() | 
|  | br label %Merge | 
|  |  | 
|  | Merge: | 
|  | ; CHECK:       Merge | 
|  | ; CHECK-NOT:     call void(i1, ...) @llvm.experimental.guard( | 
|  | %retPhi = phi i32 [ %v1, %T1 ], [ %v2, %F1 ] | 
|  | %retVal = add i32 %retPhi, 10 | 
|  | %condGuard = icmp sgt i32 %a, 10 | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ] | 
|  | ret i32 %retVal | 
|  | } | 
|  |  | 
|  | define i32 @branch_overlaps_guard(i32 %a) { | 
|  | ; CHECK-LABEL: @branch_overlaps_guard( | 
|  | %cond = icmp slt i32 %a, 20 | 
|  | br i1 %cond, label %T1, label %F1 | 
|  |  | 
|  | T1: | 
|  | ; CHECK:        T1: | 
|  | ; CHECK-NEXT:      %v1 = call i32 @f1() | 
|  | ; CHECK-NEXT:      br label %Merge | 
|  | %v1 = call i32 @f1() | 
|  | br label %Merge | 
|  |  | 
|  | F1: | 
|  | ; CHECK:        F1: | 
|  | ; CHECK-NEXT:     %v2 = call i32 @f2() | 
|  | ; CHECK-NEXT:     br label %Merge | 
|  | %v2 = call i32 @f2() | 
|  | br label %Merge | 
|  |  | 
|  | Merge: | 
|  | ; CHECK:       Merge | 
|  | ; CHECK:         %condGuard = icmp slt i32 %a, 10 | 
|  | ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ] | 
|  | %retPhi = phi i32 [ %v1, %T1 ], [ %v2, %F1 ] | 
|  | %retVal = add i32 %retPhi, 10 | 
|  | %condGuard = icmp slt i32 %a, 10 | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ] | 
|  | ret i32 %retVal | 
|  | } | 
|  |  | 
|  | define i32 @branch_doesnt_overlap_guard(i32 %a) { | 
|  | ; CHECK-LABEL: @branch_doesnt_overlap_guard( | 
|  | %cond = icmp slt i32 %a, 10 | 
|  | br i1 %cond, label %T1, label %F1 | 
|  |  | 
|  | T1: | 
|  | ; CHECK:        T1: | 
|  | ; CHECK-NEXT:      %v1 = call i32 @f1() | 
|  | ; CHECK-NEXT:      br label %Merge | 
|  | %v1 = call i32 @f1() | 
|  | br label %Merge | 
|  |  | 
|  | F1: | 
|  | ; CHECK:        F1: | 
|  | ; CHECK-NEXT:     %v2 = call i32 @f2() | 
|  | ; CHECK-NEXT:     br label %Merge | 
|  | %v2 = call i32 @f2() | 
|  | br label %Merge | 
|  |  | 
|  | Merge: | 
|  | ; CHECK:       Merge | 
|  | ; CHECK:         %condGuard = icmp sgt i32 %a, 20 | 
|  | ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ] | 
|  | %retPhi = phi i32 [ %v1, %T1 ], [ %v2, %F1 ] | 
|  | %retVal = add i32 %retPhi, 10 | 
|  | %condGuard = icmp sgt i32 %a, 20 | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ] | 
|  | ret i32 %retVal | 
|  | } | 
|  |  | 
|  | define i32 @not_a_diamond1(i32 %a, i1 %cond1) { | 
|  | ; CHECK-LABEL: @not_a_diamond1( | 
|  | br i1 %cond1, label %Pred, label %Exit | 
|  |  | 
|  | Pred: | 
|  | ; CHECK:       Pred: | 
|  | ; CHECK-NEXT:    switch i32 %a, label %Exit | 
|  | switch i32 %a, label %Exit [ | 
|  | i32 10, label %Merge | 
|  | i32 20, label %Merge | 
|  | ] | 
|  |  | 
|  | Merge: | 
|  | ; CHECK:       Merge: | 
|  | ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 %cond1) [ "deopt"() ] | 
|  | ; CHECK-NEXT:    br label %Exit | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %cond1) [ "deopt"() ] | 
|  | br label %Exit | 
|  |  | 
|  | Exit: | 
|  | ; CHECK:       Exit: | 
|  | ; CHECK-NEXT:    ret i32 %a | 
|  | ret i32 %a | 
|  | } | 
|  |  | 
|  | define void @not_a_diamond2(i32 %a, i1 %cond1) { | 
|  | ; CHECK-LABEL: @not_a_diamond2( | 
|  | br label %Parent | 
|  |  | 
|  | Merge: | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %cond1)[ "deopt"() ] | 
|  | ret void | 
|  |  | 
|  | Pred: | 
|  | ; CHECK-NEXT:  Pred: | 
|  | ; CHECK-NEXT:    switch i32 %a, label %Exit | 
|  | switch i32 %a, label %Exit [ | 
|  | i32 10, label %Merge | 
|  | i32 20, label %Merge | 
|  | ] | 
|  |  | 
|  | Parent: | 
|  | br label %Pred | 
|  |  | 
|  | Exit: | 
|  | ; CHECK:       Merge: | 
|  | ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 %cond1) [ "deopt"() ] | 
|  | ; CHECK-NEXT:    ret void | 
|  | ret void | 
|  | } | 
|  |  | 
|  | declare void @never_called(i1) | 
|  |  | 
|  | ; LVI uses guard to identify value of %c2 in branch as true, we cannot replace that | 
|  | ; guard with guard(true & c1). | 
|  | define void @dont_fold_guard(i8* %addr, i32 %i, i32 %length) { | 
|  | ; CHECK-LABEL: dont_fold_guard | 
|  | ; CHECK: %wide.chk = and i1 %c1, %c2 | 
|  | ; CHECK-NEXT: experimental.guard(i1 %wide.chk) | 
|  | ; CHECK-NEXT: call void @never_called(i1 true) | 
|  | ; CHECK-NEXT: ret void | 
|  | %c1 = icmp ult i32 %i, %length | 
|  | %c2 = icmp eq i32 %i, 0 | 
|  | %wide.chk = and i1 %c1, %c2 | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %wide.chk) [ "deopt"() ] | 
|  | br i1 %c2, label %BB1, label %BB2 | 
|  |  | 
|  | BB1: | 
|  | call void @never_called(i1 %c2) | 
|  | ret void | 
|  |  | 
|  | BB2: | 
|  | ret void | 
|  | } | 
|  |  | 
|  | declare void @dummy(i1) nounwind argmemonly | 
|  | ; same as dont_fold_guard1 but there's a use immediately after guard and before | 
|  | ; branch. We can fold that use. | 
|  | define void @dont_fold_guard2(i8* %addr, i32 %i, i32 %length) { | 
|  | ; CHECK-LABEL: dont_fold_guard2 | 
|  | ; CHECK: %wide.chk = and i1 %c1, %c2 | 
|  | ; CHECK-NEXT: experimental.guard(i1 %wide.chk) | 
|  | ; CHECK-NEXT: dummy(i1 true) | 
|  | ; CHECK-NEXT: call void @never_called(i1 true) | 
|  | ; CHECK-NEXT: ret void | 
|  | %c1 = icmp ult i32 %i, %length | 
|  | %c2 = icmp eq i32 %i, 0 | 
|  | %wide.chk = and i1 %c1, %c2 | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %wide.chk) [ "deopt"() ] | 
|  | call void @dummy(i1 %c2) | 
|  | br i1 %c2, label %BB1, label %BB2 | 
|  |  | 
|  | BB1: | 
|  | call void @never_called(i1 %c2) | 
|  | ret void | 
|  |  | 
|  | BB2: | 
|  | ret void | 
|  | } | 
|  |  | 
|  | ; same as dont_fold_guard1 but condition %cmp is not an instruction. | 
|  | ; We cannot fold the guard under any circumstance. | 
|  | ; FIXME: We can merge unreachableBB2 into not_zero. | 
|  | define void @dont_fold_guard3(i8* %addr, i1 %cmp, i32 %i, i32 %length) { | 
|  | ; CHECK-LABEL: dont_fold_guard3 | 
|  | ; CHECK: guard(i1 %cmp) | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] | 
|  | br i1 %cmp, label %BB1, label %BB2 | 
|  |  | 
|  | BB1: | 
|  | call void @never_called(i1 %cmp) | 
|  | ret void | 
|  |  | 
|  | BB2: | 
|  | ret void | 
|  | } | 
|  |  | 
|  | declare void @f(i1) | 
|  | ; Same as dont_fold_guard1 but use switch instead of branch. | 
|  | ; triggers source code `ProcessThreadableEdges`. | 
|  | define void @dont_fold_guard4(i1 %cmp1, i32 %i) nounwind { | 
|  | ; CHECK-LABEL: dont_fold_guard4 | 
|  | ; CHECK-LABEL: L2: | 
|  | ; CHECK-NEXT: %cmp = icmp eq i32 %i, 0 | 
|  | ; CHECK-NEXT: guard(i1 %cmp) | 
|  | ; CHECK-NEXT: dummy(i1 true) | 
|  | ; CHECK-NEXT: @f(i1 true) | 
|  | ; CHECK-NEXT: ret void | 
|  | entry: | 
|  | br i1 %cmp1, label %L0, label %L3 | 
|  | L0: | 
|  | %cmp = icmp eq i32 %i, 0 | 
|  | call void(i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] | 
|  | call void @dummy(i1 %cmp) | 
|  | switch i1 %cmp, label %L3 [ | 
|  | i1 false, label %L1 | 
|  | i1 true, label %L2 | 
|  | ] | 
|  |  | 
|  | L1: | 
|  | ret void | 
|  | L2: | 
|  | call void @f(i1 %cmp) | 
|  | ret void | 
|  | L3: | 
|  | ret void | 
|  | } | 
|  |  | 
|  | ; Make sure that we don't PRE a non-speculable load across a guard. | 
|  | define void @unsafe_pre_across_guard(i8* %p, i1 %load.is.valid) { | 
|  |  | 
|  | ; CHECK-LABEL: @unsafe_pre_across_guard( | 
|  | ; CHECK-NOT:   loaded.pr | 
|  | ; CHECK:       entry: | 
|  | ; CHECK-NEXT:    br label %loop | 
|  | ; CHECK:       loop: | 
|  | ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 %load.is.valid) [ "deopt"() ] | 
|  | ; CHECK-NEXT:    %loaded = load i8, i8* %p | 
|  | ; CHECK-NEXT:    %continue = icmp eq i8 %loaded, 0 | 
|  | ; CHECK-NEXT:    br i1 %continue, label %exit, label %loop | 
|  | entry: | 
|  | br label %loop | 
|  |  | 
|  | loop:                                             ; preds = %loop, %entry | 
|  | call void (i1, ...) @llvm.experimental.guard(i1 %load.is.valid) [ "deopt"() ] | 
|  | %loaded = load i8, i8* %p | 
|  | %continue = icmp eq i8 %loaded, 0 | 
|  | br i1 %continue, label %exit, label %loop | 
|  |  | 
|  | exit:                                             ; preds = %loop | 
|  | ret void | 
|  | } | 
|  |  | 
|  | ; Make sure that we can safely PRE a speculable load across a guard. | 
|  | define void @safe_pre_across_guard(i8* noalias nocapture readonly dereferenceable(8) %p, i1 %load.is.valid) { | 
|  |  | 
|  | ; CHECK-LABEL: @safe_pre_across_guard( | 
|  | ; CHECK:       entry: | 
|  | ; CHECK-NEXT:    %loaded.pr = load i8, i8* %p | 
|  | ; CHECK-NEXT:    br label %loop | 
|  | ; CHECK:       loop: | 
|  | ; CHECK-NEXT:    %loaded = phi i8 [ %loaded, %loop ], [ %loaded.pr, %entry ] | 
|  | ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 %load.is.valid) [ "deopt"() ] | 
|  | ; CHECK-NEXT:    %continue = icmp eq i8 %loaded, 0 | 
|  | ; CHECK-NEXT:    br i1 %continue, label %exit, label %loop | 
|  |  | 
|  | entry: | 
|  | br label %loop | 
|  |  | 
|  | loop:                                             ; preds = %loop, %entry | 
|  | call void (i1, ...) @llvm.experimental.guard(i1 %load.is.valid) [ "deopt"() ] | 
|  | %loaded = load i8, i8* %p | 
|  | %continue = icmp eq i8 %loaded, 0 | 
|  | br i1 %continue, label %exit, label %loop | 
|  |  | 
|  | exit:                                             ; preds = %loop | 
|  | ret void | 
|  | } | 
|  |  | 
|  | ; Make sure that we don't PRE a non-speculable load across a call which may | 
|  | ; alias with the load. | 
|  | define void @unsafe_pre_across_call(i8* %p) { | 
|  |  | 
|  | ; CHECK-LABEL: @unsafe_pre_across_call( | 
|  | ; CHECK-NOT:   loaded.pr | 
|  | ; CHECK:       entry: | 
|  | ; CHECK-NEXT:    br label %loop | 
|  | ; CHECK:       loop: | 
|  | ; CHECK-NEXT:    call i32 @f1() | 
|  | ; CHECK-NEXT:    %loaded = load i8, i8* %p | 
|  | ; CHECK-NEXT:    %continue = icmp eq i8 %loaded, 0 | 
|  | ; CHECK-NEXT:    br i1 %continue, label %exit, label %loop | 
|  | entry: | 
|  | br label %loop | 
|  |  | 
|  | loop:                                             ; preds = %loop, %entry | 
|  | call i32 @f1() | 
|  | %loaded = load i8, i8* %p | 
|  | %continue = icmp eq i8 %loaded, 0 | 
|  | br i1 %continue, label %exit, label %loop | 
|  |  | 
|  | exit:                                             ; preds = %loop | 
|  | ret void | 
|  | } | 
|  |  | 
|  | ; Make sure that we can safely PRE a speculable load across a call. | 
|  | define void @safe_pre_across_call(i8* noalias nocapture readonly dereferenceable(8) %p) { | 
|  |  | 
|  | ; CHECK-LABEL: @safe_pre_across_call( | 
|  | ; CHECK:       entry: | 
|  | ; CHECK-NEXT:    %loaded.pr = load i8, i8* %p | 
|  | ; CHECK-NEXT:    br label %loop | 
|  | ; CHECK:       loop: | 
|  | ; CHECK-NEXT:    %loaded = phi i8 [ %loaded, %loop ], [ %loaded.pr, %entry ] | 
|  | ; CHECK-NEXT:    call i32 @f1() | 
|  | ; CHECK-NEXT:    %continue = icmp eq i8 %loaded, 0 | 
|  | ; CHECK-NEXT:    br i1 %continue, label %exit, label %loop | 
|  |  | 
|  | entry: | 
|  | br label %loop | 
|  |  | 
|  | loop:                                             ; preds = %loop, %entry | 
|  | call i32 @f1() | 
|  | %loaded = load i8, i8* %p | 
|  | %continue = icmp eq i8 %loaded, 0 | 
|  | br i1 %continue, label %exit, label %loop | 
|  |  | 
|  | exit:                                             ; preds = %loop | 
|  | ret void | 
|  | } |