[GuardWidening] Freeze the introduced use. Re-land.
authorSerguei Katkov <serguei.katkov@azul.com>
Thu, 30 Mar 2023 03:21:31 +0000 (10:21 +0700)
committerSerguei Katkov <serguei.katkov@azul.com>
Thu, 30 Mar 2023 03:59:01 +0000 (10:59 +0700)
Non-determenism is fixed.

Guard widening optimization is able to move the condition from one
guard to the previous one. As a result if the condition is poison
and orginal second guard is never executed but the first one does,
we introduce undefined behavior which was not observed in original
program.

To resolve the issue we must freeze the condition we are moving.
However optimization itself does not know how to work with freeze.
Additionally optimization is written in incremental way.
For example we have three guards
G1(base + 8 < L)
G2(base + 16 < L)
G3(base + 24 < L)

On the first step GW will combine G1 and G2 as
G1(base + 8 < L && freeze(base + 16 < L))
G2(true)
G3(base + 24 < L)

while combining G1 and G3 base appears to be different.

To keep optimization enabled after freezing the moving condition, the
freeze instruction is pushed as much as possible and later all uses
of freezed values are replaced with frozen version.

This is similar what instruction combining does but more aggressevely.

13 files changed:
llvm/lib/Transforms/Scalar/GuardWidening.cpp
llvm/test/Transforms/GuardWidening/basic-loop.ll
llvm/test/Transforms/GuardWidening/basic.ll
llvm/test/Transforms/GuardWidening/basic_widenable_condition_guards.ll
llvm/test/Transforms/GuardWidening/hang.ll
llvm/test/Transforms/GuardWidening/loop-schedule.ll
llvm/test/Transforms/GuardWidening/loop_invariant_widenable_condition.ll
llvm/test/Transforms/GuardWidening/mixed_guards.ll
llvm/test/Transforms/GuardWidening/posion.ll
llvm/test/Transforms/GuardWidening/profile-based-profitability-intrinsics.ll
llvm/test/Transforms/GuardWidening/profile-based-profitability_explicit.ll
llvm/test/Transforms/GuardWidening/range-check-merging.ll
llvm/test/Transforms/GuardWidening/two_forms_behavior_consistency.ll

index 7100f53..032ce9b 100644 (file)
@@ -69,6 +69,7 @@ using namespace llvm;
 
 STATISTIC(GuardsEliminated, "Number of eliminated guards");
 STATISTIC(CondBranchEliminated, "Number of eliminated conditional branches");
+STATISTIC(FreezeAdded, "Number of freeze instruction introduced");
 
 static cl::opt<bool>
     WidenBranchGuards("guard-widening-widen-branch-guards", cl::Hidden,
@@ -209,6 +210,10 @@ class GuardWideningImpl {
   bool widenCondCommon(Value *Cond0, Value *Cond1, Instruction *InsertPt,
                        Value *&Result, bool InvertCondition);
 
+  /// Adds freeze to Orig and push it as far as possible very aggressively.
+  /// Also replaces all uses of frozen instruction with frozen version.
+  Value *freezeAndPush(Value *Orig, Instruction *InsertPt);
+
   /// Represents a range check of the form \c Base + \c Offset u< \c Length,
   /// with the constraint that \c Length is not negative.  \c CheckInst is the
   /// pre-existing instruction in the IR that computes the result of this range
@@ -558,8 +563,80 @@ void GuardWideningImpl::makeAvailableAt(Value *V, Instruction *Loc) const {
     makeAvailableAt(Op, Loc);
 
   Inst->moveBefore(Loc);
-  // If we moved instruction before guard we must clean poison generating flags.
-  Inst->dropPoisonGeneratingFlags();
+}
+
+// Return Instruction before which we can insert freeze for the value V as close
+// to def as possible. If there is no place to add freeze, return nullptr.
+static Instruction *getFreezeInsertPt(Value *V, const DominatorTree &DT) {
+  auto *I = dyn_cast<Instruction>(V);
+  if (!I)
+    return &*DT.getRoot()->getFirstNonPHIOrDbgOrAlloca();
+
+  auto *Res = I->getInsertionPointAfterDef();
+  // If there is no place to add freeze - return nullptr.
+  if (!Res || !DT.dominates(I, Res))
+    return nullptr;
+
+  // If there is a User dominated by original I, then it should be dominated
+  // by Freeze instruction as well.
+  if (any_of(I->users(), [&](User *U) {
+        Instruction *User = cast<Instruction>(U);
+        return Res != User && DT.dominates(I, User) && !DT.dominates(Res, User);
+      }))
+    return nullptr;
+  return Res;
+}
+
+Value *GuardWideningImpl::freezeAndPush(Value *Orig, Instruction *InsertPt) {
+  if (isGuaranteedNotToBePoison(Orig, nullptr, InsertPt, &DT))
+    return Orig;
+  Instruction *InsertPtAtDef = getFreezeInsertPt(Orig, DT);
+  if (!InsertPtAtDef)
+    return new FreezeInst(Orig, "gw.freeze", InsertPt);
+  SmallSet<Value *, 16> Visited;
+  SmallVector<Value *, 16> Worklist;
+  SmallSet<Instruction *, 16> DropPoisonFlags;
+  SmallVector<Value *, 16> NeedFreeze;
+  Worklist.push_back(Orig);
+  while (!Worklist.empty()) {
+    Value *V = Worklist.pop_back_val();
+    if (!Visited.insert(V).second)
+      continue;
+
+    if (isGuaranteedNotToBePoison(V, nullptr, InsertPt, &DT))
+      continue;
+
+    Instruction *I = dyn_cast<Instruction>(V);
+    if (!I || canCreateUndefOrPoison(cast<Operator>(I),
+                                     /*ConsiderFlagsAndMetadata*/ false)) {
+      NeedFreeze.push_back(V);
+      continue;
+    }
+    // Check all operands. If for any of them we cannot insert Freeze,
+    // stop here. Otherwise, iterate.
+    if (any_of(I->operands(), [&](Value *Op) {
+          return isa<Instruction>(Op) && !getFreezeInsertPt(Op, DT);
+        })) {
+      NeedFreeze.push_back(I);
+      continue;
+    }
+    DropPoisonFlags.insert(I);
+    append_range(Worklist, I->operands());
+  }
+  for (Instruction *I : DropPoisonFlags)
+    I->dropPoisonGeneratingFlagsAndMetadata();
+
+  Value *Result = Orig;
+  for (Value *V : NeedFreeze) {
+    auto *FreezeInsertPt = getFreezeInsertPt(V, DT);
+    FreezeInst *FI = new FreezeInst(V, V->getName() + ".gw.fr", FreezeInsertPt);
+    ++FreezeAdded;
+    if (V == Orig)
+      Result = FI;
+    V->replaceUsesWithIf(FI, [&](Use & U)->bool { return U.getUser() != FI; });
+  }
+
+  return Result;
 }
 
 bool GuardWideningImpl::widenCondCommon(Value *Cond0, Value *Cond1,
@@ -621,6 +698,7 @@ bool GuardWideningImpl::widenCondCommon(Value *Cond0, Value *Cond1,
         }
         assert(Result && "Failed to find result value");
         Result->setName("wide.chk");
+        Result = freezeAndPush(Result, InsertPt);
       }
       return true;
     }
@@ -633,6 +711,7 @@ bool GuardWideningImpl::widenCondCommon(Value *Cond0, Value *Cond1,
     makeAvailableAt(Cond1, InsertPt);
     if (InvertCondition)
       Cond1 = BinaryOperator::CreateNot(Cond1, "inverted", InsertPt);
+    Cond1 = freezeAndPush(Cond1, InsertPt);
     Result = BinaryOperator::CreateAnd(Cond0, Cond1, "wide.chk", InsertPt);
   }
 
index 1626cca..956d920 100644 (file)
@@ -10,11 +10,13 @@ declare void @llvm.experimental.guard(i1,...)
 define void @widen_within_loop(i1 %cond_0, i1 %cond_1, i1 %cond_2) {
 ; CHECK-LABEL: @widen_within_loop(
 ; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[COND_2_GW_FR:%.*]] = freeze i1 [[COND_2:%.*]]
+; CHECK-NEXT:    [[COND_1_GW_FR:%.*]] = freeze i1 [[COND_1:%.*]]
 ; CHECK-NEXT:    br label [[LOOP:%.*]]
 ; CHECK:       loop:
 ; CHECK-NEXT:    store i32 0, ptr @G, align 4
-; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]]
-; CHECK-NEXT:    [[WIDE_CHK1:%.*]] = and i1 [[WIDE_CHK]], [[COND_2:%.*]]
+; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1_GW_FR]]
+; CHECK-NEXT:    [[WIDE_CHK1:%.*]] = and i1 [[WIDE_CHK]], [[COND_2_GW_FR]]
 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK1]]) [ "deopt"(i32 0) ]
 ; CHECK-NEXT:    store i32 1, ptr @G, align 4
 ; CHECK-NEXT:    store i32 2, ptr @G, align 4
@@ -38,9 +40,11 @@ loop:
 define void @widen_into_preheader(i1 %cond_0, i1 %cond_1, i1 %cond_2) {
 ; CHECK-LABEL: @widen_into_preheader(
 ; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[COND_2_GW_FR:%.*]] = freeze i1 [[COND_2:%.*]]
+; CHECK-NEXT:    [[COND_1_GW_FR:%.*]] = freeze i1 [[COND_1:%.*]]
 ; CHECK-NEXT:    store i32 0, ptr @G, align 4
-; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]]
-; CHECK-NEXT:    [[WIDE_CHK1:%.*]] = and i1 [[WIDE_CHK]], [[COND_2:%.*]]
+; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1_GW_FR]]
+; CHECK-NEXT:    [[WIDE_CHK1:%.*]] = and i1 [[WIDE_CHK]], [[COND_2_GW_FR]]
 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK1]]) [ "deopt"(i32 0) ]
 ; CHECK-NEXT:    br label [[LOOP:%.*]]
 ; CHECK:       loop:
