Index: llvm/lib/Transforms/Scalar/GuardWidening.cpp =================================================================== --- llvm/lib/Transforms/Scalar/GuardWidening.cpp +++ llvm/lib/Transforms/Scalar/GuardWidening.cpp @@ -195,24 +195,40 @@ /// pre-existing instruction in the IR that computes the result of this range /// check. class RangeCheck { - const Value *Base; - const ConstantInt *Offset; - const Value *Length; + Value *Base; + ConstantInt *Offset; + Value *Length; ICmpInst *CheckInst; + bool MayNeedFreeze; + bool BaseNeedFreeze; + bool LengthNeedFreeze; + bool NeedCleanOfPoisonFlags; public: - explicit RangeCheck(const Value *Base, const ConstantInt *Offset, - const Value *Length, ICmpInst *CheckInst) - : Base(Base), Offset(Offset), Length(Length), CheckInst(CheckInst) {} - - void setBase(const Value *NewBase) { Base = NewBase; } - void setOffset(const ConstantInt *NewOffset) { Offset = NewOffset; } - - const Value *getBase() const { return Base; } - const ConstantInt *getOffset() const { return Offset; } + explicit RangeCheck(Value *Base, ConstantInt *Offset, Value *Length, + ICmpInst *CheckInst, bool MayNeedFreeze) + : Base(Base), Offset(Offset), Length(Length), CheckInst(CheckInst), + MayNeedFreeze(MayNeedFreeze), BaseNeedFreeze(false), + LengthNeedFreeze(false), NeedCleanOfPoisonFlags(false) {} + + void setBase(Value *NewBase) { Base = NewBase; } + void setOffset(ConstantInt *NewOffset) { Offset = NewOffset; } + void setBaseNeedFreeze() { BaseNeedFreeze = true; } + void setLengthNeedFreeze() { LengthNeedFreeze = true; } + void setNeedCleanOfPoisonFlags() { NeedCleanOfPoisonFlags = true; } + void setMayNeedFreeze() { MayNeedFreeze = true; } + + Value *getBase() const { return Base; } + ConstantInt *getOffset() const { return Offset; } const APInt &getOffsetValue() const { return getOffset()->getValue(); } - const Value *getLength() const { return Length; }; + Value *getLength() const { + return Length; + }; ICmpInst *getCheckInst() const { return CheckInst; } + bool getMayNeedFreeze() const { return MayNeedFreeze; } + bool getBaseNeedFreeze() const { return BaseNeedFreeze; } + bool getLengthNeedFreeze() const { return LengthNeedFreeze; } + bool getNeedCleanOfPoisonFlags() const { return NeedCleanOfPoisonFlags; } void print(raw_ostream &OS, bool PrintTypes = false) { OS << "Base: "; @@ -232,13 +248,18 @@ /// Parse \p CheckCond into a conjunction (logical-and) of range checks; and /// append them to \p Checks. Returns true on success, may clobber \c Checks /// on failure. - bool parseRangeChecks(Value *CheckCond, SmallVectorImpl &Checks) { + bool parseRangeChecks(Value *CheckCond, SmallVectorImpl &Checks, + DenseMap &ValueToFreeze, + bool MayNeedFreeze) { SmallPtrSet Visited; - return parseRangeChecks(CheckCond, Checks, Visited); + return parseRangeChecks(CheckCond, Checks, Visited, ValueToFreeze, + MayNeedFreeze); } bool parseRangeChecks(Value *CheckCond, SmallVectorImpl &Checks, - SmallPtrSetImpl &Visited); + SmallPtrSetImpl &Visited, + DenseMap &ValueToFreeze, + bool MayNeedFreeze); /// Combine the checks in \p Checks into a smaller set of checks and append /// them into \p CombinedChecks. Return true on success (i.e. all of checks @@ -495,8 +516,6 @@ makeAvailableAt(Op, Loc); Inst->moveBefore(Loc); - // If we moved instruction before guard we must clean poison generating flags. - Inst->dropPoisonGeneratingFlags(); } bool GuardWideningImpl::widenCondCommon(Value *Cond0, Value *Cond1, @@ -539,20 +558,57 @@ { SmallVector Checks, CombinedChecks; + DenseMap ValueToFreeze; + auto GetValue = [&](Value *V, bool NeedToFreeze) { + makeAvailableAt(V, InsertPt); + if (!NeedToFreeze) + return V; + auto It = ValueToFreeze.find(V); + if (It != ValueToFreeze.end()) { + V = It->second; + makeAvailableAt(V, InsertPt); + return V; + } + Value *Freeze = V; + if (!isGuaranteedNotToBePoison(V, nullptr, InsertPt, &DT)) + Freeze = new FreezeInst(V, "gw.freeze", InsertPt); + ValueToFreeze[V] = Freeze; + return Freeze; + }; // TODO: Support InvertCondition case? if (!InvertCondition && - parseRangeChecks(Cond0, Checks) && parseRangeChecks(Cond1, Checks) && + parseRangeChecks(Cond0, Checks, ValueToFreeze, false) && + parseRangeChecks(Cond1, Checks, ValueToFreeze, true) && combineRangeChecks(Checks, CombinedChecks)) { if (InsertPt) { Result = nullptr; for (auto &RC : CombinedChecks) { - makeAvailableAt(RC.getCheckInst(), InsertPt); + // Prepare candidate first. + Value *Condition = nullptr; + if (RC.getNeedCleanOfPoisonFlags()) { + // We need to generate + // freeze(base) + offset unsigned less than freeze(L). + Value *Base = GetValue(RC.getBase(), RC.getMayNeedFreeze() && + RC.getBaseNeedFreeze()); + Value *BaseAndOffset = + BinaryOperator::CreateAdd(Base, RC.getOffset(), "", InsertPt); + Value *Length = + GetValue(RC.getLength(), + RC.getMayNeedFreeze() && RC.getLengthNeedFreeze()); + Condition = new ICmpInst(InsertPt, CmpInst::Predicate::ICMP_ULT, + BaseAndOffset, Length, ""); + } else { + // Ok, this range check comes without any combining. + // It may be from guard we are widening or from other guard. + // In the second case we need to freeze it if it can be poison. + Condition = GetValue(RC.getCheckInst(), RC.getMayNeedFreeze()); + } if (Result) - Result = BinaryOperator::CreateAnd(RC.getCheckInst(), Result, "", - InsertPt); + Result = BinaryOperator::CreateAnd(Result, Condition, "", InsertPt); else - Result = RC.getCheckInst(); + Result = Condition; } + assert(Result && "Failed to find result value"); Result->setName("wide.chk"); } @@ -567,6 +623,8 @@ makeAvailableAt(Cond1, InsertPt); if (InvertCondition) Cond1 = BinaryOperator::CreateNot(Cond1, "inverted", InsertPt); + if (!isGuaranteedNotToBePoison(Cond1, nullptr, InsertPt, &DT)) + Cond1 = new FreezeInst(Cond1, "gw.freeze", InsertPt); Result = BinaryOperator::CreateAnd(Cond0, Cond1, "wide.chk", InsertPt); } @@ -576,17 +634,24 @@ bool GuardWideningImpl::parseRangeChecks( Value *CheckCond, SmallVectorImpl &Checks, - SmallPtrSetImpl &Visited) { + SmallPtrSetImpl &Visited, + DenseMap &ValueToFreeze, bool MayNeedFreeze) { if (!Visited.insert(CheckCond).second) return true; + if (auto *FreezeCheckInst = dyn_cast(CheckCond)) { + CheckCond = FreezeCheckInst->getOperand(0); + ValueToFreeze[CheckCond] = FreezeCheckInst; + MayNeedFreeze = true; + } + using namespace llvm::PatternMatch; { Value *AndLHS, *AndRHS; if (match(CheckCond, m_And(m_Value(AndLHS), m_Value(AndRHS)))) - return parseRangeChecks(AndLHS, Checks) && - parseRangeChecks(AndRHS, Checks); + return parseRangeChecks(AndLHS, Checks, ValueToFreeze, MayNeedFreeze) && + parseRangeChecks(AndRHS, Checks, ValueToFreeze, MayNeedFreeze); } auto *IC = dyn_cast(CheckCond); @@ -595,15 +660,25 @@ IC->getPredicate() != ICmpInst::ICMP_UGT)) return false; - const Value *CmpLHS = IC->getOperand(0), *CmpRHS = IC->getOperand(1); + Value *CmpLHS = IC->getOperand(0), *CmpRHS = IC->getOperand(1); if (IC->getPredicate() == ICmpInst::ICMP_UGT) std::swap(CmpLHS, CmpRHS); auto &DL = IC->getModule()->getDataLayout(); + if (auto *FreezeBase = dyn_cast(CmpLHS)) { + CmpLHS = FreezeBase->getOperand(0); + ValueToFreeze[CmpLHS] = FreezeBase; + MayNeedFreeze = true; + } + if (auto *FreezeLength = dyn_cast(CmpRHS)) { + CmpRHS = FreezeLength->getOperand(0); + ValueToFreeze[CmpRHS] = FreezeLength; + MayNeedFreeze = true; + } GuardWideningImpl::RangeCheck Check( CmpLHS, cast(ConstantInt::getNullValue(CmpRHS->getType())), - CmpRHS, IC); + CmpRHS, IC, MayNeedFreeze); if (!isKnownNonNegative(Check.getLength(), DL)) return false; @@ -626,6 +701,11 @@ #endif if (match(Check.getBase(), m_Add(m_Value(OpLHS), m_ConstantInt(OpRHS)))) { + if (auto *FreezeBase = dyn_cast(OpLHS)) { + OpLHS = FreezeBase->getOperand(0); + ValueToFreeze[OpLHS] = FreezeBase; + Check.setMayNeedFreeze(); + } Check.setBase(OpLHS); APInt NewOffset = Check.getOffsetValue() + OpRHS->getValue(); Check.setOffset(ConstantInt::get(Ctx, NewOffset)); @@ -634,6 +714,11 @@ m_Or(m_Value(OpLHS), m_ConstantInt(OpRHS)))) { KnownBits Known = computeKnownBits(OpLHS, DL); if ((OpRHS->getValue() & Known.Zero) == OpRHS->getValue()) { + if (auto *FreezeBase = dyn_cast(OpLHS)) { + OpLHS = FreezeBase->getOperand(0); + ValueToFreeze[OpLHS] = FreezeBase; + Check.setMayNeedFreeze(); + } Check.setBase(OpLHS); APInt NewOffset = Check.getOffsetValue() + OpRHS->getValue(); Check.setOffset(ConstantInt::get(Ctx, NewOffset)); @@ -650,6 +735,16 @@ SmallVectorImpl &Checks, SmallVectorImpl &RangeChecksOut) const { unsigned OldCount = Checks.size(); + // Collect all Bases and Length from the guard we are widening as + // they do not need freeze due to if they are poison we would have UB in the + // original program. + SmallPtrSet NotNeedFreeze; + for (auto &RC : Checks) { + if (!RC.getMayNeedFreeze()) { + NotNeedFreeze.insert(RC.getBase()); + NotNeedFreeze.insert(RC.getLength()); + } + } while (!Checks.empty()) { // Pick all of the range checks with a specific base and length, and try to // merge them. @@ -734,6 +829,19 @@ // For Chk_0 to succeed, we'd have to have k_f-k_0 (the range highlighted // with 'x' above) to be at least >u INT_MIN. + // Well, we need to deal with possible poison of range checks now. + // All range checks of the form Base + Offset. + if (!NotNeedFreeze.count(CurrentChecks.front().getBase())) { + CurrentChecks.front().setBaseNeedFreeze(); + CurrentChecks.back().setBaseNeedFreeze(); + } + if (!NotNeedFreeze.count(CurrentChecks.front().getLength())) { + CurrentChecks.front().setLengthNeedFreeze(); + CurrentChecks.back().setLengthNeedFreeze(); + } + CurrentChecks.front().setNeedCleanOfPoisonFlags(); + CurrentChecks.back().setNeedCleanOfPoisonFlags(); + RangeChecksOut.emplace_back(CurrentChecks.front()); RangeChecksOut.emplace_back(CurrentChecks.back()); } Index: llvm/test/Transforms/GuardWidening/basic-loop.ll =================================================================== --- llvm/test/Transforms/GuardWidening/basic-loop.ll +++ llvm/test/Transforms/GuardWidening/basic-loop.ll @@ -13,9 +13,11 @@ ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: store i32 0, i32* @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: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK1]]) [ "deopt"(i32 0) ] +; CHECK-NEXT: [[GW_FREEZE:%.*]] = freeze i1 [[COND_1:%.*]] +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[GW_FREEZE]] +; CHECK-NEXT: [[GW_FREEZE1:%.*]] = freeze i1 [[COND_2:%.*]] +; CHECK-NEXT: [[WIDE_CHK2:%.*]] = and i1 [[WIDE_CHK]], [[GW_FREEZE1]] +; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK2]]) [ "deopt"(i32 0) ] ; CHECK-NEXT: store i32 1, i32* @G, align 4 ; CHECK-NEXT: store i32 2, i32* @G, align 4 ; CHECK-NEXT: store i32 3, i32* @G, align 4 @@ -39,9 +41,11 @@ ; CHECK-LABEL: @widen_into_preheader( ; CHECK-NEXT: entry: ; CHECK-NEXT: store i32 0, i32* @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: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK1]]) [ "deopt"(i32 0) ] +; CHECK-NEXT: [[GW_FREEZE:%.*]] = freeze i1 [[COND_1:%.*]] +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[GW_FREEZE]] +; CHECK-NEXT: [[GW_FREEZE1:%.*]] = freeze i1 [[COND_2:%.*]] +; CHECK-NEXT: [[WIDE_CHK2:%.*]] = and i1 [[WIDE_CHK]], [[GW_FREEZE1]] +; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK2]]) [ "deopt"(i32 0) ] ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: store i32 1, i32* @G, align 4 @@ -103,7 +107,8 @@ ; CHECK-LABEL: @widen_over_common_exit_to_ph( ; CHECK-NEXT: entry: ; CHECK-NEXT: store i32 0, i32* @G, align 4 -; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_2:%.*]] +; CHECK-NEXT: [[GW_FREEZE:%.*]] = freeze i1 [[COND_2:%.*]] +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[GW_FREEZE]] ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"(i32 0) ] ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: Index: llvm/test/Transforms/GuardWidening/basic.ll =================================================================== --- llvm/test/Transforms/GuardWidening/basic.ll +++ 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: [[GW_FREEZE:%.*]] = freeze i1 [[COND_1:%.*]] +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[GW_FREEZE]] ; 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: [[GW_FREEZE:%.*]] = freeze i1 [[COND_1:%.*]] +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[GW_FREEZE]] ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] ; CHECK-NEXT: br i1 undef, label [[LEFT:%.*]], label [[RIGHT:%.*]] ; CHECK: left: @@ -57,7 +59,8 @@ ; CHECK-NEXT: entry: ; CHECK-NEXT: [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 10 ; CHECK-NEXT: [[COND_1:%.*]] = icmp ult i32 [[B:%.*]], 10 -; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0]], [[COND_1]] +; CHECK-NEXT: [[GW_FREEZE:%.*]] = freeze i1 [[COND_1]] +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0]], [[GW_FREEZE]] ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] ; CHECK-NEXT: br i1 undef, label [[LEFT:%.*]], label [[RIGHT:%.*]] ; CHECK: left: @@ -124,7 +127,8 @@ ; CHECK-NEXT: entry: ; CHECK-NEXT: [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 10 ; CHECK-NEXT: [[COND_1:%.*]] = icmp ult i32 [[B:%.*]], 10 -; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0]], [[COND_1]] +; CHECK-NEXT: [[GW_FREEZE:%.*]] = freeze i1 [[COND_1]] +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0]], [[GW_FREEZE]] ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] ; CHECK-NEXT: br i1 undef, label [[LOOP:%.*]], label [[LEAVE:%.*]] ; CHECK: loop: @@ -206,7 +210,8 @@ ; CHECK-NEXT: entry: ; CHECK-NEXT: [[COND_1:%.*]] = load volatile i1, i1* [[COND_BUF:%.*]], align 1 ; CHECK-NEXT: [[COND_3:%.*]] = icmp ult i32 [[A:%.*]], 7 -; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_3]] +; CHECK-NEXT: [[GW_FREEZE:%.*]] = freeze i1 [[COND_3]] +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[GW_FREEZE]] ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] ; CHECK-NEXT: [[COND_2:%.*]] = load volatile i1, i1* [[COND_BUF]], align 1 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_2]]) [ "deopt"() ] @@ -245,7 +250,8 @@ ; CHECK-NEXT: br i1 undef, label [[LOOP]], label [[LEAVE:%.*]] ; CHECK: leave: ; CHECK-NEXT: [[COND_3:%.*]] = icmp ult i32 [[A:%.*]], 7 -; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_2:%.*]], [[COND_3]] +; CHECK-NEXT: [[GW_FREEZE:%.*]] = freeze i1 [[COND_3]] +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_2:%.*]], [[GW_FREEZE]] ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] ; CHECK-NEXT: br i1 undef, label [[LOOP2:%.*]], label [[LEAVE2:%.*]] ; CHECK: loop2: @@ -334,7 +340,8 @@ ; CHECK-NEXT: entry: ; CHECK-NEXT: br label [[INNER:%.*]] ; CHECK: inner: -; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]] +; CHECK-NEXT: [[GW_FREEZE:%.*]] = freeze i1 [[COND_1:%.*]] +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[GW_FREEZE]] ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] ; CHECK-NEXT: br i1 undef, label [[INNER]], label [[OUTER:%.*]] ; CHECK: outer: @@ -389,7 +396,8 @@ ; CHECK-NEXT: [[A29:%.*]] = mul i32 [[A28]], [[A28]] ; CHECK-NEXT: [[A30:%.*]] = mul i32 [[A29]], [[A29]] ; CHECK-NEXT: [[COND:%.*]] = trunc i32 [[A30]] to i1 -; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 true, [[COND]] +; CHECK-NEXT: [[GW_FREEZE:%.*]] = freeze i1 [[COND]] +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 true, [[GW_FREEZE]] ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] ; CHECK-NEXT: ret void ; Index: llvm/test/Transforms/GuardWidening/basic_widenable_condition_guards.ll =================================================================== --- llvm/test/Transforms/GuardWidening/basic_widenable_condition_guards.ll +++ llvm/test/Transforms/GuardWidening/basic_widenable_condition_guards.ll @@ -8,7 +8,8 @@ ; CHECK-LABEL: @f_0( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition() -; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]] +; CHECK-NEXT: [[GW_FREEZE:%.*]] = freeze i1 [[COND_1:%.*]] +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[GW_FREEZE]] ; 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: deopt: @@ -51,7 +52,8 @@ ; CHECK-LABEL: @f_1( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition() -; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]] +; CHECK-NEXT: [[GW_FREEZE:%.*]] = freeze i1 [[COND_1:%.*]] +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[GW_FREEZE]] ; 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: deopt: @@ -112,7 +114,8 @@ ; CHECK-NEXT: [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 10 ; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition() ; CHECK-NEXT: [[COND_1:%.*]] = icmp ult i32 [[B:%.*]], 10 -; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0]], [[COND_1]] +; CHECK-NEXT: [[GW_FREEZE:%.*]] = freeze i1 [[COND_1]] +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0]], [[GW_FREEZE]] ; 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: deopt: @@ -233,7 +236,8 @@ ; CHECK-NEXT: [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 10 ; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition() ; CHECK-NEXT: [[COND_1:%.*]] = icmp ult i32 [[B:%.*]], 10 -; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0]], [[COND_1]] +; CHECK-NEXT: [[GW_FREEZE:%.*]] = freeze i1 [[COND_1]] +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0]], [[GW_FREEZE]] ; 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: deopt: @@ -399,7 +403,8 @@ ; CHECK-NEXT: [[COND_1:%.*]] = load volatile i1, i1* [[COND_BUF:%.*]], align 1 ; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition() ; CHECK-NEXT: [[COND_3:%.*]] = icmp ult i32 [[A:%.*]], 7 -; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_3]] +; CHECK-NEXT: [[GW_FREEZE:%.*]] = freeze i1 [[COND_3]] +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[GW_FREEZE]] ; 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: deopt: @@ -486,7 +491,8 @@ ; CHECK: leave: ; CHECK-NEXT: [[WIDENABLE_COND3:%.*]] = call i1 @llvm.experimental.widenable.condition() ; CHECK-NEXT: [[COND_3:%.*]] = icmp ult i32 [[A:%.*]], 7 -; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_2:%.*]], [[COND_3]] +; CHECK-NEXT: [[GW_FREEZE:%.*]] = freeze i1 [[COND_3]] +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_2:%.*]], [[GW_FREEZE]] ; CHECK-NEXT: [[EXIPLICIT_GUARD_COND4:%.*]] = and i1 [[WIDE_CHK]], [[WIDENABLE_COND3]] ; CHECK-NEXT: br i1 [[EXIPLICIT_GUARD_COND4]], label [[GUARDED1:%.*]], label [[DEOPT2:%.*]], !prof [[PROF0]] ; CHECK: deopt2: @@ -664,7 +670,8 @@ ; CHECK-NEXT: br label [[OUTER_HEADER:%.*]] ; CHECK: outer_header: ; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition() -; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]] +; CHECK-NEXT: [[GW_FREEZE:%.*]] = freeze i1 [[COND_1:%.*]] +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[GW_FREEZE]] ; 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: deopt: @@ -757,7 +764,8 @@ ; CHECK-NEXT: [[A29:%.*]] = mul i32 [[A28]], [[A28]] ; CHECK-NEXT: [[A30:%.*]] = mul i32 [[A29]], [[A29]] ; CHECK-NEXT: [[COND:%.*]] = trunc i32 [[A30]] to i1 -; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 true, [[COND]] +; CHECK-NEXT: [[GW_FREEZE:%.*]] = freeze i1 [[COND]] +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 true, [[GW_FREEZE]] ; 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: deopt: @@ -1026,7 +1034,8 @@ ; CHECK-LABEL: @swapped_wb( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition() -; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]] +; CHECK-NEXT: [[GW_FREEZE:%.*]] = freeze i1 [[COND_1:%.*]] +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[GW_FREEZE]] ; 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: deopt: @@ -1068,7 +1077,8 @@ ; CHECK-LABEL: @trivial_wb( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition() -; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 true, [[COND_0:%.*]] +; CHECK-NEXT: [[GW_FREEZE:%.*]] = freeze i1 [[COND_0:%.*]] +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 true, [[GW_FREEZE]] ; CHECK-NEXT: [[TMP0:%.*]] = and i1 [[WIDE_CHK]], [[WIDENABLE_COND]] ; CHECK-NEXT: br i1 [[TMP0]], label [[GUARDED:%.*]], label [[DEOPT:%.*]], !prof [[PROF0]] ; CHECK: deopt: Index: llvm/test/Transforms/GuardWidening/loop-schedule.ll =================================================================== --- llvm/test/Transforms/GuardWidening/loop-schedule.ll +++ llvm/test/Transforms/GuardWidening/loop-schedule.ll @@ -15,7 +15,8 @@ ; CHECK-NEXT: entry: ; CHECK-NEXT: [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 10 ; CHECK-NEXT: [[COND_1:%.*]] = icmp ult i32 [[B:%.*]], 10 -; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0]], [[COND_1]] +; CHECK-NEXT: [[GW_FREEZE:%.*]] = freeze i1 [[COND_1]] +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0]], [[GW_FREEZE]] ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] ; CHECK-NEXT: [[CND:%.*]] = load i1, i1* [[C_P:%.*]], align 1 ; CHECK-NEXT: br label [[LOOP:%.*]] @@ -50,7 +51,8 @@ ; CHECK-NEXT: entry: ; CHECK-NEXT: [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 10 ; CHECK-NEXT: [[COND_1:%.*]] = icmp ult i32 [[B:%.*]], 10 -; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0]], [[COND_1]] +; CHECK-NEXT: [[GW_FREEZE:%.*]] = freeze i1 [[COND_1]] +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0]], [[GW_FREEZE]] ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] ; CHECK-NEXT: [[CND:%.*]] = load i1, i1* [[C_P:%.*]], align 1 ; CHECK-NEXT: br label [[LOOP:%.*]] Index: llvm/test/Transforms/GuardWidening/mixed_guards.ll =================================================================== --- llvm/test/Transforms/GuardWidening/mixed_guards.ll +++ llvm/test/Transforms/GuardWidening/mixed_guards.ll @@ -15,7 +15,8 @@ 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: [[GW_FREEZE:%.*]] = freeze i1 [[COND_1:%.*]] +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[GW_FREEZE]] ; 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]] @@ -45,7 +46,8 @@ ; CHECK-LABEL: @test_02( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition() -; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]] +; CHECK-NEXT: [[GW_FREEZE:%.*]] = freeze i1 [[COND_1:%.*]] +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[GW_FREEZE]] ; 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: deopt: Index: llvm/test/Transforms/GuardWidening/posion.ll =================================================================== --- llvm/test/Transforms/GuardWidening/posion.ll +++ llvm/test/Transforms/GuardWidening/posion.ll @@ -26,11 +26,11 @@ ; CHECK-NEXT: entry: ; CHECK-NEXT: [[X2:%.*]] = add i32 [[X:%.*]], 0 ; CHECK-NEXT: [[C2:%.*]] = icmp ult i32 [[X2]], 200 -; CHECK-NEXT: [[X3:%.*]] = add nuw nsw i32 [[X]], 3 -; CHECK-NEXT: [[C3:%.*]] = icmp ult i32 [[X3]], 100 -; CHECK-NEXT: [[X4:%.*]] = add nuw nsw i32 [[X]], 20 -; CHECK-NEXT: [[C4:%.*]] = icmp ult i32 [[X4]], 100 -; CHECK-NEXT: [[WIDE_CHK2:%.*]] = and i1 [[C4]], [[C3]] +; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[X]], 3 +; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[TMP0]], 100 +; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[X]], 20 +; CHECK-NEXT: [[TMP3:%.*]] = icmp ult i32 [[TMP2]], 100 +; CHECK-NEXT: [[WIDE_CHK2:%.*]] = and i1 [[TMP1]], [[TMP3]] ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK2]]) [ "deopt"(i64 1) ] ; CHECK-NEXT: br i1 [[C2]], label [[OK:%.*]], label [[OUT:%.*]] ; CHECK: ok: @@ -70,11 +70,11 @@ ; CHECK-NEXT: entry: ; CHECK-NEXT: [[X2:%.*]] = add i32 [[X:%.*]], 0 ; CHECK-NEXT: [[C2:%.*]] = icmp ult i32 [[X2]], 200 -; CHECK-NEXT: [[X3:%.*]] = add nuw nsw i32 [[X]], 3 -; CHECK-NEXT: [[C3:%.*]] = icmp ult i32 [[X3]], 100 -; CHECK-NEXT: [[X4:%.*]] = add nuw nsw i32 [[X]], 20 -; CHECK-NEXT: [[C4:%.*]] = icmp ult i32 [[X4]], 100 -; CHECK-NEXT: [[WIDE_CHK2:%.*]] = and i1 [[C4]], [[C3]] +; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[X]], 3 +; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[TMP0]], 100 +; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[X]], 20 +; CHECK-NEXT: [[TMP3:%.*]] = icmp ult i32 [[TMP2]], 100 +; CHECK-NEXT: [[WIDE_CHK2:%.*]] = and i1 [[TMP1]], [[TMP3]] ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK2]]) [ "deopt"(i64 1) ] ; CHECK-NEXT: store i32 0, i32* [[P:%.*]], align 4 ; CHECK-NEXT: br i1 [[C2]], label [[OK:%.*]], label [[OUT:%.*]] @@ -117,7 +117,8 @@ ; CHECK-NEXT: [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 10 ; CHECK-NEXT: [[B_SHIFT:%.*]] = add nuw nsw i32 [[B:%.*]], 5 ; CHECK-NEXT: [[COND_2:%.*]] = icmp ult i32 [[B_SHIFT]], 10 -; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0]], [[COND_2]] +; CHECK-NEXT: [[GW_FREEZE:%.*]] = freeze i1 [[COND_2]] +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0]], [[GW_FREEZE]] ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: @@ -150,3 +151,195 @@ leave: ret void } + +; The case checks that base needs a freeze. +define void @combine_range_checks_base_need_freeze(i32 %y, i32 %x, i32* %p) { +; CHECK-LABEL: @combine_range_checks_base_need_freeze( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[X2:%.*]] = add i32 [[X:%.*]], 0 +; CHECK-NEXT: [[C2:%.*]] = icmp ult i32 [[X2]], 200 +; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[Y:%.*]], 100 +; CHECK-NEXT: [[GW_FREEZE3:%.*]] = freeze i32 [[X]] +; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[GW_FREEZE3]], 3 +; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[TMP0]], 100 +; CHECK-NEXT: [[TMP2:%.*]] = and i1 [[C]], [[TMP1]] +; CHECK-NEXT: [[TMP3:%.*]] = add i32 [[GW_FREEZE3]], 20 +; CHECK-NEXT: [[TMP4:%.*]] = icmp ult i32 [[TMP3]], 100 +; CHECK-NEXT: [[WIDE_CHK5:%.*]] = and i1 [[TMP2]], [[TMP4]] +; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK5]]) [ "deopt"(i64 1) ] +; CHECK-NEXT: store i32 0, i32* [[P:%.*]], align 4 +; CHECK-NEXT: br i1 [[C2]], label [[OK:%.*]], label [[OUT:%.*]] +; CHECK: ok: +; CHECK-NEXT: br label [[OUT]] +; CHECK: out: +; CHECK-NEXT: ret void +; +entry: + %x1 = add i32 %x, 10 + %c1 = icmp ult i32 %x1, 100 + %x2 = add i32 %x, 0 + %c2 = icmp ult i32 %x2, 200 + %x3 = add nuw nsw i32 %x, 3 + %c3 = icmp ult i32 %x3, 100 + %x4 = add nuw nsw i32 %x, 20 + %c4 = icmp ult i32 %x4, 100 + %x5 = add i32 %x, 15 + %c5 = icmp ult i32 %x5, 100 + %c = icmp ult i32 %y, 100 + call void(i1, ...) @llvm.experimental.guard(i1 %c) [ "deopt"(i64 1) ] + call void(i1, ...) @llvm.experimental.guard(i1 %c1) [ "deopt"(i64 1) ] + call void(i1, ...) @llvm.experimental.guard(i1 %c5) [ "deopt"(i64 5) ] + store i32 0, i32* %p + br i1 %c2, label %ok, label %out +ok: + call void(i1, ...) @llvm.experimental.guard(i1 %c4) [ "deopt"(i64 4) ] + call void(i1, ...) @llvm.experimental.guard(i1 %c3) [ "deopt"(i64 3) ] + br label %out +out: + ret void +} + +; The case checks that base does not need a freeze due to it is known not a poison. +define void @combine_range_checks_base_neednot_freeze(i32 %y, i32 noundef %x, i32* %p) { +; CHECK-LABEL: @combine_range_checks_base_neednot_freeze( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[X2:%.*]] = add i32 [[X:%.*]], 0 +; CHECK-NEXT: [[C2:%.*]] = icmp ult i32 [[X2]], 200 +; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[Y:%.*]], 100 +; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[X]], 3 +; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[TMP0]], 100 +; CHECK-NEXT: [[TMP2:%.*]] = and i1 [[C]], [[TMP1]] +; CHECK-NEXT: [[TMP3:%.*]] = add i32 [[X]], 20 +; CHECK-NEXT: [[TMP4:%.*]] = icmp ult i32 [[TMP3]], 100 +; CHECK-NEXT: [[WIDE_CHK3:%.*]] = and i1 [[TMP2]], [[TMP4]] +; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK3]]) [ "deopt"(i64 1) ] +; CHECK-NEXT: store i32 0, i32* [[P:%.*]], align 4 +; CHECK-NEXT: br i1 [[C2]], label [[OK:%.*]], label [[OUT:%.*]] +; CHECK: ok: +; CHECK-NEXT: br label [[OUT]] +; CHECK: out: +; CHECK-NEXT: ret void +; +entry: + %x1 = add i32 %x, 10 + %c1 = icmp ult i32 %x1, 100 + %x2 = add i32 %x, 0 + %c2 = icmp ult i32 %x2, 200 + %x3 = add nuw nsw i32 %x, 3 + %c3 = icmp ult i32 %x3, 100 + %x4 = add nuw nsw i32 %x, 20 + %c4 = icmp ult i32 %x4, 100 + %x5 = add i32 %x, 15 + %c5 = icmp ult i32 %x5, 100 + %c = icmp ult i32 %y, 100 + call void(i1, ...) @llvm.experimental.guard(i1 %c) [ "deopt"(i64 1) ] + call void(i1, ...) @llvm.experimental.guard(i1 %c1) [ "deopt"(i64 1) ] + call void(i1, ...) @llvm.experimental.guard(i1 %c5) [ "deopt"(i64 5) ] + store i32 0, i32* %p + br i1 %c2, label %ok, label %out +ok: + call void(i1, ...) @llvm.experimental.guard(i1 %c4) [ "deopt"(i64 4) ] + call void(i1, ...) @llvm.experimental.guard(i1 %c3) [ "deopt"(i64 3) ] + br label %out +out: + ret void +} + +; The case checks that length needs a freeze. +define void @combine_range_checks_length_need_freeze(i32 %y, i32 noundef %x, i32* %p) { +; CHECK-LABEL: @combine_range_checks_length_need_freeze( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[L:%.*]] = load i32, i32* [[P:%.*]], align 4, !range [[RNG0:![0-9]+]] +; CHECK-NEXT: [[X2:%.*]] = add i32 [[X:%.*]], 0 +; CHECK-NEXT: [[C2:%.*]] = icmp ult i32 [[X2]], 200 +; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[Y:%.*]], 100 +; CHECK-NEXT: [[GW_FREEZE3:%.*]] = freeze i32 [[L]] +; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[X]], 3 +; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[TMP0]], [[GW_FREEZE3]] +; CHECK-NEXT: [[TMP2:%.*]] = and i1 [[C]], [[TMP1]] +; CHECK-NEXT: [[TMP3:%.*]] = add i32 [[X]], 20 +; CHECK-NEXT: [[TMP4:%.*]] = icmp ult i32 [[TMP3]], [[GW_FREEZE3]] +; CHECK-NEXT: [[WIDE_CHK5:%.*]] = and i1 [[TMP2]], [[TMP4]] +; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK5]]) [ "deopt"(i64 1) ] +; CHECK-NEXT: store i32 0, i32* [[P]], align 4 +; CHECK-NEXT: br i1 [[C2]], label [[OK:%.*]], label [[OUT:%.*]] +; CHECK: ok: +; CHECK-NEXT: br label [[OUT]] +; CHECK: out: +; CHECK-NEXT: ret void +; +entry: + %L = load i32, i32* %p, !range !1 + %x1 = add i32 %x, 10 + %c1 = icmp ult i32 %x1, %L + %x2 = add i32 %x, 0 + %c2 = icmp ult i32 %x2, 200 + %x3 = add nuw nsw i32 %x, 3 + %c3 = icmp ult i32 %x3, %L + %x4 = add nuw nsw i32 %x, 20 + %c4 = icmp ult i32 %x4, %L + %x5 = add i32 %x, 15 + %c5 = icmp ult i32 %x5, %L + %c = icmp ult i32 %y, 100 + call void(i1, ...) @llvm.experimental.guard(i1 %c) [ "deopt"(i64 1) ] + call void(i1, ...) @llvm.experimental.guard(i1 %c1) [ "deopt"(i64 1) ] + call void(i1, ...) @llvm.experimental.guard(i1 %c5) [ "deopt"(i64 5) ] + store i32 0, i32* %p + br i1 %c2, label %ok, label %out +ok: + call void(i1, ...) @llvm.experimental.guard(i1 %c4) [ "deopt"(i64 4) ] + call void(i1, ...) @llvm.experimental.guard(i1 %c3) [ "deopt"(i64 3) ] + br label %out +out: + ret void +} + +; The case checks that base does not need a freeze due to it is known not a posion. +define void @combine_range_checks_length_neednot_freeze(i32 %y, i32 noundef %x, i32* %p) { +; CHECK-LABEL: @combine_range_checks_length_neednot_freeze( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[L:%.*]] = load i32, i32* [[P:%.*]], align 4, !range [[RNG0]], !noundef !1 +; CHECK-NEXT: [[X2:%.*]] = add i32 [[X:%.*]], 0 +; CHECK-NEXT: [[C2:%.*]] = icmp ult i32 [[X2]], 200 +; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[Y:%.*]], 100 +; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[X]], 3 +; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[TMP0]], [[L]] +; CHECK-NEXT: [[TMP2:%.*]] = and i1 [[C]], [[TMP1]] +; CHECK-NEXT: [[TMP3:%.*]] = add i32 [[X]], 20 +; CHECK-NEXT: [[TMP4:%.*]] = icmp ult i32 [[TMP3]], [[L]] +; CHECK-NEXT: [[WIDE_CHK3:%.*]] = and i1 [[TMP2]], [[TMP4]] +; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK3]]) [ "deopt"(i64 1) ] +; CHECK-NEXT: store i32 0, i32* [[P]], align 4 +; CHECK-NEXT: br i1 [[C2]], label [[OK:%.*]], label [[OUT:%.*]] +; CHECK: ok: +; CHECK-NEXT: br label [[OUT]] +; CHECK: out: +; CHECK-NEXT: ret void +; +entry: + %L = load i32, i32* %p, !range !1, !noundef !{} + %x1 = add i32 %x, 10 + %c1 = icmp ult i32 %x1, %L + %x2 = add i32 %x, 0 + %c2 = icmp ult i32 %x2, 200 + %x3 = add nuw nsw i32 %x, 3 + %c3 = icmp ult i32 %x3, %L + %x4 = add nuw nsw i32 %x, 20 + %c4 = icmp ult i32 %x4, %L + %x5 = add i32 %x, 15 + %c5 = icmp ult i32 %x5, %L + %c = icmp ult i32 %y, 100 + call void(i1, ...) @llvm.experimental.guard(i1 %c) [ "deopt"(i64 1) ] + call void(i1, ...) @llvm.experimental.guard(i1 %c1) [ "deopt"(i64 1) ] + call void(i1, ...) @llvm.experimental.guard(i1 %c5) [ "deopt"(i64 5) ] + store i32 0, i32* %p + br i1 %c2, label %ok, label %out +ok: + call void(i1, ...) @llvm.experimental.guard(i1 %c4) [ "deopt"(i64 4) ] + call void(i1, ...) @llvm.experimental.guard(i1 %c3) [ "deopt"(i64 3) ] + br label %out +out: + ret void +} + +!1 = !{i32 100, i32 200} Index: llvm/test/Transforms/GuardWidening/range-check-merging.ll =================================================================== --- llvm/test/Transforms/GuardWidening/range-check-merging.ll +++ llvm/test/Transforms/GuardWidening/range-check-merging.ll @@ -10,14 +10,23 @@ ; 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]] -; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[CHK0]], [[CHK1]] +; CHECK-NEXT: [[GW_FREEZE:%.*]] = freeze i1 [[CHK1]] +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[CHK0]], [[GW_FREEZE]] +; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[X]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[TMP0]], [[LENGTH]] +; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[X]], 2 +; CHECK-NEXT: [[TMP3:%.*]] = icmp ult i32 [[TMP2]], [[LENGTH]] +; CHECK-NEXT: [[WIDE_CHK1:%.*]] = and i1 [[TMP1]], [[TMP3]] +; CHECK-NEXT: [[TMP4:%.*]] = add i32 [[X]], 0 +; CHECK-NEXT: [[TMP5:%.*]] = icmp ult i32 [[TMP4]], [[LENGTH]] +; CHECK-NEXT: [[TMP6:%.*]] = add i32 [[X]], 3 +; CHECK-NEXT: [[TMP7:%.*]] = icmp ult i32 [[TMP6]], [[LENGTH]] +; CHECK-NEXT: [[WIDE_CHK2:%.*]] = and i1 [[TMP5]], [[TMP7]] +; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK2]]) [ "deopt"() ] ; CHECK-NEXT: [[X_INC2:%.*]] = add i32 [[X]], 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: [[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: @@ -46,14 +55,23 @@ ; 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]] -; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[CHK0]], [[CHK1]] +; CHECK-NEXT: [[GW_FREEZE:%.*]] = freeze i1 [[CHK1]] +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[CHK0]], [[GW_FREEZE]] +; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[X]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[TMP0]], [[LENGTH]] +; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[X]], 3 +; CHECK-NEXT: [[TMP3:%.*]] = icmp ult i32 [[TMP2]], [[LENGTH]] +; CHECK-NEXT: [[WIDE_CHK1:%.*]] = and i1 [[TMP1]], [[TMP3]] +; CHECK-NEXT: [[TMP4:%.*]] = add i32 [[X]], 0 +; CHECK-NEXT: [[TMP5:%.*]] = icmp ult i32 [[TMP4]], [[LENGTH]] +; CHECK-NEXT: [[TMP6:%.*]] = add i32 [[X]], 6 +; CHECK-NEXT: [[TMP7:%.*]] = icmp ult i32 [[TMP6]], [[LENGTH]] +; CHECK-NEXT: [[WIDE_CHK2:%.*]] = and i1 [[TMP5]], [[TMP7]] +; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK2]]) [ "deopt"() ] ; CHECK-NEXT: [[X_INC2:%.*]] = add i32 [[X_INC1]], 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_INC2]], 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: @@ -83,14 +101,23 @@ ; CHECK-NEXT: [[CHK0:%.*]] = icmp ult i32 [[X]], [[LENGTH]] ; CHECK-NEXT: [[X_INC1:%.*]] = or i32 [[X]], 1 ; CHECK-NEXT: [[CHK1:%.*]] = icmp ult i32 [[X_INC1]], [[LENGTH]] -; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[CHK0]], [[CHK1]] +; CHECK-NEXT: [[GW_FREEZE:%.*]] = freeze i1 [[CHK1]] +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[CHK0]], [[GW_FREEZE]] +; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[X]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[TMP0]], [[LENGTH]] +; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[X]], 2 +; CHECK-NEXT: [[TMP3:%.*]] = icmp ult i32 [[TMP2]], [[LENGTH]] +; CHECK-NEXT: [[WIDE_CHK1:%.*]] = and i1 [[TMP1]], [[TMP3]] +; CHECK-NEXT: [[TMP4:%.*]] = add i32 [[X]], 0 +; CHECK-NEXT: [[TMP5:%.*]] = icmp ult i32 [[TMP4]], [[LENGTH]] +; CHECK-NEXT: [[TMP6:%.*]] = add i32 [[X]], 3 +; CHECK-NEXT: [[TMP7:%.*]] = icmp ult i32 [[TMP6]], [[LENGTH]] +; CHECK-NEXT: [[WIDE_CHK2:%.*]] = and i1 [[TMP5]], [[TMP7]] +; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK2]]) [ "deopt"() ] ; 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: [[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: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK2]]) [ "deopt"() ] ; CHECK-NEXT: ret void ; entry: @@ -121,14 +148,23 @@ ; 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]] -; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[CHK0]], [[CHK1]] +; CHECK-NEXT: [[GW_FREEZE:%.*]] = freeze i1 [[CHK1]] +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[CHK0]], [[GW_FREEZE]] +; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[X]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[TMP0]], [[LENGTH]] +; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[X]], 3 +; CHECK-NEXT: [[TMP3:%.*]] = icmp ult i32 [[TMP2]], [[LENGTH]] +; CHECK-NEXT: [[WIDE_CHK1:%.*]] = and i1 [[TMP1]], [[TMP3]] +; CHECK-NEXT: [[TMP4:%.*]] = add i32 [[X]], 0 +; CHECK-NEXT: [[TMP5:%.*]] = icmp ult i32 [[TMP4]], [[LENGTH]] +; CHECK-NEXT: [[TMP6:%.*]] = add i32 [[X]], 6 +; CHECK-NEXT: [[TMP7:%.*]] = icmp ult i32 [[TMP6]], [[LENGTH]] +; CHECK-NEXT: [[WIDE_CHK2:%.*]] = and i1 [[TMP5]], [[TMP7]] +; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK2]]) [ "deopt"() ] ; CHECK-NEXT: [[X_INC2:%.*]] = or i32 [[X_INC1]], 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_INC2]], 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: @@ -158,14 +194,23 @@ ; CHECK-NEXT: [[CHK0:%.*]] = icmp ult i32 [[X:%.*]], [[LENGTH]] ; CHECK-NEXT: [[X_INC1:%.*]] = add i32 [[X]], -1024 ; CHECK-NEXT: [[CHK1:%.*]] = icmp ult i32 [[X_INC1]], [[LENGTH]] -; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[CHK0]], [[CHK1]] +; CHECK-NEXT: [[GW_FREEZE:%.*]] = freeze i1 [[CHK1]] +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[CHK0]], [[GW_FREEZE]] +; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[X]], -1024 +; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[TMP0]], [[LENGTH]] +; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[X]], 2 +; CHECK-NEXT: [[TMP3:%.*]] = icmp ult i32 [[TMP2]], [[LENGTH]] +; CHECK-NEXT: [[WIDE_CHK1:%.*]] = and i1 [[TMP1]], [[TMP3]] +; CHECK-NEXT: [[TMP4:%.*]] = add i32 [[X]], -1024 +; CHECK-NEXT: [[TMP5:%.*]] = icmp ult i32 [[TMP4]], [[LENGTH]] +; CHECK-NEXT: [[TMP6:%.*]] = add i32 [[X]], 3 +; CHECK-NEXT: [[TMP7:%.*]] = icmp ult i32 [[TMP6]], [[LENGTH]] +; CHECK-NEXT: [[WIDE_CHK2:%.*]] = and i1 [[TMP5]], [[TMP7]] +; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK2]]) [ "deopt"() ] ; CHECK-NEXT: [[X_INC2:%.*]] = add i32 [[X]], 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: [[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"() ] ; CHECK-NEXT: ret void ; @@ -196,12 +241,21 @@ ; 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]] -; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[CHK0]], [[CHK1]] +; CHECK-NEXT: [[GW_FREEZE:%.*]] = freeze i1 [[CHK1]] +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[CHK0]], [[GW_FREEZE]] +; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[X]], -199 +; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[TMP0]], [[LENGTH]] +; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[X]], 1 +; CHECK-NEXT: [[TMP3:%.*]] = icmp ult i32 [[TMP2]], [[LENGTH]] +; CHECK-NEXT: [[WIDE_CHK1:%.*]] = and i1 [[TMP1]], [[TMP3]] +; CHECK-NEXT: [[TMP4:%.*]] = add i32 [[X]], -199 +; CHECK-NEXT: [[TMP5:%.*]] = icmp ult i32 [[TMP4]], [[LENGTH]] +; CHECK-NEXT: [[TMP6:%.*]] = add i32 [[X]], 1 +; CHECK-NEXT: [[TMP7:%.*]] = icmp ult i32 [[TMP6]], [[LENGTH]] +; CHECK-NEXT: [[WIDE_CHK2:%.*]] = and i1 [[TMP5]], [[TMP7]] +; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK2]]) [ "deopt"() ] ; CHECK-NEXT: [[X_INC2:%.*]] = add i32 [[X_INC1]], -200 ; CHECK-NEXT: [[CHK2:%.*]] = icmp ult i32 [[X_INC2]], [[LENGTH]] -; CHECK-NEXT: [[WIDE_CHK1:%.*]] = and i1 [[CHK1]], [[CHK2]] -; CHECK-NEXT: [[WIDE_CHK2:%.*]] = and i1 [[CHK1]], [[CHK2]] -; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK2]]) [ "deopt"() ] ; CHECK-NEXT: [[X_INC3:%.*]] = add i32 [[X_INC2]], 3 ; CHECK-NEXT: [[CHK3:%.*]] = icmp ult i32 [[X_INC3]], [[LENGTH]] ; CHECK-NEXT: ret void @@ -244,14 +298,17 @@ ; CHECK-NEXT: [[CHK0:%.*]] = icmp ult i32 [[X:%.*]], [[LENGTH]] ; CHECK-NEXT: [[X_INC1:%.*]] = add i32 [[X]], -2147483647 ; CHECK-NEXT: [[CHK1:%.*]] = icmp ult i32 [[X_INC1]], [[LENGTH]] -; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[CHK0]], [[CHK1]] +; CHECK-NEXT: [[GW_FREEZE:%.*]] = freeze i1 [[CHK1]] +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[CHK0]], [[GW_FREEZE]] ; CHECK-NEXT: [[X_INC2:%.*]] = add i32 [[X]], 2 ; CHECK-NEXT: [[CHK2:%.*]] = icmp ult i32 [[X_INC2]], [[LENGTH]] -; CHECK-NEXT: [[WIDE_CHK1:%.*]] = and i1 [[WIDE_CHK]], [[CHK2]] +; CHECK-NEXT: [[GW_FREEZE1:%.*]] = freeze i1 [[CHK2]] +; CHECK-NEXT: [[WIDE_CHK2:%.*]] = and i1 [[WIDE_CHK]], [[GW_FREEZE1]] ; CHECK-NEXT: [[X_INC3:%.*]] = add i32 [[X]], 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: [[GW_FREEZE3:%.*]] = freeze i1 [[CHK3]] +; CHECK-NEXT: [[WIDE_CHK4:%.*]] = and i1 [[WIDE_CHK2]], [[GW_FREEZE3]] +; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK4]]) [ "deopt"() ] ; CHECK-NEXT: ret void ; entry: @@ -286,21 +343,38 @@ ; 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: [[GW_FREEZE:%.*]] = freeze i1 [[CHK1]] +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[CHK0]], [[GW_FREEZE]] +; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[X]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[TMP0]], [[LENGTH_A]] +; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[X]], 2 +; CHECK-NEXT: [[TMP3:%.*]] = icmp ult i32 [[TMP2]], [[LENGTH_A]] +; CHECK-NEXT: [[TMP4:%.*]] = and i1 [[TMP1]], [[TMP3]] +; CHECK-NEXT: [[TMP5:%.*]] = add i32 [[X]], 0 +; CHECK-NEXT: [[TMP6:%.*]] = icmp ult i32 [[TMP5]], [[LENGTH_B]] +; CHECK-NEXT: [[TMP7:%.*]] = and i1 [[TMP4]], [[TMP6]] +; CHECK-NEXT: [[TMP8:%.*]] = add i32 [[X]], 2 +; CHECK-NEXT: [[TMP9:%.*]] = icmp ult i32 [[TMP8]], [[LENGTH_B]] +; CHECK-NEXT: [[WIDE_CHK1:%.*]] = and i1 [[TMP7]], [[TMP9]] +; CHECK-NEXT: [[TMP10:%.*]] = add i32 [[X]], 0 +; CHECK-NEXT: [[TMP11:%.*]] = icmp ult i32 [[TMP10]], [[LENGTH_A]] +; CHECK-NEXT: [[TMP12:%.*]] = add i32 [[X]], 3 +; CHECK-NEXT: [[TMP13:%.*]] = icmp ult i32 [[TMP12]], [[LENGTH_A]] +; CHECK-NEXT: [[TMP14:%.*]] = and i1 [[TMP11]], [[TMP13]] +; CHECK-NEXT: [[TMP15:%.*]] = add i32 [[X]], 0 +; CHECK-NEXT: [[TMP16:%.*]] = icmp ult i32 [[TMP15]], [[LENGTH_B]] +; CHECK-NEXT: [[TMP17:%.*]] = and i1 [[TMP14]], [[TMP16]] +; CHECK-NEXT: [[TMP18:%.*]] = add i32 [[X]], 3 +; CHECK-NEXT: [[TMP19:%.*]] = icmp ult i32 [[TMP18]], [[LENGTH_B]] +; CHECK-NEXT: [[WIDE_CHK2:%.*]] = and i1 [[TMP17]], [[TMP19]] +; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK2]]) [ "deopt"() ] ; CHECK-NEXT: [[X_INC2:%.*]] = add i32 [[X]], 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: [[CHK2:%.*]] = and i1 [[CHK2_A]], [[CHK2_B]] ; CHECK-NEXT: [[X_INC3:%.*]] = add i32 [[X]], 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]] ; CHECK-NEXT: [[CHK3_A:%.*]] = icmp ult i32 [[X_INC3]], [[LENGTH_A]] -; CHECK-NEXT: [[WIDE_CHK2:%.*]] = and i1 [[CHK3_A]], [[TMP3]] -; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK2]]) [ "deopt"() ] -; CHECK-NEXT: [[CHK2:%.*]] = and i1 [[CHK2_A]], [[CHK2_B]] +; CHECK-NEXT: [[CHK3_B:%.*]] = icmp ult i32 [[X_INC3]], [[LENGTH_B]] ; CHECK-NEXT: [[CHK3:%.*]] = and i1 [[CHK3_A]], [[CHK3_B]] ; CHECK-NEXT: ret void ; @@ -340,9 +414,10 @@ ; CHECK-NEXT: entry: ; CHECK-NEXT: [[LENGTH:%.*]] = load i32, i32* [[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_INC1:%.*]] = add nuw nsw i32 [[X]], 1 ; CHECK-NEXT: [[CHK1:%.*]] = icmp ult i32 [[X_INC1]], [[LENGTH]] -; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[CHK0]], [[CHK1]] +; CHECK-NEXT: [[GW_FREEZE:%.*]] = freeze i1 [[CHK1]] +; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[CHK0]], [[GW_FREEZE]] ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ] ; CHECK-NEXT: ret void ;