diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp index 2a957737697c3..de2502b56d91c 100644 --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -267,267 +267,6 @@ struct ValueEqualityComparisonCase { bool operator==(BasicBlock *RHSDest) const { return Dest == RHSDest; } }; -class SimplifyCFGOpt { - const TargetTransformInfo &TTI; - DomTreeUpdater *DTU; - const DataLayout &DL; - ArrayRef LoopHeaders; - const SimplifyCFGOptions &Options; - bool Resimplify; - - Value *isValueEqualityComparison(Instruction *TI); - BasicBlock *getValueEqualityComparisonCases( - Instruction *TI, std::vector &Cases); - bool simplifyEqualityComparisonWithOnlyPredecessor(Instruction *TI, - BasicBlock *Pred, - IRBuilder<> &Builder); - bool performValueComparisonIntoPredecessorFolding(Instruction *TI, Value *&CV, - Instruction *PTI, - IRBuilder<> &Builder); - bool foldValueComparisonIntoPredecessors(Instruction *TI, - IRBuilder<> &Builder); - - bool simplifyResume(ResumeInst *RI, IRBuilder<> &Builder); - bool simplifySingleResume(ResumeInst *RI); - bool simplifyCommonResume(ResumeInst *RI); - bool simplifyCleanupReturn(CleanupReturnInst *RI); - bool simplifyUnreachable(UnreachableInst *UI); - bool simplifySwitch(SwitchInst *SI, IRBuilder<> &Builder); - bool simplifyDuplicateSwitchArms(SwitchInst *SI, DomTreeUpdater *DTU); - bool simplifyIndirectBr(IndirectBrInst *IBI); - bool simplifyBranch(BranchInst *Branch, IRBuilder<> &Builder); - bool simplifyUncondBranch(BranchInst *BI, IRBuilder<> &Builder); - bool simplifyCondBranch(BranchInst *BI, IRBuilder<> &Builder); - bool foldCondBranchOnValueKnownInPredecessor(BranchInst *BI); - - bool tryToSimplifyUncondBranchWithICmpInIt(ICmpInst *ICI, - IRBuilder<> &Builder); - bool tryToSimplifyUncondBranchWithICmpSelectInIt(ICmpInst *ICI, - SelectInst *Select, - IRBuilder<> &Builder); - bool hoistCommonCodeFromSuccessors(Instruction *TI, bool AllInstsEqOnly); - bool hoistSuccIdenticalTerminatorToSwitchOrIf( - Instruction *TI, Instruction *I1, - SmallVectorImpl &OtherSuccTIs, - ArrayRef UniqueSuccessors); - bool speculativelyExecuteBB(BranchInst *BI, BasicBlock *ThenBB); - bool simplifyTerminatorOnSelect(Instruction *OldTerm, Value *Cond, - BasicBlock *TrueBB, BasicBlock *FalseBB, - uint32_t TrueWeight, uint32_t FalseWeight); - bool simplifyBranchOnICmpChain(BranchInst *BI, IRBuilder<> &Builder, - const DataLayout &DL); - bool simplifySwitchOnSelect(SwitchInst *SI, SelectInst *Select); - bool simplifyIndirectBrOnSelect(IndirectBrInst *IBI, SelectInst *SI); - bool turnSwitchRangeIntoICmp(SwitchInst *SI, IRBuilder<> &Builder); - -public: - SimplifyCFGOpt(const TargetTransformInfo &TTI, DomTreeUpdater *DTU, - const DataLayout &DL, ArrayRef LoopHeaders, - const SimplifyCFGOptions &Opts) - : TTI(TTI), DTU(DTU), DL(DL), LoopHeaders(LoopHeaders), Options(Opts) { - assert((!DTU || !DTU->hasPostDomTree()) && - "SimplifyCFG is not yet capable of maintaining validity of a " - "PostDomTree, so don't ask for it."); - } - - bool simplifyOnce(BasicBlock *BB); - bool run(BasicBlock *BB); - - // Helper to set Resimplify and return change indication. - bool requestResimplify() { - Resimplify = true; - return true; - } -}; - -// we synthesize a || b as select a, true, b -// we synthesize a && b as select a, b, false -// this function determines if SI is playing one of those roles. -[[maybe_unused]] bool -isSelectInRoleOfConjunctionOrDisjunction(const SelectInst *SI) { - return ((isa(SI->getTrueValue()) && - (dyn_cast(SI->getTrueValue())->isOne())) || - (isa(SI->getFalseValue()) && - (dyn_cast(SI->getFalseValue())->isNullValue()))); -} - -} // end anonymous namespace - -/// Return true if all the PHI nodes in the basic block \p BB -/// receive compatible (identical) incoming values when coming from -/// all of the predecessor blocks that are specified in \p IncomingBlocks. -/// -/// Note that if the values aren't exactly identical, but \p EquivalenceSet -/// is provided, and *both* of the values are present in the set, -/// then they are considered equal. -static bool incomingValuesAreCompatible( - BasicBlock *BB, ArrayRef IncomingBlocks, - SmallPtrSetImpl *EquivalenceSet = nullptr) { - assert(IncomingBlocks.size() == 2 && - "Only for a pair of incoming blocks at the time!"); - - // FIXME: it is okay if one of the incoming values is an `undef` value, - // iff the other incoming value is guaranteed to be a non-poison value. - // FIXME: it is okay if one of the incoming values is a `poison` value. - return all_of(BB->phis(), [IncomingBlocks, EquivalenceSet](PHINode &PN) { - Value *IV0 = PN.getIncomingValueForBlock(IncomingBlocks[0]); - Value *IV1 = PN.getIncomingValueForBlock(IncomingBlocks[1]); - if (IV0 == IV1) - return true; - if (EquivalenceSet && EquivalenceSet->contains(IV0) && - EquivalenceSet->contains(IV1)) - return true; - return false; - }); -} - -/// Return true if it is safe to merge these two -/// terminator instructions together. -static bool -safeToMergeTerminators(Instruction *SI1, Instruction *SI2, - SmallSetVector *FailBlocks = nullptr) { - if (SI1 == SI2) - return false; // Can't merge with self! - - // It is not safe to merge these two switch instructions if they have a common - // successor, and if that successor has a PHI node, and if *that* PHI node has - // conflicting incoming values from the two switch blocks. - BasicBlock *SI1BB = SI1->getParent(); - BasicBlock *SI2BB = SI2->getParent(); - - SmallPtrSet SI1Succs(llvm::from_range, successors(SI1BB)); - bool Fail = false; - for (BasicBlock *Succ : successors(SI2BB)) { - if (!SI1Succs.count(Succ)) - continue; - if (incomingValuesAreCompatible(Succ, {SI1BB, SI2BB})) - continue; - Fail = true; - if (FailBlocks) - FailBlocks->insert(Succ); - else - break; - } - - return !Fail; -} - -/// Update PHI nodes in Succ to indicate that there will now be entries in it -/// from the 'NewPred' block. The values that will be flowing into the PHI nodes -/// will be the same as those coming in from ExistPred, an existing predecessor -/// of Succ. -static void addPredecessorToBlock(BasicBlock *Succ, BasicBlock *NewPred, - BasicBlock *ExistPred, - MemorySSAUpdater *MSSAU = nullptr) { - for (PHINode &PN : Succ->phis()) - PN.addIncoming(PN.getIncomingValueForBlock(ExistPred), NewPred); - if (MSSAU) - if (auto *MPhi = MSSAU->getMemorySSA()->getMemoryAccess(Succ)) - MPhi->addIncoming(MPhi->getIncomingValueForBlock(ExistPred), NewPred); -} - -/// Compute an abstract "cost" of speculating the given instruction, -/// which is assumed to be safe to speculate. TCC_Free means cheap, -/// TCC_Basic means less cheap, and TCC_Expensive means prohibitively -/// expensive. -static InstructionCost computeSpeculationCost(const User *I, - const TargetTransformInfo &TTI) { - return TTI.getInstructionCost(I, TargetTransformInfo::TCK_SizeAndLatency); -} - -/// If we have a merge point of an "if condition" as accepted above, -/// return true if the specified value dominates the block. We don't handle -/// the true generality of domination here, just a special case which works -/// well enough for us. -/// -/// If AggressiveInsts is non-null, and if V does not dominate BB, we check to -/// see if V (which must be an instruction) and its recursive operands -/// that do not dominate BB have a combined cost lower than Budget and -/// are non-trapping. If both are true, the instruction is inserted into the -/// set and true is returned. -/// -/// The cost for most non-trapping instructions is defined as 1 except for -/// Select whose cost is 2. -/// -/// After this function returns, Cost is increased by the cost of -/// V plus its non-dominating operands. If that cost is greater than -/// Budget, false is returned and Cost is undefined. -static bool dominatesMergePoint( - Value *V, BasicBlock *BB, Instruction *InsertPt, - SmallPtrSetImpl &AggressiveInsts, InstructionCost &Cost, - InstructionCost Budget, const TargetTransformInfo &TTI, AssumptionCache *AC, - SmallPtrSetImpl &ZeroCostInstructions, unsigned Depth = 0) { - // It is possible to hit a zero-cost cycle (phi/gep instructions for example), - // so limit the recursion depth. - // TODO: While this recursion limit does prevent pathological behavior, it - // would be better to track visited instructions to avoid cycles. - if (Depth == MaxSpeculationDepth) - return false; - - Instruction *I = dyn_cast(V); - if (!I) { - // Non-instructions dominate all instructions and can be executed - // unconditionally. - return true; - } - BasicBlock *PBB = I->getParent(); - - // We don't want to allow weird loops that might have the "if condition" in - // the bottom of this block. - if (PBB == BB) - return false; - - // If this instruction is defined in a block that contains an unconditional - // branch to BB, then it must be in the 'conditional' part of the "if - // statement". If not, it definitely dominates the region. - BranchInst *BI = dyn_cast(PBB->getTerminator()); - if (!BI || BI->isConditional() || BI->getSuccessor(0) != BB) - return true; - - // If we have seen this instruction before, don't count it again. - if (AggressiveInsts.count(I)) - return true; - - // Okay, it looks like the instruction IS in the "condition". Check to - // see if it's a cheap instruction to unconditionally compute, and if it - // only uses stuff defined outside of the condition. If so, hoist it out. - if (!isSafeToSpeculativelyExecute(I, InsertPt, AC)) - return false; - - // Overflow arithmetic instruction plus extract value are usually generated - // when a division is being replaced. But, in this case, the zero check may - // still be kept in the code. In that case it would be worth to hoist these - // two instruction out of the basic block. Let's treat this pattern as one - // single cheap instruction here! - WithOverflowInst *OverflowInst; - if (match(I, m_ExtractValue<1>(m_OneUse(m_WithOverflowInst(OverflowInst))))) { - ZeroCostInstructions.insert(OverflowInst); - Cost += 1; - } else if (!ZeroCostInstructions.contains(I)) - Cost += computeSpeculationCost(I, TTI); - - // Allow exactly one instruction to be speculated regardless of its cost - // (as long as it is safe to do so). - // This is intended to flatten the CFG even if the instruction is a division - // or other expensive operation. The speculation of an expensive instruction - // is expected to be undone in CodeGenPrepare if the speculation has not - // enabled further IR optimizations. - if (Cost > Budget && - (!SpeculateOneExpensiveInst || !AggressiveInsts.empty() || Depth > 0 || - !Cost.isValid())) - return false; - - // Okay, we can only really hoist these out if their operands do - // not take us over the cost threshold. - for (Use &Op : I->operands()) - if (!dominatesMergePoint(Op, BB, InsertPt, AggressiveInsts, Cost, Budget, - TTI, AC, ZeroCostInstructions, Depth + 1)) - return false; - // Okay, it's safe to do this! Remember this instruction. - AggressiveInsts.insert(I); - return true; -} - /// Extract ConstantInt from value, looking through IntToPtr /// and PointerNullValue. Return NULL if value is not a constant int. static ConstantInt *getConstantInt(Value *V, const DataLayout &DL) { @@ -564,8 +303,6 @@ static ConstantInt *getConstantInt(Value *V, const DataLayout &DL) { return nullptr; } -namespace { - /// Given a chain of or (||) or and (&&) comparison of a value against a /// constant, this will try to recover the information required for a switch /// structure. @@ -577,7 +314,7 @@ namespace { /// while for a chain of '&&' it will build the set elements that make the test /// fail. struct ConstantComparesGatherer { - const DataLayout &DL; + const DataLayout *DL; /// Value found for the switch comparison Value *CompValue = nullptr; @@ -599,7 +336,7 @@ struct ConstantComparesGatherer { bool MultipleMatches = false; /// Construct and compute the result for the comparison instruction Cond - ConstantComparesGatherer(Instruction *Cond, const DataLayout &DL) : DL(DL) { + ConstantComparesGatherer(Instruction *Cond, const DataLayout &DL) : DL(&DL) { gather(Cond); if (CompValue || !MultipleMatches) return; @@ -613,6 +350,8 @@ struct ConstantComparesGatherer { ConstantComparesGatherer(const ConstantComparesGatherer &) = delete; ConstantComparesGatherer & operator=(const ConstantComparesGatherer &) = delete; + ConstantComparesGatherer(ConstantComparesGatherer &&) = default; + ConstantComparesGatherer &operator=(ConstantComparesGatherer &&) = default; private: /// Try to set the current value used for the comparison, it succeeds only if @@ -654,7 +393,7 @@ struct ConstantComparesGatherer { ICmpInst *ICI; ConstantInt *C; if (!((ICI = dyn_cast(I)) && - (C = getConstantInt(I->getOperand(1), DL)))) { + (C = getConstantInt(I->getOperand(1), *DL)))) { return false; } @@ -748,101 +487,364 @@ struct ConstantComparesGatherer { if (!setValueOnce(ICI->getOperand(0))) return false; - UsedICmps++; - Vals.push_back(C); + UsedICmps++; + Vals.push_back(C); + return true; + } + + // If we have "x ult 3", for example, then we can add 0,1,2 to the set. + ConstantRange Span = + ConstantRange::makeExactICmpRegion(ICI->getPredicate(), C->getValue()); + + // Shift the range if the compare is fed by an add. This is the range + // compare idiom as emitted by instcombine. + Value *CandidateVal = I->getOperand(0); + if (match(I->getOperand(0), m_Add(m_Value(RHSVal), m_APInt(RHSC)))) { + Span = Span.subtract(*RHSC); + CandidateVal = RHSVal; + } + + // If this is an and/!= check, then we are looking to build the set of + // value that *don't* pass the and chain. I.e. to turn "x ugt 2" into + // x != 0 && x != 1. + if (!isEQ) + Span = Span.inverse(); + + // If there are a ton of values, we don't want to make a ginormous switch. + if (Span.isSizeLargerThan(8) || Span.isEmptySet()) { + return false; + } + + // If we already have a value for the switch, it has to match! + if (!setValueOnce(CandidateVal)) + return false; + + // Add all values from the range to the set + APInt Tmp = Span.getLower(); + do + Vals.push_back(ConstantInt::get(I->getContext(), Tmp)); + while (++Tmp != Span.getUpper()); + + UsedICmps++; + return true; + } + + /// Given a potentially 'or'd or 'and'd together collection of icmp + /// eq/ne/lt/gt instructions that compare a value against a constant, extract + /// the value being compared, and stick the list constants into the Vals + /// vector. + /// One "Extra" case is allowed to differ from the other. + void gather(Value *V) { + Value *Op0, *Op1; + if (match(V, m_LogicalOr(m_Value(Op0), m_Value(Op1)))) + IsEq = true; + else if (match(V, m_LogicalAnd(m_Value(Op0), m_Value(Op1)))) + IsEq = false; + else + return; + // Keep a stack (SmallVector for efficiency) for depth-first traversal + SmallVector DFT{Op0, Op1}; + SmallPtrSet Visited{V, Op0, Op1}; + + while (!DFT.empty()) { + V = DFT.pop_back_val(); + + if (Instruction *I = dyn_cast(V)) { + // If it is a || (or && depending on isEQ), process the operands. + if (IsEq ? match(I, m_LogicalOr(m_Value(Op0), m_Value(Op1))) + : match(I, m_LogicalAnd(m_Value(Op0), m_Value(Op1)))) { + if (Visited.insert(Op1).second) + DFT.push_back(Op1); + if (Visited.insert(Op0).second) + DFT.push_back(Op0); + + continue; + } + + // Try to match the current instruction + if (matchInstruction(I, IsEq)) + // Match succeed, continue the loop + continue; + } + + // One element of the sequence of || (or &&) could not be match as a + // comparison against the same value as the others. + // We allow only one "Extra" case to be checked before the switch + if (!Extra) { + Extra = V; + continue; + } + // Failed to parse a proper sequence, abort now + CompValue = nullptr; + break; + } + } +}; + +class SimplifyCFGOpt { + const TargetTransformInfo &TTI; + DomTreeUpdater *DTU; + const DataLayout &DL; + ArrayRef LoopHeaders; + const SimplifyCFGOptions &Options; + bool Resimplify; + + Value *isValueEqualityComparison(Instruction *TI); + BasicBlock *getValueEqualityComparisonCases( + Instruction *TI, std::vector &Cases); + bool simplifyEqualityComparisonWithOnlyPredecessor(Instruction *TI, + BasicBlock *Pred, + IRBuilder<> &Builder); + bool performValueComparisonIntoPredecessorFolding(Instruction *TI, Value *&CV, + Instruction *PTI, + IRBuilder<> &Builder); + bool foldValueComparisonIntoPredecessors(Instruction *TI, + IRBuilder<> &Builder); + + bool simplifyResume(ResumeInst *RI, IRBuilder<> &Builder); + bool simplifySingleResume(ResumeInst *RI); + bool simplifyCommonResume(ResumeInst *RI); + bool simplifyCleanupReturn(CleanupReturnInst *RI); + bool simplifyUnreachable(UnreachableInst *UI); + bool simplifySwitch(SwitchInst *SI, IRBuilder<> &Builder); + bool simplifyDuplicateSwitchArms(SwitchInst *SI, DomTreeUpdater *DTU); + bool simplifyIndirectBr(IndirectBrInst *IBI); + bool simplifyBranch(BranchInst *Branch, IRBuilder<> &Builder); + bool simplifyUncondBranch(BranchInst *BI, IRBuilder<> &Builder); + bool simplifyCondBranch(BranchInst *BI, IRBuilder<> &Builder); + bool foldCondBranchOnValueKnownInPredecessor(BranchInst *BI); + + bool tryToSimplifyUncondBranchWithICmpInIt(ICmpInst *ICI, + IRBuilder<> &Builder); + bool tryToSimplifyUncondBranchWithICmpSelectInIt(ICmpInst *ICI, + SelectInst *Select, + IRBuilder<> &Builder); + bool hoistCommonCodeFromSuccessors(Instruction *TI, bool AllInstsEqOnly); + bool hoistSuccIdenticalTerminatorToSwitchOrIf( + Instruction *TI, Instruction *I1, + SmallVectorImpl &OtherSuccTIs, + ArrayRef UniqueSuccessors); + bool speculativelyExecuteBB(BranchInst *BI, BasicBlock *ThenBB); + bool simplifyTerminatorOnSelect(Instruction *OldTerm, Value *Cond, + BasicBlock *TrueBB, BasicBlock *FalseBB, + uint32_t TrueWeight, uint32_t FalseWeight); + bool simplifyBranchOnICmpChain( + BranchInst *BI, IRBuilder<> &Builder, const DataLayout &DL, + std::optional ExistingConstantComparesGatherer = + std::nullopt); + bool simplifyRetOfIcmpChain(ReturnInst &RI, IRBuilder<> &Builder, + const DataLayout &DL); + bool simplifySwitchOnSelect(SwitchInst *SI, SelectInst *Select); + bool simplifyIndirectBrOnSelect(IndirectBrInst *IBI, SelectInst *SI); + bool turnSwitchRangeIntoICmp(SwitchInst *SI, IRBuilder<> &Builder); + +public: + SimplifyCFGOpt(const TargetTransformInfo &TTI, DomTreeUpdater *DTU, + const DataLayout &DL, ArrayRef LoopHeaders, + const SimplifyCFGOptions &Opts) + : TTI(TTI), DTU(DTU), DL(DL), LoopHeaders(LoopHeaders), Options(Opts) { + assert((!DTU || !DTU->hasPostDomTree()) && + "SimplifyCFG is not yet capable of maintaining validity of a " + "PostDomTree, so don't ask for it."); + } + + bool simplifyOnce(BasicBlock *BB); + bool run(BasicBlock *BB); + + // Helper to set Resimplify and return change indication. + bool requestResimplify() { + Resimplify = true; + return true; + } +}; + +// we synthesize a || b as select a, true, b +// we synthesize a && b as select a, b, false +// this function determines if SI is playing one of those roles. +[[maybe_unused]] bool +isSelectInRoleOfConjunctionOrDisjunction(const SelectInst *SI) { + return ((isa(SI->getTrueValue()) && + (dyn_cast(SI->getTrueValue())->isOne())) || + (isa(SI->getFalseValue()) && + (dyn_cast(SI->getFalseValue())->isNullValue()))); +} + +} // end anonymous namespace + +/// Return true if all the PHI nodes in the basic block \p BB +/// receive compatible (identical) incoming values when coming from +/// all of the predecessor blocks that are specified in \p IncomingBlocks. +/// +/// Note that if the values aren't exactly identical, but \p EquivalenceSet +/// is provided, and *both* of the values are present in the set, +/// then they are considered equal. +static bool incomingValuesAreCompatible( + BasicBlock *BB, ArrayRef IncomingBlocks, + SmallPtrSetImpl *EquivalenceSet = nullptr) { + assert(IncomingBlocks.size() == 2 && + "Only for a pair of incoming blocks at the time!"); + + // FIXME: it is okay if one of the incoming values is an `undef` value, + // iff the other incoming value is guaranteed to be a non-poison value. + // FIXME: it is okay if one of the incoming values is a `poison` value. + return all_of(BB->phis(), [IncomingBlocks, EquivalenceSet](PHINode &PN) { + Value *IV0 = PN.getIncomingValueForBlock(IncomingBlocks[0]); + Value *IV1 = PN.getIncomingValueForBlock(IncomingBlocks[1]); + if (IV0 == IV1) return true; - } + if (EquivalenceSet && EquivalenceSet->contains(IV0) && + EquivalenceSet->contains(IV1)) + return true; + return false; + }); +} - // If we have "x ult 3", for example, then we can add 0,1,2 to the set. - ConstantRange Span = - ConstantRange::makeExactICmpRegion(ICI->getPredicate(), C->getValue()); +/// Return true if it is safe to merge these two +/// terminator instructions together. +static bool +safeToMergeTerminators(Instruction *SI1, Instruction *SI2, + SmallSetVector *FailBlocks = nullptr) { + if (SI1 == SI2) + return false; // Can't merge with self! - // Shift the range if the compare is fed by an add. This is the range - // compare idiom as emitted by instcombine. - Value *CandidateVal = I->getOperand(0); - if (match(I->getOperand(0), m_Add(m_Value(RHSVal), m_APInt(RHSC)))) { - Span = Span.subtract(*RHSC); - CandidateVal = RHSVal; - } + // It is not safe to merge these two switch instructions if they have a common + // successor, and if that successor has a PHI node, and if *that* PHI node has + // conflicting incoming values from the two switch blocks. + BasicBlock *SI1BB = SI1->getParent(); + BasicBlock *SI2BB = SI2->getParent(); - // If this is an and/!= check, then we are looking to build the set of - // value that *don't* pass the and chain. I.e. to turn "x ugt 2" into - // x != 0 && x != 1. - if (!isEQ) - Span = Span.inverse(); + SmallPtrSet SI1Succs(llvm::from_range, successors(SI1BB)); + bool Fail = false; + for (BasicBlock *Succ : successors(SI2BB)) { + if (!SI1Succs.count(Succ)) + continue; + if (incomingValuesAreCompatible(Succ, {SI1BB, SI2BB})) + continue; + Fail = true; + if (FailBlocks) + FailBlocks->insert(Succ); + else + break; + } - // If there are a ton of values, we don't want to make a ginormous switch. - if (Span.isSizeLargerThan(8) || Span.isEmptySet()) { - return false; - } + return !Fail; +} - // If we already have a value for the switch, it has to match! - if (!setValueOnce(CandidateVal)) - return false; +/// Update PHI nodes in Succ to indicate that there will now be entries in it +/// from the 'NewPred' block. The values that will be flowing into the PHI nodes +/// will be the same as those coming in from ExistPred, an existing predecessor +/// of Succ. +static void addPredecessorToBlock(BasicBlock *Succ, BasicBlock *NewPred, + BasicBlock *ExistPred, + MemorySSAUpdater *MSSAU = nullptr) { + for (PHINode &PN : Succ->phis()) + PN.addIncoming(PN.getIncomingValueForBlock(ExistPred), NewPred); + if (MSSAU) + if (auto *MPhi = MSSAU->getMemorySSA()->getMemoryAccess(Succ)) + MPhi->addIncoming(MPhi->getIncomingValueForBlock(ExistPred), NewPred); +} - // Add all values from the range to the set - APInt Tmp = Span.getLower(); - do - Vals.push_back(ConstantInt::get(I->getContext(), Tmp)); - while (++Tmp != Span.getUpper()); +/// Compute an abstract "cost" of speculating the given instruction, +/// which is assumed to be safe to speculate. TCC_Free means cheap, +/// TCC_Basic means less cheap, and TCC_Expensive means prohibitively +/// expensive. +static InstructionCost computeSpeculationCost(const User *I, + const TargetTransformInfo &TTI) { + return TTI.getInstructionCost(I, TargetTransformInfo::TCK_SizeAndLatency); +} - UsedICmps++; +/// If we have a merge point of an "if condition" as accepted above, +/// return true if the specified value dominates the block. We don't handle +/// the true generality of domination here, just a special case which works +/// well enough for us. +/// +/// If AggressiveInsts is non-null, and if V does not dominate BB, we check to +/// see if V (which must be an instruction) and its recursive operands +/// that do not dominate BB have a combined cost lower than Budget and +/// are non-trapping. If both are true, the instruction is inserted into the +/// set and true is returned. +/// +/// The cost for most non-trapping instructions is defined as 1 except for +/// Select whose cost is 2. +/// +/// After this function returns, Cost is increased by the cost of +/// V plus its non-dominating operands. If that cost is greater than +/// Budget, false is returned and Cost is undefined. +static bool dominatesMergePoint( + Value *V, BasicBlock *BB, Instruction *InsertPt, + SmallPtrSetImpl &AggressiveInsts, InstructionCost &Cost, + InstructionCost Budget, const TargetTransformInfo &TTI, AssumptionCache *AC, + SmallPtrSetImpl &ZeroCostInstructions, unsigned Depth = 0) { + // It is possible to hit a zero-cost cycle (phi/gep instructions for example), + // so limit the recursion depth. + // TODO: While this recursion limit does prevent pathological behavior, it + // would be better to track visited instructions to avoid cycles. + if (Depth == MaxSpeculationDepth) + return false; + + Instruction *I = dyn_cast(V); + if (!I) { + // Non-instructions dominate all instructions and can be executed + // unconditionally. return true; } + BasicBlock *PBB = I->getParent(); - /// Given a potentially 'or'd or 'and'd together collection of icmp - /// eq/ne/lt/gt instructions that compare a value against a constant, extract - /// the value being compared, and stick the list constants into the Vals - /// vector. - /// One "Extra" case is allowed to differ from the other. - void gather(Value *V) { - Value *Op0, *Op1; - if (match(V, m_LogicalOr(m_Value(Op0), m_Value(Op1)))) - IsEq = true; - else if (match(V, m_LogicalAnd(m_Value(Op0), m_Value(Op1)))) - IsEq = false; - else - return; - // Keep a stack (SmallVector for efficiency) for depth-first traversal - SmallVector DFT{Op0, Op1}; - SmallPtrSet Visited{V, Op0, Op1}; + // We don't want to allow weird loops that might have the "if condition" in + // the bottom of this block. + if (PBB == BB) + return false; - while (!DFT.empty()) { - V = DFT.pop_back_val(); + // If this instruction is defined in a block that contains an unconditional + // branch to BB, then it must be in the 'conditional' part of the "if + // statement". If not, it definitely dominates the region. + BranchInst *BI = dyn_cast(PBB->getTerminator()); + if (!BI || BI->isConditional() || BI->getSuccessor(0) != BB) + return true; - if (Instruction *I = dyn_cast(V)) { - // If it is a || (or && depending on isEQ), process the operands. - if (IsEq ? match(I, m_LogicalOr(m_Value(Op0), m_Value(Op1))) - : match(I, m_LogicalAnd(m_Value(Op0), m_Value(Op1)))) { - if (Visited.insert(Op1).second) - DFT.push_back(Op1); - if (Visited.insert(Op0).second) - DFT.push_back(Op0); + // If we have seen this instruction before, don't count it again. + if (AggressiveInsts.count(I)) + return true; - continue; - } + // Okay, it looks like the instruction IS in the "condition". Check to + // see if it's a cheap instruction to unconditionally compute, and if it + // only uses stuff defined outside of the condition. If so, hoist it out. + if (!isSafeToSpeculativelyExecute(I, InsertPt, AC)) + return false; - // Try to match the current instruction - if (matchInstruction(I, IsEq)) - // Match succeed, continue the loop - continue; - } + // Overflow arithmetic instruction plus extract value are usually generated + // when a division is being replaced. But, in this case, the zero check may + // still be kept in the code. In that case it would be worth to hoist these + // two instruction out of the basic block. Let's treat this pattern as one + // single cheap instruction here! + WithOverflowInst *OverflowInst; + if (match(I, m_ExtractValue<1>(m_OneUse(m_WithOverflowInst(OverflowInst))))) { + ZeroCostInstructions.insert(OverflowInst); + Cost += 1; + } else if (!ZeroCostInstructions.contains(I)) + Cost += computeSpeculationCost(I, TTI); - // One element of the sequence of || (or &&) could not be match as a - // comparison against the same value as the others. - // We allow only one "Extra" case to be checked before the switch - if (!Extra) { - Extra = V; - continue; - } - // Failed to parse a proper sequence, abort now - CompValue = nullptr; - break; - } - } -}; + // Allow exactly one instruction to be speculated regardless of its cost + // (as long as it is safe to do so). + // This is intended to flatten the CFG even if the instruction is a division + // or other expensive operation. The speculation of an expensive instruction + // is expected to be undone in CodeGenPrepare if the speculation has not + // enabled further IR optimizations. + if (Cost > Budget && + (!SpeculateOneExpensiveInst || !AggressiveInsts.empty() || Depth > 0 || + !Cost.isValid())) + return false; -} // end anonymous namespace + // Okay, we can only really hoist these out if their operands do + // not take us over the cost threshold. + for (Use &Op : I->operands()) + if (!dominatesMergePoint(Op, BB, InsertPt, AggressiveInsts, Cost, Budget, + TTI, AC, ZeroCostInstructions, Depth + 1)) + return false; + // Okay, it's safe to do this! Remember this instruction. + AggressiveInsts.insert(I); + return true; +} static void eraseTerminatorAndDCECond(Instruction *TI, MemorySSAUpdater *MSSAU = nullptr) { @@ -5222,9 +5224,9 @@ bool SimplifyCFGOpt::tryToSimplifyUncondBranchWithICmpSelectInIt( /// The specified branch is a conditional branch. /// Check to see if it is branching on an or/and chain of icmp instructions, and /// fold it into a switch instruction if so. -bool SimplifyCFGOpt::simplifyBranchOnICmpChain(BranchInst *BI, - IRBuilder<> &Builder, - const DataLayout &DL) { +bool SimplifyCFGOpt::simplifyBranchOnICmpChain( + BranchInst *BI, IRBuilder<> &Builder, const DataLayout &DL, + std::optional ExistingConstantComparesGatherer) { Instruction *Cond = dyn_cast(BI->getCondition()); if (!Cond) return false; @@ -5234,14 +5236,15 @@ bool SimplifyCFGOpt::simplifyBranchOnICmpChain(BranchInst *BI, // 'setne's and'ed together, collect them. // Try to gather values from a chain of and/or to be turned into a switch - ConstantComparesGatherer ConstantCompare(Cond, DL); + if (!ExistingConstantComparesGatherer.has_value()) + ExistingConstantComparesGatherer.emplace(Cond, DL); // Unpack the result - SmallVectorImpl &Values = ConstantCompare.Vals; - Value *CompVal = ConstantCompare.CompValue; - unsigned UsedICmps = ConstantCompare.UsedICmps; - Value *ExtraCase = ConstantCompare.Extra; - bool TrueWhenEqual = ConstantCompare.IsEq; - + SmallVectorImpl &Values = + ExistingConstantComparesGatherer->Vals; + Value *CompVal = ExistingConstantComparesGatherer->CompValue; + unsigned UsedICmps = ExistingConstantComparesGatherer->UsedICmps; + Value *ExtraCase = ExistingConstantComparesGatherer->Extra; + bool TrueWhenEqual = ExistingConstantComparesGatherer->IsEq; // If we didn't have a multiply compared value, fail. if (!CompVal) return false; @@ -5387,6 +5390,116 @@ bool SimplifyCFGOpt::simplifyBranchOnICmpChain(BranchInst *BI, return true; } +/// Attempt to convert a return of an icmp chain (or a select on an icmp chain) +/// into a conditional branch structure that simplifyBranchOnICmpChain can +/// convert to a switch. +bool SimplifyCFGOpt::simplifyRetOfIcmpChain(ReturnInst &RI, + IRBuilder<> &Builder, + const DataLayout &DL) { + Value *const RetVal = RI.getReturnValue(); + SelectInst *const SI = RetVal ? dyn_cast(RetVal) : nullptr; + + if (SI) { + // select+return case + // TODO: handle more than one use of the select? + if (!SI->hasOneUse()) + return false; + } else { + // direct return case - return value must be i1 + if (!RetVal || !RetVal->getType()->isIntegerTy(1)) + return false; + } + + Instruction *const Cond = SI ? dyn_cast(SI->getCondition()) + : dyn_cast(RetVal); + Value *const TrueVal = + SI ? SI->getTrueValue() : ConstantInt::getTrue(RetVal->getType()); + Value *const FalseVal = + SI ? SI->getFalseValue() : ConstantInt::getFalse(RetVal->getType()); + + if (!Cond) + return false; + + // Check if this is an icmp chain worth transforming + ConstantComparesGatherer ConstantCompare(Cond, DL); + if (!ConstantCompare.CompValue || ConstantCompare.UsedICmps <= 1) + return false; + + // For just 2 cases, check if bitmask optimization is possible. + // Otherwise, we may enter recursion with foldSwitchToSelect. + { + SmallVector Values = ConstantCompare.Vals; + array_pod_sort(Values.begin(), Values.end(), constantIntSortPredicate); + Values.erase(llvm::unique(Values), Values.end()); + + if (Values.size() == 2) { + const APInt V0 = Values[0]->getValue(); + const APInt V1 = Values[1]->getValue(); + const APInt MinVal = V0.slt(V1) ? V0 : V1; + const APInt BitMask = (V0 - MinVal) | (V1 - MinVal); + // If BitMask has more than 1 bit set, no bitmask pattern is possible. + if (BitMask.popcount() != 1) + return false; + } + } + + BasicBlock *const BB = RI.getParent(); + + LLVM_DEBUG(dbgs() << "Converting " << (SI ? "'select+ret'" : "'ret i1'") + << " on icmp chain to branch. BB is:\n" + << *BB); + + // Create intermediate blocks that branch to a common return block with PHI + BasicBlock *const TrueBB = + BasicBlock::Create(BB->getContext(), "ret.true", BB->getParent()); + BasicBlock *const FalseBB = + BasicBlock::Create(BB->getContext(), "ret.false", BB->getParent()); + BasicBlock *const CommonBB = + BasicBlock::Create(BB->getContext(), "switch.return", BB->getParent()); + + // Create branches from true/false blocks to common block + BranchInst::Create(CommonBB, TrueBB); + BranchInst::Create(CommonBB, FalseBB); + + // Create PHI and return in the common block + IRBuilder CommonBuilder(CommonBB); + PHINode *const PHI = CommonBuilder.CreatePHI(TrueVal->getType(), 2); + PHI->addIncoming(TrueVal, TrueBB); + PHI->addIncoming(FalseVal, FalseBB); + CommonBuilder.CreateRet(PHI); + + // Replace the return with a conditional branch. + // If we have a select with branch weights, propagate them to the new branch. + Builder.SetInsertPoint(&RI); + BranchInst *const NewBI = Builder.CreateCondBr(Cond, TrueBB, FalseBB); + if (SI && !ProfcheckDisableMetadataFixes) { + SmallVector Weights; + if (extractBranchWeights(*SI, Weights)) + setBranchWeights(*NewBI, Weights, false); + } + RI.eraseFromParent(); + + // The select is now dead (if present) + if (SI) { + assert(SI->use_empty() && "Select should have no uses now"); + SI->eraseFromParent(); + } + + // Update dominator tree + if (DTU) { + SmallVector Updates; + Updates.emplace_back(DominatorTree::Insert, BB, TrueBB); + Updates.emplace_back(DominatorTree::Insert, BB, FalseBB); + Updates.emplace_back(DominatorTree::Insert, TrueBB, CommonBB); + Updates.emplace_back(DominatorTree::Insert, FalseBB, CommonBB); + DTU->applyUpdates(Updates); + } + + LLVM_DEBUG(dbgs() << " ** result is:\n" << *BB << '\n'); + return simplifyBranchOnICmpChain(NewBI, Builder, DL, + std::move(ConstantCompare)); +} + bool SimplifyCFGOpt::simplifyResume(ResumeInst *RI, IRBuilder<> &Builder) { if (isa(RI->getValue())) return simplifyCommonResume(RI); @@ -8931,6 +9044,11 @@ bool SimplifyCFGOpt::simplifyOnce(BasicBlock *BB) { case Instruction::Br: Changed |= simplifyBranch(cast(Terminator), Builder); break; + case Instruction::Ret: { + Changed |= + simplifyRetOfIcmpChain(*cast(Terminator), Builder, DL); + break; + } case Instruction::Resume: Changed |= simplifyResume(cast(Terminator), Builder); break; diff --git a/llvm/test/CodeGen/ARM/setcc-logic.ll b/llvm/test/CodeGen/ARM/setcc-logic.ll index cf482f39f2b5b..48cb81a896d87 100644 --- a/llvm/test/CodeGen/ARM/setcc-logic.ll +++ b/llvm/test/CodeGen/ARM/setcc-logic.ll @@ -3,11 +3,10 @@ define zeroext i1 @ne_neg1_and_ne_zero(i32 %x) nounwind { ; CHECK-LABEL: ne_neg1_and_ne_zero: -; CHECK: @ %bb.0: -; CHECK-NEXT: add r1, r0, #1 -; CHECK-NEXT: mov r0, #0 -; CHECK-NEXT: cmp r1, #1 -; CHECK-NEXT: movwhi r0, #1 +; CHECK: @ %bb.0: @ %switch.return +; CHECK-NEXT: add r0, r0, #1 +; CHECK-NEXT: bics r0, r0, #1 +; CHECK-NEXT: movwne r0, #1 ; CHECK-NEXT: bx lr %cmp1 = icmp ne i32 %x, -1 %cmp2 = icmp ne i32 %x, 0 @@ -20,12 +19,12 @@ define zeroext i1 @ne_neg1_and_ne_zero(i32 %x) nounwind { define zeroext i1 @and_eq(i32 %a, i32 %b, i32 %c, i32 %d) nounwind { ; CHECK-LABEL: and_eq: ; CHECK: @ %bb.0: -; CHECK: eor r2, r2, r3 -; CHECK: eor r0, r0, r1 -; CHECK: orr r0, r0, r2 -; CHECK: clz r0, r0 -; CHECK: lsr r0, r0, #5 -; CHECK: bx lr +; CHECK-NEXT: eor r2, r2, r3 +; CHECK-NEXT: eor r0, r0, r1 +; CHECK-NEXT: orr r0, r0, r2 +; CHECK-NEXT: clz r0, r0 +; CHECK-NEXT: lsr r0, r0, #5 +; CHECK-NEXT: bx lr %cmp1 = icmp eq i32 %a, %b %cmp2 = icmp eq i32 %c, %d %and = and i1 %cmp1, %cmp2 diff --git a/llvm/test/Transforms/PhaseOrdering/pr39116.ll b/llvm/test/Transforms/PhaseOrdering/pr39116.ll index 4dd46bc52d8e4..7a17b457ff14a 100644 --- a/llvm/test/Transforms/PhaseOrdering/pr39116.ll +++ b/llvm/test/Transforms/PhaseOrdering/pr39116.ll @@ -24,10 +24,11 @@ bb2: define zeroext i1 @switch_ob_one_two_cases2(i32 %arg) { ; CHECK-LABEL: @switch_ob_one_two_cases2( -; CHECK-NEXT: [[I:%.*]] = icmp eq i32 [[ARG:%.*]], 7 -; CHECK-NEXT: [[I1:%.*]] = icmp eq i32 [[ARG]], 11 -; CHECK-NEXT: [[I2:%.*]] = or i1 [[I]], [[I1]] -; CHECK-NEXT: ret i1 [[I2]] +; CHECK-NEXT: switch.return: +; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[ARG:%.*]], -7 +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[TMP0]], -5 +; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 0 +; CHECK-NEXT: ret i1 [[TMP2]] ; %i = icmp eq i32 %arg, 7 %i1 = icmp eq i32 %arg, 11 diff --git a/llvm/test/Transforms/SimplifyCFG/switch-from-icmp-chain.ll b/llvm/test/Transforms/SimplifyCFG/switch-from-icmp-chain.ll new file mode 100644 index 0000000000000..7d40b059789cf --- /dev/null +++ b/llvm/test/Transforms/SimplifyCFG/switch-from-icmp-chain.ll @@ -0,0 +1,153 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 +; RUN: opt -S -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 < %s | FileCheck %s + +; See https://github.com/llvm/llvm-project/issues/56087 + +; Test that branching on an icmp chain is converted to a switch +define i32 @branch_icmp_chain(i32 %c){ +; CHECK-LABEL: define i32 @branch_icmp_chain( +; CHECK-SAME: i32 [[C:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*]]: +; CHECK-NEXT: switch i32 [[C]], label %[[IF_ELSE:.*]] [ +; CHECK-NEXT: i32 119, label %[[CLEANUP:.*]] +; CHECK-NEXT: i32 111, label %[[CLEANUP]] +; CHECK-NEXT: i32 108, label %[[CLEANUP]] +; CHECK-NEXT: i32 104, label %[[CLEANUP]] +; CHECK-NEXT: i32 101, label %[[CLEANUP]] +; CHECK-NEXT: i32 0, label %[[CLEANUP]] +; CHECK-NEXT: ] +; CHECK: [[IF_ELSE]]: +; CHECK-NEXT: br label %[[CLEANUP]] +; CHECK: [[CLEANUP]]: +; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i32 [ -1, %[[IF_ELSE]] ], [ 1, %[[ENTRY]] ], [ 1, %[[ENTRY]] ], [ 1, %[[ENTRY]] ], [ 1, %[[ENTRY]] ], [ 1, %[[ENTRY]] ], [ 1, %[[ENTRY]] ] +; CHECK-NEXT: ret i32 [[RETVAL_0]] +; +entry: + %cmp1 = icmp eq i32 %c, 101 + %0 = and i32 %c, -5 + %1 = icmp eq i32 %0, 104 + %or521 = or i1 %1, %cmp1 + %cmp6 = icmp eq i32 %c, 111 + %or822 = or i1 %or521, %cmp6 + %cmp9 = icmp eq i32 %c, 119 + %or1123 = or i1 %or822, %cmp9 + %cmp12 = icmp eq i32 %c, 0 + %or1424 = or i1 %or1123, %cmp12 + br i1 %or1424, label %if.then, label %if.else + +if.then: ; preds = %entry + br label %cleanup + +if.else: ; preds = %entry + br label %cleanup + +cleanup: ; preds = %if.else, %if.then + %retval.0 = phi i32 [ 1, %if.then ], [ -1, %if.else ] + ret i32 %retval.0 +} + +; Test that returning an icmp chain directly is converted to a switch +define i1 @return_icmp_chain(i32 %c) { +; CHECK-LABEL: define i1 @return_icmp_chain( +; CHECK-SAME: i32 [[C:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*]]: +; CHECK-NEXT: switch i32 [[C]], label %[[RET_FALSE:.*]] [ +; CHECK-NEXT: i32 119, label %[[SWITCH_RETURN:.*]] +; CHECK-NEXT: i32 111, label %[[SWITCH_RETURN]] +; CHECK-NEXT: i32 108, label %[[SWITCH_RETURN]] +; CHECK-NEXT: i32 104, label %[[SWITCH_RETURN]] +; CHECK-NEXT: i32 101, label %[[SWITCH_RETURN]] +; CHECK-NEXT: i32 0, label %[[SWITCH_RETURN]] +; CHECK-NEXT: ] +; CHECK: [[RET_FALSE]]: +; CHECK-NEXT: br label %[[SWITCH_RETURN]] +; CHECK: [[SWITCH_RETURN]]: +; CHECK-NEXT: [[TMP0:%.*]] = phi i1 [ false, %[[RET_FALSE]] ], [ true, %[[ENTRY]] ], [ true, %[[ENTRY]] ], [ true, %[[ENTRY]] ], [ true, %[[ENTRY]] ], [ true, %[[ENTRY]] ], [ true, %[[ENTRY]] ] +; CHECK-NEXT: ret i1 [[TMP0]] +; +entry: + %cmp1 = icmp eq i32 %c, 101 + %0 = and i32 %c, -5 + %1 = icmp eq i32 %0, 104 + %or521 = or i1 %1, %cmp1 + %cmp6 = icmp eq i32 %c, 111 + %or822 = or i1 %or521, %cmp6 + %cmp9 = icmp eq i32 %c, 119 + %or1123 = or i1 %or822, %cmp9 + %cmp12 = icmp eq i32 %c, 0 + %or1424 = or i1 %or1123, %cmp12 + ret i1 %or1424 +} + +; Test that a select with icmp chain condition is converted to a switch +define i32 @select_icmp_chain(i32 %c) { +; CHECK-LABEL: define i32 @select_icmp_chain( +; CHECK-SAME: i32 [[C:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*]]: +; CHECK-NEXT: switch i32 [[C]], label %[[RET_FALSE:.*]] [ +; CHECK-NEXT: i32 119, label %[[SWITCH_RETURN:.*]] +; CHECK-NEXT: i32 111, label %[[SWITCH_RETURN]] +; CHECK-NEXT: i32 108, label %[[SWITCH_RETURN]] +; CHECK-NEXT: i32 104, label %[[SWITCH_RETURN]] +; CHECK-NEXT: i32 101, label %[[SWITCH_RETURN]] +; CHECK-NEXT: i32 0, label %[[SWITCH_RETURN]] +; CHECK-NEXT: ] +; CHECK: [[RET_FALSE]]: +; CHECK-NEXT: br label %[[SWITCH_RETURN]] +; CHECK: [[SWITCH_RETURN]]: +; CHECK-NEXT: [[TMP0:%.*]] = phi i32 [ -1, %[[RET_FALSE]] ], [ 1, %[[ENTRY]] ], [ 1, %[[ENTRY]] ], [ 1, %[[ENTRY]] ], [ 1, %[[ENTRY]] ], [ 1, %[[ENTRY]] ], [ 1, %[[ENTRY]] ] +; CHECK-NEXT: ret i32 [[TMP0]] +; +entry: + %cmp1 = icmp eq i32 %c, 101 + %0 = and i32 %c, -5 + %1 = icmp eq i32 %0, 104 + %or521 = or i1 %1, %cmp1 + %cmp6 = icmp eq i32 %c, 111 + %or822 = or i1 %or521, %cmp6 + %cmp9 = icmp eq i32 %c, 119 + %or1123 = or i1 %or822, %cmp9 + %cmp12 = icmp eq i32 %c, 0 + %or1424 = or i1 %or1123, %cmp12 + %cond = select i1 %or1424, i32 1, i32 -1 + ret i32 %cond +} + +; Test that branch weights on select are preserved through the transformation +define i32 @select_icmp_chain_with_prof(i32 %c) { +; CHECK-LABEL: define i32 @select_icmp_chain_with_prof( +; CHECK-SAME: i32 [[C:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*]]: +; CHECK-NEXT: switch i32 [[C]], label %[[RET_FALSE:.*]] [ +; CHECK-NEXT: i32 119, label %[[SWITCH_RETURN:.*]] +; CHECK-NEXT: i32 111, label %[[SWITCH_RETURN]] +; CHECK-NEXT: i32 108, label %[[SWITCH_RETURN]] +; CHECK-NEXT: i32 104, label %[[SWITCH_RETURN]] +; CHECK-NEXT: i32 101, label %[[SWITCH_RETURN]] +; CHECK-NEXT: i32 0, label %[[SWITCH_RETURN]] +; CHECK-NEXT: ], !prof [[PROF0:![0-9]+]] +; CHECK: [[RET_FALSE]]: +; CHECK-NEXT: br label %[[SWITCH_RETURN]] +; CHECK: [[SWITCH_RETURN]]: +; CHECK-NEXT: [[TMP0:%.*]] = phi i32 [ -1, %[[RET_FALSE]] ], [ 1, %[[ENTRY]] ], [ 1, %[[ENTRY]] ], [ 1, %[[ENTRY]] ], [ 1, %[[ENTRY]] ], [ 1, %[[ENTRY]] ], [ 1, %[[ENTRY]] ] +; CHECK-NEXT: ret i32 [[TMP0]] +; +entry: + %cmp1 = icmp eq i32 %c, 101 + %0 = and i32 %c, -5 + %1 = icmp eq i32 %0, 104 + %or521 = or i1 %1, %cmp1 + %cmp6 = icmp eq i32 %c, 111 + %or822 = or i1 %or521, %cmp6 + %cmp9 = icmp eq i32 %c, 119 + %or1123 = or i1 %or822, %cmp9 + %cmp12 = icmp eq i32 %c, 0 + %or1424 = or i1 %or1123, %cmp12 + %cond = select i1 %or1424, i32 1, i32 -1, !prof !0 + ret i32 %cond +} + +!0 = !{!"branch_weights", i32 600, i32 100} +;. +; CHECK: [[PROF0]] = !{!"branch_weights", i32 100, i32 100, i32 100, i32 100, i32 100, i32 100, i32 100} +;.