@@ -102,8 +106,9 @@ exit:
 define void @widen_over_common_exit_to_ph(i1 %cond_0, i1 %cond_1, i1 %cond_2) {
 ; CHECK-LABEL: @widen_over_common_exit_to_ph(
 ; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[COND_2_GW_FR:%.*]] = freeze i1 [[COND_2:%.*]]
 ; CHECK-NEXT:    store i32 0, ptr @G, align 4
-; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_2:%.*]]
+; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_2_GW_FR]]
 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"(i32 0) ]
 ; CHECK-NEXT:    br label [[LOOP:%.*]]
 ; CHECK:       loop:
index dd504a4..096ea90 100644 (file)
@@ -9,7 +9,8 @@ declare void @llvm.experimental.guard(i1,...)
 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:    [[COND_1_GW_FR:%.*]] = freeze i1 [[COND_1:%.*]]
+; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1_GW_FR]]
 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
 ; CHECK-NEXT:    ret void
 ;
@@ -24,7 +25,8 @@ entry:
 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:    [[COND_1_GW_FR:%.*]] = freeze i1 [[COND_1:%.*]]
+; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1_GW_FR]]
 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
 ; CHECK-NEXT:    br i1 undef, label [[LEFT:%.*]], label [[RIGHT:%.*]]
 ; CHECK:       left:
@@ -55,8 +57,9 @@ merge:
 define void @f_2(i32 %a, i32 %b) {
 ; CHECK-LABEL: @f_2(
 ; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[B_GW_FR:%.*]] = freeze i32 [[B:%.*]]
 ; CHECK-NEXT:    [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 10
-; CHECK-NEXT:    [[COND_1:%.*]] = icmp ult i32 [[B:%.*]], 10
+; CHECK-NEXT:    [[COND_1:%.*]] = icmp ult i32 [[B_GW_FR]], 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:%.*]]
@@ -122,8 +125,9 @@ right:
 define void @f_4(i32 %a, i32 %b) {
 ; CHECK-LABEL: @f_4(
 ; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[B_GW_FR:%.*]] = freeze i32 [[B:%.*]]
 ; CHECK-NEXT:    [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 10
-; CHECK-NEXT:    [[COND_1:%.*]] = icmp ult i32 [[B:%.*]], 10
+; CHECK-NEXT:    [[COND_1:%.*]] = icmp ult i32 [[B_GW_FR]], 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:%.*]]
@@ -204,8 +208,9 @@ entry:
 define void @f_7(i32 %a, ptr %cond_buf) {
 ; CHECK-LABEL: @f_7(
 ; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[A_GW_FR:%.*]] = freeze i32 [[A:%.*]]
 ; CHECK-NEXT:    [[COND_1:%.*]] = load volatile i1, ptr [[COND_BUF:%.*]], align 1
-; CHECK-NEXT:    [[COND_3:%.*]] = icmp ult i32 [[A:%.*]], 7
+; CHECK-NEXT:    [[COND_3:%.*]] = icmp ult i32 [[A_GW_FR]], 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, ptr [[COND_BUF]], align 1
@@ -239,12 +244,13 @@ right:
 define void @f_8(i32 %a, i1 %cond_1, i1 %cond_2) {
 ; CHECK-LABEL: @f_8(
 ; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[A_GW_FR:%.*]] = freeze i32 [[A:%.*]]
 ; 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:    [[COND_3:%.*]] = icmp ult i32 [[A_GW_FR]], 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:%.*]]
@@ -332,9 +338,10 @@ no_loop:
 define void @f_11(i32 %a, i1 %cond_0, i1 %cond_1) {
 ; CHECK-LABEL: @f_11(
 ; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[COND_1_GW_FR:%.*]] = freeze i1 [[COND_1:%.*]]
 ; CHECK-NEXT:    br label [[INNER:%.*]]
 ; CHECK:       inner:
-; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]]
+; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1_GW_FR]]
 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
 ; CHECK-NEXT:    br i1 undef, label [[INNER]], label [[OUTER:%.*]]
 ; CHECK:       outer:
@@ -358,7 +365,8 @@ outer:
 define void @f_12(i32 %a0) {
 ; CHECK-LABEL: @f_12(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[A1:%.*]] = mul i32 [[A0:%.*]], [[A0]]
+; CHECK-NEXT:    [[A0_GW_FR:%.*]] = freeze i32 [[A0:%.*]]
+; CHECK-NEXT:    [[A1:%.*]] = mul i32 [[A0_GW_FR]], [[A0_GW_FR]]
 ; CHECK-NEXT:    [[A2:%.*]] = mul i32 [[A1]], [[A1]]
 ; CHECK-NEXT:    [[A3:%.*]] = mul i32 [[A2]], [[A2]]
 ; CHECK-NEXT:    [[A4:%.*]] = mul i32 [[A3]], [[A3]]
index e2a97bc..b972814 100644 (file)
@@ -7,7 +7,8 @@
 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:    [[COND_1_GW_FR:%.*]] = freeze i1 [[COND_1:%.*]]
+; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1_GW_FR]]
 ; CHECK-NEXT:    [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
 ; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[WIDE_CHK]], [[WIDENABLE_COND]]
 ; CHECK-NEXT:    br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof [[PROF0:![0-9]+]]
@@ -16,7 +17,7 @@ define void @f_0(i1 %cond_0, i1 %cond_1) {
 ; CHECK-NEXT:    ret void
 ; CHECK:       guarded:
 ; CHECK-NEXT:    [[WIDENABLE_COND3:%.*]] = call i1 @llvm.experimental.widenable.condition()
-; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 [[COND_1]], [[WIDENABLE_COND3]]
+; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 [[COND_1_GW_FR]], [[WIDENABLE_COND3]]
 ; CHECK-NEXT:    br i1 true, label [[GUARDED1:%.*]], label [[DEOPT2:%.*]], !prof [[PROF0]]
 ; CHECK:       deopt2:
 ; CHECK-NEXT:    call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
@@ -50,7 +51,8 @@ guarded1:                                         ; preds = %guarded
 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:    [[COND_1_GW_FR:%.*]] = freeze i1 [[COND_1:%.*]]
+; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1_GW_FR]]
 ; CHECK-NEXT:    [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
 ; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[WIDE_CHK]], [[WIDENABLE_COND]]
 ; CHECK-NEXT:    br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof [[PROF0]]
@@ -65,7 +67,7 @@ define void @f_1(i1 %cond_0, i1 %cond_1) {
 ; CHECK-NEXT:    br label [[MERGE]]
 ; CHECK:       merge:
 ; CHECK-NEXT:    [[WIDENABLE_COND3:%.*]] = call i1 @llvm.experimental.widenable.condition()
-; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 [[COND_1]], [[WIDENABLE_COND3]]
+; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 [[COND_1_GW_FR]], [[WIDENABLE_COND3]]
 ; CHECK-NEXT:    br i1 true, label [[GUARDED1:%.*]], label [[DEOPT2:%.*]], !prof [[PROF0]]
 ; CHECK:       deopt2:
 ; CHECK-NEXT:    call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
@@ -109,8 +111,9 @@ guarded1:                                         ; preds = %merge
 define void @f_2(i32 %a, i32 %b) {
 ; CHECK-LABEL: @f_2(
 ; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[B_GW_FR:%.*]] = freeze i32 [[B:%.*]]
 ; CHECK-NEXT:    [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 10
-; CHECK-NEXT:    [[COND_1:%.*]] = icmp ult i32 [[B:%.*]], 10
+; CHECK-NEXT:    [[COND_1:%.*]] = icmp ult i32 [[B_GW_FR]], 10
 ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0]], [[COND_1]]
 ; CHECK-NEXT:    [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
 ; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[WIDE_CHK]], [[WIDENABLE_COND]]
@@ -230,8 +233,9 @@ right:                                            ; preds = %guarded
 define void @f_4(i32 %a, i32 %b) {
 ; CHECK-LABEL: @f_4(
 ; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[B_GW_FR:%.*]] = freeze i32 [[B:%.*]]
 ; CHECK-NEXT:    [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 10
-; CHECK-NEXT:    [[COND_1:%.*]] = icmp ult i32 [[B:%.*]], 10
+; CHECK-NEXT:    [[COND_1:%.*]] = icmp ult i32 [[B_GW_FR]], 10
 ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0]], [[COND_1]]
 ; CHECK-NEXT:    [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
 ; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[WIDE_CHK]], [[WIDENABLE_COND]]
@@ -396,8 +400,9 @@ guarded1:                                         ; preds = %guarded
 define void @f_7(i32 %a, ptr %cond_buf) {
 ; CHECK-LABEL: @f_7(
 ; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[A_GW_FR:%.*]] = freeze i32 [[A:%.*]]
 ; CHECK-NEXT:    [[COND_1:%.*]] = load volatile i1, ptr [[COND_BUF:%.*]], align 1
-; CHECK-NEXT:    [[COND_3:%.*]] = icmp ult i32 [[A:%.*]], 7
+; CHECK-NEXT:    [[COND_3:%.*]] = icmp ult i32 [[A_GW_FR]], 7
 ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_3]]
 ; CHECK-NEXT:    [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
 ; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[WIDE_CHK]], [[WIDENABLE_COND]]
@@ -473,6 +478,7 @@ right:                                            ; preds = %guarded1
 define void @f_8(i32 %a, i1 %cond_1, i1 %cond_2) {
 ; CHECK-LABEL: @f_8(
 ; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[A_GW_FR:%.*]] = freeze i32 [[A:%.*]]
 ; CHECK-NEXT:    br label [[LOOP:%.*]]
 ; CHECK:       loop:
 ; CHECK-NEXT:    [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
@@ -484,7 +490,7 @@ define void @f_8(i32 %a, i1 %cond_1, i1 %cond_2) {
 ; CHECK:       guarded:
 ; CHECK-NEXT:    br i1 undef, label [[LOOP]], label [[LEAVE:%.*]]
 ; CHECK:       leave:
-; CHECK-NEXT:    [[COND_3:%.*]] = icmp ult i32 [[A:%.*]], 7
+; CHECK-NEXT:    [[COND_3:%.*]] = icmp ult i32 [[A_GW_FR]], 7
 ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_2:%.*]], [[COND_3]]
 ; CHECK-NEXT:    [[WIDENABLE_COND3:%.*]] = call i1 @llvm.experimental.widenable.condition()
 ; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 [[WIDE_CHK]], [[WIDENABLE_COND3]]
@@ -661,9 +667,10 @@ guarded1:                                         ; preds = %no_loop
 define void @f_11(i32 %a, i1 %cond_0, i1 %cond_1) {
 ; CHECK-LABEL: @f_11(
 ; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[COND_1_GW_FR:%.*]] = freeze i1 [[COND_1:%.*]]
 ; CHECK-NEXT:    br label [[OUTER_HEADER:%.*]]
 ; CHECK:       outer_header:
-; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]]
+; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1_GW_FR]]
 ; CHECK-NEXT:    [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
 ; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[WIDE_CHK]], [[WIDENABLE_COND]]
 ; CHECK-NEXT:    br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof [[PROF0]]
