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,
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
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;
+ SmallSet<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.insert(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.insert(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,
}
assert(Result && "Failed to find result value");
Result->setName("wide.chk");
+ Result = freezeAndPush(Result, InsertPt);
}
return true;
}
makeAvailableAt(Cond1, InsertPt);
if (InvertCondition)
Cond1 = BinaryOperator::CreateNot(Cond1, "inverted", InsertPt);
+ Cond1 = freezeAndPush(Cond1, InsertPt);
Result = BinaryOperator::CreateAnd(Cond0, Cond1, "wide.chk", InsertPt);
}
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
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:
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:
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
;
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:
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:%.*]]
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:%.*]]
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
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:%.*]]
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:
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]]
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]+]]
; 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"() ]
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]]
; 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"() ]
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]]
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]]
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]]
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()
; 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]]
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]]
; 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"() ]
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]]
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]]
; 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"() ]
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]]
; 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"() ]
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]]
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
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
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:
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:
; 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:
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"() ]
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]]
; 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.
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) ]
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) ]
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]]
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
+}
; 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]+]]
; 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]+]]
; 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]+]]
; 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]+]]
; 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]+]]
; 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]+]]
; 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"() ]
; 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]]
; 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"() ]
; 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]]
; 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"() ]
; 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]]
; 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"() ]
; 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]]
; 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"() ]
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"() ]
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
; 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"() ]
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
;
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]]
;
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"() ]
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"() ]
; 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"() ]
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
; 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"() ]
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"() ]
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]]
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
; 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"() ]
; 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]]
; 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]]
; 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]]