1*0b57cec5SDimitry Andric //===- StackSafetyAnalysis.cpp - Stack memory safety analysis -------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 10*0b57cec5SDimitry Andric 11*0b57cec5SDimitry Andric #include "llvm/Analysis/StackSafetyAnalysis.h" 125ffd83dbSDimitry Andric #include "llvm/ADT/APInt.h" 135ffd83dbSDimitry Andric #include "llvm/ADT/SmallPtrSet.h" 145ffd83dbSDimitry Andric #include "llvm/ADT/SmallVector.h" 155ffd83dbSDimitry Andric #include "llvm/ADT/Statistic.h" 165ffd83dbSDimitry Andric #include "llvm/Analysis/ModuleSummaryAnalysis.h" 174824e7fdSDimitry Andric #include "llvm/Analysis/ScalarEvolution.h" 18*0b57cec5SDimitry Andric #include "llvm/Analysis/ScalarEvolutionExpressions.h" 195ffd83dbSDimitry Andric #include "llvm/Analysis/StackLifetime.h" 205ffd83dbSDimitry Andric #include "llvm/IR/ConstantRange.h" 215ffd83dbSDimitry Andric #include "llvm/IR/DerivedTypes.h" 225ffd83dbSDimitry Andric #include "llvm/IR/GlobalValue.h" 23*0b57cec5SDimitry Andric #include "llvm/IR/InstIterator.h" 244824e7fdSDimitry Andric #include "llvm/IR/Instruction.h" 255ffd83dbSDimitry Andric #include "llvm/IR/Instructions.h" 26*0b57cec5SDimitry Andric #include "llvm/IR/IntrinsicInst.h" 27e8d8bef9SDimitry Andric #include "llvm/IR/ModuleSummaryIndex.h" 28480093f4SDimitry Andric #include "llvm/InitializePasses.h" 295ffd83dbSDimitry Andric #include "llvm/Support/Casting.h" 30480093f4SDimitry Andric #include "llvm/Support/CommandLine.h" 315ffd83dbSDimitry Andric #include "llvm/Support/FormatVariadic.h" 32*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 335ffd83dbSDimitry Andric #include <algorithm> 345ffd83dbSDimitry Andric #include <memory> 35349cc55cSDimitry Andric #include <tuple> 36*0b57cec5SDimitry Andric 37*0b57cec5SDimitry Andric using namespace llvm; 38*0b57cec5SDimitry Andric 39*0b57cec5SDimitry Andric #define DEBUG_TYPE "stack-safety" 40*0b57cec5SDimitry Andric 415ffd83dbSDimitry Andric STATISTIC(NumAllocaStackSafe, "Number of safe allocas"); 425ffd83dbSDimitry Andric STATISTIC(NumAllocaTotal, "Number of total allocas"); 435ffd83dbSDimitry Andric 44e8d8bef9SDimitry Andric STATISTIC(NumCombinedCalleeLookupTotal, 45e8d8bef9SDimitry Andric "Number of total callee lookups on combined index."); 46e8d8bef9SDimitry Andric STATISTIC(NumCombinedCalleeLookupFailed, 47e8d8bef9SDimitry Andric "Number of failed callee lookups on combined index."); 48e8d8bef9SDimitry Andric STATISTIC(NumModuleCalleeLookupTotal, 49e8d8bef9SDimitry Andric "Number of total callee lookups on module index."); 50e8d8bef9SDimitry Andric STATISTIC(NumModuleCalleeLookupFailed, 51e8d8bef9SDimitry Andric "Number of failed callee lookups on module index."); 52e8d8bef9SDimitry Andric STATISTIC(NumCombinedParamAccessesBefore, 53e8d8bef9SDimitry Andric "Number of total param accesses before generateParamAccessSummary."); 54e8d8bef9SDimitry Andric STATISTIC(NumCombinedParamAccessesAfter, 55e8d8bef9SDimitry Andric "Number of total param accesses after generateParamAccessSummary."); 56e8d8bef9SDimitry Andric STATISTIC(NumCombinedDataFlowNodes, 57e8d8bef9SDimitry Andric "Number of total nodes in combined index for dataflow processing."); 58e8d8bef9SDimitry Andric STATISTIC(NumIndexCalleeUnhandled, "Number of index callee which are unhandled."); 59e8d8bef9SDimitry Andric STATISTIC(NumIndexCalleeMultipleWeak, "Number of index callee non-unique weak."); 60e8d8bef9SDimitry Andric STATISTIC(NumIndexCalleeMultipleExternal, "Number of index callee non-unique external."); 61e8d8bef9SDimitry Andric 62e8d8bef9SDimitry Andric 63*0b57cec5SDimitry Andric static cl::opt<int> StackSafetyMaxIterations("stack-safety-max-iterations", 64*0b57cec5SDimitry Andric cl::init(20), cl::Hidden); 65*0b57cec5SDimitry Andric 665ffd83dbSDimitry Andric static cl::opt<bool> StackSafetyPrint("stack-safety-print", cl::init(false), 675ffd83dbSDimitry Andric cl::Hidden); 685ffd83dbSDimitry Andric 695ffd83dbSDimitry Andric static cl::opt<bool> StackSafetyRun("stack-safety-run", cl::init(false), 705ffd83dbSDimitry Andric cl::Hidden); 715ffd83dbSDimitry Andric 72*0b57cec5SDimitry Andric namespace { 73*0b57cec5SDimitry Andric 74e8d8bef9SDimitry Andric // Check if we should bailout for such ranges. 75e8d8bef9SDimitry Andric bool isUnsafe(const ConstantRange &R) { 76e8d8bef9SDimitry Andric return R.isEmptySet() || R.isFullSet() || R.isUpperSignWrapped(); 77e8d8bef9SDimitry Andric } 78e8d8bef9SDimitry Andric 79e8d8bef9SDimitry Andric ConstantRange addOverflowNever(const ConstantRange &L, const ConstantRange &R) { 80e8d8bef9SDimitry Andric assert(!L.isSignWrappedSet()); 81e8d8bef9SDimitry Andric assert(!R.isSignWrappedSet()); 82e8d8bef9SDimitry Andric if (L.signedAddMayOverflow(R) != 83e8d8bef9SDimitry Andric ConstantRange::OverflowResult::NeverOverflows) 84e8d8bef9SDimitry Andric return ConstantRange::getFull(L.getBitWidth()); 85e8d8bef9SDimitry Andric ConstantRange Result = L.add(R); 86e8d8bef9SDimitry Andric assert(!Result.isSignWrappedSet()); 87e8d8bef9SDimitry Andric return Result; 88e8d8bef9SDimitry Andric } 89e8d8bef9SDimitry Andric 90e8d8bef9SDimitry Andric ConstantRange unionNoWrap(const ConstantRange &L, const ConstantRange &R) { 91e8d8bef9SDimitry Andric assert(!L.isSignWrappedSet()); 92e8d8bef9SDimitry Andric assert(!R.isSignWrappedSet()); 93e8d8bef9SDimitry Andric auto Result = L.unionWith(R); 94e8d8bef9SDimitry Andric // Two non-wrapped sets can produce wrapped. 95e8d8bef9SDimitry Andric if (Result.isSignWrappedSet()) 96e8d8bef9SDimitry Andric Result = ConstantRange::getFull(Result.getBitWidth()); 97e8d8bef9SDimitry Andric return Result; 98e8d8bef9SDimitry Andric } 99e8d8bef9SDimitry Andric 100*0b57cec5SDimitry Andric /// Describes use of address in as a function call argument. 1015ffd83dbSDimitry Andric template <typename CalleeTy> struct CallInfo { 102*0b57cec5SDimitry Andric /// Function being called. 1035ffd83dbSDimitry Andric const CalleeTy *Callee = nullptr; 104*0b57cec5SDimitry Andric /// Index of argument which pass address. 105*0b57cec5SDimitry Andric size_t ParamNo = 0; 106*0b57cec5SDimitry Andric 107e8d8bef9SDimitry Andric CallInfo(const CalleeTy *Callee, size_t ParamNo) 108e8d8bef9SDimitry Andric : Callee(Callee), ParamNo(ParamNo) {} 109e8d8bef9SDimitry Andric 110e8d8bef9SDimitry Andric struct Less { 111e8d8bef9SDimitry Andric bool operator()(const CallInfo &L, const CallInfo &R) const { 112e8d8bef9SDimitry Andric return std::tie(L.ParamNo, L.Callee) < std::tie(R.ParamNo, R.Callee); 113*0b57cec5SDimitry Andric } 114e8d8bef9SDimitry Andric }; 115e8d8bef9SDimitry Andric }; 116*0b57cec5SDimitry Andric 117*0b57cec5SDimitry Andric /// Describe uses of address (alloca or parameter) inside of the function. 1185ffd83dbSDimitry Andric template <typename CalleeTy> struct UseInfo { 119*0b57cec5SDimitry Andric // Access range if the address (alloca or parameters). 120*0b57cec5SDimitry Andric // It is allowed to be empty-set when there are no known accesses. 121*0b57cec5SDimitry Andric ConstantRange Range; 1224824e7fdSDimitry Andric std::set<const Instruction *> UnsafeAccesses; 123*0b57cec5SDimitry Andric 124*0b57cec5SDimitry Andric // List of calls which pass address as an argument. 125e8d8bef9SDimitry Andric // Value is offset range of address from base address (alloca or calling 126e8d8bef9SDimitry Andric // function argument). Range should never set to empty-set, that is an invalid 127e8d8bef9SDimitry Andric // access range that can cause empty-set to be propagated with 128e8d8bef9SDimitry Andric // ConstantRange::add 129e8d8bef9SDimitry Andric using CallsTy = std::map<CallInfo<CalleeTy>, ConstantRange, 130e8d8bef9SDimitry Andric typename CallInfo<CalleeTy>::Less>; 131e8d8bef9SDimitry Andric CallsTy Calls; 132*0b57cec5SDimitry Andric 1335ffd83dbSDimitry Andric UseInfo(unsigned PointerSize) : Range{PointerSize, false} {} 134*0b57cec5SDimitry Andric 135e8d8bef9SDimitry Andric void updateRange(const ConstantRange &R) { Range = unionNoWrap(Range, R); } 1364824e7fdSDimitry Andric void addRange(const Instruction *I, const ConstantRange &R, bool IsSafe) { 1374824e7fdSDimitry Andric if (!IsSafe) 1384824e7fdSDimitry Andric UnsafeAccesses.insert(I); 139349cc55cSDimitry Andric updateRange(R); 140349cc55cSDimitry Andric } 141*0b57cec5SDimitry Andric }; 142*0b57cec5SDimitry Andric 1435ffd83dbSDimitry Andric template <typename CalleeTy> 1445ffd83dbSDimitry Andric raw_ostream &operator<<(raw_ostream &OS, const UseInfo<CalleeTy> &U) { 145*0b57cec5SDimitry Andric OS << U.Range; 146*0b57cec5SDimitry Andric for (auto &Call : U.Calls) 147e8d8bef9SDimitry Andric OS << ", " 148e8d8bef9SDimitry Andric << "@" << Call.first.Callee->getName() << "(arg" << Call.first.ParamNo 149e8d8bef9SDimitry Andric << ", " << Call.second << ")"; 150*0b57cec5SDimitry Andric return OS; 151*0b57cec5SDimitry Andric } 152*0b57cec5SDimitry Andric 1535ffd83dbSDimitry Andric /// Calculate the allocation size of a given alloca. Returns empty range 1545ffd83dbSDimitry Andric // in case of confution. 1555ffd83dbSDimitry Andric ConstantRange getStaticAllocaSizeRange(const AllocaInst &AI) { 1565ffd83dbSDimitry Andric const DataLayout &DL = AI.getModule()->getDataLayout(); 1575ffd83dbSDimitry Andric TypeSize TS = DL.getTypeAllocSize(AI.getAllocatedType()); 158349cc55cSDimitry Andric unsigned PointerSize = DL.getPointerTypeSizeInBits(AI.getType()); 1595ffd83dbSDimitry Andric // Fallback to empty range for alloca size. 1605ffd83dbSDimitry Andric ConstantRange R = ConstantRange::getEmpty(PointerSize); 1615ffd83dbSDimitry Andric if (TS.isScalable()) 1625ffd83dbSDimitry Andric return R; 1635ffd83dbSDimitry Andric APInt APSize(PointerSize, TS.getFixedSize(), true); 1645ffd83dbSDimitry Andric if (APSize.isNonPositive()) 1655ffd83dbSDimitry Andric return R; 1665ffd83dbSDimitry Andric if (AI.isArrayAllocation()) { 1675ffd83dbSDimitry Andric const auto *C = dyn_cast<ConstantInt>(AI.getArraySize()); 168*0b57cec5SDimitry Andric if (!C) 1695ffd83dbSDimitry Andric return R; 1705ffd83dbSDimitry Andric bool Overflow = false; 1715ffd83dbSDimitry Andric APInt Mul = C->getValue(); 1725ffd83dbSDimitry Andric if (Mul.isNonPositive()) 1735ffd83dbSDimitry Andric return R; 1745ffd83dbSDimitry Andric Mul = Mul.sextOrTrunc(PointerSize); 1755ffd83dbSDimitry Andric APSize = APSize.smul_ov(Mul, Overflow); 1765ffd83dbSDimitry Andric if (Overflow) 1775ffd83dbSDimitry Andric return R; 178*0b57cec5SDimitry Andric } 179349cc55cSDimitry Andric R = ConstantRange(APInt::getZero(PointerSize), APSize); 1805ffd83dbSDimitry Andric assert(!isUnsafe(R)); 1815ffd83dbSDimitry Andric return R; 182*0b57cec5SDimitry Andric } 183*0b57cec5SDimitry Andric 1845ffd83dbSDimitry Andric template <typename CalleeTy> struct FunctionInfo { 1855ffd83dbSDimitry Andric std::map<const AllocaInst *, UseInfo<CalleeTy>> Allocas; 1865ffd83dbSDimitry Andric std::map<uint32_t, UseInfo<CalleeTy>> Params; 187*0b57cec5SDimitry Andric // TODO: describe return value as depending on one or more of its arguments. 188*0b57cec5SDimitry Andric 189*0b57cec5SDimitry Andric // StackSafetyDataFlowAnalysis counter stored here for faster access. 190*0b57cec5SDimitry Andric int UpdateCount = 0; 191*0b57cec5SDimitry Andric 1925ffd83dbSDimitry Andric void print(raw_ostream &O, StringRef Name, const Function *F) const { 193*0b57cec5SDimitry Andric // TODO: Consider different printout format after 194*0b57cec5SDimitry Andric // StackSafetyDataFlowAnalysis. Calls and parameters are irrelevant then. 1955ffd83dbSDimitry Andric O << " @" << Name << ((F && F->isDSOLocal()) ? "" : " dso_preemptable") 1965ffd83dbSDimitry Andric << ((F && F->isInterposable()) ? " interposable" : "") << "\n"; 1975ffd83dbSDimitry Andric 198*0b57cec5SDimitry Andric O << " args uses:\n"; 1995ffd83dbSDimitry Andric for (auto &KV : Params) { 2005ffd83dbSDimitry Andric O << " "; 2015ffd83dbSDimitry Andric if (F) 2025ffd83dbSDimitry Andric O << F->getArg(KV.first)->getName(); 2035ffd83dbSDimitry Andric else 2045ffd83dbSDimitry Andric O << formatv("arg{0}", KV.first); 2055ffd83dbSDimitry Andric O << "[]: " << KV.second << "\n"; 206*0b57cec5SDimitry Andric } 207*0b57cec5SDimitry Andric 2085ffd83dbSDimitry Andric O << " allocas uses:\n"; 2095ffd83dbSDimitry Andric if (F) { 2105ffd83dbSDimitry Andric for (auto &I : instructions(F)) { 2115ffd83dbSDimitry Andric if (const AllocaInst *AI = dyn_cast<AllocaInst>(&I)) { 2125ffd83dbSDimitry Andric auto &AS = Allocas.find(AI)->second; 2135ffd83dbSDimitry Andric O << " " << AI->getName() << "[" 2145ffd83dbSDimitry Andric << getStaticAllocaSizeRange(*AI).getUpper() << "]: " << AS << "\n"; 2155ffd83dbSDimitry Andric } 2165ffd83dbSDimitry Andric } 2175ffd83dbSDimitry Andric } else { 2185ffd83dbSDimitry Andric assert(Allocas.empty()); 2195ffd83dbSDimitry Andric } 2205ffd83dbSDimitry Andric } 221*0b57cec5SDimitry Andric }; 222*0b57cec5SDimitry Andric 2235ffd83dbSDimitry Andric using GVToSSI = std::map<const GlobalValue *, FunctionInfo<GlobalValue>>; 2245ffd83dbSDimitry Andric 2255ffd83dbSDimitry Andric } // namespace 2265ffd83dbSDimitry Andric 2275ffd83dbSDimitry Andric struct StackSafetyInfo::InfoTy { 2285ffd83dbSDimitry Andric FunctionInfo<GlobalValue> Info; 2295ffd83dbSDimitry Andric }; 2305ffd83dbSDimitry Andric 2315ffd83dbSDimitry Andric struct StackSafetyGlobalInfo::InfoTy { 2325ffd83dbSDimitry Andric GVToSSI Info; 2335ffd83dbSDimitry Andric SmallPtrSet<const AllocaInst *, 8> SafeAllocas; 2344824e7fdSDimitry Andric std::set<const Instruction *> UnsafeAccesses; 2355ffd83dbSDimitry Andric }; 236*0b57cec5SDimitry Andric 237*0b57cec5SDimitry Andric namespace { 238*0b57cec5SDimitry Andric 239*0b57cec5SDimitry Andric class StackSafetyLocalAnalysis { 2405ffd83dbSDimitry Andric Function &F; 241*0b57cec5SDimitry Andric const DataLayout &DL; 242*0b57cec5SDimitry Andric ScalarEvolution &SE; 243*0b57cec5SDimitry Andric unsigned PointerSize = 0; 244*0b57cec5SDimitry Andric 245*0b57cec5SDimitry Andric const ConstantRange UnknownRange; 246*0b57cec5SDimitry Andric 2475ffd83dbSDimitry Andric ConstantRange offsetFrom(Value *Addr, Value *Base); 2485ffd83dbSDimitry Andric ConstantRange getAccessRange(Value *Addr, Value *Base, 2495ffd83dbSDimitry Andric const ConstantRange &SizeRange); 2505ffd83dbSDimitry Andric ConstantRange getAccessRange(Value *Addr, Value *Base, TypeSize Size); 251*0b57cec5SDimitry Andric ConstantRange getMemIntrinsicAccessRange(const MemIntrinsic *MI, const Use &U, 2525ffd83dbSDimitry Andric Value *Base); 253*0b57cec5SDimitry Andric 254349cc55cSDimitry Andric void analyzeAllUses(Value *Ptr, UseInfo<GlobalValue> &AS, 2555ffd83dbSDimitry Andric const StackLifetime &SL); 256*0b57cec5SDimitry Andric 2574824e7fdSDimitry Andric 2584824e7fdSDimitry Andric bool isSafeAccess(const Use &U, AllocaInst *AI, const SCEV *AccessSize); 2594824e7fdSDimitry Andric bool isSafeAccess(const Use &U, AllocaInst *AI, Value *V); 2604824e7fdSDimitry Andric bool isSafeAccess(const Use &U, AllocaInst *AI, TypeSize AccessSize); 2614824e7fdSDimitry Andric 262*0b57cec5SDimitry Andric public: 2635ffd83dbSDimitry Andric StackSafetyLocalAnalysis(Function &F, ScalarEvolution &SE) 264*0b57cec5SDimitry Andric : F(F), DL(F.getParent()->getDataLayout()), SE(SE), 265*0b57cec5SDimitry Andric PointerSize(DL.getPointerSizeInBits()), 266*0b57cec5SDimitry Andric UnknownRange(PointerSize, true) {} 267*0b57cec5SDimitry Andric 268*0b57cec5SDimitry Andric // Run the transformation on the associated function. 2695ffd83dbSDimitry Andric FunctionInfo<GlobalValue> run(); 270*0b57cec5SDimitry Andric }; 271*0b57cec5SDimitry Andric 2725ffd83dbSDimitry Andric ConstantRange StackSafetyLocalAnalysis::offsetFrom(Value *Addr, Value *Base) { 2735ffd83dbSDimitry Andric if (!SE.isSCEVable(Addr->getType()) || !SE.isSCEVable(Base->getType())) 274*0b57cec5SDimitry Andric return UnknownRange; 275*0b57cec5SDimitry Andric 2765ffd83dbSDimitry Andric auto *PtrTy = IntegerType::getInt8PtrTy(SE.getContext()); 2775ffd83dbSDimitry Andric const SCEV *AddrExp = SE.getTruncateOrZeroExtend(SE.getSCEV(Addr), PtrTy); 2785ffd83dbSDimitry Andric const SCEV *BaseExp = SE.getTruncateOrZeroExtend(SE.getSCEV(Base), PtrTy); 2795ffd83dbSDimitry Andric const SCEV *Diff = SE.getMinusSCEV(AddrExp, BaseExp); 280fe6060f1SDimitry Andric if (isa<SCEVCouldNotCompute>(Diff)) 281fe6060f1SDimitry Andric return UnknownRange; 2825ffd83dbSDimitry Andric 2835ffd83dbSDimitry Andric ConstantRange Offset = SE.getSignedRange(Diff); 2845ffd83dbSDimitry Andric if (isUnsafe(Offset)) 2855ffd83dbSDimitry Andric return UnknownRange; 2865ffd83dbSDimitry Andric return Offset.sextOrTrunc(PointerSize); 287*0b57cec5SDimitry Andric } 288*0b57cec5SDimitry Andric 2895ffd83dbSDimitry Andric ConstantRange 2905ffd83dbSDimitry Andric StackSafetyLocalAnalysis::getAccessRange(Value *Addr, Value *Base, 2915ffd83dbSDimitry Andric const ConstantRange &SizeRange) { 2925ffd83dbSDimitry Andric // Zero-size loads and stores do not access memory. 2935ffd83dbSDimitry Andric if (SizeRange.isEmptySet()) 2945ffd83dbSDimitry Andric return ConstantRange::getEmpty(PointerSize); 2955ffd83dbSDimitry Andric assert(!isUnsafe(SizeRange)); 2965ffd83dbSDimitry Andric 2975ffd83dbSDimitry Andric ConstantRange Offsets = offsetFrom(Addr, Base); 2985ffd83dbSDimitry Andric if (isUnsafe(Offsets)) 299*0b57cec5SDimitry Andric return UnknownRange; 300*0b57cec5SDimitry Andric 3015ffd83dbSDimitry Andric Offsets = addOverflowNever(Offsets, SizeRange); 3025ffd83dbSDimitry Andric if (isUnsafe(Offsets)) 3035ffd83dbSDimitry Andric return UnknownRange; 3045ffd83dbSDimitry Andric return Offsets; 3055ffd83dbSDimitry Andric } 306*0b57cec5SDimitry Andric 3075ffd83dbSDimitry Andric ConstantRange StackSafetyLocalAnalysis::getAccessRange(Value *Addr, Value *Base, 3085ffd83dbSDimitry Andric TypeSize Size) { 3095ffd83dbSDimitry Andric if (Size.isScalable()) 3105ffd83dbSDimitry Andric return UnknownRange; 3115ffd83dbSDimitry Andric APInt APSize(PointerSize, Size.getFixedSize(), true); 3125ffd83dbSDimitry Andric if (APSize.isNegative()) 3135ffd83dbSDimitry Andric return UnknownRange; 314349cc55cSDimitry Andric return getAccessRange(Addr, Base, 315349cc55cSDimitry Andric ConstantRange(APInt::getZero(PointerSize), APSize)); 316*0b57cec5SDimitry Andric } 317*0b57cec5SDimitry Andric 318*0b57cec5SDimitry Andric ConstantRange StackSafetyLocalAnalysis::getMemIntrinsicAccessRange( 3195ffd83dbSDimitry Andric const MemIntrinsic *MI, const Use &U, Value *Base) { 3205ffd83dbSDimitry Andric if (const auto *MTI = dyn_cast<MemTransferInst>(MI)) { 321*0b57cec5SDimitry Andric if (MTI->getRawSource() != U && MTI->getRawDest() != U) 3225ffd83dbSDimitry Andric return ConstantRange::getEmpty(PointerSize); 323*0b57cec5SDimitry Andric } else { 324*0b57cec5SDimitry Andric if (MI->getRawDest() != U) 3255ffd83dbSDimitry Andric return ConstantRange::getEmpty(PointerSize); 326*0b57cec5SDimitry Andric } 3275ffd83dbSDimitry Andric 3285ffd83dbSDimitry Andric auto *CalculationTy = IntegerType::getIntNTy(SE.getContext(), PointerSize); 3295ffd83dbSDimitry Andric if (!SE.isSCEVable(MI->getLength()->getType())) 330*0b57cec5SDimitry Andric return UnknownRange; 3315ffd83dbSDimitry Andric 3325ffd83dbSDimitry Andric const SCEV *Expr = 3335ffd83dbSDimitry Andric SE.getTruncateOrZeroExtend(SE.getSCEV(MI->getLength()), CalculationTy); 3345ffd83dbSDimitry Andric ConstantRange Sizes = SE.getSignedRange(Expr); 3355ffd83dbSDimitry Andric if (Sizes.getUpper().isNegative() || isUnsafe(Sizes)) 3365ffd83dbSDimitry Andric return UnknownRange; 3375ffd83dbSDimitry Andric Sizes = Sizes.sextOrTrunc(PointerSize); 338349cc55cSDimitry Andric ConstantRange SizeRange(APInt::getZero(PointerSize), Sizes.getUpper() - 1); 3395ffd83dbSDimitry Andric return getAccessRange(U, Base, SizeRange); 340*0b57cec5SDimitry Andric } 341*0b57cec5SDimitry Andric 3424824e7fdSDimitry Andric bool StackSafetyLocalAnalysis::isSafeAccess(const Use &U, AllocaInst *AI, 3434824e7fdSDimitry Andric Value *V) { 3444824e7fdSDimitry Andric return isSafeAccess(U, AI, SE.getSCEV(V)); 3454824e7fdSDimitry Andric } 3464824e7fdSDimitry Andric 3474824e7fdSDimitry Andric bool StackSafetyLocalAnalysis::isSafeAccess(const Use &U, AllocaInst *AI, 3484824e7fdSDimitry Andric TypeSize TS) { 3494824e7fdSDimitry Andric if (TS.isScalable()) 3504824e7fdSDimitry Andric return false; 3514824e7fdSDimitry Andric auto *CalculationTy = IntegerType::getIntNTy(SE.getContext(), PointerSize); 3524824e7fdSDimitry Andric const SCEV *SV = SE.getConstant(CalculationTy, TS.getFixedSize()); 3534824e7fdSDimitry Andric return isSafeAccess(U, AI, SV); 3544824e7fdSDimitry Andric } 3554824e7fdSDimitry Andric 3564824e7fdSDimitry Andric bool StackSafetyLocalAnalysis::isSafeAccess(const Use &U, AllocaInst *AI, 3574824e7fdSDimitry Andric const SCEV *AccessSize) { 3584824e7fdSDimitry Andric 3594824e7fdSDimitry Andric if (!AI) 3604824e7fdSDimitry Andric return true; 3614824e7fdSDimitry Andric if (isa<SCEVCouldNotCompute>(AccessSize)) 3624824e7fdSDimitry Andric return false; 3634824e7fdSDimitry Andric 3644824e7fdSDimitry Andric const auto *I = cast<Instruction>(U.getUser()); 3654824e7fdSDimitry Andric 3664824e7fdSDimitry Andric auto ToCharPtr = [&](const SCEV *V) { 3674824e7fdSDimitry Andric auto *PtrTy = IntegerType::getInt8PtrTy(SE.getContext()); 3684824e7fdSDimitry Andric return SE.getTruncateOrZeroExtend(V, PtrTy); 3694824e7fdSDimitry Andric }; 3704824e7fdSDimitry Andric 3714824e7fdSDimitry Andric const SCEV *AddrExp = ToCharPtr(SE.getSCEV(U.get())); 3724824e7fdSDimitry Andric const SCEV *BaseExp = ToCharPtr(SE.getSCEV(AI)); 3734824e7fdSDimitry Andric const SCEV *Diff = SE.getMinusSCEV(AddrExp, BaseExp); 3744824e7fdSDimitry Andric if (isa<SCEVCouldNotCompute>(Diff)) 3754824e7fdSDimitry Andric return false; 3764824e7fdSDimitry Andric 3774824e7fdSDimitry Andric auto Size = getStaticAllocaSizeRange(*AI); 3784824e7fdSDimitry Andric 3794824e7fdSDimitry Andric auto *CalculationTy = IntegerType::getIntNTy(SE.getContext(), PointerSize); 3804824e7fdSDimitry Andric auto ToDiffTy = [&](const SCEV *V) { 3814824e7fdSDimitry Andric return SE.getTruncateOrZeroExtend(V, CalculationTy); 3824824e7fdSDimitry Andric }; 3834824e7fdSDimitry Andric const SCEV *Min = ToDiffTy(SE.getConstant(Size.getLower())); 3844824e7fdSDimitry Andric const SCEV *Max = SE.getMinusSCEV(ToDiffTy(SE.getConstant(Size.getUpper())), 3854824e7fdSDimitry Andric ToDiffTy(AccessSize)); 3864824e7fdSDimitry Andric return SE.evaluatePredicateAt(ICmpInst::Predicate::ICMP_SGE, Diff, Min, I) 3874824e7fdSDimitry Andric .getValueOr(false) && 3884824e7fdSDimitry Andric SE.evaluatePredicateAt(ICmpInst::Predicate::ICMP_SLE, Diff, Max, I) 3894824e7fdSDimitry Andric .getValueOr(false); 3904824e7fdSDimitry Andric } 3914824e7fdSDimitry Andric 392*0b57cec5SDimitry Andric /// The function analyzes all local uses of Ptr (alloca or argument) and 393*0b57cec5SDimitry Andric /// calculates local access range and all function calls where it was used. 394349cc55cSDimitry Andric void StackSafetyLocalAnalysis::analyzeAllUses(Value *Ptr, 3955ffd83dbSDimitry Andric UseInfo<GlobalValue> &US, 3965ffd83dbSDimitry Andric const StackLifetime &SL) { 397*0b57cec5SDimitry Andric SmallPtrSet<const Value *, 16> Visited; 398*0b57cec5SDimitry Andric SmallVector<const Value *, 8> WorkList; 399*0b57cec5SDimitry Andric WorkList.push_back(Ptr); 4004824e7fdSDimitry Andric AllocaInst *AI = dyn_cast<AllocaInst>(Ptr); 401*0b57cec5SDimitry Andric 402*0b57cec5SDimitry Andric // A DFS search through all uses of the alloca in bitcasts/PHI/GEPs/etc. 403*0b57cec5SDimitry Andric while (!WorkList.empty()) { 404*0b57cec5SDimitry Andric const Value *V = WorkList.pop_back_val(); 405*0b57cec5SDimitry Andric for (const Use &UI : V->uses()) { 4065ffd83dbSDimitry Andric const auto *I = cast<Instruction>(UI.getUser()); 4075ffd83dbSDimitry Andric if (!SL.isReachable(I)) 4085ffd83dbSDimitry Andric continue; 4095ffd83dbSDimitry Andric 410*0b57cec5SDimitry Andric assert(V == UI.get()); 411*0b57cec5SDimitry Andric 412*0b57cec5SDimitry Andric switch (I->getOpcode()) { 413*0b57cec5SDimitry Andric case Instruction::Load: { 4145ffd83dbSDimitry Andric if (AI && !SL.isAliveAfter(AI, I)) { 4154824e7fdSDimitry Andric US.addRange(I, UnknownRange, /*IsSafe=*/false); 416349cc55cSDimitry Andric break; 4175ffd83dbSDimitry Andric } 4184824e7fdSDimitry Andric auto TypeSize = DL.getTypeStoreSize(I->getType()); 4194824e7fdSDimitry Andric auto AccessRange = getAccessRange(UI, Ptr, TypeSize); 4204824e7fdSDimitry Andric bool Safe = isSafeAccess(UI, AI, TypeSize); 4214824e7fdSDimitry Andric US.addRange(I, AccessRange, Safe); 422*0b57cec5SDimitry Andric break; 423*0b57cec5SDimitry Andric } 424*0b57cec5SDimitry Andric 425*0b57cec5SDimitry Andric case Instruction::VAArg: 426*0b57cec5SDimitry Andric // "va-arg" from a pointer is safe. 427*0b57cec5SDimitry Andric break; 428*0b57cec5SDimitry Andric case Instruction::Store: { 429*0b57cec5SDimitry Andric if (V == I->getOperand(0)) { 430*0b57cec5SDimitry Andric // Stored the pointer - conservatively assume it may be unsafe. 4314824e7fdSDimitry Andric US.addRange(I, UnknownRange, /*IsSafe=*/false); 432349cc55cSDimitry Andric break; 433*0b57cec5SDimitry Andric } 4345ffd83dbSDimitry Andric if (AI && !SL.isAliveAfter(AI, I)) { 4354824e7fdSDimitry Andric US.addRange(I, UnknownRange, /*IsSafe=*/false); 436349cc55cSDimitry Andric break; 4375ffd83dbSDimitry Andric } 4384824e7fdSDimitry Andric auto TypeSize = DL.getTypeStoreSize(I->getOperand(0)->getType()); 4394824e7fdSDimitry Andric auto AccessRange = getAccessRange(UI, Ptr, TypeSize); 4404824e7fdSDimitry Andric bool Safe = isSafeAccess(UI, AI, TypeSize); 4414824e7fdSDimitry Andric US.addRange(I, AccessRange, Safe); 442*0b57cec5SDimitry Andric break; 443*0b57cec5SDimitry Andric } 444*0b57cec5SDimitry Andric 445*0b57cec5SDimitry Andric case Instruction::Ret: 446*0b57cec5SDimitry Andric // Information leak. 447*0b57cec5SDimitry Andric // FIXME: Process parameters correctly. This is a leak only if we return 448*0b57cec5SDimitry Andric // alloca. 4494824e7fdSDimitry Andric US.addRange(I, UnknownRange, /*IsSafe=*/false); 450349cc55cSDimitry Andric break; 451*0b57cec5SDimitry Andric 452*0b57cec5SDimitry Andric case Instruction::Call: 453*0b57cec5SDimitry Andric case Instruction::Invoke: { 454*0b57cec5SDimitry Andric if (I->isLifetimeStartOrEnd()) 455*0b57cec5SDimitry Andric break; 456*0b57cec5SDimitry Andric 4575ffd83dbSDimitry Andric if (AI && !SL.isAliveAfter(AI, I)) { 4584824e7fdSDimitry Andric US.addRange(I, UnknownRange, /*IsSafe=*/false); 459349cc55cSDimitry Andric break; 4605ffd83dbSDimitry Andric } 461*0b57cec5SDimitry Andric if (const MemIntrinsic *MI = dyn_cast<MemIntrinsic>(I)) { 4624824e7fdSDimitry Andric auto AccessRange = getMemIntrinsicAccessRange(MI, UI, Ptr); 4634824e7fdSDimitry Andric bool Safe = false; 4644824e7fdSDimitry Andric if (const auto *MTI = dyn_cast<MemTransferInst>(MI)) { 4654824e7fdSDimitry Andric if (MTI->getRawSource() != UI && MTI->getRawDest() != UI) 4664824e7fdSDimitry Andric Safe = true; 4674824e7fdSDimitry Andric } else if (MI->getRawDest() != UI) { 4684824e7fdSDimitry Andric Safe = true; 4694824e7fdSDimitry Andric } 4704824e7fdSDimitry Andric Safe = Safe || isSafeAccess(UI, AI, MI->getLength()); 4714824e7fdSDimitry Andric US.addRange(I, AccessRange, Safe); 472*0b57cec5SDimitry Andric break; 473*0b57cec5SDimitry Andric } 474*0b57cec5SDimitry Andric 4755ffd83dbSDimitry Andric const auto &CB = cast<CallBase>(*I); 476349cc55cSDimitry Andric if (CB.getReturnedArgOperand() == V) { 477349cc55cSDimitry Andric if (Visited.insert(I).second) 478349cc55cSDimitry Andric WorkList.push_back(cast<const Instruction>(I)); 479349cc55cSDimitry Andric } 480349cc55cSDimitry Andric 4815ffd83dbSDimitry Andric if (!CB.isArgOperand(&UI)) { 4824824e7fdSDimitry Andric US.addRange(I, UnknownRange, /*IsSafe=*/false); 483349cc55cSDimitry Andric break; 4845ffd83dbSDimitry Andric } 4855ffd83dbSDimitry Andric 4865ffd83dbSDimitry Andric unsigned ArgNo = CB.getArgOperandNo(&UI); 4875ffd83dbSDimitry Andric if (CB.isByValArgument(ArgNo)) { 4884824e7fdSDimitry Andric auto TypeSize = DL.getTypeStoreSize(CB.getParamByValType(ArgNo)); 4894824e7fdSDimitry Andric auto AccessRange = getAccessRange(UI, Ptr, TypeSize); 4904824e7fdSDimitry Andric bool Safe = isSafeAccess(UI, AI, TypeSize); 4914824e7fdSDimitry Andric US.addRange(I, AccessRange, Safe); 4925ffd83dbSDimitry Andric break; 4935ffd83dbSDimitry Andric } 4945ffd83dbSDimitry Andric 495*0b57cec5SDimitry Andric // FIXME: consult devirt? 496*0b57cec5SDimitry Andric // Do not follow aliases, otherwise we could inadvertently follow 497*0b57cec5SDimitry Andric // dso_preemptable aliases or aliases with interposable linkage. 4988bcb0991SDimitry Andric const GlobalValue *Callee = 4995ffd83dbSDimitry Andric dyn_cast<GlobalValue>(CB.getCalledOperand()->stripPointerCasts()); 500*0b57cec5SDimitry Andric if (!Callee) { 5014824e7fdSDimitry Andric US.addRange(I, UnknownRange, /*IsSafe=*/false); 502349cc55cSDimitry Andric break; 503*0b57cec5SDimitry Andric } 504*0b57cec5SDimitry Andric 505*0b57cec5SDimitry Andric assert(isa<Function>(Callee) || isa<GlobalAlias>(Callee)); 506e8d8bef9SDimitry Andric ConstantRange Offsets = offsetFrom(UI, Ptr); 507e8d8bef9SDimitry Andric auto Insert = 508e8d8bef9SDimitry Andric US.Calls.emplace(CallInfo<GlobalValue>(Callee, ArgNo), Offsets); 509e8d8bef9SDimitry Andric if (!Insert.second) 510e8d8bef9SDimitry Andric Insert.first->second = Insert.first->second.unionWith(Offsets); 511*0b57cec5SDimitry Andric break; 512*0b57cec5SDimitry Andric } 513*0b57cec5SDimitry Andric 514*0b57cec5SDimitry Andric default: 515*0b57cec5SDimitry Andric if (Visited.insert(I).second) 516*0b57cec5SDimitry Andric WorkList.push_back(cast<const Instruction>(I)); 517*0b57cec5SDimitry Andric } 518*0b57cec5SDimitry Andric } 519*0b57cec5SDimitry Andric } 520*0b57cec5SDimitry Andric } 521*0b57cec5SDimitry Andric 5225ffd83dbSDimitry Andric FunctionInfo<GlobalValue> StackSafetyLocalAnalysis::run() { 5235ffd83dbSDimitry Andric FunctionInfo<GlobalValue> Info; 524*0b57cec5SDimitry Andric assert(!F.isDeclaration() && 525*0b57cec5SDimitry Andric "Can't run StackSafety on a function declaration"); 526*0b57cec5SDimitry Andric 527*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "[StackSafety] " << F.getName() << "\n"); 528*0b57cec5SDimitry Andric 5295ffd83dbSDimitry Andric SmallVector<AllocaInst *, 64> Allocas; 5305ffd83dbSDimitry Andric for (auto &I : instructions(F)) 5315ffd83dbSDimitry Andric if (auto *AI = dyn_cast<AllocaInst>(&I)) 5325ffd83dbSDimitry Andric Allocas.push_back(AI); 5335ffd83dbSDimitry Andric StackLifetime SL(F, Allocas, StackLifetime::LivenessType::Must); 5345ffd83dbSDimitry Andric SL.run(); 5355ffd83dbSDimitry Andric 5365ffd83dbSDimitry Andric for (auto *AI : Allocas) { 5375ffd83dbSDimitry Andric auto &UI = Info.Allocas.emplace(AI, PointerSize).first->second; 5385ffd83dbSDimitry Andric analyzeAllUses(AI, UI, SL); 5395ffd83dbSDimitry Andric } 5405ffd83dbSDimitry Andric 541e8d8bef9SDimitry Andric for (Argument &A : F.args()) { 5425ffd83dbSDimitry Andric // Non pointers and bypass arguments are not going to be used in any global 5435ffd83dbSDimitry Andric // processing. 5445ffd83dbSDimitry Andric if (A.getType()->isPointerTy() && !A.hasByValAttr()) { 5455ffd83dbSDimitry Andric auto &UI = Info.Params.emplace(A.getArgNo(), PointerSize).first->second; 5465ffd83dbSDimitry Andric analyzeAllUses(&A, UI, SL); 547*0b57cec5SDimitry Andric } 548*0b57cec5SDimitry Andric } 549*0b57cec5SDimitry Andric 5505ffd83dbSDimitry Andric LLVM_DEBUG(Info.print(dbgs(), F.getName(), &F)); 551349cc55cSDimitry Andric LLVM_DEBUG(dbgs() << "\n[StackSafety] done\n"); 5525ffd83dbSDimitry Andric return Info; 553*0b57cec5SDimitry Andric } 554*0b57cec5SDimitry Andric 5555ffd83dbSDimitry Andric template <typename CalleeTy> class StackSafetyDataFlowAnalysis { 5565ffd83dbSDimitry Andric using FunctionMap = std::map<const CalleeTy *, FunctionInfo<CalleeTy>>; 557*0b57cec5SDimitry Andric 558*0b57cec5SDimitry Andric FunctionMap Functions; 559*0b57cec5SDimitry Andric const ConstantRange UnknownRange; 560*0b57cec5SDimitry Andric 5615ffd83dbSDimitry Andric // Callee-to-Caller multimap. 5625ffd83dbSDimitry Andric DenseMap<const CalleeTy *, SmallVector<const CalleeTy *, 4>> Callers; 5635ffd83dbSDimitry Andric SetVector<const CalleeTy *> WorkList; 5645ffd83dbSDimitry Andric 5655ffd83dbSDimitry Andric bool updateOneUse(UseInfo<CalleeTy> &US, bool UpdateToFullSet); 5665ffd83dbSDimitry Andric void updateOneNode(const CalleeTy *Callee, FunctionInfo<CalleeTy> &FS); 5675ffd83dbSDimitry Andric void updateOneNode(const CalleeTy *Callee) { 568*0b57cec5SDimitry Andric updateOneNode(Callee, Functions.find(Callee)->second); 569*0b57cec5SDimitry Andric } 570*0b57cec5SDimitry Andric void updateAllNodes() { 571*0b57cec5SDimitry Andric for (auto &F : Functions) 572*0b57cec5SDimitry Andric updateOneNode(F.first, F.second); 573*0b57cec5SDimitry Andric } 574*0b57cec5SDimitry Andric void runDataFlow(); 575*0b57cec5SDimitry Andric #ifndef NDEBUG 576*0b57cec5SDimitry Andric void verifyFixedPoint(); 577*0b57cec5SDimitry Andric #endif 578*0b57cec5SDimitry Andric 579*0b57cec5SDimitry Andric public: 5805ffd83dbSDimitry Andric StackSafetyDataFlowAnalysis(uint32_t PointerBitWidth, FunctionMap Functions) 5815ffd83dbSDimitry Andric : Functions(std::move(Functions)), 5825ffd83dbSDimitry Andric UnknownRange(ConstantRange::getFull(PointerBitWidth)) {} 5835ffd83dbSDimitry Andric 5845ffd83dbSDimitry Andric const FunctionMap &run(); 5855ffd83dbSDimitry Andric 5865ffd83dbSDimitry Andric ConstantRange getArgumentAccessRange(const CalleeTy *Callee, unsigned ParamNo, 5875ffd83dbSDimitry Andric const ConstantRange &Offsets) const; 588*0b57cec5SDimitry Andric }; 589*0b57cec5SDimitry Andric 5905ffd83dbSDimitry Andric template <typename CalleeTy> 5915ffd83dbSDimitry Andric ConstantRange StackSafetyDataFlowAnalysis<CalleeTy>::getArgumentAccessRange( 5925ffd83dbSDimitry Andric const CalleeTy *Callee, unsigned ParamNo, 5935ffd83dbSDimitry Andric const ConstantRange &Offsets) const { 5945ffd83dbSDimitry Andric auto FnIt = Functions.find(Callee); 595*0b57cec5SDimitry Andric // Unknown callee (outside of LTO domain or an indirect call). 5965ffd83dbSDimitry Andric if (FnIt == Functions.end()) 597*0b57cec5SDimitry Andric return UnknownRange; 5985ffd83dbSDimitry Andric auto &FS = FnIt->second; 5995ffd83dbSDimitry Andric auto ParamIt = FS.Params.find(ParamNo); 6005ffd83dbSDimitry Andric if (ParamIt == FS.Params.end()) 601*0b57cec5SDimitry Andric return UnknownRange; 6025ffd83dbSDimitry Andric auto &Access = ParamIt->second.Range; 6035ffd83dbSDimitry Andric if (Access.isEmptySet()) 6045ffd83dbSDimitry Andric return Access; 6055ffd83dbSDimitry Andric if (Access.isFullSet()) 606*0b57cec5SDimitry Andric return UnknownRange; 6075ffd83dbSDimitry Andric return addOverflowNever(Access, Offsets); 608*0b57cec5SDimitry Andric } 609*0b57cec5SDimitry Andric 6105ffd83dbSDimitry Andric template <typename CalleeTy> 6115ffd83dbSDimitry Andric bool StackSafetyDataFlowAnalysis<CalleeTy>::updateOneUse(UseInfo<CalleeTy> &US, 612*0b57cec5SDimitry Andric bool UpdateToFullSet) { 613*0b57cec5SDimitry Andric bool Changed = false; 614e8d8bef9SDimitry Andric for (auto &KV : US.Calls) { 615e8d8bef9SDimitry Andric assert(!KV.second.isEmptySet() && 616*0b57cec5SDimitry Andric "Param range can't be empty-set, invalid offset range"); 617*0b57cec5SDimitry Andric 6185ffd83dbSDimitry Andric ConstantRange CalleeRange = 619e8d8bef9SDimitry Andric getArgumentAccessRange(KV.first.Callee, KV.first.ParamNo, KV.second); 620*0b57cec5SDimitry Andric if (!US.Range.contains(CalleeRange)) { 621*0b57cec5SDimitry Andric Changed = true; 622*0b57cec5SDimitry Andric if (UpdateToFullSet) 623*0b57cec5SDimitry Andric US.Range = UnknownRange; 624*0b57cec5SDimitry Andric else 625e8d8bef9SDimitry Andric US.updateRange(CalleeRange); 626*0b57cec5SDimitry Andric } 627*0b57cec5SDimitry Andric } 628*0b57cec5SDimitry Andric return Changed; 629*0b57cec5SDimitry Andric } 630*0b57cec5SDimitry Andric 6315ffd83dbSDimitry Andric template <typename CalleeTy> 6325ffd83dbSDimitry Andric void StackSafetyDataFlowAnalysis<CalleeTy>::updateOneNode( 6335ffd83dbSDimitry Andric const CalleeTy *Callee, FunctionInfo<CalleeTy> &FS) { 634*0b57cec5SDimitry Andric bool UpdateToFullSet = FS.UpdateCount > StackSafetyMaxIterations; 635*0b57cec5SDimitry Andric bool Changed = false; 6365ffd83dbSDimitry Andric for (auto &KV : FS.Params) 6375ffd83dbSDimitry Andric Changed |= updateOneUse(KV.second, UpdateToFullSet); 638*0b57cec5SDimitry Andric 639*0b57cec5SDimitry Andric if (Changed) { 640*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "=== update [" << FS.UpdateCount 6415ffd83dbSDimitry Andric << (UpdateToFullSet ? ", full-set" : "") << "] " << &FS 6425ffd83dbSDimitry Andric << "\n"); 643*0b57cec5SDimitry Andric // Callers of this function may need updating. 644*0b57cec5SDimitry Andric for (auto &CallerID : Callers[Callee]) 645*0b57cec5SDimitry Andric WorkList.insert(CallerID); 646*0b57cec5SDimitry Andric 647*0b57cec5SDimitry Andric ++FS.UpdateCount; 648*0b57cec5SDimitry Andric } 649*0b57cec5SDimitry Andric } 650*0b57cec5SDimitry Andric 6515ffd83dbSDimitry Andric template <typename CalleeTy> 6525ffd83dbSDimitry Andric void StackSafetyDataFlowAnalysis<CalleeTy>::runDataFlow() { 6535ffd83dbSDimitry Andric SmallVector<const CalleeTy *, 16> Callees; 654*0b57cec5SDimitry Andric for (auto &F : Functions) { 655*0b57cec5SDimitry Andric Callees.clear(); 6565ffd83dbSDimitry Andric auto &FS = F.second; 6575ffd83dbSDimitry Andric for (auto &KV : FS.Params) 6585ffd83dbSDimitry Andric for (auto &CS : KV.second.Calls) 659e8d8bef9SDimitry Andric Callees.push_back(CS.first.Callee); 660*0b57cec5SDimitry Andric 661*0b57cec5SDimitry Andric llvm::sort(Callees); 662*0b57cec5SDimitry Andric Callees.erase(std::unique(Callees.begin(), Callees.end()), Callees.end()); 663*0b57cec5SDimitry Andric 664*0b57cec5SDimitry Andric for (auto &Callee : Callees) 665*0b57cec5SDimitry Andric Callers[Callee].push_back(F.first); 666*0b57cec5SDimitry Andric } 667*0b57cec5SDimitry Andric 668*0b57cec5SDimitry Andric updateAllNodes(); 669*0b57cec5SDimitry Andric 670*0b57cec5SDimitry Andric while (!WorkList.empty()) { 671349cc55cSDimitry Andric const CalleeTy *Callee = WorkList.pop_back_val(); 672*0b57cec5SDimitry Andric updateOneNode(Callee); 673*0b57cec5SDimitry Andric } 674*0b57cec5SDimitry Andric } 675*0b57cec5SDimitry Andric 676*0b57cec5SDimitry Andric #ifndef NDEBUG 6775ffd83dbSDimitry Andric template <typename CalleeTy> 6785ffd83dbSDimitry Andric void StackSafetyDataFlowAnalysis<CalleeTy>::verifyFixedPoint() { 679*0b57cec5SDimitry Andric WorkList.clear(); 680*0b57cec5SDimitry Andric updateAllNodes(); 681*0b57cec5SDimitry Andric assert(WorkList.empty()); 682*0b57cec5SDimitry Andric } 683*0b57cec5SDimitry Andric #endif 684*0b57cec5SDimitry Andric 6855ffd83dbSDimitry Andric template <typename CalleeTy> 6865ffd83dbSDimitry Andric const typename StackSafetyDataFlowAnalysis<CalleeTy>::FunctionMap & 6875ffd83dbSDimitry Andric StackSafetyDataFlowAnalysis<CalleeTy>::run() { 688*0b57cec5SDimitry Andric runDataFlow(); 689*0b57cec5SDimitry Andric LLVM_DEBUG(verifyFixedPoint()); 6905ffd83dbSDimitry Andric return Functions; 6915ffd83dbSDimitry Andric } 692*0b57cec5SDimitry Andric 693e8d8bef9SDimitry Andric FunctionSummary *findCalleeFunctionSummary(ValueInfo VI, StringRef ModuleId) { 694e8d8bef9SDimitry Andric if (!VI) 695e8d8bef9SDimitry Andric return nullptr; 696e8d8bef9SDimitry Andric auto SummaryList = VI.getSummaryList(); 697e8d8bef9SDimitry Andric GlobalValueSummary* S = nullptr; 698e8d8bef9SDimitry Andric for (const auto& GVS : SummaryList) { 699e8d8bef9SDimitry Andric if (!GVS->isLive()) 700e8d8bef9SDimitry Andric continue; 701e8d8bef9SDimitry Andric if (const AliasSummary *AS = dyn_cast<AliasSummary>(GVS.get())) 702e8d8bef9SDimitry Andric if (!AS->hasAliasee()) 703e8d8bef9SDimitry Andric continue; 704e8d8bef9SDimitry Andric if (!isa<FunctionSummary>(GVS->getBaseObject())) 705e8d8bef9SDimitry Andric continue; 706e8d8bef9SDimitry Andric if (GlobalValue::isLocalLinkage(GVS->linkage())) { 707e8d8bef9SDimitry Andric if (GVS->modulePath() == ModuleId) { 708e8d8bef9SDimitry Andric S = GVS.get(); 709e8d8bef9SDimitry Andric break; 710e8d8bef9SDimitry Andric } 711e8d8bef9SDimitry Andric } else if (GlobalValue::isExternalLinkage(GVS->linkage())) { 712e8d8bef9SDimitry Andric if (S) { 713e8d8bef9SDimitry Andric ++NumIndexCalleeMultipleExternal; 714e8d8bef9SDimitry Andric return nullptr; 715e8d8bef9SDimitry Andric } 716e8d8bef9SDimitry Andric S = GVS.get(); 717e8d8bef9SDimitry Andric } else if (GlobalValue::isWeakLinkage(GVS->linkage())) { 718e8d8bef9SDimitry Andric if (S) { 719e8d8bef9SDimitry Andric ++NumIndexCalleeMultipleWeak; 720e8d8bef9SDimitry Andric return nullptr; 721e8d8bef9SDimitry Andric } 722e8d8bef9SDimitry Andric S = GVS.get(); 723e8d8bef9SDimitry Andric } else if (GlobalValue::isAvailableExternallyLinkage(GVS->linkage()) || 724e8d8bef9SDimitry Andric GlobalValue::isLinkOnceLinkage(GVS->linkage())) { 725e8d8bef9SDimitry Andric if (SummaryList.size() == 1) 726e8d8bef9SDimitry Andric S = GVS.get(); 727e8d8bef9SDimitry Andric // According thinLTOResolvePrevailingGUID these are unlikely prevailing. 728e8d8bef9SDimitry Andric } else { 729e8d8bef9SDimitry Andric ++NumIndexCalleeUnhandled; 730e8d8bef9SDimitry Andric } 731e8d8bef9SDimitry Andric }; 7325ffd83dbSDimitry Andric while (S) { 7335ffd83dbSDimitry Andric if (!S->isLive() || !S->isDSOLocal()) 7345ffd83dbSDimitry Andric return nullptr; 7355ffd83dbSDimitry Andric if (FunctionSummary *FS = dyn_cast<FunctionSummary>(S)) 7365ffd83dbSDimitry Andric return FS; 7375ffd83dbSDimitry Andric AliasSummary *AS = dyn_cast<AliasSummary>(S); 738e8d8bef9SDimitry Andric if (!AS || !AS->hasAliasee()) 7395ffd83dbSDimitry Andric return nullptr; 7405ffd83dbSDimitry Andric S = AS->getBaseObject(); 7415ffd83dbSDimitry Andric if (S == AS) 7425ffd83dbSDimitry Andric return nullptr; 7435ffd83dbSDimitry Andric } 7445ffd83dbSDimitry Andric return nullptr; 7455ffd83dbSDimitry Andric } 7465ffd83dbSDimitry Andric 7475ffd83dbSDimitry Andric const Function *findCalleeInModule(const GlobalValue *GV) { 7485ffd83dbSDimitry Andric while (GV) { 7495ffd83dbSDimitry Andric if (GV->isDeclaration() || GV->isInterposable() || !GV->isDSOLocal()) 7505ffd83dbSDimitry Andric return nullptr; 7515ffd83dbSDimitry Andric if (const Function *F = dyn_cast<Function>(GV)) 7525ffd83dbSDimitry Andric return F; 7535ffd83dbSDimitry Andric const GlobalAlias *A = dyn_cast<GlobalAlias>(GV); 7545ffd83dbSDimitry Andric if (!A) 7555ffd83dbSDimitry Andric return nullptr; 756349cc55cSDimitry Andric GV = A->getAliaseeObject(); 7575ffd83dbSDimitry Andric if (GV == A) 7585ffd83dbSDimitry Andric return nullptr; 7595ffd83dbSDimitry Andric } 7605ffd83dbSDimitry Andric return nullptr; 7615ffd83dbSDimitry Andric } 7625ffd83dbSDimitry Andric 7635ffd83dbSDimitry Andric const ConstantRange *findParamAccess(const FunctionSummary &FS, 7645ffd83dbSDimitry Andric uint32_t ParamNo) { 7655ffd83dbSDimitry Andric assert(FS.isLive()); 7665ffd83dbSDimitry Andric assert(FS.isDSOLocal()); 7675ffd83dbSDimitry Andric for (auto &PS : FS.paramAccesses()) 7685ffd83dbSDimitry Andric if (ParamNo == PS.ParamNo) 7695ffd83dbSDimitry Andric return &PS.Use; 7705ffd83dbSDimitry Andric return nullptr; 7715ffd83dbSDimitry Andric } 7725ffd83dbSDimitry Andric 7735ffd83dbSDimitry Andric void resolveAllCalls(UseInfo<GlobalValue> &Use, 7745ffd83dbSDimitry Andric const ModuleSummaryIndex *Index) { 7755ffd83dbSDimitry Andric ConstantRange FullSet(Use.Range.getBitWidth(), true); 776e8d8bef9SDimitry Andric // Move Use.Calls to a temp storage and repopulate - don't use std::move as it 777e8d8bef9SDimitry Andric // leaves Use.Calls in an undefined state. 778e8d8bef9SDimitry Andric UseInfo<GlobalValue>::CallsTy TmpCalls; 779e8d8bef9SDimitry Andric std::swap(TmpCalls, Use.Calls); 780e8d8bef9SDimitry Andric for (const auto &C : TmpCalls) { 781e8d8bef9SDimitry Andric const Function *F = findCalleeInModule(C.first.Callee); 7825ffd83dbSDimitry Andric if (F) { 783e8d8bef9SDimitry Andric Use.Calls.emplace(CallInfo<GlobalValue>(F, C.first.ParamNo), C.second); 7845ffd83dbSDimitry Andric continue; 7855ffd83dbSDimitry Andric } 7865ffd83dbSDimitry Andric 7875ffd83dbSDimitry Andric if (!Index) 7885ffd83dbSDimitry Andric return Use.updateRange(FullSet); 789e8d8bef9SDimitry Andric FunctionSummary *FS = 790e8d8bef9SDimitry Andric findCalleeFunctionSummary(Index->getValueInfo(C.first.Callee->getGUID()), 791e8d8bef9SDimitry Andric C.first.Callee->getParent()->getModuleIdentifier()); 792e8d8bef9SDimitry Andric ++NumModuleCalleeLookupTotal; 793e8d8bef9SDimitry Andric if (!FS) { 794e8d8bef9SDimitry Andric ++NumModuleCalleeLookupFailed; 7955ffd83dbSDimitry Andric return Use.updateRange(FullSet); 796e8d8bef9SDimitry Andric } 797e8d8bef9SDimitry Andric const ConstantRange *Found = findParamAccess(*FS, C.first.ParamNo); 798e8d8bef9SDimitry Andric if (!Found || Found->isFullSet()) 7995ffd83dbSDimitry Andric return Use.updateRange(FullSet); 8005ffd83dbSDimitry Andric ConstantRange Access = Found->sextOrTrunc(Use.Range.getBitWidth()); 801e8d8bef9SDimitry Andric if (!Access.isEmptySet()) 802e8d8bef9SDimitry Andric Use.updateRange(addOverflowNever(Access, C.second)); 8035ffd83dbSDimitry Andric } 8045ffd83dbSDimitry Andric } 8055ffd83dbSDimitry Andric 8065ffd83dbSDimitry Andric GVToSSI createGlobalStackSafetyInfo( 8075ffd83dbSDimitry Andric std::map<const GlobalValue *, FunctionInfo<GlobalValue>> Functions, 8085ffd83dbSDimitry Andric const ModuleSummaryIndex *Index) { 8095ffd83dbSDimitry Andric GVToSSI SSI; 8105ffd83dbSDimitry Andric if (Functions.empty()) 811*0b57cec5SDimitry Andric return SSI; 8125ffd83dbSDimitry Andric 8135ffd83dbSDimitry Andric // FIXME: Simplify printing and remove copying here. 8145ffd83dbSDimitry Andric auto Copy = Functions; 8155ffd83dbSDimitry Andric 8165ffd83dbSDimitry Andric for (auto &FnKV : Copy) 817e8d8bef9SDimitry Andric for (auto &KV : FnKV.second.Params) { 8185ffd83dbSDimitry Andric resolveAllCalls(KV.second, Index); 819e8d8bef9SDimitry Andric if (KV.second.Range.isFullSet()) 820e8d8bef9SDimitry Andric KV.second.Calls.clear(); 821e8d8bef9SDimitry Andric } 8225ffd83dbSDimitry Andric 823349cc55cSDimitry Andric uint32_t PointerSize = 824349cc55cSDimitry Andric Copy.begin()->first->getParent()->getDataLayout().getPointerSizeInBits(); 8255ffd83dbSDimitry Andric StackSafetyDataFlowAnalysis<GlobalValue> SSDFA(PointerSize, std::move(Copy)); 8265ffd83dbSDimitry Andric 8275ffd83dbSDimitry Andric for (auto &F : SSDFA.run()) { 8285ffd83dbSDimitry Andric auto FI = F.second; 8295ffd83dbSDimitry Andric auto &SrcF = Functions[F.first]; 8305ffd83dbSDimitry Andric for (auto &KV : FI.Allocas) { 8315ffd83dbSDimitry Andric auto &A = KV.second; 8325ffd83dbSDimitry Andric resolveAllCalls(A, Index); 8335ffd83dbSDimitry Andric for (auto &C : A.Calls) { 834e8d8bef9SDimitry Andric A.updateRange(SSDFA.getArgumentAccessRange(C.first.Callee, 835e8d8bef9SDimitry Andric C.first.ParamNo, C.second)); 8365ffd83dbSDimitry Andric } 8375ffd83dbSDimitry Andric // FIXME: This is needed only to preserve calls in print() results. 8385ffd83dbSDimitry Andric A.Calls = SrcF.Allocas.find(KV.first)->second.Calls; 8395ffd83dbSDimitry Andric } 8405ffd83dbSDimitry Andric for (auto &KV : FI.Params) { 8415ffd83dbSDimitry Andric auto &P = KV.second; 8425ffd83dbSDimitry Andric P.Calls = SrcF.Params.find(KV.first)->second.Calls; 8435ffd83dbSDimitry Andric } 8445ffd83dbSDimitry Andric SSI[F.first] = std::move(FI); 845*0b57cec5SDimitry Andric } 846*0b57cec5SDimitry Andric 8475ffd83dbSDimitry Andric return SSI; 848*0b57cec5SDimitry Andric } 849*0b57cec5SDimitry Andric 850*0b57cec5SDimitry Andric } // end anonymous namespace 851*0b57cec5SDimitry Andric 852*0b57cec5SDimitry Andric StackSafetyInfo::StackSafetyInfo() = default; 853*0b57cec5SDimitry Andric 8545ffd83dbSDimitry Andric StackSafetyInfo::StackSafetyInfo(Function *F, 8555ffd83dbSDimitry Andric std::function<ScalarEvolution &()> GetSE) 8565ffd83dbSDimitry Andric : F(F), GetSE(GetSE) {} 8575ffd83dbSDimitry Andric 8585ffd83dbSDimitry Andric StackSafetyInfo::StackSafetyInfo(StackSafetyInfo &&) = default; 8595ffd83dbSDimitry Andric 8605ffd83dbSDimitry Andric StackSafetyInfo &StackSafetyInfo::operator=(StackSafetyInfo &&) = default; 861*0b57cec5SDimitry Andric 862*0b57cec5SDimitry Andric StackSafetyInfo::~StackSafetyInfo() = default; 863*0b57cec5SDimitry Andric 8645ffd83dbSDimitry Andric const StackSafetyInfo::InfoTy &StackSafetyInfo::getInfo() const { 8655ffd83dbSDimitry Andric if (!Info) { 8665ffd83dbSDimitry Andric StackSafetyLocalAnalysis SSLA(*F, GetSE()); 8675ffd83dbSDimitry Andric Info.reset(new InfoTy{SSLA.run()}); 8685ffd83dbSDimitry Andric } 8695ffd83dbSDimitry Andric return *Info; 8705ffd83dbSDimitry Andric } 8715ffd83dbSDimitry Andric 8725ffd83dbSDimitry Andric void StackSafetyInfo::print(raw_ostream &O) const { 8735ffd83dbSDimitry Andric getInfo().Info.print(O, F->getName(), dyn_cast<Function>(F)); 874349cc55cSDimitry Andric O << "\n"; 8755ffd83dbSDimitry Andric } 8765ffd83dbSDimitry Andric 8775ffd83dbSDimitry Andric const StackSafetyGlobalInfo::InfoTy &StackSafetyGlobalInfo::getInfo() const { 8785ffd83dbSDimitry Andric if (!Info) { 8795ffd83dbSDimitry Andric std::map<const GlobalValue *, FunctionInfo<GlobalValue>> Functions; 8805ffd83dbSDimitry Andric for (auto &F : M->functions()) { 8815ffd83dbSDimitry Andric if (!F.isDeclaration()) { 8825ffd83dbSDimitry Andric auto FI = GetSSI(F).getInfo().Info; 8835ffd83dbSDimitry Andric Functions.emplace(&F, std::move(FI)); 8845ffd83dbSDimitry Andric } 8855ffd83dbSDimitry Andric } 8865ffd83dbSDimitry Andric Info.reset(new InfoTy{ 887349cc55cSDimitry Andric createGlobalStackSafetyInfo(std::move(Functions), Index), {}, {}}); 888349cc55cSDimitry Andric 8895ffd83dbSDimitry Andric for (auto &FnKV : Info->Info) { 8905ffd83dbSDimitry Andric for (auto &KV : FnKV.second.Allocas) { 8915ffd83dbSDimitry Andric ++NumAllocaTotal; 8925ffd83dbSDimitry Andric const AllocaInst *AI = KV.first; 893349cc55cSDimitry Andric auto AIRange = getStaticAllocaSizeRange(*AI); 894349cc55cSDimitry Andric if (AIRange.contains(KV.second.Range)) { 8955ffd83dbSDimitry Andric Info->SafeAllocas.insert(AI); 8965ffd83dbSDimitry Andric ++NumAllocaStackSafe; 8975ffd83dbSDimitry Andric } 8984824e7fdSDimitry Andric Info->UnsafeAccesses.insert(KV.second.UnsafeAccesses.begin(), 8994824e7fdSDimitry Andric KV.second.UnsafeAccesses.end()); 9005ffd83dbSDimitry Andric } 9015ffd83dbSDimitry Andric } 902349cc55cSDimitry Andric 9035ffd83dbSDimitry Andric if (StackSafetyPrint) 9045ffd83dbSDimitry Andric print(errs()); 9055ffd83dbSDimitry Andric } 9065ffd83dbSDimitry Andric return *Info; 9075ffd83dbSDimitry Andric } 9085ffd83dbSDimitry Andric 9095ffd83dbSDimitry Andric std::vector<FunctionSummary::ParamAccess> 910e8d8bef9SDimitry Andric StackSafetyInfo::getParamAccesses(ModuleSummaryIndex &Index) const { 9115ffd83dbSDimitry Andric // Implementation transforms internal representation of parameter information 9125ffd83dbSDimitry Andric // into FunctionSummary format. 9135ffd83dbSDimitry Andric std::vector<FunctionSummary::ParamAccess> ParamAccesses; 9145ffd83dbSDimitry Andric for (const auto &KV : getInfo().Info.Params) { 9155ffd83dbSDimitry Andric auto &PS = KV.second; 9165ffd83dbSDimitry Andric // Parameter accessed by any or unknown offset, represented as FullSet by 9175ffd83dbSDimitry Andric // StackSafety, is handled as the parameter for which we have no 9185ffd83dbSDimitry Andric // StackSafety info at all. So drop it to reduce summary size. 9195ffd83dbSDimitry Andric if (PS.Range.isFullSet()) 9205ffd83dbSDimitry Andric continue; 9215ffd83dbSDimitry Andric 9225ffd83dbSDimitry Andric ParamAccesses.emplace_back(KV.first, PS.Range); 9235ffd83dbSDimitry Andric FunctionSummary::ParamAccess &Param = ParamAccesses.back(); 9245ffd83dbSDimitry Andric 9255ffd83dbSDimitry Andric Param.Calls.reserve(PS.Calls.size()); 9265ffd83dbSDimitry Andric for (auto &C : PS.Calls) { 9275ffd83dbSDimitry Andric // Parameter forwarded into another function by any or unknown offset 9285ffd83dbSDimitry Andric // will make ParamAccess::Range as FullSet anyway. So we can drop the 9295ffd83dbSDimitry Andric // entire parameter like we did above. 9305ffd83dbSDimitry Andric // TODO(vitalybuka): Return already filtered parameters from getInfo(). 931e8d8bef9SDimitry Andric if (C.second.isFullSet()) { 9325ffd83dbSDimitry Andric ParamAccesses.pop_back(); 9335ffd83dbSDimitry Andric break; 9345ffd83dbSDimitry Andric } 935e8d8bef9SDimitry Andric Param.Calls.emplace_back(C.first.ParamNo, 936e8d8bef9SDimitry Andric Index.getOrInsertValueInfo(C.first.Callee), 937e8d8bef9SDimitry Andric C.second); 9385ffd83dbSDimitry Andric } 9395ffd83dbSDimitry Andric } 940e8d8bef9SDimitry Andric for (FunctionSummary::ParamAccess &Param : ParamAccesses) { 941e8d8bef9SDimitry Andric sort(Param.Calls, [](const FunctionSummary::ParamAccess::Call &L, 942e8d8bef9SDimitry Andric const FunctionSummary::ParamAccess::Call &R) { 943e8d8bef9SDimitry Andric return std::tie(L.ParamNo, L.Callee) < std::tie(R.ParamNo, R.Callee); 944e8d8bef9SDimitry Andric }); 945e8d8bef9SDimitry Andric } 9465ffd83dbSDimitry Andric return ParamAccesses; 9475ffd83dbSDimitry Andric } 9485ffd83dbSDimitry Andric 9495ffd83dbSDimitry Andric StackSafetyGlobalInfo::StackSafetyGlobalInfo() = default; 9505ffd83dbSDimitry Andric 9515ffd83dbSDimitry Andric StackSafetyGlobalInfo::StackSafetyGlobalInfo( 9525ffd83dbSDimitry Andric Module *M, std::function<const StackSafetyInfo &(Function &F)> GetSSI, 9535ffd83dbSDimitry Andric const ModuleSummaryIndex *Index) 9545ffd83dbSDimitry Andric : M(M), GetSSI(GetSSI), Index(Index) { 9555ffd83dbSDimitry Andric if (StackSafetyRun) 9565ffd83dbSDimitry Andric getInfo(); 9575ffd83dbSDimitry Andric } 9585ffd83dbSDimitry Andric 9595ffd83dbSDimitry Andric StackSafetyGlobalInfo::StackSafetyGlobalInfo(StackSafetyGlobalInfo &&) = 9605ffd83dbSDimitry Andric default; 9615ffd83dbSDimitry Andric 9625ffd83dbSDimitry Andric StackSafetyGlobalInfo & 9635ffd83dbSDimitry Andric StackSafetyGlobalInfo::operator=(StackSafetyGlobalInfo &&) = default; 9645ffd83dbSDimitry Andric 9655ffd83dbSDimitry Andric StackSafetyGlobalInfo::~StackSafetyGlobalInfo() = default; 9665ffd83dbSDimitry Andric 9675ffd83dbSDimitry Andric bool StackSafetyGlobalInfo::isSafe(const AllocaInst &AI) const { 9685ffd83dbSDimitry Andric const auto &Info = getInfo(); 9695ffd83dbSDimitry Andric return Info.SafeAllocas.count(&AI); 9705ffd83dbSDimitry Andric } 9715ffd83dbSDimitry Andric 972349cc55cSDimitry Andric bool StackSafetyGlobalInfo::stackAccessIsSafe(const Instruction &I) const { 973349cc55cSDimitry Andric const auto &Info = getInfo(); 9744824e7fdSDimitry Andric return Info.UnsafeAccesses.find(&I) == Info.UnsafeAccesses.end(); 975349cc55cSDimitry Andric } 976349cc55cSDimitry Andric 9775ffd83dbSDimitry Andric void StackSafetyGlobalInfo::print(raw_ostream &O) const { 9785ffd83dbSDimitry Andric auto &SSI = getInfo().Info; 9795ffd83dbSDimitry Andric if (SSI.empty()) 9805ffd83dbSDimitry Andric return; 9815ffd83dbSDimitry Andric const Module &M = *SSI.begin()->first->getParent(); 9825ffd83dbSDimitry Andric for (auto &F : M.functions()) { 9835ffd83dbSDimitry Andric if (!F.isDeclaration()) { 9845ffd83dbSDimitry Andric SSI.find(&F)->second.print(O, F.getName(), &F); 985349cc55cSDimitry Andric O << " safe accesses:" 986349cc55cSDimitry Andric << "\n"; 987349cc55cSDimitry Andric for (const auto &I : instructions(F)) { 988349cc55cSDimitry Andric const CallInst *Call = dyn_cast<CallInst>(&I); 989349cc55cSDimitry Andric if ((isa<StoreInst>(I) || isa<LoadInst>(I) || isa<MemIntrinsic>(I) || 990349cc55cSDimitry Andric (Call && Call->hasByValArgument())) && 991349cc55cSDimitry Andric stackAccessIsSafe(I)) { 992349cc55cSDimitry Andric O << " " << I << "\n"; 993349cc55cSDimitry Andric } 994349cc55cSDimitry Andric } 9955ffd83dbSDimitry Andric O << "\n"; 9965ffd83dbSDimitry Andric } 9975ffd83dbSDimitry Andric } 9985ffd83dbSDimitry Andric } 9995ffd83dbSDimitry Andric 10005ffd83dbSDimitry Andric LLVM_DUMP_METHOD void StackSafetyGlobalInfo::dump() const { print(dbgs()); } 1001*0b57cec5SDimitry Andric 1002*0b57cec5SDimitry Andric AnalysisKey StackSafetyAnalysis::Key; 1003*0b57cec5SDimitry Andric 1004*0b57cec5SDimitry Andric StackSafetyInfo StackSafetyAnalysis::run(Function &F, 1005*0b57cec5SDimitry Andric FunctionAnalysisManager &AM) { 10065ffd83dbSDimitry Andric return StackSafetyInfo(&F, [&AM, &F]() -> ScalarEvolution & { 10075ffd83dbSDimitry Andric return AM.getResult<ScalarEvolutionAnalysis>(F); 10085ffd83dbSDimitry Andric }); 1009*0b57cec5SDimitry Andric } 1010*0b57cec5SDimitry Andric 1011*0b57cec5SDimitry Andric PreservedAnalyses StackSafetyPrinterPass::run(Function &F, 1012*0b57cec5SDimitry Andric FunctionAnalysisManager &AM) { 1013*0b57cec5SDimitry Andric OS << "'Stack Safety Local Analysis' for function '" << F.getName() << "'\n"; 1014*0b57cec5SDimitry Andric AM.getResult<StackSafetyAnalysis>(F).print(OS); 1015*0b57cec5SDimitry Andric return PreservedAnalyses::all(); 1016*0b57cec5SDimitry Andric } 1017*0b57cec5SDimitry Andric 1018*0b57cec5SDimitry Andric char StackSafetyInfoWrapperPass::ID = 0; 1019*0b57cec5SDimitry Andric 1020*0b57cec5SDimitry Andric StackSafetyInfoWrapperPass::StackSafetyInfoWrapperPass() : FunctionPass(ID) { 1021*0b57cec5SDimitry Andric initializeStackSafetyInfoWrapperPassPass(*PassRegistry::getPassRegistry()); 1022*0b57cec5SDimitry Andric } 1023*0b57cec5SDimitry Andric 1024*0b57cec5SDimitry Andric void StackSafetyInfoWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const { 10255ffd83dbSDimitry Andric AU.addRequiredTransitive<ScalarEvolutionWrapperPass>(); 1026*0b57cec5SDimitry Andric AU.setPreservesAll(); 1027*0b57cec5SDimitry Andric } 1028*0b57cec5SDimitry Andric 1029*0b57cec5SDimitry Andric void StackSafetyInfoWrapperPass::print(raw_ostream &O, const Module *M) const { 1030*0b57cec5SDimitry Andric SSI.print(O); 1031*0b57cec5SDimitry Andric } 1032*0b57cec5SDimitry Andric 1033*0b57cec5SDimitry Andric bool StackSafetyInfoWrapperPass::runOnFunction(Function &F) { 10345ffd83dbSDimitry Andric auto *SE = &getAnalysis<ScalarEvolutionWrapperPass>().getSE(); 10355ffd83dbSDimitry Andric SSI = {&F, [SE]() -> ScalarEvolution & { return *SE; }}; 1036*0b57cec5SDimitry Andric return false; 1037*0b57cec5SDimitry Andric } 1038*0b57cec5SDimitry Andric 1039*0b57cec5SDimitry Andric AnalysisKey StackSafetyGlobalAnalysis::Key; 1040*0b57cec5SDimitry Andric 1041*0b57cec5SDimitry Andric StackSafetyGlobalInfo 1042*0b57cec5SDimitry Andric StackSafetyGlobalAnalysis::run(Module &M, ModuleAnalysisManager &AM) { 10435ffd83dbSDimitry Andric // FIXME: Lookup Module Summary. 1044*0b57cec5SDimitry Andric FunctionAnalysisManager &FAM = 1045*0b57cec5SDimitry Andric AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); 10465ffd83dbSDimitry Andric return {&M, 10475ffd83dbSDimitry Andric [&FAM](Function &F) -> const StackSafetyInfo & { 1048*0b57cec5SDimitry Andric return FAM.getResult<StackSafetyAnalysis>(F); 10495ffd83dbSDimitry Andric }, 10505ffd83dbSDimitry Andric nullptr}; 1051*0b57cec5SDimitry Andric } 1052*0b57cec5SDimitry Andric 1053*0b57cec5SDimitry Andric PreservedAnalyses StackSafetyGlobalPrinterPass::run(Module &M, 1054*0b57cec5SDimitry Andric ModuleAnalysisManager &AM) { 1055*0b57cec5SDimitry Andric OS << "'Stack Safety Analysis' for module '" << M.getName() << "'\n"; 10565ffd83dbSDimitry Andric AM.getResult<StackSafetyGlobalAnalysis>(M).print(OS); 1057*0b57cec5SDimitry Andric return PreservedAnalyses::all(); 1058*0b57cec5SDimitry Andric } 1059*0b57cec5SDimitry Andric 1060*0b57cec5SDimitry Andric char StackSafetyGlobalInfoWrapperPass::ID = 0; 1061*0b57cec5SDimitry Andric 1062*0b57cec5SDimitry Andric StackSafetyGlobalInfoWrapperPass::StackSafetyGlobalInfoWrapperPass() 1063*0b57cec5SDimitry Andric : ModulePass(ID) { 1064*0b57cec5SDimitry Andric initializeStackSafetyGlobalInfoWrapperPassPass( 1065*0b57cec5SDimitry Andric *PassRegistry::getPassRegistry()); 1066*0b57cec5SDimitry Andric } 1067*0b57cec5SDimitry Andric 10685ffd83dbSDimitry Andric StackSafetyGlobalInfoWrapperPass::~StackSafetyGlobalInfoWrapperPass() = default; 10695ffd83dbSDimitry Andric 1070*0b57cec5SDimitry Andric void StackSafetyGlobalInfoWrapperPass::print(raw_ostream &O, 1071*0b57cec5SDimitry Andric const Module *M) const { 10725ffd83dbSDimitry Andric SSGI.print(O); 1073*0b57cec5SDimitry Andric } 1074*0b57cec5SDimitry Andric 1075*0b57cec5SDimitry Andric void StackSafetyGlobalInfoWrapperPass::getAnalysisUsage( 1076*0b57cec5SDimitry Andric AnalysisUsage &AU) const { 10775ffd83dbSDimitry Andric AU.setPreservesAll(); 1078*0b57cec5SDimitry Andric AU.addRequired<StackSafetyInfoWrapperPass>(); 1079*0b57cec5SDimitry Andric } 1080*0b57cec5SDimitry Andric 1081*0b57cec5SDimitry Andric bool StackSafetyGlobalInfoWrapperPass::runOnModule(Module &M) { 10825ffd83dbSDimitry Andric const ModuleSummaryIndex *ImportSummary = nullptr; 10835ffd83dbSDimitry Andric if (auto *IndexWrapperPass = 10845ffd83dbSDimitry Andric getAnalysisIfAvailable<ImmutableModuleSummaryIndexWrapperPass>()) 10855ffd83dbSDimitry Andric ImportSummary = IndexWrapperPass->getIndex(); 10865ffd83dbSDimitry Andric 10875ffd83dbSDimitry Andric SSGI = {&M, 10885ffd83dbSDimitry Andric [this](Function &F) -> const StackSafetyInfo & { 1089*0b57cec5SDimitry Andric return getAnalysis<StackSafetyInfoWrapperPass>(F).getResult(); 10905ffd83dbSDimitry Andric }, 10915ffd83dbSDimitry Andric ImportSummary}; 1092*0b57cec5SDimitry Andric return false; 1093*0b57cec5SDimitry Andric } 1094*0b57cec5SDimitry Andric 10955ffd83dbSDimitry Andric bool llvm::needsParamAccessSummary(const Module &M) { 10965ffd83dbSDimitry Andric if (StackSafetyRun) 10975ffd83dbSDimitry Andric return true; 10985ffd83dbSDimitry Andric for (auto &F : M.functions()) 10995ffd83dbSDimitry Andric if (F.hasFnAttribute(Attribute::SanitizeMemTag)) 11005ffd83dbSDimitry Andric return true; 11015ffd83dbSDimitry Andric return false; 11025ffd83dbSDimitry Andric } 11035ffd83dbSDimitry Andric 11045ffd83dbSDimitry Andric void llvm::generateParamAccessSummary(ModuleSummaryIndex &Index) { 1105e8d8bef9SDimitry Andric if (!Index.hasParamAccess()) 1106e8d8bef9SDimitry Andric return; 11075ffd83dbSDimitry Andric const ConstantRange FullSet(FunctionSummary::ParamAccess::RangeWidth, true); 1108e8d8bef9SDimitry Andric 1109e8d8bef9SDimitry Andric auto CountParamAccesses = [&](auto &Stat) { 1110e8d8bef9SDimitry Andric if (!AreStatisticsEnabled()) 1111e8d8bef9SDimitry Andric return; 1112e8d8bef9SDimitry Andric for (auto &GVS : Index) 1113e8d8bef9SDimitry Andric for (auto &GV : GVS.second.SummaryList) 1114e8d8bef9SDimitry Andric if (FunctionSummary *FS = dyn_cast<FunctionSummary>(GV.get())) 1115e8d8bef9SDimitry Andric Stat += FS->paramAccesses().size(); 1116e8d8bef9SDimitry Andric }; 1117e8d8bef9SDimitry Andric 1118e8d8bef9SDimitry Andric CountParamAccesses(NumCombinedParamAccessesBefore); 1119e8d8bef9SDimitry Andric 11205ffd83dbSDimitry Andric std::map<const FunctionSummary *, FunctionInfo<FunctionSummary>> Functions; 11215ffd83dbSDimitry Andric 11225ffd83dbSDimitry Andric // Convert the ModuleSummaryIndex to a FunctionMap 11235ffd83dbSDimitry Andric for (auto &GVS : Index) { 11245ffd83dbSDimitry Andric for (auto &GV : GVS.second.SummaryList) { 11255ffd83dbSDimitry Andric FunctionSummary *FS = dyn_cast<FunctionSummary>(GV.get()); 1126e8d8bef9SDimitry Andric if (!FS || FS->paramAccesses().empty()) 11275ffd83dbSDimitry Andric continue; 11285ffd83dbSDimitry Andric if (FS->isLive() && FS->isDSOLocal()) { 11295ffd83dbSDimitry Andric FunctionInfo<FunctionSummary> FI; 11305ffd83dbSDimitry Andric for (auto &PS : FS->paramAccesses()) { 11315ffd83dbSDimitry Andric auto &US = 11325ffd83dbSDimitry Andric FI.Params 11335ffd83dbSDimitry Andric .emplace(PS.ParamNo, FunctionSummary::ParamAccess::RangeWidth) 11345ffd83dbSDimitry Andric .first->second; 11355ffd83dbSDimitry Andric US.Range = PS.Use; 11365ffd83dbSDimitry Andric for (auto &Call : PS.Calls) { 11375ffd83dbSDimitry Andric assert(!Call.Offsets.isFullSet()); 1138e8d8bef9SDimitry Andric FunctionSummary *S = 1139e8d8bef9SDimitry Andric findCalleeFunctionSummary(Call.Callee, FS->modulePath()); 1140e8d8bef9SDimitry Andric ++NumCombinedCalleeLookupTotal; 11415ffd83dbSDimitry Andric if (!S) { 1142e8d8bef9SDimitry Andric ++NumCombinedCalleeLookupFailed; 11435ffd83dbSDimitry Andric US.Range = FullSet; 11445ffd83dbSDimitry Andric US.Calls.clear(); 11455ffd83dbSDimitry Andric break; 11465ffd83dbSDimitry Andric } 1147e8d8bef9SDimitry Andric US.Calls.emplace(CallInfo<FunctionSummary>(S, Call.ParamNo), 1148e8d8bef9SDimitry Andric Call.Offsets); 11495ffd83dbSDimitry Andric } 11505ffd83dbSDimitry Andric } 11515ffd83dbSDimitry Andric Functions.emplace(FS, std::move(FI)); 11525ffd83dbSDimitry Andric } 11535ffd83dbSDimitry Andric // Reset data for all summaries. Alive and DSO local will be set back from 11545ffd83dbSDimitry Andric // of data flow results below. Anything else will not be accessed 11555ffd83dbSDimitry Andric // by ThinLTO backend, so we can save on bitcode size. 11565ffd83dbSDimitry Andric FS->setParamAccesses({}); 11575ffd83dbSDimitry Andric } 11585ffd83dbSDimitry Andric } 1159e8d8bef9SDimitry Andric NumCombinedDataFlowNodes += Functions.size(); 11605ffd83dbSDimitry Andric StackSafetyDataFlowAnalysis<FunctionSummary> SSDFA( 11615ffd83dbSDimitry Andric FunctionSummary::ParamAccess::RangeWidth, std::move(Functions)); 11625ffd83dbSDimitry Andric for (auto &KV : SSDFA.run()) { 11635ffd83dbSDimitry Andric std::vector<FunctionSummary::ParamAccess> NewParams; 11645ffd83dbSDimitry Andric NewParams.reserve(KV.second.Params.size()); 11655ffd83dbSDimitry Andric for (auto &Param : KV.second.Params) { 1166e8d8bef9SDimitry Andric // It's not needed as FullSet is processed the same as a missing value. 1167e8d8bef9SDimitry Andric if (Param.second.Range.isFullSet()) 1168e8d8bef9SDimitry Andric continue; 11695ffd83dbSDimitry Andric NewParams.emplace_back(); 11705ffd83dbSDimitry Andric FunctionSummary::ParamAccess &New = NewParams.back(); 11715ffd83dbSDimitry Andric New.ParamNo = Param.first; 11725ffd83dbSDimitry Andric New.Use = Param.second.Range; // Only range is needed. 11735ffd83dbSDimitry Andric } 11745ffd83dbSDimitry Andric const_cast<FunctionSummary *>(KV.first)->setParamAccesses( 11755ffd83dbSDimitry Andric std::move(NewParams)); 11765ffd83dbSDimitry Andric } 1177e8d8bef9SDimitry Andric 1178e8d8bef9SDimitry Andric CountParamAccesses(NumCombinedParamAccessesAfter); 11795ffd83dbSDimitry Andric } 11805ffd83dbSDimitry Andric 1181*0b57cec5SDimitry Andric static const char LocalPassArg[] = "stack-safety-local"; 1182*0b57cec5SDimitry Andric static const char LocalPassName[] = "Stack Safety Local Analysis"; 1183*0b57cec5SDimitry Andric INITIALIZE_PASS_BEGIN(StackSafetyInfoWrapperPass, LocalPassArg, LocalPassName, 1184*0b57cec5SDimitry Andric false, true) 1185*0b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass) 1186*0b57cec5SDimitry Andric INITIALIZE_PASS_END(StackSafetyInfoWrapperPass, LocalPassArg, LocalPassName, 1187*0b57cec5SDimitry Andric false, true) 1188*0b57cec5SDimitry Andric 1189*0b57cec5SDimitry Andric static const char GlobalPassName[] = "Stack Safety Analysis"; 1190*0b57cec5SDimitry Andric INITIALIZE_PASS_BEGIN(StackSafetyGlobalInfoWrapperPass, DEBUG_TYPE, 11915ffd83dbSDimitry Andric GlobalPassName, false, true) 1192*0b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(StackSafetyInfoWrapperPass) 11935ffd83dbSDimitry Andric INITIALIZE_PASS_DEPENDENCY(ImmutableModuleSummaryIndexWrapperPass) 1194*0b57cec5SDimitry Andric INITIALIZE_PASS_END(StackSafetyGlobalInfoWrapperPass, DEBUG_TYPE, 11955ffd83dbSDimitry Andric GlobalPassName, false, true) 1196