@@ -674,7 +681,7 @@ define void @f_11(i32 %a, i1 %cond_0, i1 %cond_1) {
 ; CHECK-NEXT:    br label [[INNER:%.*]]
 ; CHECK:       inner:
 ; CHECK-NEXT:    [[WIDENABLE_COND3:%.*]] = call i1 @llvm.experimental.widenable.condition()
-; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 [[COND_1]], [[WIDENABLE_COND3]]
+; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 [[COND_1_GW_FR]], [[WIDENABLE_COND3]]
 ; CHECK-NEXT:    br i1 true, label [[GUARDED1:%.*]], label [[DEOPT2:%.*]], !prof [[PROF0]]
 ; CHECK:       deopt2:
 ; CHECK-NEXT:    call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
@@ -725,7 +732,8 @@ exit:                                             ; preds = %outer_latch
 define void @f_12(i32 %a0) {
 ; CHECK-LABEL: @f_12(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[A1:%.*]] = mul i32 [[A0:%.*]], [[A0]]
+; CHECK-NEXT:    [[A0_GW_FR:%.*]] = freeze i32 [[A0:%.*]]
+; CHECK-NEXT:    [[A1:%.*]] = mul i32 [[A0_GW_FR]], [[A0_GW_FR]]
 ; CHECK-NEXT:    [[A2:%.*]] = mul i32 [[A1]], [[A1]]
 ; CHECK-NEXT:    [[A3:%.*]] = mul i32 [[A2]], [[A2]]
 ; CHECK-NEXT:    [[A4:%.*]] = mul i32 [[A3]], [[A3]]
@@ -1025,7 +1033,8 @@ guarded1:                                         ; preds = %guarded
 define void @swapped_wb(i1 %cond_0, i1 %cond_1) {
 ; CHECK-LABEL: @swapped_wb(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]]
+; CHECK-NEXT:    [[COND_1_GW_FR:%.*]] = freeze i1 [[COND_1:%.*]]
+; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1_GW_FR]]
 ; CHECK-NEXT:    [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
 ; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[WIDENABLE_COND]], [[WIDE_CHK]]
 ; CHECK-NEXT:    br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof [[PROF0]]
