10b57cec5SDimitry Andric //===- GuardWidening.cpp - ---- Guard widening ----------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file implements the guard widening pass. The semantics of the 100b57cec5SDimitry Andric // @llvm.experimental.guard intrinsic lets LLVM transform it so that it fails 110b57cec5SDimitry Andric // more often that it did before the transform. This optimization is called 120b57cec5SDimitry Andric // "widening" and can be used hoist and common runtime checks in situations like 130b57cec5SDimitry Andric // these: 140b57cec5SDimitry Andric // 150b57cec5SDimitry Andric // %cmp0 = 7 u< Length 160b57cec5SDimitry Andric // call @llvm.experimental.guard(i1 %cmp0) [ "deopt"(...) ] 170b57cec5SDimitry Andric // call @unknown_side_effects() 180b57cec5SDimitry Andric // %cmp1 = 9 u< Length 190b57cec5SDimitry Andric // call @llvm.experimental.guard(i1 %cmp1) [ "deopt"(...) ] 200b57cec5SDimitry Andric // ... 210b57cec5SDimitry Andric // 220b57cec5SDimitry Andric // => 230b57cec5SDimitry Andric // 240b57cec5SDimitry Andric // %cmp0 = 9 u< Length 250b57cec5SDimitry Andric // call @llvm.experimental.guard(i1 %cmp0) [ "deopt"(...) ] 260b57cec5SDimitry Andric // call @unknown_side_effects() 270b57cec5SDimitry Andric // ... 280b57cec5SDimitry Andric // 290b57cec5SDimitry Andric // If %cmp0 is false, @llvm.experimental.guard will "deoptimize" back to a 300b57cec5SDimitry Andric // generic implementation of the same function, which will have the correct 310b57cec5SDimitry Andric // semantics from that point onward. It is always _legal_ to deoptimize (so 320b57cec5SDimitry Andric // replacing %cmp0 with false is "correct"), though it may not always be 330b57cec5SDimitry Andric // profitable to do so. 340b57cec5SDimitry Andric // 350b57cec5SDimitry Andric // NB! This pass is a work in progress. It hasn't been tuned to be "production 360b57cec5SDimitry Andric // ready" yet. It is known to have quadriatic running time and will not scale 370b57cec5SDimitry Andric // to large numbers of guards 380b57cec5SDimitry Andric // 390b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric #include "llvm/Transforms/Scalar/GuardWidening.h" 420b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h" 430b57cec5SDimitry Andric #include "llvm/ADT/DepthFirstIterator.h" 440b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h" 45bdd1243dSDimitry Andric #include "llvm/Analysis/AssumptionCache.h" 460b57cec5SDimitry Andric #include "llvm/Analysis/GuardUtils.h" 470b57cec5SDimitry Andric #include "llvm/Analysis/LoopInfo.h" 48349cc55cSDimitry Andric #include "llvm/Analysis/MemorySSAUpdater.h" 490b57cec5SDimitry Andric #include "llvm/Analysis/PostDominators.h" 500b57cec5SDimitry Andric #include "llvm/Analysis/ValueTracking.h" 510b57cec5SDimitry Andric #include "llvm/IR/ConstantRange.h" 520b57cec5SDimitry Andric #include "llvm/IR/Dominators.h" 535f757f3fSDimitry Andric #include "llvm/IR/IRBuilder.h" 540b57cec5SDimitry Andric #include "llvm/IR/IntrinsicInst.h" 55*0fca6ea1SDimitry Andric #include "llvm/IR/Module.h" 560b57cec5SDimitry Andric #include "llvm/IR/PatternMatch.h" 57480093f4SDimitry Andric #include "llvm/Support/CommandLine.h" 580b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 590b57cec5SDimitry Andric #include "llvm/Support/KnownBits.h" 600b57cec5SDimitry Andric #include "llvm/Transforms/Scalar.h" 61480093f4SDimitry Andric #include "llvm/Transforms/Utils/GuardUtils.h" 620b57cec5SDimitry Andric #include "llvm/Transforms/Utils/LoopUtils.h" 63480093f4SDimitry Andric #include <functional> 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric using namespace llvm; 660b57cec5SDimitry Andric 670b57cec5SDimitry Andric #define DEBUG_TYPE "guard-widening" 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric STATISTIC(GuardsEliminated, "Number of eliminated guards"); 700b57cec5SDimitry Andric STATISTIC(CondBranchEliminated, "Number of eliminated conditional branches"); 7106c3fb27SDimitry Andric STATISTIC(FreezeAdded, "Number of freeze instruction introduced"); 720b57cec5SDimitry Andric 730b57cec5SDimitry Andric static cl::opt<bool> 740b57cec5SDimitry Andric WidenBranchGuards("guard-widening-widen-branch-guards", cl::Hidden, 750b57cec5SDimitry Andric cl::desc("Whether or not we should widen guards " 760b57cec5SDimitry Andric "expressed as branches by widenable conditions"), 770b57cec5SDimitry Andric cl::init(true)); 780b57cec5SDimitry Andric 790b57cec5SDimitry Andric namespace { 800b57cec5SDimitry Andric 810b57cec5SDimitry Andric // Get the condition of \p I. It can either be a guard or a conditional branch. 820b57cec5SDimitry Andric static Value *getCondition(Instruction *I) { 830b57cec5SDimitry Andric if (IntrinsicInst *GI = dyn_cast<IntrinsicInst>(I)) { 840b57cec5SDimitry Andric assert(GI->getIntrinsicID() == Intrinsic::experimental_guard && 850b57cec5SDimitry Andric "Bad guard intrinsic?"); 860b57cec5SDimitry Andric return GI->getArgOperand(0); 870b57cec5SDimitry Andric } 88480093f4SDimitry Andric Value *Cond, *WC; 89480093f4SDimitry Andric BasicBlock *IfTrueBB, *IfFalseBB; 90480093f4SDimitry Andric if (parseWidenableBranch(I, Cond, WC, IfTrueBB, IfFalseBB)) 91480093f4SDimitry Andric return Cond; 92480093f4SDimitry Andric 930b57cec5SDimitry Andric return cast<BranchInst>(I)->getCondition(); 940b57cec5SDimitry Andric } 950b57cec5SDimitry Andric 960b57cec5SDimitry Andric // Set the condition for \p I to \p NewCond. \p I can either be a guard or a 970b57cec5SDimitry Andric // conditional branch. 980b57cec5SDimitry Andric static void setCondition(Instruction *I, Value *NewCond) { 990b57cec5SDimitry Andric if (IntrinsicInst *GI = dyn_cast<IntrinsicInst>(I)) { 1000b57cec5SDimitry Andric assert(GI->getIntrinsicID() == Intrinsic::experimental_guard && 1010b57cec5SDimitry Andric "Bad guard intrinsic?"); 1020b57cec5SDimitry Andric GI->setArgOperand(0, NewCond); 1030b57cec5SDimitry Andric return; 1040b57cec5SDimitry Andric } 1050b57cec5SDimitry Andric cast<BranchInst>(I)->setCondition(NewCond); 1060b57cec5SDimitry Andric } 1070b57cec5SDimitry Andric 1080b57cec5SDimitry Andric // Eliminates the guard instruction properly. 109349cc55cSDimitry Andric static void eliminateGuard(Instruction *GuardInst, MemorySSAUpdater *MSSAU) { 1100b57cec5SDimitry Andric GuardInst->eraseFromParent(); 111349cc55cSDimitry Andric if (MSSAU) 112349cc55cSDimitry Andric MSSAU->removeMemoryAccess(GuardInst); 1130b57cec5SDimitry Andric ++GuardsEliminated; 1140b57cec5SDimitry Andric } 1150b57cec5SDimitry Andric 11606c3fb27SDimitry Andric /// Find a point at which the widened condition of \p Guard should be inserted. 11706c3fb27SDimitry Andric /// When it is represented as intrinsic call, we can do it right before the call 11806c3fb27SDimitry Andric /// instruction. However, when we are dealing with widenable branch, we must 11906c3fb27SDimitry Andric /// account for the following situation: widening should not turn a 12006c3fb27SDimitry Andric /// loop-invariant condition into a loop-variant. It means that if 12106c3fb27SDimitry Andric /// widenable.condition() call is invariant (w.r.t. any loop), the new wide 12206c3fb27SDimitry Andric /// condition should stay invariant. Otherwise there can be a miscompile, like 12306c3fb27SDimitry Andric /// the one described at https://github.com/llvm/llvm-project/issues/60234. The 12406c3fb27SDimitry Andric /// safest way to do it is to expand the new condition at WC's block. 125*0fca6ea1SDimitry Andric static std::optional<BasicBlock::iterator> 126*0fca6ea1SDimitry Andric findInsertionPointForWideCondition(Instruction *WCOrGuard) { 1275f757f3fSDimitry Andric if (isGuard(WCOrGuard)) 128*0fca6ea1SDimitry Andric return WCOrGuard->getIterator(); 1295f757f3fSDimitry Andric if (auto WC = extractWidenableCondition(WCOrGuard)) 130*0fca6ea1SDimitry Andric return cast<Instruction>(WC)->getIterator(); 131*0fca6ea1SDimitry Andric return std::nullopt; 13206c3fb27SDimitry Andric } 13306c3fb27SDimitry Andric 1340b57cec5SDimitry Andric class GuardWideningImpl { 1350b57cec5SDimitry Andric DominatorTree &DT; 1360b57cec5SDimitry Andric PostDominatorTree *PDT; 1370b57cec5SDimitry Andric LoopInfo &LI; 138bdd1243dSDimitry Andric AssumptionCache &AC; 139349cc55cSDimitry Andric MemorySSAUpdater *MSSAU; 1400b57cec5SDimitry Andric 1410b57cec5SDimitry Andric /// Together, these describe the region of interest. This might be all of 1420b57cec5SDimitry Andric /// the blocks within a function, or only a given loop's blocks and preheader. 1430b57cec5SDimitry Andric DomTreeNode *Root; 1440b57cec5SDimitry Andric std::function<bool(BasicBlock*)> BlockFilter; 1450b57cec5SDimitry Andric 1460b57cec5SDimitry Andric /// The set of guards and conditional branches whose conditions have been 1470b57cec5SDimitry Andric /// widened into dominating guards. 1480b57cec5SDimitry Andric SmallVector<Instruction *, 16> EliminatedGuardsAndBranches; 1490b57cec5SDimitry Andric 1500b57cec5SDimitry Andric /// The set of guards which have been widened to include conditions to other 1510b57cec5SDimitry Andric /// guards. 1520b57cec5SDimitry Andric DenseSet<Instruction *> WidenedGuards; 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric /// Try to eliminate instruction \p Instr by widening it into an earlier 1550b57cec5SDimitry Andric /// dominating guard. \p DFSI is the DFS iterator on the dominator tree that 1560b57cec5SDimitry Andric /// is currently visiting the block containing \p Guard, and \p GuardsPerBlock 1570b57cec5SDimitry Andric /// maps BasicBlocks to the set of guards seen in that block. 1580b57cec5SDimitry Andric bool eliminateInstrViaWidening( 1590b57cec5SDimitry Andric Instruction *Instr, const df_iterator<DomTreeNode *> &DFSI, 1605f757f3fSDimitry Andric const DenseMap<BasicBlock *, SmallVector<Instruction *, 8>> 1615f757f3fSDimitry Andric &GuardsPerBlock); 1620b57cec5SDimitry Andric 1630b57cec5SDimitry Andric /// Used to keep track of which widening potential is more effective. 1640b57cec5SDimitry Andric enum WideningScore { 1650b57cec5SDimitry Andric /// Don't widen. 1660b57cec5SDimitry Andric WS_IllegalOrNegative, 1670b57cec5SDimitry Andric 1680b57cec5SDimitry Andric /// Widening is performance neutral as far as the cycles spent in check 1690b57cec5SDimitry Andric /// conditions goes (but can still help, e.g., code layout, having less 1700b57cec5SDimitry Andric /// deopt state). 1710b57cec5SDimitry Andric WS_Neutral, 1720b57cec5SDimitry Andric 1730b57cec5SDimitry Andric /// Widening is profitable. 1740b57cec5SDimitry Andric WS_Positive, 1750b57cec5SDimitry Andric 1760b57cec5SDimitry Andric /// Widening is very profitable. Not significantly different from \c 1770b57cec5SDimitry Andric /// WS_Positive, except by the order. 1780b57cec5SDimitry Andric WS_VeryPositive 1790b57cec5SDimitry Andric }; 1800b57cec5SDimitry Andric 1810b57cec5SDimitry Andric static StringRef scoreTypeToString(WideningScore WS); 1820b57cec5SDimitry Andric 1830b57cec5SDimitry Andric /// Compute the score for widening the condition in \p DominatedInstr 1845f757f3fSDimitry Andric /// into \p WideningPoint. 1850b57cec5SDimitry Andric WideningScore computeWideningScore(Instruction *DominatedInstr, 1865f757f3fSDimitry Andric Instruction *ToWiden, 187*0fca6ea1SDimitry Andric BasicBlock::iterator WideningPoint, 1885f757f3fSDimitry Andric SmallVectorImpl<Value *> &ChecksToHoist, 1895f757f3fSDimitry Andric SmallVectorImpl<Value *> &ChecksToWiden); 1900b57cec5SDimitry Andric 1910b57cec5SDimitry Andric /// Helper to check if \p V can be hoisted to \p InsertPos. 192*0fca6ea1SDimitry Andric bool canBeHoistedTo(const Value *V, BasicBlock::iterator InsertPos) const { 1930b57cec5SDimitry Andric SmallPtrSet<const Instruction *, 8> Visited; 19406c3fb27SDimitry Andric return canBeHoistedTo(V, InsertPos, Visited); 1950b57cec5SDimitry Andric } 1960b57cec5SDimitry Andric 197*0fca6ea1SDimitry Andric bool canBeHoistedTo(const Value *V, BasicBlock::iterator InsertPos, 1980b57cec5SDimitry Andric SmallPtrSetImpl<const Instruction *> &Visited) const; 1990b57cec5SDimitry Andric 2005f757f3fSDimitry Andric bool canBeHoistedTo(const SmallVectorImpl<Value *> &Checks, 201*0fca6ea1SDimitry Andric BasicBlock::iterator InsertPos) const { 2025f757f3fSDimitry Andric return all_of(Checks, 2035f757f3fSDimitry Andric [&](const Value *V) { return canBeHoistedTo(V, InsertPos); }); 2045f757f3fSDimitry Andric } 2050b57cec5SDimitry Andric /// Helper to hoist \p V to \p InsertPos. Guaranteed to succeed if \c 20606c3fb27SDimitry Andric /// canBeHoistedTo returned true. 207*0fca6ea1SDimitry Andric void makeAvailableAt(Value *V, BasicBlock::iterator InsertPos) const; 2080b57cec5SDimitry Andric 2095f757f3fSDimitry Andric void makeAvailableAt(const SmallVectorImpl<Value *> &Checks, 210*0fca6ea1SDimitry Andric BasicBlock::iterator InsertPos) const { 2115f757f3fSDimitry Andric for (Value *V : Checks) 2125f757f3fSDimitry Andric makeAvailableAt(V, InsertPos); 2135f757f3fSDimitry Andric } 2145f757f3fSDimitry Andric 2150b57cec5SDimitry Andric /// Common helper used by \c widenGuard and \c isWideningCondProfitable. Try 2165f757f3fSDimitry Andric /// to generate an expression computing the logical AND of \p ChecksToHoist 2175f757f3fSDimitry Andric /// and \p ChecksToWiden. Return true if the expression computing the AND is 2185f757f3fSDimitry Andric /// only as expensive as computing one of the set of expressions. If \p 2195f757f3fSDimitry Andric /// InsertPt is true then actually generate the resulting expression, make it 2205f757f3fSDimitry Andric /// available at \p InsertPt and return it in \p Result (else no change to the 2215f757f3fSDimitry Andric /// IR is made). 222*0fca6ea1SDimitry Andric std::optional<Value *> 223*0fca6ea1SDimitry Andric mergeChecks(SmallVectorImpl<Value *> &ChecksToHoist, 2245f757f3fSDimitry Andric SmallVectorImpl<Value *> &ChecksToWiden, 225*0fca6ea1SDimitry Andric std::optional<BasicBlock::iterator> InsertPt); 2265f757f3fSDimitry Andric 2275f757f3fSDimitry Andric /// Generate the logical AND of \p ChecksToHoist and \p OldCondition and make 2285f757f3fSDimitry Andric /// it available at InsertPt 2295f757f3fSDimitry Andric Value *hoistChecks(SmallVectorImpl<Value *> &ChecksToHoist, 230*0fca6ea1SDimitry Andric Value *OldCondition, BasicBlock::iterator InsertPt); 2310b57cec5SDimitry Andric 23206c3fb27SDimitry Andric /// Adds freeze to Orig and push it as far as possible very aggressively. 23306c3fb27SDimitry Andric /// Also replaces all uses of frozen instruction with frozen version. 234*0fca6ea1SDimitry Andric Value *freezeAndPush(Value *Orig, BasicBlock::iterator InsertPt); 23506c3fb27SDimitry Andric 2360b57cec5SDimitry Andric /// Represents a range check of the form \c Base + \c Offset u< \c Length, 2370b57cec5SDimitry Andric /// with the constraint that \c Length is not negative. \c CheckInst is the 2380b57cec5SDimitry Andric /// pre-existing instruction in the IR that computes the result of this range 2390b57cec5SDimitry Andric /// check. 2400b57cec5SDimitry Andric class RangeCheck { 2410b57cec5SDimitry Andric const Value *Base; 2420b57cec5SDimitry Andric const ConstantInt *Offset; 2430b57cec5SDimitry Andric const Value *Length; 2440b57cec5SDimitry Andric ICmpInst *CheckInst; 2450b57cec5SDimitry Andric 2460b57cec5SDimitry Andric public: 2470b57cec5SDimitry Andric explicit RangeCheck(const Value *Base, const ConstantInt *Offset, 2480b57cec5SDimitry Andric const Value *Length, ICmpInst *CheckInst) 2490b57cec5SDimitry Andric : Base(Base), Offset(Offset), Length(Length), CheckInst(CheckInst) {} 2500b57cec5SDimitry Andric 2510b57cec5SDimitry Andric void setBase(const Value *NewBase) { Base = NewBase; } 2520b57cec5SDimitry Andric void setOffset(const ConstantInt *NewOffset) { Offset = NewOffset; } 2530b57cec5SDimitry Andric 2540b57cec5SDimitry Andric const Value *getBase() const { return Base; } 2550b57cec5SDimitry Andric const ConstantInt *getOffset() const { return Offset; } 2560b57cec5SDimitry Andric const APInt &getOffsetValue() const { return getOffset()->getValue(); } 2570b57cec5SDimitry Andric const Value *getLength() const { return Length; }; 2580b57cec5SDimitry Andric ICmpInst *getCheckInst() const { return CheckInst; } 2590b57cec5SDimitry Andric 2600b57cec5SDimitry Andric void print(raw_ostream &OS, bool PrintTypes = false) { 2610b57cec5SDimitry Andric OS << "Base: "; 2620b57cec5SDimitry Andric Base->printAsOperand(OS, PrintTypes); 2630b57cec5SDimitry Andric OS << " Offset: "; 2640b57cec5SDimitry Andric Offset->printAsOperand(OS, PrintTypes); 2650b57cec5SDimitry Andric OS << " Length: "; 2660b57cec5SDimitry Andric Length->printAsOperand(OS, PrintTypes); 2670b57cec5SDimitry Andric } 2680b57cec5SDimitry Andric 2690b57cec5SDimitry Andric LLVM_DUMP_METHOD void dump() { 2700b57cec5SDimitry Andric print(dbgs()); 2710b57cec5SDimitry Andric dbgs() << "\n"; 2720b57cec5SDimitry Andric } 2730b57cec5SDimitry Andric }; 2740b57cec5SDimitry Andric 2755f757f3fSDimitry Andric /// Parse \p ToParse into a conjunction (logical-and) of range checks; and 2760b57cec5SDimitry Andric /// append them to \p Checks. Returns true on success, may clobber \c Checks 2770b57cec5SDimitry Andric /// on failure. 2785f757f3fSDimitry Andric bool parseRangeChecks(SmallVectorImpl<Value *> &ToParse, 2795f757f3fSDimitry Andric SmallVectorImpl<RangeCheck> &Checks) { 2805f757f3fSDimitry Andric for (auto CheckCond : ToParse) { 2815f757f3fSDimitry Andric if (!parseRangeChecks(CheckCond, Checks)) 2825f757f3fSDimitry Andric return false; 2835f757f3fSDimitry Andric } 2845f757f3fSDimitry Andric return true; 2850b57cec5SDimitry Andric } 2860b57cec5SDimitry Andric 2875f757f3fSDimitry Andric bool parseRangeChecks(Value *CheckCond, SmallVectorImpl<RangeCheck> &Checks); 2880b57cec5SDimitry Andric 2890b57cec5SDimitry Andric /// Combine the checks in \p Checks into a smaller set of checks and append 2900b57cec5SDimitry Andric /// them into \p CombinedChecks. Return true on success (i.e. all of checks 2910b57cec5SDimitry Andric /// in \p Checks were combined into \p CombinedChecks). Clobbers \p Checks 2920b57cec5SDimitry Andric /// and \p CombinedChecks on success and on failure. 2930b57cec5SDimitry Andric bool combineRangeChecks(SmallVectorImpl<RangeCheck> &Checks, 2940b57cec5SDimitry Andric SmallVectorImpl<RangeCheck> &CombinedChecks) const; 2950b57cec5SDimitry Andric 2965f757f3fSDimitry Andric /// Can we compute the logical AND of \p ChecksToHoist and \p ChecksToWiden 2975f757f3fSDimitry Andric /// for the price of computing only one of the set of expressions? 2985f757f3fSDimitry Andric bool isWideningCondProfitable(SmallVectorImpl<Value *> &ChecksToHoist, 2995f757f3fSDimitry Andric SmallVectorImpl<Value *> &ChecksToWiden) { 300*0fca6ea1SDimitry Andric return mergeChecks(ChecksToHoist, ChecksToWiden, /*InsertPt=*/std::nullopt) 3015f757f3fSDimitry Andric .has_value(); 3020b57cec5SDimitry Andric } 3030b57cec5SDimitry Andric 3045f757f3fSDimitry Andric /// Widen \p ChecksToWiden to fail if any of \p ChecksToHoist is false 3055f757f3fSDimitry Andric void widenGuard(SmallVectorImpl<Value *> &ChecksToHoist, 3065f757f3fSDimitry Andric SmallVectorImpl<Value *> &ChecksToWiden, 3075f757f3fSDimitry Andric Instruction *ToWiden) { 308*0fca6ea1SDimitry Andric auto InsertPt = findInsertionPointForWideCondition(ToWiden); 3095f757f3fSDimitry Andric auto MergedCheck = mergeChecks(ChecksToHoist, ChecksToWiden, InsertPt); 3105f757f3fSDimitry Andric Value *Result = MergedCheck ? *MergedCheck 3115f757f3fSDimitry Andric : hoistChecks(ChecksToHoist, 312*0fca6ea1SDimitry Andric getCondition(ToWiden), *InsertPt); 3135f757f3fSDimitry Andric 3140b57cec5SDimitry Andric if (isGuardAsWidenableBranch(ToWiden)) { 315480093f4SDimitry Andric setWidenableBranchCond(cast<BranchInst>(ToWiden), Result); 316480093f4SDimitry Andric return; 3170b57cec5SDimitry Andric } 3180b57cec5SDimitry Andric setCondition(ToWiden, Result); 3190b57cec5SDimitry Andric } 3200b57cec5SDimitry Andric 3210b57cec5SDimitry Andric public: 3220b57cec5SDimitry Andric explicit GuardWideningImpl(DominatorTree &DT, PostDominatorTree *PDT, 323bdd1243dSDimitry Andric LoopInfo &LI, AssumptionCache &AC, 324bdd1243dSDimitry Andric MemorySSAUpdater *MSSAU, DomTreeNode *Root, 3250b57cec5SDimitry Andric std::function<bool(BasicBlock *)> BlockFilter) 326bdd1243dSDimitry Andric : DT(DT), PDT(PDT), LI(LI), AC(AC), MSSAU(MSSAU), Root(Root), 327349cc55cSDimitry Andric BlockFilter(BlockFilter) {} 3280b57cec5SDimitry Andric 3290b57cec5SDimitry Andric /// The entry point for this pass. 3300b57cec5SDimitry Andric bool run(); 3310b57cec5SDimitry Andric }; 3320b57cec5SDimitry Andric } 3330b57cec5SDimitry Andric 3340b57cec5SDimitry Andric static bool isSupportedGuardInstruction(const Instruction *Insn) { 3350b57cec5SDimitry Andric if (isGuard(Insn)) 3360b57cec5SDimitry Andric return true; 3370b57cec5SDimitry Andric if (WidenBranchGuards && isGuardAsWidenableBranch(Insn)) 3380b57cec5SDimitry Andric return true; 3390b57cec5SDimitry Andric return false; 3400b57cec5SDimitry Andric } 3410b57cec5SDimitry Andric 3420b57cec5SDimitry Andric bool GuardWideningImpl::run() { 3430b57cec5SDimitry Andric DenseMap<BasicBlock *, SmallVector<Instruction *, 8>> GuardsInBlock; 3440b57cec5SDimitry Andric bool Changed = false; 3450b57cec5SDimitry Andric for (auto DFI = df_begin(Root), DFE = df_end(Root); 3460b57cec5SDimitry Andric DFI != DFE; ++DFI) { 3470b57cec5SDimitry Andric auto *BB = (*DFI)->getBlock(); 3480b57cec5SDimitry Andric if (!BlockFilter(BB)) 3490b57cec5SDimitry Andric continue; 3500b57cec5SDimitry Andric 3510b57cec5SDimitry Andric auto &CurrentList = GuardsInBlock[BB]; 3520b57cec5SDimitry Andric 3530b57cec5SDimitry Andric for (auto &I : *BB) 3540b57cec5SDimitry Andric if (isSupportedGuardInstruction(&I)) 3550b57cec5SDimitry Andric CurrentList.push_back(cast<Instruction>(&I)); 3560b57cec5SDimitry Andric 3570b57cec5SDimitry Andric for (auto *II : CurrentList) 3580b57cec5SDimitry Andric Changed |= eliminateInstrViaWidening(II, DFI, GuardsInBlock); 3590b57cec5SDimitry Andric } 3600b57cec5SDimitry Andric 3610b57cec5SDimitry Andric assert(EliminatedGuardsAndBranches.empty() || Changed); 3620b57cec5SDimitry Andric for (auto *I : EliminatedGuardsAndBranches) 3630b57cec5SDimitry Andric if (!WidenedGuards.count(I)) { 3640b57cec5SDimitry Andric assert(isa<ConstantInt>(getCondition(I)) && "Should be!"); 3650b57cec5SDimitry Andric if (isSupportedGuardInstruction(I)) 366349cc55cSDimitry Andric eliminateGuard(I, MSSAU); 3670b57cec5SDimitry Andric else { 3680b57cec5SDimitry Andric assert(isa<BranchInst>(I) && 3690b57cec5SDimitry Andric "Eliminated something other than guard or branch?"); 3700b57cec5SDimitry Andric ++CondBranchEliminated; 3710b57cec5SDimitry Andric } 3720b57cec5SDimitry Andric } 3730b57cec5SDimitry Andric 3740b57cec5SDimitry Andric return Changed; 3750b57cec5SDimitry Andric } 3760b57cec5SDimitry Andric 3770b57cec5SDimitry Andric bool GuardWideningImpl::eliminateInstrViaWidening( 3780b57cec5SDimitry Andric Instruction *Instr, const df_iterator<DomTreeNode *> &DFSI, 3795f757f3fSDimitry Andric const DenseMap<BasicBlock *, SmallVector<Instruction *, 8>> 3805f757f3fSDimitry Andric &GuardsInBlock) { 3815f757f3fSDimitry Andric SmallVector<Value *> ChecksToHoist; 3825f757f3fSDimitry Andric parseWidenableGuard(Instr, ChecksToHoist); 3830b57cec5SDimitry Andric // Ignore trivial true or false conditions. These instructions will be 3840b57cec5SDimitry Andric // trivially eliminated by any cleanup pass. Do not erase them because other 3850b57cec5SDimitry Andric // guards can possibly be widened into them. 3865f757f3fSDimitry Andric if (ChecksToHoist.empty() || 3875f757f3fSDimitry Andric (ChecksToHoist.size() == 1 && isa<ConstantInt>(ChecksToHoist.front()))) 3880b57cec5SDimitry Andric return false; 3890b57cec5SDimitry Andric 3900b57cec5SDimitry Andric Instruction *BestSoFar = nullptr; 3910b57cec5SDimitry Andric auto BestScoreSoFar = WS_IllegalOrNegative; 3920b57cec5SDimitry Andric 3930b57cec5SDimitry Andric // In the set of dominating guards, find the one we can merge GuardInst with 3940b57cec5SDimitry Andric // for the most profit. 3950b57cec5SDimitry Andric for (unsigned i = 0, e = DFSI.getPathLength(); i != e; ++i) { 3960b57cec5SDimitry Andric auto *CurBB = DFSI.getPath(i)->getBlock(); 3970b57cec5SDimitry Andric if (!BlockFilter(CurBB)) 3980b57cec5SDimitry Andric break; 3990b57cec5SDimitry Andric assert(GuardsInBlock.count(CurBB) && "Must have been populated by now!"); 4000b57cec5SDimitry Andric const auto &GuardsInCurBB = GuardsInBlock.find(CurBB)->second; 4010b57cec5SDimitry Andric 4020b57cec5SDimitry Andric auto I = GuardsInCurBB.begin(); 403e8d8bef9SDimitry Andric auto E = Instr->getParent() == CurBB ? find(GuardsInCurBB, Instr) 4040b57cec5SDimitry Andric : GuardsInCurBB.end(); 4050b57cec5SDimitry Andric 4060b57cec5SDimitry Andric #ifndef NDEBUG 4070b57cec5SDimitry Andric { 4080b57cec5SDimitry Andric unsigned Index = 0; 4090b57cec5SDimitry Andric for (auto &I : *CurBB) { 4100b57cec5SDimitry Andric if (Index == GuardsInCurBB.size()) 4110b57cec5SDimitry Andric break; 4120b57cec5SDimitry Andric if (GuardsInCurBB[Index] == &I) 4130b57cec5SDimitry Andric Index++; 4140b57cec5SDimitry Andric } 4150b57cec5SDimitry Andric assert(Index == GuardsInCurBB.size() && 4160b57cec5SDimitry Andric "Guards expected to be in order!"); 4170b57cec5SDimitry Andric } 4180b57cec5SDimitry Andric #endif 4190b57cec5SDimitry Andric 4200b57cec5SDimitry Andric assert((i == (e - 1)) == (Instr->getParent() == CurBB) && "Bad DFS?"); 4210b57cec5SDimitry Andric 4220b57cec5SDimitry Andric for (auto *Candidate : make_range(I, E)) { 423*0fca6ea1SDimitry Andric auto WideningPoint = findInsertionPointForWideCondition(Candidate); 4245f757f3fSDimitry Andric if (!WideningPoint) 4255f757f3fSDimitry Andric continue; 4265f757f3fSDimitry Andric SmallVector<Value *> CandidateChecks; 4275f757f3fSDimitry Andric parseWidenableGuard(Candidate, CandidateChecks); 428*0fca6ea1SDimitry Andric auto Score = computeWideningScore(Instr, Candidate, *WideningPoint, 4295f757f3fSDimitry Andric ChecksToHoist, CandidateChecks); 4305f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "Score between " << *Instr << " and " << *Candidate 4315f757f3fSDimitry Andric << " is " << scoreTypeToString(Score) << "\n"); 4320b57cec5SDimitry Andric if (Score > BestScoreSoFar) { 4330b57cec5SDimitry Andric BestScoreSoFar = Score; 4340b57cec5SDimitry Andric BestSoFar = Candidate; 4350b57cec5SDimitry Andric } 4360b57cec5SDimitry Andric } 4370b57cec5SDimitry Andric } 4380b57cec5SDimitry Andric 4390b57cec5SDimitry Andric if (BestScoreSoFar == WS_IllegalOrNegative) { 4400b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Did not eliminate guard " << *Instr << "\n"); 4410b57cec5SDimitry Andric return false; 4420b57cec5SDimitry Andric } 4430b57cec5SDimitry Andric 4440b57cec5SDimitry Andric assert(BestSoFar != Instr && "Should have never visited same guard!"); 4450b57cec5SDimitry Andric assert(DT.dominates(BestSoFar, Instr) && "Should be!"); 4460b57cec5SDimitry Andric 4470b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Widening " << *Instr << " into " << *BestSoFar 4480b57cec5SDimitry Andric << " with score " << scoreTypeToString(BestScoreSoFar) 4490b57cec5SDimitry Andric << "\n"); 4505f757f3fSDimitry Andric SmallVector<Value *> ChecksToWiden; 4515f757f3fSDimitry Andric parseWidenableGuard(BestSoFar, ChecksToWiden); 4525f757f3fSDimitry Andric widenGuard(ChecksToHoist, ChecksToWiden, BestSoFar); 4535f757f3fSDimitry Andric auto NewGuardCondition = ConstantInt::getTrue(Instr->getContext()); 4540b57cec5SDimitry Andric setCondition(Instr, NewGuardCondition); 4550b57cec5SDimitry Andric EliminatedGuardsAndBranches.push_back(Instr); 4560b57cec5SDimitry Andric WidenedGuards.insert(BestSoFar); 4570b57cec5SDimitry Andric return true; 4580b57cec5SDimitry Andric } 4590b57cec5SDimitry Andric 4605f757f3fSDimitry Andric GuardWideningImpl::WideningScore GuardWideningImpl::computeWideningScore( 4615f757f3fSDimitry Andric Instruction *DominatedInstr, Instruction *ToWiden, 462*0fca6ea1SDimitry Andric BasicBlock::iterator WideningPoint, SmallVectorImpl<Value *> &ChecksToHoist, 4635f757f3fSDimitry Andric SmallVectorImpl<Value *> &ChecksToWiden) { 4640b57cec5SDimitry Andric Loop *DominatedInstrLoop = LI.getLoopFor(DominatedInstr->getParent()); 4655f757f3fSDimitry Andric Loop *DominatingGuardLoop = LI.getLoopFor(WideningPoint->getParent()); 4660b57cec5SDimitry Andric bool HoistingOutOfLoop = false; 4670b57cec5SDimitry Andric 4680b57cec5SDimitry Andric if (DominatingGuardLoop != DominatedInstrLoop) { 4690b57cec5SDimitry Andric // Be conservative and don't widen into a sibling loop. TODO: If the 4700b57cec5SDimitry Andric // sibling is colder, we should consider allowing this. 4710b57cec5SDimitry Andric if (DominatingGuardLoop && 4720b57cec5SDimitry Andric !DominatingGuardLoop->contains(DominatedInstrLoop)) 4730b57cec5SDimitry Andric return WS_IllegalOrNegative; 4740b57cec5SDimitry Andric 4750b57cec5SDimitry Andric HoistingOutOfLoop = true; 4760b57cec5SDimitry Andric } 4770b57cec5SDimitry Andric 4785f757f3fSDimitry Andric if (!canBeHoistedTo(ChecksToHoist, WideningPoint)) 47906c3fb27SDimitry Andric return WS_IllegalOrNegative; 4805f757f3fSDimitry Andric // Further in the GuardWideningImpl::hoistChecks the entire condition might be 4815f757f3fSDimitry Andric // widened, not the parsed list of checks. So we need to check the possibility 4825f757f3fSDimitry Andric // of that condition hoisting. 4835f757f3fSDimitry Andric if (!canBeHoistedTo(getCondition(ToWiden), WideningPoint)) 4840b57cec5SDimitry Andric return WS_IllegalOrNegative; 4850b57cec5SDimitry Andric 4860b57cec5SDimitry Andric // If the guard was conditional executed, it may never be reached 4870b57cec5SDimitry Andric // dynamically. There are two potential downsides to hoisting it out of the 4880b57cec5SDimitry Andric // conditionally executed region: 1) we may spuriously deopt without need and 4890b57cec5SDimitry Andric // 2) we have the extra cost of computing the guard condition in the common 4900b57cec5SDimitry Andric // case. At the moment, we really only consider the second in our heuristic 4910b57cec5SDimitry Andric // here. TODO: evaluate cost model for spurious deopt 4920b57cec5SDimitry Andric // NOTE: As written, this also lets us hoist right over another guard which 4930b57cec5SDimitry Andric // is essentially just another spelling for control flow. 4945f757f3fSDimitry Andric if (isWideningCondProfitable(ChecksToHoist, ChecksToWiden)) 4950b57cec5SDimitry Andric return HoistingOutOfLoop ? WS_VeryPositive : WS_Positive; 4960b57cec5SDimitry Andric 4970b57cec5SDimitry Andric if (HoistingOutOfLoop) 4980b57cec5SDimitry Andric return WS_Positive; 4990b57cec5SDimitry Andric 50006c3fb27SDimitry Andric // For a given basic block \p BB, return its successor which is guaranteed or 50106c3fb27SDimitry Andric // highly likely will be taken as its successor. 50206c3fb27SDimitry Andric auto GetLikelySuccessor = [](const BasicBlock * BB)->const BasicBlock * { 50306c3fb27SDimitry Andric if (auto *UniqueSucc = BB->getUniqueSuccessor()) 50406c3fb27SDimitry Andric return UniqueSucc; 50506c3fb27SDimitry Andric auto *Term = BB->getTerminator(); 50606c3fb27SDimitry Andric Value *Cond = nullptr; 50706c3fb27SDimitry Andric const BasicBlock *IfTrue = nullptr, *IfFalse = nullptr; 50806c3fb27SDimitry Andric using namespace PatternMatch; 50906c3fb27SDimitry Andric if (!match(Term, m_Br(m_Value(Cond), m_BasicBlock(IfTrue), 51006c3fb27SDimitry Andric m_BasicBlock(IfFalse)))) 51106c3fb27SDimitry Andric return nullptr; 51206c3fb27SDimitry Andric // For constant conditions, only one dynamical successor is possible 51306c3fb27SDimitry Andric if (auto *ConstCond = dyn_cast<ConstantInt>(Cond)) 51406c3fb27SDimitry Andric return ConstCond->isAllOnesValue() ? IfTrue : IfFalse; 51506c3fb27SDimitry Andric // If one of successors ends with deopt, another one is likely. 51606c3fb27SDimitry Andric if (IfFalse->getPostdominatingDeoptimizeCall()) 51706c3fb27SDimitry Andric return IfTrue; 51806c3fb27SDimitry Andric if (IfTrue->getPostdominatingDeoptimizeCall()) 51906c3fb27SDimitry Andric return IfFalse; 52006c3fb27SDimitry Andric // TODO: Use branch frequency metatada to allow hoisting through non-deopt 52106c3fb27SDimitry Andric // branches? 52206c3fb27SDimitry Andric return nullptr; 52306c3fb27SDimitry Andric }; 5240b57cec5SDimitry Andric 52506c3fb27SDimitry Andric // Returns true if we might be hoisting above explicit control flow into a 52606c3fb27SDimitry Andric // considerably hotter block. Note that this completely ignores implicit 52706c3fb27SDimitry Andric // control flow (guards, calls which throw, etc...). That choice appears 52806c3fb27SDimitry Andric // arbitrary (we assume that implicit control flow exits are all rare). 52906c3fb27SDimitry Andric auto MaybeHoistingToHotterBlock = [&]() { 5305f757f3fSDimitry Andric const auto *DominatingBlock = WideningPoint->getParent(); 53106c3fb27SDimitry Andric const auto *DominatedBlock = DominatedInstr->getParent(); 53206c3fb27SDimitry Andric 53306c3fb27SDimitry Andric // Descend as low as we can, always taking the likely successor. 53406c3fb27SDimitry Andric assert(DT.isReachableFromEntry(DominatingBlock) && "Unreached code"); 53506c3fb27SDimitry Andric assert(DT.isReachableFromEntry(DominatedBlock) && "Unreached code"); 53606c3fb27SDimitry Andric assert(DT.dominates(DominatingBlock, DominatedBlock) && "No dominance"); 53706c3fb27SDimitry Andric while (DominatedBlock != DominatingBlock) { 53806c3fb27SDimitry Andric auto *LikelySucc = GetLikelySuccessor(DominatingBlock); 53906c3fb27SDimitry Andric // No likely successor? 54006c3fb27SDimitry Andric if (!LikelySucc) 54106c3fb27SDimitry Andric break; 54206c3fb27SDimitry Andric // Only go down the dominator tree. 54306c3fb27SDimitry Andric if (!DT.properlyDominates(DominatingBlock, LikelySucc)) 54406c3fb27SDimitry Andric break; 54506c3fb27SDimitry Andric DominatingBlock = LikelySucc; 54606c3fb27SDimitry Andric } 54706c3fb27SDimitry Andric 54806c3fb27SDimitry Andric // Found? 5490b57cec5SDimitry Andric if (DominatedBlock == DominatingBlock) 5500b57cec5SDimitry Andric return false; 55106c3fb27SDimitry Andric // We followed the likely successor chain and went past the dominated 55206c3fb27SDimitry Andric // block. It means that the dominated guard is in dead/very cold code. 55306c3fb27SDimitry Andric if (!DT.dominates(DominatingBlock, DominatedBlock)) 55406c3fb27SDimitry Andric return true; 5550b57cec5SDimitry Andric // TODO: diamond, triangle cases 5565f757f3fSDimitry Andric if (!PDT) 5575f757f3fSDimitry Andric return true; 5580b57cec5SDimitry Andric return !PDT->dominates(DominatedBlock, DominatingBlock); 5590b57cec5SDimitry Andric }; 5600b57cec5SDimitry Andric 56106c3fb27SDimitry Andric return MaybeHoistingToHotterBlock() ? WS_IllegalOrNegative : WS_Neutral; 5620b57cec5SDimitry Andric } 5630b57cec5SDimitry Andric 56406c3fb27SDimitry Andric bool GuardWideningImpl::canBeHoistedTo( 565*0fca6ea1SDimitry Andric const Value *V, BasicBlock::iterator Loc, 5660b57cec5SDimitry Andric SmallPtrSetImpl<const Instruction *> &Visited) const { 5670b57cec5SDimitry Andric auto *Inst = dyn_cast<Instruction>(V); 5680b57cec5SDimitry Andric if (!Inst || DT.dominates(Inst, Loc) || Visited.count(Inst)) 5690b57cec5SDimitry Andric return true; 5700b57cec5SDimitry Andric 571bdd1243dSDimitry Andric if (!isSafeToSpeculativelyExecute(Inst, Loc, &AC, &DT) || 5720b57cec5SDimitry Andric Inst->mayReadFromMemory()) 5730b57cec5SDimitry Andric return false; 5740b57cec5SDimitry Andric 5750b57cec5SDimitry Andric Visited.insert(Inst); 5760b57cec5SDimitry Andric 5770b57cec5SDimitry Andric // We only want to go _up_ the dominance chain when recursing. 5780b57cec5SDimitry Andric assert(!isa<PHINode>(Loc) && 5790b57cec5SDimitry Andric "PHIs should return false for isSafeToSpeculativelyExecute"); 5800b57cec5SDimitry Andric assert(DT.isReachableFromEntry(Inst->getParent()) && 5810b57cec5SDimitry Andric "We did a DFS from the block entry!"); 5820b57cec5SDimitry Andric return all_of(Inst->operands(), 58306c3fb27SDimitry Andric [&](Value *Op) { return canBeHoistedTo(Op, Loc, Visited); }); 5840b57cec5SDimitry Andric } 5850b57cec5SDimitry Andric 586*0fca6ea1SDimitry Andric void GuardWideningImpl::makeAvailableAt(Value *V, 587*0fca6ea1SDimitry Andric BasicBlock::iterator Loc) const { 5880b57cec5SDimitry Andric auto *Inst = dyn_cast<Instruction>(V); 5890b57cec5SDimitry Andric if (!Inst || DT.dominates(Inst, Loc)) 5900b57cec5SDimitry Andric return; 5910b57cec5SDimitry Andric 592bdd1243dSDimitry Andric assert(isSafeToSpeculativelyExecute(Inst, Loc, &AC, &DT) && 59306c3fb27SDimitry Andric !Inst->mayReadFromMemory() && 59406c3fb27SDimitry Andric "Should've checked with canBeHoistedTo!"); 5950b57cec5SDimitry Andric 5960b57cec5SDimitry Andric for (Value *Op : Inst->operands()) 5970b57cec5SDimitry Andric makeAvailableAt(Op, Loc); 5980b57cec5SDimitry Andric 599*0fca6ea1SDimitry Andric Inst->moveBefore(*Loc->getParent(), Loc); 60006c3fb27SDimitry Andric } 60106c3fb27SDimitry Andric 60206c3fb27SDimitry Andric // Return Instruction before which we can insert freeze for the value V as close 6035f757f3fSDimitry Andric // to def as possible. If there is no place to add freeze, return empty. 6045f757f3fSDimitry Andric static std::optional<BasicBlock::iterator> 6055f757f3fSDimitry Andric getFreezeInsertPt(Value *V, const DominatorTree &DT) { 60606c3fb27SDimitry Andric auto *I = dyn_cast<Instruction>(V); 60706c3fb27SDimitry Andric if (!I) 6085f757f3fSDimitry Andric return DT.getRoot()->getFirstNonPHIOrDbgOrAlloca()->getIterator(); 60906c3fb27SDimitry Andric 6105f757f3fSDimitry Andric std::optional<BasicBlock::iterator> Res = I->getInsertionPointAfterDef(); 61106c3fb27SDimitry Andric // If there is no place to add freeze - return nullptr. 6125f757f3fSDimitry Andric if (!Res || !DT.dominates(I, &**Res)) 6135f757f3fSDimitry Andric return std::nullopt; 6145f757f3fSDimitry Andric 6155f757f3fSDimitry Andric Instruction *ResInst = &**Res; 61606c3fb27SDimitry Andric 61706c3fb27SDimitry Andric // If there is a User dominated by original I, then it should be dominated 61806c3fb27SDimitry Andric // by Freeze instruction as well. 61906c3fb27SDimitry Andric if (any_of(I->users(), [&](User *U) { 62006c3fb27SDimitry Andric Instruction *User = cast<Instruction>(U); 6215f757f3fSDimitry Andric return ResInst != User && DT.dominates(I, User) && 6225f757f3fSDimitry Andric !DT.dominates(ResInst, User); 62306c3fb27SDimitry Andric })) 6245f757f3fSDimitry Andric return std::nullopt; 62506c3fb27SDimitry Andric return Res; 62606c3fb27SDimitry Andric } 62706c3fb27SDimitry Andric 628*0fca6ea1SDimitry Andric Value *GuardWideningImpl::freezeAndPush(Value *Orig, 629*0fca6ea1SDimitry Andric BasicBlock::iterator InsertPt) { 63006c3fb27SDimitry Andric if (isGuaranteedNotToBePoison(Orig, nullptr, InsertPt, &DT)) 63106c3fb27SDimitry Andric return Orig; 6325f757f3fSDimitry Andric std::optional<BasicBlock::iterator> InsertPtAtDef = 6335f757f3fSDimitry Andric getFreezeInsertPt(Orig, DT); 6345f757f3fSDimitry Andric if (!InsertPtAtDef) { 6355f757f3fSDimitry Andric FreezeInst *FI = new FreezeInst(Orig, "gw.freeze"); 636*0fca6ea1SDimitry Andric FI->insertBefore(*InsertPt->getParent(), InsertPt); 6375f757f3fSDimitry Andric return FI; 6385f757f3fSDimitry Andric } 6395f757f3fSDimitry Andric if (isa<Constant>(Orig) || isa<GlobalValue>(Orig)) { 6405f757f3fSDimitry Andric BasicBlock::iterator InsertPt = *InsertPtAtDef; 6415f757f3fSDimitry Andric FreezeInst *FI = new FreezeInst(Orig, "gw.freeze"); 6425f757f3fSDimitry Andric FI->insertBefore(*InsertPt->getParent(), InsertPt); 6435f757f3fSDimitry Andric return FI; 6445f757f3fSDimitry Andric } 64506c3fb27SDimitry Andric 64606c3fb27SDimitry Andric SmallSet<Value *, 16> Visited; 64706c3fb27SDimitry Andric SmallVector<Value *, 16> Worklist; 64806c3fb27SDimitry Andric SmallSet<Instruction *, 16> DropPoisonFlags; 64906c3fb27SDimitry Andric SmallVector<Value *, 16> NeedFreeze; 65006c3fb27SDimitry Andric DenseMap<Value *, FreezeInst *> CacheOfFreezes; 65106c3fb27SDimitry Andric 65206c3fb27SDimitry Andric // A bit overloaded data structures. Visited contains constant/GV 65306c3fb27SDimitry Andric // if we already met it. In this case CacheOfFreezes has a freeze if it is 65406c3fb27SDimitry Andric // required. 65506c3fb27SDimitry Andric auto handleConstantOrGlobal = [&](Use &U) { 65606c3fb27SDimitry Andric Value *Def = U.get(); 65706c3fb27SDimitry Andric if (!isa<Constant>(Def) && !isa<GlobalValue>(Def)) 65806c3fb27SDimitry Andric return false; 65906c3fb27SDimitry Andric 66006c3fb27SDimitry Andric if (Visited.insert(Def).second) { 66106c3fb27SDimitry Andric if (isGuaranteedNotToBePoison(Def, nullptr, InsertPt, &DT)) 66206c3fb27SDimitry Andric return true; 6635f757f3fSDimitry Andric BasicBlock::iterator InsertPt = *getFreezeInsertPt(Def, DT); 6645f757f3fSDimitry Andric FreezeInst *FI = new FreezeInst(Def, Def->getName() + ".gw.fr"); 6655f757f3fSDimitry Andric FI->insertBefore(*InsertPt->getParent(), InsertPt); 6665f757f3fSDimitry Andric CacheOfFreezes[Def] = FI; 66706c3fb27SDimitry Andric } 66806c3fb27SDimitry Andric 66906c3fb27SDimitry Andric if (CacheOfFreezes.count(Def)) 67006c3fb27SDimitry Andric U.set(CacheOfFreezes[Def]); 67106c3fb27SDimitry Andric return true; 67206c3fb27SDimitry Andric }; 67306c3fb27SDimitry Andric 67406c3fb27SDimitry Andric Worklist.push_back(Orig); 67506c3fb27SDimitry Andric while (!Worklist.empty()) { 67606c3fb27SDimitry Andric Value *V = Worklist.pop_back_val(); 67706c3fb27SDimitry Andric if (!Visited.insert(V).second) 67806c3fb27SDimitry Andric continue; 67906c3fb27SDimitry Andric 68006c3fb27SDimitry Andric if (isGuaranteedNotToBePoison(V, nullptr, InsertPt, &DT)) 68106c3fb27SDimitry Andric continue; 68206c3fb27SDimitry Andric 68306c3fb27SDimitry Andric Instruction *I = dyn_cast<Instruction>(V); 68406c3fb27SDimitry Andric if (!I || canCreateUndefOrPoison(cast<Operator>(I), 68506c3fb27SDimitry Andric /*ConsiderFlagsAndMetadata*/ false)) { 68606c3fb27SDimitry Andric NeedFreeze.push_back(V); 68706c3fb27SDimitry Andric continue; 68806c3fb27SDimitry Andric } 68906c3fb27SDimitry Andric // Check all operands. If for any of them we cannot insert Freeze, 69006c3fb27SDimitry Andric // stop here. Otherwise, iterate. 69106c3fb27SDimitry Andric if (any_of(I->operands(), [&](Value *Op) { 69206c3fb27SDimitry Andric return isa<Instruction>(Op) && !getFreezeInsertPt(Op, DT); 69306c3fb27SDimitry Andric })) { 69406c3fb27SDimitry Andric NeedFreeze.push_back(I); 69506c3fb27SDimitry Andric continue; 69606c3fb27SDimitry Andric } 69706c3fb27SDimitry Andric DropPoisonFlags.insert(I); 69806c3fb27SDimitry Andric for (Use &U : I->operands()) 69906c3fb27SDimitry Andric if (!handleConstantOrGlobal(U)) 70006c3fb27SDimitry Andric Worklist.push_back(U.get()); 70106c3fb27SDimitry Andric } 70206c3fb27SDimitry Andric for (Instruction *I : DropPoisonFlags) 703*0fca6ea1SDimitry Andric I->dropPoisonGeneratingAnnotations(); 70406c3fb27SDimitry Andric 70506c3fb27SDimitry Andric Value *Result = Orig; 70606c3fb27SDimitry Andric for (Value *V : NeedFreeze) { 7075f757f3fSDimitry Andric BasicBlock::iterator FreezeInsertPt = *getFreezeInsertPt(V, DT); 7085f757f3fSDimitry Andric FreezeInst *FI = new FreezeInst(V, V->getName() + ".gw.fr"); 7095f757f3fSDimitry Andric FI->insertBefore(*FreezeInsertPt->getParent(), FreezeInsertPt); 71006c3fb27SDimitry Andric ++FreezeAdded; 71106c3fb27SDimitry Andric if (V == Orig) 71206c3fb27SDimitry Andric Result = FI; 71306c3fb27SDimitry Andric V->replaceUsesWithIf( 71406c3fb27SDimitry Andric FI, [&](const Use & U)->bool { return U.getUser() != FI; }); 71506c3fb27SDimitry Andric } 71606c3fb27SDimitry Andric 71706c3fb27SDimitry Andric return Result; 7180b57cec5SDimitry Andric } 7190b57cec5SDimitry Andric 7205f757f3fSDimitry Andric std::optional<Value *> 7215f757f3fSDimitry Andric GuardWideningImpl::mergeChecks(SmallVectorImpl<Value *> &ChecksToHoist, 7225f757f3fSDimitry Andric SmallVectorImpl<Value *> &ChecksToWiden, 723*0fca6ea1SDimitry Andric std::optional<BasicBlock::iterator> InsertPt) { 7240b57cec5SDimitry Andric using namespace llvm::PatternMatch; 7250b57cec5SDimitry Andric 7265f757f3fSDimitry Andric Value *Result = nullptr; 7270b57cec5SDimitry Andric { 7280b57cec5SDimitry Andric // L >u C0 && L >u C1 -> L >u max(C0, C1) 7290b57cec5SDimitry Andric ConstantInt *RHS0, *RHS1; 7300b57cec5SDimitry Andric Value *LHS; 7310b57cec5SDimitry Andric ICmpInst::Predicate Pred0, Pred1; 7325f757f3fSDimitry Andric // TODO: Support searching for pairs to merge from both whole lists of 7335f757f3fSDimitry Andric // ChecksToHoist and ChecksToWiden. 7345f757f3fSDimitry Andric if (ChecksToWiden.size() == 1 && ChecksToHoist.size() == 1 && 7355f757f3fSDimitry Andric match(ChecksToWiden.front(), 7365f757f3fSDimitry Andric m_ICmp(Pred0, m_Value(LHS), m_ConstantInt(RHS0))) && 7375f757f3fSDimitry Andric match(ChecksToHoist.front(), 7385f757f3fSDimitry Andric m_ICmp(Pred1, m_Specific(LHS), m_ConstantInt(RHS1)))) { 7390b57cec5SDimitry Andric 7400b57cec5SDimitry Andric ConstantRange CR0 = 7410b57cec5SDimitry Andric ConstantRange::makeExactICmpRegion(Pred0, RHS0->getValue()); 7420b57cec5SDimitry Andric ConstantRange CR1 = 7430b57cec5SDimitry Andric ConstantRange::makeExactICmpRegion(Pred1, RHS1->getValue()); 7440b57cec5SDimitry Andric 7450b57cec5SDimitry Andric // Given what we're doing here and the semantics of guards, it would 746349cc55cSDimitry Andric // be correct to use a subset intersection, but that may be too 7470b57cec5SDimitry Andric // aggressive in cases we care about. 748bdd1243dSDimitry Andric if (std::optional<ConstantRange> Intersect = 749bdd1243dSDimitry Andric CR0.exactIntersectWith(CR1)) { 7500b57cec5SDimitry Andric APInt NewRHSAP; 7510b57cec5SDimitry Andric CmpInst::Predicate Pred; 752349cc55cSDimitry Andric if (Intersect->getEquivalentICmp(Pred, NewRHSAP)) { 7530b57cec5SDimitry Andric if (InsertPt) { 754349cc55cSDimitry Andric ConstantInt *NewRHS = 755*0fca6ea1SDimitry Andric ConstantInt::get((*InsertPt)->getContext(), NewRHSAP); 756*0fca6ea1SDimitry Andric assert(canBeHoistedTo(LHS, *InsertPt) && "must be"); 757*0fca6ea1SDimitry Andric makeAvailableAt(LHS, *InsertPt); 758*0fca6ea1SDimitry Andric Result = new ICmpInst(*InsertPt, Pred, LHS, NewRHS, "wide.chk"); 7590b57cec5SDimitry Andric } 7605f757f3fSDimitry Andric return Result; 7610b57cec5SDimitry Andric } 7620b57cec5SDimitry Andric } 7630b57cec5SDimitry Andric } 764349cc55cSDimitry Andric } 7650b57cec5SDimitry Andric 7660b57cec5SDimitry Andric { 7670b57cec5SDimitry Andric SmallVector<GuardWideningImpl::RangeCheck, 4> Checks, CombinedChecks; 7685f757f3fSDimitry Andric if (parseRangeChecks(ChecksToWiden, Checks) && 7695f757f3fSDimitry Andric parseRangeChecks(ChecksToHoist, Checks) && 7700b57cec5SDimitry Andric combineRangeChecks(Checks, CombinedChecks)) { 7710b57cec5SDimitry Andric if (InsertPt) { 7720b57cec5SDimitry Andric for (auto &RC : CombinedChecks) { 773*0fca6ea1SDimitry Andric makeAvailableAt(RC.getCheckInst(), *InsertPt); 7740b57cec5SDimitry Andric if (Result) 7750b57cec5SDimitry Andric Result = BinaryOperator::CreateAnd(RC.getCheckInst(), Result, "", 776*0fca6ea1SDimitry Andric *InsertPt); 7770b57cec5SDimitry Andric else 7780b57cec5SDimitry Andric Result = RC.getCheckInst(); 7790b57cec5SDimitry Andric } 7808bcb0991SDimitry Andric assert(Result && "Failed to find result value"); 7810b57cec5SDimitry Andric Result->setName("wide.chk"); 782*0fca6ea1SDimitry Andric Result = freezeAndPush(Result, *InsertPt); 7830b57cec5SDimitry Andric } 7845f757f3fSDimitry Andric return Result; 7850b57cec5SDimitry Andric } 7860b57cec5SDimitry Andric } 7875f757f3fSDimitry Andric // We were not able to compute ChecksToHoist AND ChecksToWiden for the price 7885f757f3fSDimitry Andric // of one. 7895f757f3fSDimitry Andric return std::nullopt; 7900b57cec5SDimitry Andric } 7910b57cec5SDimitry Andric 7925f757f3fSDimitry Andric Value *GuardWideningImpl::hoistChecks(SmallVectorImpl<Value *> &ChecksToHoist, 7935f757f3fSDimitry Andric Value *OldCondition, 794*0fca6ea1SDimitry Andric BasicBlock::iterator InsertPt) { 7955f757f3fSDimitry Andric assert(!ChecksToHoist.empty()); 796*0fca6ea1SDimitry Andric IRBuilder<> Builder(InsertPt->getParent(), InsertPt); 7975f757f3fSDimitry Andric makeAvailableAt(ChecksToHoist, InsertPt); 7985f757f3fSDimitry Andric makeAvailableAt(OldCondition, InsertPt); 7995f757f3fSDimitry Andric Value *Result = Builder.CreateAnd(ChecksToHoist); 8005f757f3fSDimitry Andric Result = freezeAndPush(Result, InsertPt); 8015f757f3fSDimitry Andric Result = Builder.CreateAnd(OldCondition, Result); 8025f757f3fSDimitry Andric Result->setName("wide.chk"); 8035f757f3fSDimitry Andric return Result; 8040b57cec5SDimitry Andric } 8050b57cec5SDimitry Andric 8060b57cec5SDimitry Andric bool GuardWideningImpl::parseRangeChecks( 8075f757f3fSDimitry Andric Value *CheckCond, SmallVectorImpl<GuardWideningImpl::RangeCheck> &Checks) { 8080b57cec5SDimitry Andric using namespace llvm::PatternMatch; 8090b57cec5SDimitry Andric 8100b57cec5SDimitry Andric auto *IC = dyn_cast<ICmpInst>(CheckCond); 8110b57cec5SDimitry Andric if (!IC || !IC->getOperand(0)->getType()->isIntegerTy() || 8120b57cec5SDimitry Andric (IC->getPredicate() != ICmpInst::ICMP_ULT && 8130b57cec5SDimitry Andric IC->getPredicate() != ICmpInst::ICMP_UGT)) 8140b57cec5SDimitry Andric return false; 8150b57cec5SDimitry Andric 8160b57cec5SDimitry Andric const Value *CmpLHS = IC->getOperand(0), *CmpRHS = IC->getOperand(1); 8170b57cec5SDimitry Andric if (IC->getPredicate() == ICmpInst::ICMP_UGT) 8180b57cec5SDimitry Andric std::swap(CmpLHS, CmpRHS); 8190b57cec5SDimitry Andric 820*0fca6ea1SDimitry Andric auto &DL = IC->getDataLayout(); 8210b57cec5SDimitry Andric 8220b57cec5SDimitry Andric GuardWideningImpl::RangeCheck Check( 8230b57cec5SDimitry Andric CmpLHS, cast<ConstantInt>(ConstantInt::getNullValue(CmpRHS->getType())), 8240b57cec5SDimitry Andric CmpRHS, IC); 8250b57cec5SDimitry Andric 8260b57cec5SDimitry Andric if (!isKnownNonNegative(Check.getLength(), DL)) 8270b57cec5SDimitry Andric return false; 8280b57cec5SDimitry Andric 8290b57cec5SDimitry Andric // What we have in \c Check now is a correct interpretation of \p CheckCond. 8300b57cec5SDimitry Andric // Try to see if we can move some constant offsets into the \c Offset field. 8310b57cec5SDimitry Andric 8320b57cec5SDimitry Andric bool Changed; 8330b57cec5SDimitry Andric auto &Ctx = CheckCond->getContext(); 8340b57cec5SDimitry Andric 8350b57cec5SDimitry Andric do { 8360b57cec5SDimitry Andric Value *OpLHS; 8370b57cec5SDimitry Andric ConstantInt *OpRHS; 8380b57cec5SDimitry Andric Changed = false; 8390b57cec5SDimitry Andric 8400b57cec5SDimitry Andric #ifndef NDEBUG 8410b57cec5SDimitry Andric auto *BaseInst = dyn_cast<Instruction>(Check.getBase()); 8420b57cec5SDimitry Andric assert((!BaseInst || DT.isReachableFromEntry(BaseInst->getParent())) && 8430b57cec5SDimitry Andric "Unreachable instruction?"); 8440b57cec5SDimitry Andric #endif 8450b57cec5SDimitry Andric 8460b57cec5SDimitry Andric if (match(Check.getBase(), m_Add(m_Value(OpLHS), m_ConstantInt(OpRHS)))) { 8470b57cec5SDimitry Andric Check.setBase(OpLHS); 8480b57cec5SDimitry Andric APInt NewOffset = Check.getOffsetValue() + OpRHS->getValue(); 8490b57cec5SDimitry Andric Check.setOffset(ConstantInt::get(Ctx, NewOffset)); 8500b57cec5SDimitry Andric Changed = true; 8510b57cec5SDimitry Andric } else if (match(Check.getBase(), 8520b57cec5SDimitry Andric m_Or(m_Value(OpLHS), m_ConstantInt(OpRHS)))) { 8530b57cec5SDimitry Andric KnownBits Known = computeKnownBits(OpLHS, DL); 8540b57cec5SDimitry Andric if ((OpRHS->getValue() & Known.Zero) == OpRHS->getValue()) { 8550b57cec5SDimitry Andric Check.setBase(OpLHS); 8560b57cec5SDimitry Andric APInt NewOffset = Check.getOffsetValue() + OpRHS->getValue(); 8570b57cec5SDimitry Andric Check.setOffset(ConstantInt::get(Ctx, NewOffset)); 8580b57cec5SDimitry Andric Changed = true; 8590b57cec5SDimitry Andric } 8600b57cec5SDimitry Andric } 8610b57cec5SDimitry Andric } while (Changed); 8620b57cec5SDimitry Andric 8630b57cec5SDimitry Andric Checks.push_back(Check); 8640b57cec5SDimitry Andric return true; 8650b57cec5SDimitry Andric } 8660b57cec5SDimitry Andric 8670b57cec5SDimitry Andric bool GuardWideningImpl::combineRangeChecks( 8680b57cec5SDimitry Andric SmallVectorImpl<GuardWideningImpl::RangeCheck> &Checks, 8690b57cec5SDimitry Andric SmallVectorImpl<GuardWideningImpl::RangeCheck> &RangeChecksOut) const { 8700b57cec5SDimitry Andric unsigned OldCount = Checks.size(); 8710b57cec5SDimitry Andric while (!Checks.empty()) { 8720b57cec5SDimitry Andric // Pick all of the range checks with a specific base and length, and try to 8730b57cec5SDimitry Andric // merge them. 8740b57cec5SDimitry Andric const Value *CurrentBase = Checks.front().getBase(); 8750b57cec5SDimitry Andric const Value *CurrentLength = Checks.front().getLength(); 8760b57cec5SDimitry Andric 8770b57cec5SDimitry Andric SmallVector<GuardWideningImpl::RangeCheck, 3> CurrentChecks; 8780b57cec5SDimitry Andric 8790b57cec5SDimitry Andric auto IsCurrentCheck = [&](GuardWideningImpl::RangeCheck &RC) { 8800b57cec5SDimitry Andric return RC.getBase() == CurrentBase && RC.getLength() == CurrentLength; 8810b57cec5SDimitry Andric }; 8820b57cec5SDimitry Andric 8830b57cec5SDimitry Andric copy_if(Checks, std::back_inserter(CurrentChecks), IsCurrentCheck); 884e8d8bef9SDimitry Andric erase_if(Checks, IsCurrentCheck); 8850b57cec5SDimitry Andric 8860b57cec5SDimitry Andric assert(CurrentChecks.size() != 0 && "We know we have at least one!"); 8870b57cec5SDimitry Andric 8880b57cec5SDimitry Andric if (CurrentChecks.size() < 3) { 889e8d8bef9SDimitry Andric llvm::append_range(RangeChecksOut, CurrentChecks); 8900b57cec5SDimitry Andric continue; 8910b57cec5SDimitry Andric } 8920b57cec5SDimitry Andric 8930b57cec5SDimitry Andric // CurrentChecks.size() will typically be 3 here, but so far there has been 8940b57cec5SDimitry Andric // no need to hard-code that fact. 8950b57cec5SDimitry Andric 8960b57cec5SDimitry Andric llvm::sort(CurrentChecks, [&](const GuardWideningImpl::RangeCheck &LHS, 8970b57cec5SDimitry Andric const GuardWideningImpl::RangeCheck &RHS) { 8980b57cec5SDimitry Andric return LHS.getOffsetValue().slt(RHS.getOffsetValue()); 8990b57cec5SDimitry Andric }); 9000b57cec5SDimitry Andric 9010b57cec5SDimitry Andric // Note: std::sort should not invalidate the ChecksStart iterator. 9020b57cec5SDimitry Andric 9030b57cec5SDimitry Andric const ConstantInt *MinOffset = CurrentChecks.front().getOffset(); 9040b57cec5SDimitry Andric const ConstantInt *MaxOffset = CurrentChecks.back().getOffset(); 9050b57cec5SDimitry Andric 9060b57cec5SDimitry Andric unsigned BitWidth = MaxOffset->getValue().getBitWidth(); 9070b57cec5SDimitry Andric if ((MaxOffset->getValue() - MinOffset->getValue()) 9080b57cec5SDimitry Andric .ugt(APInt::getSignedMinValue(BitWidth))) 9090b57cec5SDimitry Andric return false; 9100b57cec5SDimitry Andric 9110b57cec5SDimitry Andric APInt MaxDiff = MaxOffset->getValue() - MinOffset->getValue(); 9120b57cec5SDimitry Andric const APInt &HighOffset = MaxOffset->getValue(); 9130b57cec5SDimitry Andric auto OffsetOK = [&](const GuardWideningImpl::RangeCheck &RC) { 9140b57cec5SDimitry Andric return (HighOffset - RC.getOffsetValue()).ult(MaxDiff); 9150b57cec5SDimitry Andric }; 9160b57cec5SDimitry Andric 917e8d8bef9SDimitry Andric if (MaxDiff.isMinValue() || !all_of(drop_begin(CurrentChecks), OffsetOK)) 9180b57cec5SDimitry Andric return false; 9190b57cec5SDimitry Andric 9200b57cec5SDimitry Andric // We have a series of f+1 checks as: 9210b57cec5SDimitry Andric // 9220b57cec5SDimitry Andric // I+k_0 u< L ... Chk_0 9230b57cec5SDimitry Andric // I+k_1 u< L ... Chk_1 9240b57cec5SDimitry Andric // ... 9250b57cec5SDimitry Andric // I+k_f u< L ... Chk_f 9260b57cec5SDimitry Andric // 9270b57cec5SDimitry Andric // with forall i in [0,f]: k_f-k_i u< k_f-k_0 ... Precond_0 9280b57cec5SDimitry Andric // k_f-k_0 u< INT_MIN+k_f ... Precond_1 9290b57cec5SDimitry Andric // k_f != k_0 ... Precond_2 9300b57cec5SDimitry Andric // 9310b57cec5SDimitry Andric // Claim: 9320b57cec5SDimitry Andric // Chk_0 AND Chk_f implies all the other checks 9330b57cec5SDimitry Andric // 9340b57cec5SDimitry Andric // Informal proof sketch: 9350b57cec5SDimitry Andric // 9360b57cec5SDimitry Andric // We will show that the integer range [I+k_0,I+k_f] does not unsigned-wrap 9370b57cec5SDimitry Andric // (i.e. going from I+k_0 to I+k_f does not cross the -1,0 boundary) and 9380b57cec5SDimitry Andric // thus I+k_f is the greatest unsigned value in that range. 9390b57cec5SDimitry Andric // 9400b57cec5SDimitry Andric // This combined with Ckh_(f+1) shows that everything in that range is u< L. 9410b57cec5SDimitry Andric // Via Precond_0 we know that all of the indices in Chk_0 through Chk_(f+1) 9420b57cec5SDimitry Andric // lie in [I+k_0,I+k_f], this proving our claim. 9430b57cec5SDimitry Andric // 9440b57cec5SDimitry Andric // To see that [I+k_0,I+k_f] is not a wrapping range, note that there are 9450b57cec5SDimitry Andric // two possibilities: I+k_0 u< I+k_f or I+k_0 >u I+k_f (they can't be equal 9460b57cec5SDimitry Andric // since k_0 != k_f). In the former case, [I+k_0,I+k_f] is not a wrapping 9470b57cec5SDimitry Andric // range by definition, and the latter case is impossible: 9480b57cec5SDimitry Andric // 9490b57cec5SDimitry Andric // 0-----I+k_f---I+k_0----L---INT_MAX,INT_MIN------------------(-1) 9500b57cec5SDimitry Andric // xxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 9510b57cec5SDimitry Andric // 9520b57cec5SDimitry Andric // For Chk_0 to succeed, we'd have to have k_f-k_0 (the range highlighted 9530b57cec5SDimitry Andric // with 'x' above) to be at least >u INT_MIN. 9540b57cec5SDimitry Andric 9550b57cec5SDimitry Andric RangeChecksOut.emplace_back(CurrentChecks.front()); 9560b57cec5SDimitry Andric RangeChecksOut.emplace_back(CurrentChecks.back()); 9570b57cec5SDimitry Andric } 9580b57cec5SDimitry Andric 9590b57cec5SDimitry Andric assert(RangeChecksOut.size() <= OldCount && "We pessimized!"); 9600b57cec5SDimitry Andric return RangeChecksOut.size() != OldCount; 9610b57cec5SDimitry Andric } 9620b57cec5SDimitry Andric 9630b57cec5SDimitry Andric #ifndef NDEBUG 9640b57cec5SDimitry Andric StringRef GuardWideningImpl::scoreTypeToString(WideningScore WS) { 9650b57cec5SDimitry Andric switch (WS) { 9660b57cec5SDimitry Andric case WS_IllegalOrNegative: 9670b57cec5SDimitry Andric return "IllegalOrNegative"; 9680b57cec5SDimitry Andric case WS_Neutral: 9690b57cec5SDimitry Andric return "Neutral"; 9700b57cec5SDimitry Andric case WS_Positive: 9710b57cec5SDimitry Andric return "Positive"; 9720b57cec5SDimitry Andric case WS_VeryPositive: 9730b57cec5SDimitry Andric return "VeryPositive"; 9740b57cec5SDimitry Andric } 9750b57cec5SDimitry Andric 9760b57cec5SDimitry Andric llvm_unreachable("Fully covered switch above!"); 9770b57cec5SDimitry Andric } 9780b57cec5SDimitry Andric #endif 9790b57cec5SDimitry Andric 9800b57cec5SDimitry Andric PreservedAnalyses GuardWideningPass::run(Function &F, 9810b57cec5SDimitry Andric FunctionAnalysisManager &AM) { 9825f757f3fSDimitry Andric // Avoid requesting analyses if there are no guards or widenable conditions. 9835f757f3fSDimitry Andric auto *GuardDecl = F.getParent()->getFunction( 9845f757f3fSDimitry Andric Intrinsic::getName(Intrinsic::experimental_guard)); 9855f757f3fSDimitry Andric bool HasIntrinsicGuards = GuardDecl && !GuardDecl->use_empty(); 9865f757f3fSDimitry Andric auto *WCDecl = F.getParent()->getFunction( 9875f757f3fSDimitry Andric Intrinsic::getName(Intrinsic::experimental_widenable_condition)); 9885f757f3fSDimitry Andric bool HasWidenableConditions = WCDecl && !WCDecl->use_empty(); 9895f757f3fSDimitry Andric if (!HasIntrinsicGuards && !HasWidenableConditions) 9905f757f3fSDimitry Andric return PreservedAnalyses::all(); 9910b57cec5SDimitry Andric auto &DT = AM.getResult<DominatorTreeAnalysis>(F); 9920b57cec5SDimitry Andric auto &LI = AM.getResult<LoopAnalysis>(F); 9930b57cec5SDimitry Andric auto &PDT = AM.getResult<PostDominatorTreeAnalysis>(F); 994bdd1243dSDimitry Andric auto &AC = AM.getResult<AssumptionAnalysis>(F); 995349cc55cSDimitry Andric auto *MSSAA = AM.getCachedResult<MemorySSAAnalysis>(F); 996349cc55cSDimitry Andric std::unique_ptr<MemorySSAUpdater> MSSAU; 997349cc55cSDimitry Andric if (MSSAA) 998349cc55cSDimitry Andric MSSAU = std::make_unique<MemorySSAUpdater>(&MSSAA->getMSSA()); 999bdd1243dSDimitry Andric if (!GuardWideningImpl(DT, &PDT, LI, AC, MSSAU ? MSSAU.get() : nullptr, 1000349cc55cSDimitry Andric DT.getRootNode(), [](BasicBlock *) { return true; }) 1001349cc55cSDimitry Andric .run()) 10020b57cec5SDimitry Andric return PreservedAnalyses::all(); 10030b57cec5SDimitry Andric 10040b57cec5SDimitry Andric PreservedAnalyses PA; 10050b57cec5SDimitry Andric PA.preserveSet<CFGAnalyses>(); 1006349cc55cSDimitry Andric PA.preserve<MemorySSAAnalysis>(); 10070b57cec5SDimitry Andric return PA; 10080b57cec5SDimitry Andric } 10090b57cec5SDimitry Andric 10100b57cec5SDimitry Andric PreservedAnalyses GuardWideningPass::run(Loop &L, LoopAnalysisManager &AM, 10110b57cec5SDimitry Andric LoopStandardAnalysisResults &AR, 10120b57cec5SDimitry Andric LPMUpdater &U) { 10130b57cec5SDimitry Andric BasicBlock *RootBB = L.getLoopPredecessor(); 10140b57cec5SDimitry Andric if (!RootBB) 10150b57cec5SDimitry Andric RootBB = L.getHeader(); 10160b57cec5SDimitry Andric auto BlockFilter = [&](BasicBlock *BB) { 10170b57cec5SDimitry Andric return BB == RootBB || L.contains(BB); 10180b57cec5SDimitry Andric }; 1019349cc55cSDimitry Andric std::unique_ptr<MemorySSAUpdater> MSSAU; 1020349cc55cSDimitry Andric if (AR.MSSA) 1021349cc55cSDimitry Andric MSSAU = std::make_unique<MemorySSAUpdater>(AR.MSSA); 1022bdd1243dSDimitry Andric if (!GuardWideningImpl(AR.DT, nullptr, AR.LI, AR.AC, 1023bdd1243dSDimitry Andric MSSAU ? MSSAU.get() : nullptr, AR.DT.getNode(RootBB), 1024bdd1243dSDimitry Andric BlockFilter) 1025bdd1243dSDimitry Andric .run()) 10260b57cec5SDimitry Andric return PreservedAnalyses::all(); 10270b57cec5SDimitry Andric 1028349cc55cSDimitry Andric auto PA = getLoopPassPreservedAnalyses(); 1029349cc55cSDimitry Andric if (AR.MSSA) 1030349cc55cSDimitry Andric PA.preserve<MemorySSAAnalysis>(); 1031349cc55cSDimitry Andric return PA; 10320b57cec5SDimitry Andric } 1033