diff --git a/llvm/lib/Transforms/Scalar/GuardWidening.cpp b/llvm/lib/Transforms/Scalar/GuardWidening.cpp --- a/llvm/lib/Transforms/Scalar/GuardWidening.cpp +++ b/llvm/lib/Transforms/Scalar/GuardWidening.cpp @@ -69,6 +69,7 @@ STATISTIC(GuardsEliminated, "Number of eliminated guards"); STATISTIC(CondBranchEliminated, "Number of eliminated conditional branches"); +STATISTIC(FreezeAdded, "Number of freeze instruction introduced"); static cl::opt WidenBranchGuards("guard-widening-widen-branch-guards", cl::Hidden, @@ -209,6 +210,10 @@ 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 @@ 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(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(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 Visited; + SmallVector Worklist; + SmallSet DropPoisonFlags; + SmallSet 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(V); + if (!I || canCreateUndefOrPoison(cast(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(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, @@ -621,6 +698,7 @@ } assert(Result && "Failed to find result value"); Result->setName("wide.chk"); + Result = freezeAndPush(Result, InsertPt); } return true; } @@ -633,6 +711,7 @@ makeAvailableAt(Cond1, InsertPt); if (InvertCondition) Cond1 = BinaryOperator::CreateNot(Cond1, "inverted", InsertPt); + Cond1 = freezeAndPush(Cond1, InsertPt); Result = BinaryOperator::CreateAnd(Cond0, Cond1, "wide.chk", InsertPt); } diff --git a/llvm/test/Transforms/GuardWidening/basic-loop.ll b/llvm/test/Transforms/GuardWidening/basic-loop.ll --- a/llvm/test/Transforms/GuardWidening/basic-loop.ll +++ b/llvm/test/Transforms/GuardWidening/basic-loop.ll @@ -10,11 +10,13 @@ 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 @@ 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 @@ 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: diff --git a/llvm/test/Transforms/GuardWidening/basic.ll b/llvm/test/Transforms/GuardWidening/basic.ll --- a/llvm/test/Transforms/GuardWidening/basic.ll +++ b/llvm/test/Transforms/GuardWidening/basic.ll @@ -9,7 +9,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: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] ; CHECK-NEXT: ret void ; @@ -24,7 +25,8 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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]] diff --git a/llvm/test/Transforms/GuardWidening/basic_widenable_condition_guards.ll b/llvm/test/Transforms/GuardWidening/basic_widenable_condition_guards.ll --- a/llvm/test/Transforms/GuardWidening/basic_widenable_condition_guards.ll +++ b/llvm/test/Transforms/GuardWidening/basic_widenable_condition_guards.ll @@ -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 @@ ; 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 @@ 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 @@ ; 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ ; 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 @@ 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 @@ ; 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 @@ 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 @@ 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 @@ ; 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 @@ 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 @@ ; 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"() ] diff --git a/llvm/test/Transforms/GuardWidening/hang.ll b/llvm/test/Transforms/GuardWidening/hang.ll --- a/llvm/test/Transforms/GuardWidening/hang.ll +++ b/llvm/test/Transforms/GuardWidening/hang.ll @@ -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]] diff --git a/llvm/test/Transforms/GuardWidening/loop-schedule.ll b/llvm/test/Transforms/GuardWidening/loop-schedule.ll --- a/llvm/test/Transforms/GuardWidening/loop-schedule.ll +++ b/llvm/test/Transforms/GuardWidening/loop-schedule.ll @@ -13,8 +13,9 @@ 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 @@ 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 diff --git a/llvm/test/Transforms/GuardWidening/loop_invariant_widenable_condition.ll b/llvm/test/Transforms/GuardWidening/loop_invariant_widenable_condition.ll --- a/llvm/test/Transforms/GuardWidening/loop_invariant_widenable_condition.ll +++ b/llvm/test/Transforms/GuardWidening/loop_invariant_widenable_condition.ll @@ -8,12 +8,14 @@ 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 @@ 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 @@ ; 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: diff --git a/llvm/test/Transforms/GuardWidening/mixed_guards.ll b/llvm/test/Transforms/GuardWidening/mixed_guards.ll --- a/llvm/test/Transforms/GuardWidening/mixed_guards.ll +++ b/llvm/test/Transforms/GuardWidening/mixed_guards.ll @@ -15,10 +15,11 @@ 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 @@ 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]] diff --git a/llvm/test/Transforms/GuardWidening/posion.ll b/llvm/test/Transforms/GuardWidening/posion.ll --- a/llvm/test/Transforms/GuardWidening/posion.ll +++ b/llvm/test/Transforms/GuardWidening/posion.ll @@ -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 @@ 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 @@ 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 @@ 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: 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 +} diff --git a/llvm/test/Transforms/GuardWidening/profile-based-profitability-intrinsics.ll b/llvm/test/Transforms/GuardWidening/profile-based-profitability-intrinsics.ll --- a/llvm/test/Transforms/GuardWidening/profile-based-profitability-intrinsics.ll +++ b/llvm/test/Transforms/GuardWidening/profile-based-profitability-intrinsics.ll @@ -9,7 +9,8 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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]+]] diff --git a/llvm/test/Transforms/GuardWidening/profile-based-profitability_explicit.ll b/llvm/test/Transforms/GuardWidening/profile-based-profitability_explicit.ll --- a/llvm/test/Transforms/GuardWidening/profile-based-profitability_explicit.ll +++ b/llvm/test/Transforms/GuardWidening/profile-based-profitability_explicit.ll @@ -6,7 +6,8 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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"() ] diff --git a/llvm/test/Transforms/GuardWidening/range-check-merging.ll b/llvm/test/Transforms/GuardWidening/range-check-merging.ll --- a/llvm/test/Transforms/GuardWidening/range-check-merging.ll +++ b/llvm/test/Transforms/GuardWidening/range-check-merging.ll @@ -6,22 +6,23 @@ 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 @@ 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 @@ ; 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 @@ 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 @@ 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 @@ ; 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 @@ 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 @@ ; 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 @@ 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 @@ ; 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 @@ 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 @@ 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 @@ 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 @@ ; 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"() ] diff --git a/llvm/test/Transforms/GuardWidening/two_forms_behavior_consistency.ll b/llvm/test/Transforms/GuardWidening/two_forms_behavior_consistency.ll --- a/llvm/test/Transforms/GuardWidening/two_forms_behavior_consistency.ll +++ b/llvm/test/Transforms/GuardWidening/two_forms_behavior_consistency.ll @@ -14,16 +14,19 @@ ; 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 @@ ; 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 @@ ; 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]]