@@ -1034,7 +1043,7 @@ define void @swapped_wb(i1 %cond_0, i1 %cond_1) {
 ; CHECK-NEXT:    ret void
 ; CHECK:       guarded:
 ; CHECK-NEXT:    [[WIDENABLE_COND3:%.*]] = call i1 @llvm.experimental.widenable.condition()
-; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 [[COND_1]], [[WIDENABLE_COND3]]
+; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 [[COND_1_GW_FR]], [[WIDENABLE_COND3]]
 ; CHECK-NEXT:    br i1 true, label [[GUARDED1:%.*]], label [[DEOPT2:%.*]], !prof [[PROF0]]
 ; CHECK:       deopt2:
 ; CHECK-NEXT:    call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
@@ -1067,7 +1076,8 @@ guarded1:                                         ; preds = %guarded
 define void @trivial_wb(i1 %cond_0) {
 ; CHECK-LABEL: @trivial_wb(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 true, [[COND_0:%.*]]
+; CHECK-NEXT:    [[COND_0_GW_FR:%.*]] = freeze i1 [[COND_0:%.*]]
+; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 true, [[COND_0_GW_FR]]
 ; CHECK-NEXT:    [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
 ; CHECK-NEXT:    [[TMP0:%.*]] = and i1 [[WIDE_CHK]], [[WIDENABLE_COND]]
 ; CHECK-NEXT:    br i1 [[TMP0]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof [[PROF0]]
@@ -1076,7 +1086,7 @@ define void @trivial_wb(i1 %cond_0) {
 ; CHECK-NEXT:    ret void
 ; CHECK:       guarded:
 ; CHECK-NEXT:    [[WIDENABLE_COND3:%.*]] = call i1 @llvm.experimental.widenable.condition()
-; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 [[COND_0]], [[WIDENABLE_COND3]]
+; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 [[COND_0_GW_FR]], [[WIDENABLE_COND3]]
 ; CHECK-NEXT:    br i1 true, label [[GUARDED1:%.*]], label [[DEOPT2:%.*]], !prof [[PROF0]]
 ; CHECK:       deopt2:
 ; CHECK-NEXT:    call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
index 071a201..6123d5d 100644 (file)
@@ -5,11 +5,12 @@
 define i64 @test() {
 ; CHECK-LABEL: define i64 @test() {
 ; CHECK-NEXT:  bb:
-; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 poison, poison
+; CHECK-NEXT:    [[DOTGW_FR:%.*]] = freeze i1 poison
+; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 poison, [[DOTGW_FR]]
 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
 ; CHECK-NEXT:    br label [[BB2:%.*]]
 ; CHECK:       bb2:
-; CHECK-NEXT:    br i1 poison, label [[BB3:%.*]], label [[BB2]]
+; CHECK-NEXT:    br i1 [[DOTGW_FR]], label [[BB3:%.*]], label [[BB2]]
 ; CHECK:       bb3:
 ; CHECK-NEXT:    [[CALL:%.*]] = call i64 (...) @llvm.experimental.deoptimize.i64() [ "deopt"() ]
 ; CHECK-NEXT:    ret i64 [[CALL]]
index 2abdf6c..79fe619 100644 (file)
@@ -13,8 +13,9 @@ declare void @llvm.experimental.guard(i1,...)
 define void @iter(i32 %a, i32 %b, ptr %c_p) {
 ; CHECK-LABEL: @iter(
 ; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[B_GW_FR:%.*]] = freeze i32 [[B:%.*]]
 ; CHECK-NEXT:    [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 10
-; CHECK-NEXT:    [[COND_1:%.*]] = icmp ult i32 [[B:%.*]], 10
+; CHECK-NEXT:    [[COND_1:%.*]] = icmp ult i32 [[B_GW_FR]], 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:    [[CND:%.*]] = load i1, ptr [[C_P:%.*]], align 1
@@ -48,8 +49,9 @@ leave:                                            ; preds = %leave.loopexit, %en
 define void @within_loop(i32 %a, i32 %b, ptr %c_p) {
 ; CHECK-LABEL: @within_loop(
 ; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[B_GW_FR:%.*]] = freeze i32 [[B:%.*]]
 ; CHECK-NEXT:    [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 10
-; CHECK-NEXT:    [[COND_1:%.*]] = icmp ult i32 [[B:%.*]], 10
+; CHECK-NEXT:    [[COND_1:%.*]] = icmp ult i32 [[B_GW_FR]], 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:    [[CND:%.*]] = load i1, ptr [[C_P:%.*]], align 1
index 28a9228..b528cf0 100644 (file)
@@ -8,12 +8,14 @@ declare i32 @llvm.experimental.deoptimize.i32(...)
 define i32 @test_01(i32 %start, i32 %x) {
 ; CHECK-LABEL: @test_01(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[START:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[START_GW_FR:%.*]] = freeze i32 [[START:%.*]]
+; CHECK-NEXT:    [[X_GW_FR:%.*]] = freeze i32 [[X:%.*]]
+; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[START_GW_FR]], [[X_GW_FR]]
 ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 true, [[COND]]
 ; CHECK-NEXT:    [[WC1:%.*]] = call i1 @llvm.experimental.widenable.condition()
 ; CHECK-NEXT:    br label [[LOOP:%.*]]
 ; CHECK:       loop:
-; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ [[START]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
+; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ [[START_GW_FR]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
 ; CHECK-NEXT:    [[TMP0:%.*]] = and i1 [[WIDE_CHK]], [[WC1]]
 ; CHECK-NEXT:    br i1 [[TMP0]], label [[GUARD_BLOCK:%.*]], label [[EXIT_BY_WC:%.*]]
 ; CHECK:       exit_by_wc:
@@ -127,12 +129,14 @@ failure:
 define i32 @test_03(i32 %start, i32 %x, i1 %c) {
 ; CHECK-LABEL: @test_03(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[START:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[START_GW_FR:%.*]] = freeze i32 [[START:%.*]]
+; CHECK-NEXT:    [[X_GW_FR:%.*]] = freeze i32 [[X:%.*]]
+; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[START_GW_FR]], [[X_GW_FR]]
 ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[C:%.*]], [[COND]]
 ; CHECK-NEXT:    [[WC1:%.*]] = call i1 @llvm.experimental.widenable.condition()
 ; CHECK-NEXT:    br label [[LOOP:%.*]]
 ; CHECK:       loop:
-; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ [[START]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
+; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ [[START_GW_FR]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
 ; CHECK-NEXT:    [[INVARIANT:%.*]] = and i1 [[WIDE_CHK]], [[WC1]]
 ; CHECK-NEXT:    br i1 [[INVARIANT]], label [[GUARD_BLOCK:%.*]], label [[EXIT_BY_WC:%.*]]
 ; CHECK:       exit_by_wc:
@@ -152,7 +156,7 @@ define i32 @test_03(i32 %start, i32 %x, i1 %c) {
 ; CHECK-NEXT:    [[RVAL2:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 [[IV]]) ]
 ; CHECK-NEXT:    ret i32 [[RVAL2]]
 ; CHECK:       early_failure:
-; CHECK-NEXT:    [[RVAL3:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 [[X]]) ]
+; CHECK-NEXT:    [[RVAL3:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 [[X_GW_FR]]) ]
 ; CHECK-NEXT:    ret i32 [[RVAL3]]
 ;
 entry:
index 92d42b3..e778ecc 100644 (file)
@@ -15,10 +15,11 @@ declare i1 @llvm.experimental.widenable.condition() #0
 define void @test_01(i1 %cond_0, i1 %cond_1) {
 ; CHECK-LABEL: @test_01(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]]
+; CHECK-NEXT:    [[COND_1_GW_FR:%.*]] = freeze i1 [[COND_1:%.*]]
+; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1_GW_FR]]
 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
 ; CHECK-NEXT:    [[WIDENABLE_COND3:%.*]] = call i1 @llvm.experimental.widenable.condition()
-; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 [[COND_1]], [[WIDENABLE_COND3]]
+; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 [[COND_1_GW_FR]], [[WIDENABLE_COND3]]
 ; CHECK-NEXT:    br i1 true, label [[GUARDED1:%.*]], label [[DEOPT2:%.*]], !prof [[PROF0:![0-9]+]]
 ; CHECK:       deopt2:
 ; CHECK-NEXT:    call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
@@ -44,7 +45,8 @@ guarded1:                                         ; preds = %guarded
 define void @test_02(i1 %cond_0, i1 %cond_1) {
 ; CHECK-LABEL: @test_02(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]]
+; CHECK-NEXT:    [[COND_1_GW_FR:%.*]] = freeze i1 [[COND_1:%.*]]
+; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1_GW_FR]]
 ; CHECK-NEXT:    [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
 ; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[WIDE_CHK]], [[WIDENABLE_COND]]
 ; CHECK-NEXT:    br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof [[PROF0]]
index 3568f1d..d55a367 100644 (file)
@@ -1,9 +1,8 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
 ; RUN: opt -S -passes=guard-widening,dce < %s | FileCheck %s
 
-; FIXME: All the tests below must be fixed.
-
 declare void @llvm.experimental.guard(i1,...)
+declare i1 @dummy()
 
 ; This tests shows the incorrect behavior of guard widening in terms of
 ; interaction with poison values.
@@ -24,11 +23,12 @@ declare void @llvm.experimental.guard(i1,...)
 define void @combine_range_checks(i32 %x) {
 ; CHECK-LABEL: @combine_range_checks(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[X2:%.*]] = add i32 [[X:%.*]], 0
+; CHECK-NEXT:    [[X_GW_FR:%.*]] = freeze i32 [[X:%.*]]
+; CHECK-NEXT:    [[X2:%.*]] = add i32 [[X_GW_FR]], 0
 ; CHECK-NEXT:    [[C2:%.*]] = icmp ult i32 [[X2]], 200
-; CHECK-NEXT:    [[X3:%.*]] = add nuw nsw i32 [[X]], 3
+; CHECK-NEXT:    [[X3:%.*]] = add i32 [[X_GW_FR]], 3
 ; CHECK-NEXT:    [[C3:%.*]] = icmp ult i32 [[X3]], 100
-; CHECK-NEXT:    [[X4:%.*]] = add nuw nsw i32 [[X]], 20
+; CHECK-NEXT:    [[X4:%.*]] = add i32 [[X_GW_FR]], 20
 ; CHECK-NEXT:    [[C4:%.*]] = icmp ult i32 [[X4]], 100
 ; CHECK-NEXT:    [[WIDE_CHK2:%.*]] = and i1 [[C4]], [[C3]]
 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK2]]) [ "deopt"(i64 1) ]
@@ -68,11 +68,12 @@ out:
 define void @combine_range_checks_with_side_effect(i32 %x, ptr %p) {
 ; CHECK-LABEL: @combine_range_checks_with_side_effect(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[X2:%.*]] = add i32 [[X:%.*]], 0
+; CHECK-NEXT:    [[X_GW_FR:%.*]] = freeze i32 [[X:%.*]]
+; CHECK-NEXT:    [[X2:%.*]] = add i32 [[X_GW_FR]], 0
 ; CHECK-NEXT:    [[C2:%.*]] = icmp ult i32 [[X2]], 200
-; CHECK-NEXT:    [[X3:%.*]] = add nuw nsw i32 [[X]], 3
+; CHECK-NEXT:    [[X3:%.*]] = add i32 [[X_GW_FR]], 3
 ; CHECK-NEXT:    [[C3:%.*]] = icmp ult i32 [[X3]], 100
-; CHECK-NEXT:    [[X4:%.*]] = add nuw nsw i32 [[X]], 20
+; CHECK-NEXT:    [[X4:%.*]] = add i32 [[X_GW_FR]], 20
 ; CHECK-NEXT:    [[C4:%.*]] = icmp ult i32 [[X4]], 100
 ; CHECK-NEXT:    [[WIDE_CHK2:%.*]] = and i1 [[C4]], [[C3]]
 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK2]]) [ "deopt"(i64 1) ]
@@ -114,14 +115,15 @@ out:
 define void @simple_case(i32 %a, i32 %b, i1 %cnd) {
 ; CHECK-LABEL: @simple_case(
 ; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[B_GW_FR:%.*]] = freeze i32 [[B:%.*]]
 ; CHECK-NEXT:    [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 10
-; CHECK-NEXT:    [[B_SHIFT:%.*]] = add nuw nsw i32 [[B:%.*]], 5
+; CHECK-NEXT:    [[B_SHIFT:%.*]] = add i32 [[B_GW_FR]], 5
 ; CHECK-NEXT:    [[COND_2:%.*]] = icmp ult i32 [[B_SHIFT]], 10
 ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0]], [[COND_2]]
 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
 ; CHECK-NEXT:    br label [[LOOP:%.*]]
 ; CHECK:       loop:
-; CHECK-NEXT:    [[COND_1:%.*]] = icmp ult i32 [[B]], 10
+; CHECK-NEXT:    [[COND_1:%.*]] = icmp ult i32 [[B_GW_FR]], 10
 ; CHECK-NEXT:    br i1 [[COND_1]], label [[OK:%.*]], label [[LEAVE_LOOPEXIT:%.*]]
 ; CHECK:       ok:
 ; CHECK-NEXT:    br i1 [[CND:%.*]], label [[LOOP]], label [[LEAVE_LOOPEXIT]]
@@ -150,3 +152,70 @@ leave.loopexit:
 leave:
   ret void
 }
+
+declare ptr @fake_personality_function()
+
+define void @case_with_invoke(i1 %c, i1 %gc) personality ptr @fake_personality_function {
+; CHECK-LABEL: @case_with_invoke(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[C:%.*]], label [[NORMAL:%.*]], label [[INVOK:%.*]]
+; CHECK:       invok:
+; CHECK-NEXT:    [[INVOKE_RESULT:%.*]] = invoke i1 @dummy()
+; CHECK-NEXT:    to label [[NORMAL]] unwind label [[EXCEPTION:%.*]]
+; CHECK:       normal:
+; CHECK-NEXT:    [[PHI_C:%.*]] = phi i1 [ true, [[ENTRY:%.*]] ], [ [[INVOKE_RESULT]], [[INVOK]] ]
+; CHECK-NEXT:    [[PHI_C_GW_FR:%.*]] = freeze i1 [[PHI_C]]
+; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[GC:%.*]], [[PHI_C_GW_FR]]
+; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
+; CHECK-NEXT:    ret void
+; CHECK:       exception:
+; CHECK-NEXT:    [[LANDING_PAD:%.*]] = landingpad { ptr, i32 }
+; CHECK-NEXT:    cleanup
+; CHECK-NEXT:    ret void
+;
+entry:
+  br i1 %c, label %normal, label %invok
+
+invok:
+  %invoke.result = invoke i1 @dummy() to label %normal unwind label %exception
+
+normal:
+  %phi.c = phi i1 [true, %entry], [%invoke.result, %invok]
+  call void (i1, ...) @llvm.experimental.guard(i1 %gc) [ "deopt"() ]
+  call void (i1, ...) @llvm.experimental.guard(i1 %phi.c) [ "deopt"() ]
+  ret void
+
+exception:
+  %landing_pad = landingpad { ptr, i32 } cleanup
+  ret void
+}
+
+define void @case_with_invoke_in_latch(i1 %c, i1 %gc) personality ptr @fake_personality_function {
+; CHECK-LABEL: @case_with_invoke_in_latch(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[HEADER:%.*]]
+; CHECK:       header:
+; CHECK-NEXT:    [[PHI_C:%.*]] = phi i1 [ false, [[ENTRY:%.*]] ], [ [[INVOKE_RESULT:%.*]], [[HEADER]] ]
+; CHECK-NEXT:    [[PHI_C_GW_FR:%.*]] = freeze i1 [[PHI_C]]
+; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[GC:%.*]], [[PHI_C_GW_FR]]
+; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
+; CHECK-NEXT:    [[INVOKE_RESULT]] = invoke i1 @dummy()
+; CHECK-NEXT:    to label [[HEADER]] unwind label [[EXCEPTION:%.*]]
+; CHECK:       exception:
+; CHECK-NEXT:    [[LANDING_PAD:%.*]] = landingpad { ptr, i32 }
+; CHECK-NEXT:    cleanup
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %header
+
+header:
+  %phi.c = phi i1 [false, %entry], [%invoke.result, %header]
+  call void (i1, ...) @llvm.experimental.guard(i1 %gc) [ "deopt"() ]
+  call void (i1, ...) @llvm.experimental.guard(i1 %phi.c) [ "deopt"() ]
+  %invoke.result = invoke i1 @dummy() to label %header unwind label %exception
+
+exception:
+  %landing_pad = landingpad { ptr, i32 } cleanup
+  ret void
+}
index 73b2957..a194a99 100644 (file)
@@ -9,7 +9,8 @@ define i32 @test_intrinsic_very_profitable(i32 %n, i1 %cond.1, i1 %cond.2) {
 ; CHECK-LABEL: define i32 @test_intrinsic_very_profitable
 ; CHECK-SAME: (i32 [[N:%.*]], i1 [[COND_1:%.*]], i1 [[COND_2:%.*]]) {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_2]]
+; CHECK-NEXT:    [[COND_2_GW_FR:%.*]] = freeze i1 [[COND_2]]
+; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_2_GW_FR]]
 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
 ; CHECK-NEXT:    [[LOOP_PRECONDITION:%.*]] = icmp uge i32 [[N]], 100
 ; CHECK-NEXT:    br i1 [[LOOP_PRECONDITION]], label [[LOOP:%.*]], label [[FAILED:%.*]], !prof [[PROF0:![0-9]+]]
@@ -48,7 +49,8 @@ define i32 @test_intrinsic_profitable(i32 %n, i1 %cond.1, i1 %cond.2) {
 ; CHECK-LABEL: define i32 @test_intrinsic_profitable
 ; CHECK-SAME: (i32 [[N:%.*]], i1 [[COND_1:%.*]], i1 [[COND_2:%.*]]) {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_2]]
+; CHECK-NEXT:    [[COND_2_GW_FR:%.*]] = freeze i1 [[COND_2]]
+; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_2_GW_FR]]
 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
 ; CHECK-NEXT:    [[LOOP_PRECONDITION:%.*]] = icmp uge i32 [[N]], 100
 ; CHECK-NEXT:    br i1 [[LOOP_PRECONDITION]], label [[LOOP:%.*]], label [[FAILED:%.*]], !prof [[PROF2:![0-9]+]]
@@ -87,7 +89,8 @@ define i32 @test_intrinsic_neutral(i32 %n, i1 %cond.1, i1 %cond.2) {
 ; CHECK-LABEL: define i32 @test_intrinsic_neutral
 ; CHECK-SAME: (i32 [[N:%.*]], i1 [[COND_1:%.*]], i1 [[COND_2:%.*]]) {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_2]]
+; CHECK-NEXT:    [[COND_2_GW_FR:%.*]] = freeze i1 [[COND_2]]
+; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_2_GW_FR]]
 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
 ; CHECK-NEXT:    [[LOOP_PRECONDITION:%.*]] = icmp uge i32 [[N]], 100
 ; CHECK-NEXT:    br i1 [[LOOP_PRECONDITION]], label [[LOOP:%.*]], label [[FAILED:%.*]], !prof [[PROF3:![0-9]+]]
@@ -125,7 +128,8 @@ define i32 @test_intrinsic_very_unprofitable(i32 %n, i1 %cond.1, i1 %cond.2) {
 ; CHECK-LABEL: define i32 @test_intrinsic_very_unprofitable
 ; CHECK-SAME: (i32 [[N:%.*]], i1 [[COND_1:%.*]], i1 [[COND_2:%.*]]) {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_2]]
+; CHECK-NEXT:    [[COND_2_GW_FR:%.*]] = freeze i1 [[COND_2]]
+; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_2_GW_FR]]
 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
 ; CHECK-NEXT:    [[LOOP_PRECONDITION:%.*]] = icmp uge i32 [[N]], 100
 ; CHECK-NEXT:    br i1 [[LOOP_PRECONDITION]], label [[LOOP:%.*]], label [[FAILED:%.*]], !prof [[PROF4:![0-9]+]]
@@ -163,7 +167,8 @@ define i32 @test_intrinsic_unprofitable(i32 %n, i1 %cond.1, i1 %cond.2) {
 ; CHECK-LABEL: define i32 @test_intrinsic_unprofitable
 ; CHECK-SAME: (i32 [[N:%.*]], i1 [[COND_1:%.*]], i1 [[COND_2:%.*]]) {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_2]]
+; CHECK-NEXT:    [[COND_2_GW_FR:%.*]] = freeze i1 [[COND_2]]
+; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_2_GW_FR]]
 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
 ; CHECK-NEXT:    [[LOOP_PRECONDITION:%.*]] = icmp uge i32 [[N]], 100
 ; CHECK-NEXT:    br i1 [[LOOP_PRECONDITION]], label [[LOOP:%.*]], label [[FAILED:%.*]], !prof [[PROF5:![0-9]+]]
index 89aeb62..0114a6e 100644 (file)
@@ -6,7 +6,8 @@ define i32 @test_intrinsic_very_profitable(i32 %n, i1 %cond.1, i1 %cond.2) {
 ; CHECK-LABEL: define i32 @test_intrinsic_very_profitable
 ; CHECK-SAME: (i32 [[N:%.*]], i1 [[COND_1:%.*]], i1 [[COND_2:%.*]]) {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_2]]
+; CHECK-NEXT:    [[COND_2_GW_FR:%.*]] = freeze i1 [[COND_2]]
+; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_2_GW_FR]]
 ; CHECK-NEXT:    [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
 ; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[WIDE_CHK]], [[WIDENABLE_COND]]
 ; CHECK-NEXT:    br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof [[PROF0:![0-9]+]]
@@ -19,7 +20,7 @@ define i32 @test_intrinsic_very_profitable(i32 %n, i1 %cond.1, i1 %cond.2) {
 ; CHECK:       loop:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[GUARDED]] ], [ [[IV_NEXT:%.*]], [[GUARDED1:%.*]] ]
 ; CHECK-NEXT:    [[WIDENABLE_COND4:%.*]] = call i1 @llvm.experimental.widenable.condition()
-; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND5:%.*]] = and i1 [[COND_2]], [[WIDENABLE_COND4]]
+; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND5:%.*]] = and i1 [[COND_2_GW_FR]], [[WIDENABLE_COND4]]
 ; CHECK-NEXT:    br i1 true, label [[GUARDED1]], label [[DEOPT2:%.*]], !prof [[PROF0]]
 ; CHECK:       deopt2:
 ; CHECK-NEXT:    [[DEOPTCALL3:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
@@ -74,7 +75,8 @@ define i32 @test_intrinsic_profitable(i32 %n, i1 %cond.1, i1 %cond.2) {
 ; CHECK-LABEL: define i32 @test_intrinsic_profitable
 ; CHECK-SAME: (i32 [[N:%.*]], i1 [[COND_1:%.*]], i1 [[COND_2:%.*]]) {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_2]]
+; CHECK-NEXT:    [[COND_2_GW_FR:%.*]] = freeze i1 [[COND_2]]
+; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_2_GW_FR]]
 ; CHECK-NEXT:    [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
 ; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[WIDE_CHK]], [[WIDENABLE_COND]]
 ; CHECK-NEXT:    br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof [[PROF0]]
@@ -87,7 +89,7 @@ define i32 @test_intrinsic_profitable(i32 %n, i1 %cond.1, i1 %cond.2) {
 ; CHECK:       loop:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[GUARDED]] ], [ [[IV_NEXT:%.*]], [[GUARDED1:%.*]] ]
 ; CHECK-NEXT:    [[WIDENABLE_COND4:%.*]] = call i1 @llvm.experimental.widenable.condition()
-; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND5:%.*]] = and i1 [[COND_2]], [[WIDENABLE_COND4]]
+; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND5:%.*]] = and i1 [[COND_2_GW_FR]], [[WIDENABLE_COND4]]
 ; CHECK-NEXT:    br i1 true, label [[GUARDED1]], label [[DEOPT2:%.*]], !prof [[PROF0]]
 ; CHECK:       deopt2:
 ; CHECK-NEXT:    [[DEOPTCALL3:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
@@ -142,7 +144,8 @@ define i32 @test_intrinsic_neutral(i32 %n, i1 %cond.1, i1 %cond.2) {
 ; CHECK-LABEL: define i32 @test_intrinsic_neutral
 ; CHECK-SAME: (i32 [[N:%.*]], i1 [[COND_1:%.*]], i1 [[COND_2:%.*]]) {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_2]]
+; CHECK-NEXT:    [[COND_2_GW_FR:%.*]] = freeze i1 [[COND_2]]
+; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_2_GW_FR]]
 ; CHECK-NEXT:    [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
 ; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[WIDE_CHK]], [[WIDENABLE_COND]]
 ; CHECK-NEXT:    br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof [[PROF0]]
@@ -155,7 +158,7 @@ define i32 @test_intrinsic_neutral(i32 %n, i1 %cond.1, i1 %cond.2) {
 ; CHECK:       loop:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[GUARDED]] ], [ [[IV_NEXT:%.*]], [[GUARDED1:%.*]] ]
 ; CHECK-NEXT:    [[WIDENABLE_COND4:%.*]] = call i1 @llvm.experimental.widenable.condition()
-; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND5:%.*]] = and i1 [[COND_2]], [[WIDENABLE_COND4]]
+; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND5:%.*]] = and i1 [[COND_2_GW_FR]], [[WIDENABLE_COND4]]
 ; CHECK-NEXT:    br i1 true, label [[GUARDED1]], label [[DEOPT2:%.*]], !prof [[PROF0]]
 ; CHECK:       deopt2:
 ; CHECK-NEXT:    [[DEOPTCALL3:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
@@ -209,7 +212,8 @@ define i32 @test_intrinsic_very_unprofitable(i32 %n, i1 %cond.1, i1 %cond.2) {
 ; CHECK-LABEL: define i32 @test_intrinsic_very_unprofitable
 ; CHECK-SAME: (i32 [[N:%.*]], i1 [[COND_1:%.*]], i1 [[COND_2:%.*]]) {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_2]]
+; CHECK-NEXT:    [[COND_2_GW_FR:%.*]] = freeze i1 [[COND_2]]
+; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_2_GW_FR]]
 ; CHECK-NEXT:    [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
 ; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[WIDE_CHK]], [[WIDENABLE_COND]]
 ; CHECK-NEXT:    br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof [[PROF0]]
@@ -222,7 +226,7 @@ define i32 @test_intrinsic_very_unprofitable(i32 %n, i1 %cond.1, i1 %cond.2) {
 ; CHECK:       loop:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[GUARDED]] ], [ [[IV_NEXT:%.*]], [[GUARDED1:%.*]] ]
 ; CHECK-NEXT:    [[WIDENABLE_COND4:%.*]] = call i1 @llvm.experimental.widenable.condition()
-; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND5:%.*]] = and i1 [[COND_2]], [[WIDENABLE_COND4]]
+; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND5:%.*]] = and i1 [[COND_2_GW_FR]], [[WIDENABLE_COND4]]
 ; CHECK-NEXT:    br i1 true, label [[GUARDED1]], label [[DEOPT2:%.*]], !prof [[PROF0]]
 ; CHECK:       deopt2:
 ; CHECK-NEXT:    [[DEOPTCALL3:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
@@ -276,7 +280,8 @@ define i32 @test_intrinsic_unprofitable(i32 %n, i1 %cond.1, i1 %cond.2) {
 ; CHECK-LABEL: define i32 @test_intrinsic_unprofitable
 ; CHECK-SAME: (i32 [[N:%.*]], i1 [[COND_1:%.*]], i1 [[COND_2:%.*]]) {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_2]]
+; CHECK-NEXT:    [[COND_2_GW_FR:%.*]] = freeze i1 [[COND_2]]
+; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_2_GW_FR]]
 ; CHECK-NEXT:    [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
 ; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[WIDE_CHK]], [[WIDENABLE_COND]]
 ; CHECK-NEXT:    br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof [[PROF0]]
@@ -289,7 +294,7 @@ define i32 @test_intrinsic_unprofitable(i32 %n, i1 %cond.1, i1 %cond.2) {
 ; CHECK:       loop:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[GUARDED]] ], [ [[IV_NEXT:%.*]], [[GUARDED1:%.*]] ]
 ; CHECK-NEXT:    [[WIDENABLE_COND4:%.*]] = call i1 @llvm.experimental.widenable.condition()
-; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND5:%.*]] = and i1 [[COND_2]], [[WIDENABLE_COND4]]
+; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND5:%.*]] = and i1 [[COND_2_GW_FR]], [[WIDENABLE_COND4]]
 ; CHECK-NEXT:    br i1 true, label [[GUARDED1]], label [[DEOPT2:%.*]], !prof [[PROF0]]
 ; CHECK:       deopt2:
 ; CHECK-NEXT:    [[DEOPTCALL3:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"() ]
index e591b1a..1f49856 100644 (file)
@@ -6,22 +6,23 @@ declare void @llvm.experimental.guard(i1,...)
 define void @f_0(i32 %x, ptr %length_buf) {
 ; CHECK-LABEL: @f_0(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[LENGTH:%.*]] = load i32, ptr [[LENGTH_BUF:%.*]], align 4, !range [[RNG0:![0-9]+]]
-; CHECK-NEXT:    [[CHK0:%.*]] = icmp ult i32 [[X:%.*]], [[LENGTH]]
-; CHECK-NEXT:    [[X_INC1:%.*]] = add i32 [[X]], 1
+; CHECK-NEXT:    [[X_GW_FR:%.*]] = freeze i32 [[X:%.*]]
+; CHECK-NEXT:    [[LENGTH:%.*]] = load i32, ptr [[LENGTH_BUF:%.*]], align 4, !range [[RNG0:![0-9]+]], !noundef !1
+; CHECK-NEXT:    [[CHK0:%.*]] = icmp ult i32 [[X_GW_FR]], [[LENGTH]]
+; CHECK-NEXT:    [[X_INC1:%.*]] = add i32 [[X_GW_FR]], 1
 ; CHECK-NEXT:    [[CHK1:%.*]] = icmp ult i32 [[X_INC1]], [[LENGTH]]
 ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[CHK0]], [[CHK1]]
-; CHECK-NEXT:    [[X_INC2:%.*]] = add i32 [[X]], 2
+; CHECK-NEXT:    [[X_INC2:%.*]] = add i32 [[X_GW_FR]], 2
 ; CHECK-NEXT:    [[CHK2:%.*]] = icmp ult i32 [[X_INC2]], [[LENGTH]]
 ; CHECK-NEXT:    [[WIDE_CHK1:%.*]] = and i1 [[CHK2]], [[CHK0]]
-; CHECK-NEXT:    [[X_INC3:%.*]] = add i32 [[X]], 3
+; CHECK-NEXT:    [[X_INC3:%.*]] = add i32 [[X_GW_FR]], 3
 ; CHECK-NEXT:    [[CHK3:%.*]] = icmp ult i32 [[X_INC3]], [[LENGTH]]
 ; CHECK-NEXT:    [[WIDE_CHK2:%.*]] = and i1 [[CHK3]], [[CHK0]]
 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK2]]) [ "deopt"() ]
 ; CHECK-NEXT:    ret void
 ;
 entry:
-  %length = load i32, ptr %length_buf, !range !0
+  %length = load i32, ptr %length_buf, !range !0, !noundef !{}
   %chk0 = icmp ult i32 %x, %length
   call void(i1, ...) @llvm.experimental.guard(i1 %chk0) [ "deopt"() ]
 
@@ -42,9 +43,10 @@ entry:
 define void @f_1(i32 %x, ptr %length_buf) {
 ; CHECK-LABEL: @f_1(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[LENGTH:%.*]] = load i32, ptr [[LENGTH_BUF:%.*]], align 4, !range [[RNG0]]
-; CHECK-NEXT:    [[CHK0:%.*]] = icmp ult i32 [[X:%.*]], [[LENGTH]]
-; CHECK-NEXT:    [[X_INC1:%.*]] = add i32 [[X]], 1
+; CHECK-NEXT:    [[X_GW_FR:%.*]] = freeze i32 [[X:%.*]]
+; CHECK-NEXT:    [[LENGTH:%.*]] = load i32, ptr [[LENGTH_BUF:%.*]], align 4, !range [[RNG0]], !noundef !1
+; CHECK-NEXT:    [[CHK0:%.*]] = icmp ult i32 [[X_GW_FR]], [[LENGTH]]
+; CHECK-NEXT:    [[X_INC1:%.*]] = add i32 [[X_GW_FR]], 1
 ; CHECK-NEXT:    [[CHK1:%.*]] = icmp ult i32 [[X_INC1]], [[LENGTH]]
 ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[CHK0]], [[CHK1]]
 ; CHECK-NEXT:    [[X_INC2:%.*]] = add i32 [[X_INC1]], 2
@@ -57,7 +59,7 @@ define void @f_1(i32 %x, ptr %length_buf) {
 ; CHECK-NEXT:    ret void
 ;
 entry:
-  %length = load i32, ptr %length_buf, !range !0
+  %length = load i32, ptr %length_buf, !range !0, !noundef !{}
   %chk0 = icmp ult i32 %x, %length
   call void(i1, ...) @llvm.experimental.guard(i1 %chk0) [ "deopt"() ]
 
@@ -78,18 +80,20 @@ entry:
 define void @f_2(i32 %a, ptr %length_buf) {
 ; CHECK-LABEL: @f_2(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[X:%.*]] = and i32 [[A:%.*]], -256
+; CHECK-NEXT:    [[A_GW_FR:%.*]] = freeze i32 [[A:%.*]]
+; CHECK-NEXT:    [[X:%.*]] = and i32 [[A_GW_FR]], -256
 ; CHECK-NEXT:    [[LENGTH:%.*]] = load i32, ptr [[LENGTH_BUF:%.*]], align 4, !range [[RNG0]]
-; CHECK-NEXT:    [[CHK0:%.*]] = icmp ult i32 [[X]], [[LENGTH]]
+; CHECK-NEXT:    [[LENGTH_GW_FR:%.*]] = freeze i32 [[LENGTH]]
+; CHECK-NEXT:    [[CHK0:%.*]] = icmp ult i32 [[X]], [[LENGTH_GW_FR]]
 ; CHECK-NEXT:    [[X_INC1:%.*]] = or i32 [[X]], 1
-; CHECK-NEXT:    [[CHK1:%.*]] = icmp ult i32 [[X_INC1]], [[LENGTH]]
+; CHECK-NEXT:    [[CHK1:%.*]] = icmp ult i32 [[X_INC1]], [[LENGTH_GW_FR]]
 ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[CHK0]], [[CHK1]]
 ; CHECK-NEXT:    [[X_INC2:%.*]] = or i32 [[X]], 2
-; CHECK-NEXT:    [[CHK2:%.*]] = icmp ult i32 [[X_INC2]], [[LENGTH]]
-; CHECK-NEXT:    [[WIDE_CHK1:%.*]] = and i1 [[CHK2]], [[CHK0]]
+; CHECK-NEXT:    [[CHK2:%.*]] = icmp ult i32 [[X_INC2]], [[LENGTH_GW_FR]]
+; CHECK-NEXT:    [[WIDE_CHK1:%.*]] = and i1 [[WIDE_CHK]], [[CHK2]]
 ; CHECK-NEXT:    [[X_INC3:%.*]] = or i32 [[X]], 3
-; CHECK-NEXT:    [[CHK3:%.*]] = icmp ult i32 [[X_INC3]], [[LENGTH]]
-; CHECK-NEXT:    [[WIDE_CHK2:%.*]] = and i1 [[CHK3]], [[CHK0]]
+; CHECK-NEXT:    [[CHK3:%.*]] = icmp ult i32 [[X_INC3]], [[LENGTH_GW_FR]]
+; CHECK-NEXT:    [[WIDE_CHK2:%.*]] = and i1 [[WIDE_CHK1]], [[CHK3]]
 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK2]]) [ "deopt"() ]
 ; CHECK-NEXT:    ret void
 ;
@@ -116,8 +120,9 @@ entry:
 define void @f_3(i32 %a, ptr %length_buf) {
 ; CHECK-LABEL: @f_3(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[X:%.*]] = and i32 [[A:%.*]], -256
-; CHECK-NEXT:    [[LENGTH:%.*]] = load i32, ptr [[LENGTH_BUF:%.*]], align 4, !range [[RNG0]]
+; CHECK-NEXT:    [[A_GW_FR:%.*]] = freeze i32 [[A:%.*]]
+; CHECK-NEXT:    [[X:%.*]] = and i32 [[A_GW_FR]], -256
+; CHECK-NEXT:    [[LENGTH:%.*]] = load i32, ptr [[LENGTH_BUF:%.*]], align 4, !range [[RNG0]], !noundef !1
 ; CHECK-NEXT:    [[CHK0:%.*]] = icmp ult i32 [[X]], [[LENGTH]]
 ; CHECK-NEXT:    [[X_INC1:%.*]] = add i32 [[X]], 1
 ; CHECK-NEXT:    [[CHK1:%.*]] = icmp ult i32 [[X_INC1]], [[LENGTH]]
@@ -133,7 +138,7 @@ define void @f_3(i32 %a, ptr %length_buf) {
 ;
 entry:
   %x = and i32 %a, 4294967040 ;; 4294967040 == 0xffffff00
-  %length = load i32, ptr %length_buf, !range !0
+  %length = load i32, ptr %length_buf, !range !0, !noundef !{}
   %chk0 = icmp ult i32 %x, %length
   call void(i1, ...) @llvm.experimental.guard(i1 %chk0) [ "deopt"() ]
 
@@ -154,15 +159,16 @@ entry:
 define void @f_4(i32 %x, ptr %length_buf) {
 ; CHECK-LABEL: @f_4(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[LENGTH:%.*]] = load i32, ptr [[LENGTH_BUF:%.*]], align 4, !range [[RNG0]]
-; CHECK-NEXT:    [[CHK0:%.*]] = icmp ult i32 [[X:%.*]], [[LENGTH]]
-; CHECK-NEXT:    [[X_INC1:%.*]] = add i32 [[X]], -1024
+; CHECK-NEXT:    [[X_GW_FR:%.*]] = freeze i32 [[X:%.*]]
+; CHECK-NEXT:    [[LENGTH:%.*]] = load i32, ptr [[LENGTH_BUF:%.*]], align 4, !range [[RNG0]], !noundef !1
+; CHECK-NEXT:    [[CHK0:%.*]] = icmp ult i32 [[X_GW_FR]], [[LENGTH]]
+; CHECK-NEXT:    [[X_INC1:%.*]] = add i32 [[X_GW_FR]], -1024
 ; CHECK-NEXT:    [[CHK1:%.*]] = icmp ult i32 [[X_INC1]], [[LENGTH]]
 ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[CHK0]], [[CHK1]]
-; CHECK-NEXT:    [[X_INC2:%.*]] = add i32 [[X]], 2
+; CHECK-NEXT:    [[X_INC2:%.*]] = add i32 [[X_GW_FR]], 2
 ; CHECK-NEXT:    [[CHK2:%.*]] = icmp ult i32 [[X_INC2]], [[LENGTH]]
 ; CHECK-NEXT:    [[WIDE_CHK1:%.*]] = and i1 [[CHK2]], [[CHK1]]
-; CHECK-NEXT:    [[X_INC3:%.*]] = add i32 [[X]], 3
+; CHECK-NEXT:    [[X_INC3:%.*]] = add i32 [[X_GW_FR]], 3
 ; CHECK-NEXT:    [[CHK3:%.*]] = icmp ult i32 [[X_INC3]], [[LENGTH]]
 ; CHECK-NEXT:    [[WIDE_CHK2:%.*]] = and i1 [[CHK3]], [[CHK1]]
 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK2]]) [ "deopt"() ]
@@ -171,7 +177,7 @@ define void @f_4(i32 %x, ptr %length_buf) {
 
 ; Note: we NOT guarding on "and i1 %chk3, %chk0", that would be incorrect.
 entry:
-  %length = load i32, ptr %length_buf, !range !0
+  %length = load i32, ptr %length_buf, !range !0, !noundef !{}
   %chk0 = icmp ult i32 %x, %length
   call void(i1, ...) @llvm.experimental.guard(i1 %chk0) [ "deopt"() ]
 
@@ -192,9 +198,10 @@ entry:
 define void @f_5(i32 %x, ptr %length_buf) {
 ; CHECK-LABEL: @f_5(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[LENGTH:%.*]] = load i32, ptr [[LENGTH_BUF:%.*]], align 4, !range [[RNG0]]
-; CHECK-NEXT:    [[CHK0:%.*]] = icmp ult i32 [[X:%.*]], [[LENGTH]]
-; CHECK-NEXT:    [[X_INC1:%.*]] = add i32 [[X]], 1
+; CHECK-NEXT:    [[X_GW_FR:%.*]] = freeze i32 [[X:%.*]]
+; CHECK-NEXT:    [[LENGTH:%.*]] = load i32, ptr [[LENGTH_BUF:%.*]], align 4, !range [[RNG0]], !noundef !1
+; CHECK-NEXT:    [[CHK0:%.*]] = icmp ult i32 [[X_GW_FR]], [[LENGTH]]
+; CHECK-NEXT:    [[X_INC1:%.*]] = add i32 [[X_GW_FR]], 1
 ; CHECK-NEXT:    [[CHK1:%.*]] = icmp ult i32 [[X_INC1]], [[LENGTH]]
 ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[CHK0]], [[CHK1]]
 ; CHECK-NEXT:    [[X_INC2:%.*]] = add i32 [[X_INC1]], -200
@@ -207,7 +214,7 @@ define void @f_5(i32 %x, ptr %length_buf) {
 ; CHECK-NEXT:    ret void
 ;
 entry:
-  %length = load i32, ptr %length_buf, !range !0
+  %length = load i32, ptr %length_buf, !range !0, !noundef !{}
   %chk0 = icmp ult i32 %x, %length
   call void(i1, ...) @llvm.experimental.guard(i1 %chk0) [ "deopt"() ]
 
@@ -240,22 +247,23 @@ entry:
 define void @f_6(i32 %x, ptr %length_buf) {
 ; CHECK-LABEL: @f_6(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[LENGTH:%.*]] = load i32, ptr [[LENGTH_BUF:%.*]], align 4, !range [[RNG0]]
-; CHECK-NEXT:    [[CHK0:%.*]] = icmp ult i32 [[X:%.*]], [[LENGTH]]
-; CHECK-NEXT:    [[X_INC1:%.*]] = add i32 [[X]], -2147483647
+; CHECK-NEXT:    [[X_GW_FR:%.*]] = freeze i32 [[X:%.*]]
+; CHECK-NEXT:    [[LENGTH:%.*]] = load i32, ptr [[LENGTH_BUF:%.*]], align 4, !range [[RNG0]], !noundef !1
+; CHECK-NEXT:    [[CHK0:%.*]] = icmp ult i32 [[X_GW_FR]], [[LENGTH]]
+; CHECK-NEXT:    [[X_INC1:%.*]] = add i32 [[X_GW_FR]], -2147483647
 ; CHECK-NEXT:    [[CHK1:%.*]] = icmp ult i32 [[X_INC1]], [[LENGTH]]
 ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[CHK0]], [[CHK1]]
-; CHECK-NEXT:    [[X_INC2:%.*]] = add i32 [[X]], 2
+; CHECK-NEXT:    [[X_INC2:%.*]] = add i32 [[X_GW_FR]], 2
 ; CHECK-NEXT:    [[CHK2:%.*]] = icmp ult i32 [[X_INC2]], [[LENGTH]]
 ; CHECK-NEXT:    [[WIDE_CHK1:%.*]] = and i1 [[WIDE_CHK]], [[CHK2]]
-; CHECK-NEXT:    [[X_INC3:%.*]] = add i32 [[X]], 3
+; CHECK-NEXT:    [[X_INC3:%.*]] = add i32 [[X_GW_FR]], 3
 ; CHECK-NEXT:    [[CHK3:%.*]] = icmp ult i32 [[X_INC3]], [[LENGTH]]
 ; CHECK-NEXT:    [[WIDE_CHK2:%.*]] = and i1 [[WIDE_CHK1]], [[CHK3]]
 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK2]]) [ "deopt"() ]
 ; CHECK-NEXT:    ret void
 ;
 entry:
-  %length = load i32, ptr %length_buf, !range !0
+  %length = load i32, ptr %length_buf, !range !0, !noundef !{}
   %chk0 = icmp ult i32 %x, %length
   call void(i1, ...) @llvm.experimental.guard(i1 %chk0) [ "deopt"() ]
 
@@ -277,23 +285,24 @@ entry:
 define void @f_7(i32 %x, ptr %length_buf) {
 ; CHECK-LABEL: @f_7(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[LENGTH_A:%.*]] = load volatile i32, ptr [[LENGTH_BUF:%.*]], align 4, !range [[RNG0]]
-; CHECK-NEXT:    [[LENGTH_B:%.*]] = load volatile i32, ptr [[LENGTH_BUF]], align 4, !range [[RNG0]]
-; CHECK-NEXT:    [[CHK0_A:%.*]] = icmp ult i32 [[X:%.*]], [[LENGTH_A]]
-; CHECK-NEXT:    [[CHK0_B:%.*]] = icmp ult i32 [[X]], [[LENGTH_B]]
+; CHECK-NEXT:    [[X_GW_FR:%.*]] = freeze i32 [[X:%.*]]
+; CHECK-NEXT:    [[LENGTH_A:%.*]] = load volatile i32, ptr [[LENGTH_BUF:%.*]], align 4, !range [[RNG0]], !noundef !1
+; CHECK-NEXT:    [[LENGTH_B:%.*]] = load volatile i32, ptr [[LENGTH_BUF]], align 4, !range [[RNG0]], !noundef !1
+; CHECK-NEXT:    [[CHK0_A:%.*]] = icmp ult i32 [[X_GW_FR]], [[LENGTH_A]]
+; CHECK-NEXT:    [[CHK0_B:%.*]] = icmp ult i32 [[X_GW_FR]], [[LENGTH_B]]
 ; CHECK-NEXT:    [[CHK0:%.*]] = and i1 [[CHK0_A]], [[CHK0_B]]
-; CHECK-NEXT:    [[X_INC1:%.*]] = add i32 [[X]], 1
+; CHECK-NEXT:    [[X_INC1:%.*]] = add i32 [[X_GW_FR]], 1
 ; CHECK-NEXT:    [[CHK1_A:%.*]] = icmp ult i32 [[X_INC1]], [[LENGTH_A]]
 ; CHECK-NEXT:    [[CHK1_B:%.*]] = icmp ult i32 [[X_INC1]], [[LENGTH_B]]
 ; CHECK-NEXT:    [[CHK1:%.*]] = and i1 [[CHK1_A]], [[CHK1_B]]
 ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[CHK0]], [[CHK1]]
-; CHECK-NEXT:    [[X_INC2:%.*]] = add i32 [[X]], 2
+; CHECK-NEXT:    [[X_INC2:%.*]] = add i32 [[X_GW_FR]], 2
 ; CHECK-NEXT:    [[CHK2_A:%.*]] = icmp ult i32 [[X_INC2]], [[LENGTH_A]]
 ; CHECK-NEXT:    [[TMP0:%.*]] = and i1 [[CHK2_A]], [[CHK0_A]]
 ; CHECK-NEXT:    [[TMP1:%.*]] = and i1 [[CHK0_B]], [[TMP0]]
 ; CHECK-NEXT:    [[CHK2_B:%.*]] = icmp ult i32 [[X_INC2]], [[LENGTH_B]]
 ; CHECK-NEXT:    [[WIDE_CHK1:%.*]] = and i1 [[CHK2_B]], [[TMP1]]
-; CHECK-NEXT:    [[X_INC3:%.*]] = add i32 [[X]], 3
+; CHECK-NEXT:    [[X_INC3:%.*]] = add i32 [[X_GW_FR]], 3
 ; CHECK-NEXT:    [[CHK3_B:%.*]] = icmp ult i32 [[X_INC3]], [[LENGTH_B]]
 ; CHECK-NEXT:    [[TMP2:%.*]] = and i1 [[CHK3_B]], [[CHK0_B]]
 ; CHECK-NEXT:    [[TMP3:%.*]] = and i1 [[CHK0_A]], [[TMP2]]
@@ -307,8 +316,8 @@ define void @f_7(i32 %x, ptr %length_buf) {
 
 
 entry:
-  %length_a = load volatile i32, ptr %length_buf, !range !0
-  %length_b = load volatile i32, ptr %length_buf, !range !0
+  %length_a = load volatile i32, ptr %length_buf, !range !0, !noundef !{}
+  %length_b = load volatile i32, ptr %length_buf, !range !0, !noundef !{}
   %chk0.a = icmp ult i32 %x, %length_a
   %chk0.b = icmp ult i32 %x, %length_b
   %chk0 = and i1 %chk0.a, %chk0.b
@@ -338,16 +347,17 @@ define void @f_8(i32 %x, ptr %length_buf) {
 ; Check that we clean nuw nsw flags
 ; CHECK-LABEL: @f_8(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[LENGTH:%.*]] = load i32, ptr [[LENGTH_BUF:%.*]], align 4, !range [[RNG0]]
-; CHECK-NEXT:    [[CHK0:%.*]] = icmp ult i32 [[X:%.*]], [[LENGTH]]
-; CHECK-NEXT:    [[X_INC1:%.*]] = add i32 [[X]], 1
+; CHECK-NEXT:    [[X_GW_FR:%.*]] = freeze i32 [[X:%.*]]
+; CHECK-NEXT:    [[LENGTH:%.*]] = load i32, ptr [[LENGTH_BUF:%.*]], align 4, !range [[RNG0]], !noundef !1
+; CHECK-NEXT:    [[CHK0:%.*]] = icmp ult i32 [[X_GW_FR]], [[LENGTH]]
+; CHECK-NEXT:    [[X_INC1:%.*]] = add i32 [[X_GW_FR]], 1
 ; CHECK-NEXT:    [[CHK1:%.*]] = icmp ult i32 [[X_INC1]], [[LENGTH]]
 ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[CHK0]], [[CHK1]]
 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
 ; CHECK-NEXT:    ret void
 ;
 entry:
-  %length = load i32, ptr %length_buf, !range !0
+  %length = load i32, ptr %length_buf, !range !0, !noundef !{}
   %chk0 = icmp ult i32 %x, %length
   call void(i1, ...) @llvm.experimental.guard(i1 %chk0) [ "deopt"() ]
 
index 9b60f4e..1a9ff30 100644 (file)
@@ -14,16 +14,19 @@ define void @test_01(i32 %a, i32 %b, i32 %c, i32 %d) {
 ; INTRINSIC_FORM-LABEL: define void @test_01
 ; INTRINSIC_FORM-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], i32 [[D:%.*]]) {
 ; INTRINSIC_FORM-NEXT:  entry:
+; INTRINSIC_FORM-NEXT:    [[D_GW_FR:%.*]] = freeze i32 [[D]]
+; INTRINSIC_FORM-NEXT:    [[C_GW_FR:%.*]] = freeze i32 [[C]]
+; INTRINSIC_FORM-NEXT:    [[B_GW_FR:%.*]] = freeze i32 [[B]]
 ; INTRINSIC_FORM-NEXT:    br label [[LOOP:%.*]]
 ; INTRINSIC_FORM:       loop:
 ; INTRINSIC_FORM-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[GUARDED:%.*]] ]
 ; INTRINSIC_FORM-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
 ; INTRINSIC_FORM-NEXT:    [[C1:%.*]] = icmp ult i32 [[IV]], [[A]]
-; INTRINSIC_FORM-NEXT:    [[C2:%.*]] = icmp ult i32 [[IV]], [[B]]
+; INTRINSIC_FORM-NEXT:    [[C2:%.*]] = icmp ult i32 [[IV]], [[B_GW_FR]]
 ; INTRINSIC_FORM-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[C1]], [[C2]]
-; INTRINSIC_FORM-NEXT:    [[C3:%.*]] = icmp ult i32 [[IV]], [[C]]
+; INTRINSIC_FORM-NEXT:    [[C3:%.*]] = icmp ult i32 [[IV]], [[C_GW_FR]]
 ; INTRINSIC_FORM-NEXT:    [[WIDE_CHK1:%.*]] = and i1 [[WIDE_CHK]], [[C3]]
-; INTRINSIC_FORM-NEXT:    [[C4:%.*]] = icmp ult i32 [[IV]], [[D]]
+; INTRINSIC_FORM-NEXT:    [[C4:%.*]] = icmp ult i32 [[IV]], [[D_GW_FR]]
 ; INTRINSIC_FORM-NEXT:    [[WIDE_CHK2:%.*]] = and i1 [[WIDE_CHK1]], [[C4]]
 ; INTRINSIC_FORM-NEXT:    [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
 ; INTRINSIC_FORM-NEXT:    [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[WIDE_CHK2]], [[WIDENABLE_COND]]
@@ -40,16 +43,19 @@ define void @test_01(i32 %a, i32 %b, i32 %c, i32 %d) {
 ; BRANCH_FORM-LABEL: define void @test_01
 ; BRANCH_FORM-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], i32 [[D:%.*]]) {
 ; BRANCH_FORM-NEXT:  entry:
+; BRANCH_FORM-NEXT:    [[D_GW_FR:%.*]] = freeze i32 [[D]]
+; BRANCH_FORM-NEXT:    [[C_GW_FR:%.*]] = freeze i32 [[C]]
+; BRANCH_FORM-NEXT:    [[B_GW_FR:%.*]] = freeze i32 [[B]]
 ; BRANCH_FORM-NEXT:    br label [[LOOP:%.*]]
 ; BRANCH_FORM:       loop:
 ; BRANCH_FORM-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[GUARDED:%.*]] ]
 ; BRANCH_FORM-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
 ; BRANCH_FORM-NEXT:    [[C1:%.*]] = icmp ult i32 [[IV]], [[A]]
-; BRANCH_FORM-NEXT:    [[C2:%.*]] = icmp ult i32 [[IV]], [[B]]
+; BRANCH_FORM-NEXT:    [[C2:%.*]] = icmp ult i32 [[IV]], [[B_GW_FR]]
 ; BRANCH_FORM-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[C1]], [[C2]]
-; BRANCH_FORM-NEXT:    [[C3:%.*]] = icmp ult i32 [[IV]], [[C]]
+; BRANCH_FORM-NEXT:    [[C3:%.*]] = icmp ult i32 [[IV]], [[C_GW_FR]]
 ; BRANCH_FORM-NEXT:    [[WIDE_CHK13:%.*]] = and i1 [[WIDE_CHK]], [[C3]]
-; BRANCH_FORM-NEXT:    [[C4:%.*]] = icmp ult i32 [[IV]], [[D]]
+; BRANCH_FORM-NEXT:    [[C4:%.*]] = icmp ult i32 [[IV]], [[D_GW_FR]]
 ; BRANCH_FORM-NEXT:    [[WIDE_CHK14:%.*]] = and i1 [[WIDE_CHK13]], [[C4]]
 ; BRANCH_FORM-NEXT:    [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
 ; BRANCH_FORM-NEXT:    [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[WIDE_CHK14]], [[WIDENABLE_COND]]
@@ -72,16 +78,19 @@ define void @test_01(i32 %a, i32 %b, i32 %c, i32 %d) {
 ; BRANCH_FORM_LICM-LABEL: define void @test_01
 ; BRANCH_FORM_LICM-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], i32 [[D:%.*]]) {
 ; BRANCH_FORM_LICM-NEXT:  entry:
+; BRANCH_FORM_LICM-NEXT:    [[D_GW_FR:%.*]] = freeze i32 [[D]]
+; BRANCH_FORM_LICM-NEXT:    [[C_GW_FR:%.*]] = freeze i32 [[C]]
+; BRANCH_FORM_LICM-NEXT:    [[B_GW_FR:%.*]] = freeze i32 [[B]]
 ; BRANCH_FORM_LICM-NEXT:    br label [[LOOP:%.*]]
 ; BRANCH_FORM_LICM:       loop:
 ; BRANCH_FORM_LICM-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[GUARDED:%.*]] ]
 ; BRANCH_FORM_LICM-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
 ; BRANCH_FORM_LICM-NEXT:    [[C1:%.*]] = icmp ult i32 [[IV]], [[A]]
-; BRANCH_FORM_LICM-NEXT:    [[C2:%.*]] = icmp ult i32 [[IV]], [[B]]
+; BRANCH_FORM_LICM-NEXT:    [[C2:%.*]] = icmp ult i32 [[IV]], [[B_GW_FR]]
 ; BRANCH_FORM_LICM-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[C1]], [[C2]]
-; BRANCH_FORM_LICM-NEXT:    [[C3:%.*]] = icmp ult i32 [[IV]], [[C]]
+; BRANCH_FORM_LICM-NEXT:    [[C3:%.*]] = icmp ult i32 [[IV]], [[C_GW_FR]]
 ; BRANCH_FORM_LICM-NEXT:    [[WIDE_CHK13:%.*]] = and i1 [[WIDE_CHK]], [[C3]]
-; BRANCH_FORM_LICM-NEXT:    [[C4:%.*]] = icmp ult i32 [[IV]], [[D]]
+; BRANCH_FORM_LICM-NEXT:    [[C4:%.*]] = icmp ult i32 [[IV]], [[D_GW_FR]]
 ; BRANCH_FORM_LICM-NEXT:    [[WIDE_CHK14:%.*]] = and i1 [[WIDE_CHK13]], [[C4]]
 ; BRANCH_FORM_LICM-NEXT:    [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
 ; BRANCH_FORM_LICM-NEXT:    [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[WIDE_CHK14]], [[WIDENABLE_COND]]