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" 17*0b57cec5SDimitry Andric #include "llvm/Analysis/ScalarEvolutionExpressions.h" 185ffd83dbSDimitry Andric #include "llvm/Analysis/StackLifetime.h" 195ffd83dbSDimitry Andric #include "llvm/IR/ConstantRange.h" 205ffd83dbSDimitry Andric #include "llvm/IR/DerivedTypes.h" 215ffd83dbSDimitry Andric #include "llvm/IR/GlobalValue.h" 22*0b57cec5SDimitry Andric #include "llvm/IR/InstIterator.h" 235ffd83dbSDimitry Andric #include "llvm/IR/Instructions.h" 24*0b57cec5SDimitry Andric #include "llvm/IR/IntrinsicInst.h" 25480093f4SDimitry Andric #include "llvm/InitializePasses.h" 265ffd83dbSDimitry Andric #include "llvm/Support/Casting.h" 27480093f4SDimitry Andric #include "llvm/Support/CommandLine.h" 285ffd83dbSDimitry Andric #include "llvm/Support/FormatVariadic.h" 29*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 305ffd83dbSDimitry Andric #include <algorithm> 315ffd83dbSDimitry Andric #include <memory> 32*0b57cec5SDimitry Andric 33*0b57cec5SDimitry Andric using namespace llvm; 34*0b57cec5SDimitry Andric 35*0b57cec5SDimitry Andric #define DEBUG_TYPE "stack-safety" 36*0b57cec5SDimitry Andric 375ffd83dbSDimitry Andric STATISTIC(NumAllocaStackSafe, "Number of safe allocas"); 385ffd83dbSDimitry Andric STATISTIC(NumAllocaTotal, "Number of total allocas"); 395ffd83dbSDimitry Andric 40*0b57cec5SDimitry Andric static cl::opt<int> StackSafetyMaxIterations("stack-safety-max-iterations", 41*0b57cec5SDimitry Andric cl::init(20), cl::Hidden); 42*0b57cec5SDimitry Andric 435ffd83dbSDimitry Andric static cl::opt<bool> StackSafetyPrint("stack-safety-print", cl::init(false), 445ffd83dbSDimitry Andric cl::Hidden); 455ffd83dbSDimitry Andric 465ffd83dbSDimitry Andric static cl::opt<bool> StackSafetyRun("stack-safety-run", cl::init(false), 475ffd83dbSDimitry Andric cl::Hidden); 485ffd83dbSDimitry Andric 49*0b57cec5SDimitry Andric namespace { 50*0b57cec5SDimitry Andric 51*0b57cec5SDimitry Andric /// Describes use of address in as a function call argument. 525ffd83dbSDimitry Andric template <typename CalleeTy> struct CallInfo { 53*0b57cec5SDimitry Andric /// Function being called. 545ffd83dbSDimitry Andric const CalleeTy *Callee = nullptr; 55*0b57cec5SDimitry Andric /// Index of argument which pass address. 56*0b57cec5SDimitry Andric size_t ParamNo = 0; 57*0b57cec5SDimitry Andric // Offset range of address from base address (alloca or calling function 58*0b57cec5SDimitry Andric // argument). 59*0b57cec5SDimitry Andric // Range should never set to empty-set, that is an invalid access range 60*0b57cec5SDimitry Andric // that can cause empty-set to be propagated with ConstantRange::add 61*0b57cec5SDimitry Andric ConstantRange Offset; 625ffd83dbSDimitry Andric CallInfo(const CalleeTy *Callee, size_t ParamNo, const ConstantRange &Offset) 63*0b57cec5SDimitry Andric : Callee(Callee), ParamNo(ParamNo), Offset(Offset) {} 64*0b57cec5SDimitry Andric }; 65*0b57cec5SDimitry Andric 665ffd83dbSDimitry Andric template <typename CalleeTy> 675ffd83dbSDimitry Andric raw_ostream &operator<<(raw_ostream &OS, const CallInfo<CalleeTy> &P) { 685ffd83dbSDimitry Andric return OS << "@" << P.Callee->getName() << "(arg" << P.ParamNo << ", " 695ffd83dbSDimitry Andric << P.Offset << ")"; 70*0b57cec5SDimitry Andric } 71*0b57cec5SDimitry Andric 72*0b57cec5SDimitry Andric /// Describe uses of address (alloca or parameter) inside of the function. 735ffd83dbSDimitry Andric template <typename CalleeTy> struct UseInfo { 74*0b57cec5SDimitry Andric // Access range if the address (alloca or parameters). 75*0b57cec5SDimitry Andric // It is allowed to be empty-set when there are no known accesses. 76*0b57cec5SDimitry Andric ConstantRange Range; 77*0b57cec5SDimitry Andric 78*0b57cec5SDimitry Andric // List of calls which pass address as an argument. 795ffd83dbSDimitry Andric SmallVector<CallInfo<CalleeTy>, 4> Calls; 80*0b57cec5SDimitry Andric 815ffd83dbSDimitry Andric UseInfo(unsigned PointerSize) : Range{PointerSize, false} {} 82*0b57cec5SDimitry Andric 835ffd83dbSDimitry Andric void updateRange(const ConstantRange &R) { 845ffd83dbSDimitry Andric assert(!R.isUpperSignWrapped()); 855ffd83dbSDimitry Andric Range = Range.unionWith(R); 865ffd83dbSDimitry Andric assert(!Range.isUpperSignWrapped()); 875ffd83dbSDimitry Andric } 88*0b57cec5SDimitry Andric }; 89*0b57cec5SDimitry Andric 905ffd83dbSDimitry Andric template <typename CalleeTy> 915ffd83dbSDimitry Andric raw_ostream &operator<<(raw_ostream &OS, const UseInfo<CalleeTy> &U) { 92*0b57cec5SDimitry Andric OS << U.Range; 93*0b57cec5SDimitry Andric for (auto &Call : U.Calls) 94*0b57cec5SDimitry Andric OS << ", " << Call; 95*0b57cec5SDimitry Andric return OS; 96*0b57cec5SDimitry Andric } 97*0b57cec5SDimitry Andric 985ffd83dbSDimitry Andric // Check if we should bailout for such ranges. 995ffd83dbSDimitry Andric bool isUnsafe(const ConstantRange &R) { 1005ffd83dbSDimitry Andric return R.isEmptySet() || R.isFullSet() || R.isUpperSignWrapped(); 101*0b57cec5SDimitry Andric } 102*0b57cec5SDimitry Andric 1035ffd83dbSDimitry Andric ConstantRange addOverflowNever(const ConstantRange &L, const ConstantRange &R) { 1045ffd83dbSDimitry Andric if (L.signedAddMayOverflow(R) != 1055ffd83dbSDimitry Andric ConstantRange::OverflowResult::NeverOverflows) 1065ffd83dbSDimitry Andric return ConstantRange(L.getBitWidth(), true); 1075ffd83dbSDimitry Andric return L.add(R); 108*0b57cec5SDimitry Andric } 109*0b57cec5SDimitry Andric 1105ffd83dbSDimitry Andric /// Calculate the allocation size of a given alloca. Returns empty range 1115ffd83dbSDimitry Andric // in case of confution. 1125ffd83dbSDimitry Andric ConstantRange getStaticAllocaSizeRange(const AllocaInst &AI) { 1135ffd83dbSDimitry Andric const DataLayout &DL = AI.getModule()->getDataLayout(); 1145ffd83dbSDimitry Andric TypeSize TS = DL.getTypeAllocSize(AI.getAllocatedType()); 1155ffd83dbSDimitry Andric unsigned PointerSize = DL.getMaxPointerSizeInBits(); 1165ffd83dbSDimitry Andric // Fallback to empty range for alloca size. 1175ffd83dbSDimitry Andric ConstantRange R = ConstantRange::getEmpty(PointerSize); 1185ffd83dbSDimitry Andric if (TS.isScalable()) 1195ffd83dbSDimitry Andric return R; 1205ffd83dbSDimitry Andric APInt APSize(PointerSize, TS.getFixedSize(), true); 1215ffd83dbSDimitry Andric if (APSize.isNonPositive()) 1225ffd83dbSDimitry Andric return R; 1235ffd83dbSDimitry Andric if (AI.isArrayAllocation()) { 1245ffd83dbSDimitry Andric const auto *C = dyn_cast<ConstantInt>(AI.getArraySize()); 125*0b57cec5SDimitry Andric if (!C) 1265ffd83dbSDimitry Andric return R; 1275ffd83dbSDimitry Andric bool Overflow = false; 1285ffd83dbSDimitry Andric APInt Mul = C->getValue(); 1295ffd83dbSDimitry Andric if (Mul.isNonPositive()) 1305ffd83dbSDimitry Andric return R; 1315ffd83dbSDimitry Andric Mul = Mul.sextOrTrunc(PointerSize); 1325ffd83dbSDimitry Andric APSize = APSize.smul_ov(Mul, Overflow); 1335ffd83dbSDimitry Andric if (Overflow) 1345ffd83dbSDimitry Andric return R; 135*0b57cec5SDimitry Andric } 1365ffd83dbSDimitry Andric R = ConstantRange(APInt::getNullValue(PointerSize), APSize); 1375ffd83dbSDimitry Andric assert(!isUnsafe(R)); 1385ffd83dbSDimitry Andric return R; 139*0b57cec5SDimitry Andric } 140*0b57cec5SDimitry Andric 1415ffd83dbSDimitry Andric template <typename CalleeTy> struct FunctionInfo { 1425ffd83dbSDimitry Andric std::map<const AllocaInst *, UseInfo<CalleeTy>> Allocas; 1435ffd83dbSDimitry Andric std::map<uint32_t, UseInfo<CalleeTy>> Params; 144*0b57cec5SDimitry Andric // TODO: describe return value as depending on one or more of its arguments. 145*0b57cec5SDimitry Andric 146*0b57cec5SDimitry Andric // StackSafetyDataFlowAnalysis counter stored here for faster access. 147*0b57cec5SDimitry Andric int UpdateCount = 0; 148*0b57cec5SDimitry Andric 1495ffd83dbSDimitry Andric void print(raw_ostream &O, StringRef Name, const Function *F) const { 150*0b57cec5SDimitry Andric // TODO: Consider different printout format after 151*0b57cec5SDimitry Andric // StackSafetyDataFlowAnalysis. Calls and parameters are irrelevant then. 1525ffd83dbSDimitry Andric O << " @" << Name << ((F && F->isDSOLocal()) ? "" : " dso_preemptable") 1535ffd83dbSDimitry Andric << ((F && F->isInterposable()) ? " interposable" : "") << "\n"; 1545ffd83dbSDimitry Andric 155*0b57cec5SDimitry Andric O << " args uses:\n"; 1565ffd83dbSDimitry Andric for (auto &KV : Params) { 1575ffd83dbSDimitry Andric O << " "; 1585ffd83dbSDimitry Andric if (F) 1595ffd83dbSDimitry Andric O << F->getArg(KV.first)->getName(); 1605ffd83dbSDimitry Andric else 1615ffd83dbSDimitry Andric O << formatv("arg{0}", KV.first); 1625ffd83dbSDimitry Andric O << "[]: " << KV.second << "\n"; 163*0b57cec5SDimitry Andric } 164*0b57cec5SDimitry Andric 1655ffd83dbSDimitry Andric O << " allocas uses:\n"; 1665ffd83dbSDimitry Andric if (F) { 1675ffd83dbSDimitry Andric for (auto &I : instructions(F)) { 1685ffd83dbSDimitry Andric if (const AllocaInst *AI = dyn_cast<AllocaInst>(&I)) { 1695ffd83dbSDimitry Andric auto &AS = Allocas.find(AI)->second; 1705ffd83dbSDimitry Andric O << " " << AI->getName() << "[" 1715ffd83dbSDimitry Andric << getStaticAllocaSizeRange(*AI).getUpper() << "]: " << AS << "\n"; 1725ffd83dbSDimitry Andric } 1735ffd83dbSDimitry Andric } 1745ffd83dbSDimitry Andric } else { 1755ffd83dbSDimitry Andric assert(Allocas.empty()); 1765ffd83dbSDimitry Andric } 1775ffd83dbSDimitry Andric } 178*0b57cec5SDimitry Andric }; 179*0b57cec5SDimitry Andric 1805ffd83dbSDimitry Andric using GVToSSI = std::map<const GlobalValue *, FunctionInfo<GlobalValue>>; 1815ffd83dbSDimitry Andric 1825ffd83dbSDimitry Andric } // namespace 1835ffd83dbSDimitry Andric 1845ffd83dbSDimitry Andric struct StackSafetyInfo::InfoTy { 1855ffd83dbSDimitry Andric FunctionInfo<GlobalValue> Info; 1865ffd83dbSDimitry Andric }; 1875ffd83dbSDimitry Andric 1885ffd83dbSDimitry Andric struct StackSafetyGlobalInfo::InfoTy { 1895ffd83dbSDimitry Andric GVToSSI Info; 1905ffd83dbSDimitry Andric SmallPtrSet<const AllocaInst *, 8> SafeAllocas; 1915ffd83dbSDimitry Andric }; 192*0b57cec5SDimitry Andric 193*0b57cec5SDimitry Andric namespace { 194*0b57cec5SDimitry Andric 195*0b57cec5SDimitry Andric class StackSafetyLocalAnalysis { 1965ffd83dbSDimitry Andric Function &F; 197*0b57cec5SDimitry Andric const DataLayout &DL; 198*0b57cec5SDimitry Andric ScalarEvolution &SE; 199*0b57cec5SDimitry Andric unsigned PointerSize = 0; 200*0b57cec5SDimitry Andric 201*0b57cec5SDimitry Andric const ConstantRange UnknownRange; 202*0b57cec5SDimitry Andric 2035ffd83dbSDimitry Andric ConstantRange offsetFrom(Value *Addr, Value *Base); 2045ffd83dbSDimitry Andric ConstantRange getAccessRange(Value *Addr, Value *Base, 2055ffd83dbSDimitry Andric const ConstantRange &SizeRange); 2065ffd83dbSDimitry Andric ConstantRange getAccessRange(Value *Addr, Value *Base, TypeSize Size); 207*0b57cec5SDimitry Andric ConstantRange getMemIntrinsicAccessRange(const MemIntrinsic *MI, const Use &U, 2085ffd83dbSDimitry Andric Value *Base); 209*0b57cec5SDimitry Andric 2105ffd83dbSDimitry Andric bool analyzeAllUses(Value *Ptr, UseInfo<GlobalValue> &AS, 2115ffd83dbSDimitry Andric const StackLifetime &SL); 212*0b57cec5SDimitry Andric 213*0b57cec5SDimitry Andric public: 2145ffd83dbSDimitry Andric StackSafetyLocalAnalysis(Function &F, ScalarEvolution &SE) 215*0b57cec5SDimitry Andric : F(F), DL(F.getParent()->getDataLayout()), SE(SE), 216*0b57cec5SDimitry Andric PointerSize(DL.getPointerSizeInBits()), 217*0b57cec5SDimitry Andric UnknownRange(PointerSize, true) {} 218*0b57cec5SDimitry Andric 219*0b57cec5SDimitry Andric // Run the transformation on the associated function. 2205ffd83dbSDimitry Andric FunctionInfo<GlobalValue> run(); 221*0b57cec5SDimitry Andric }; 222*0b57cec5SDimitry Andric 2235ffd83dbSDimitry Andric ConstantRange StackSafetyLocalAnalysis::offsetFrom(Value *Addr, Value *Base) { 2245ffd83dbSDimitry Andric if (!SE.isSCEVable(Addr->getType()) || !SE.isSCEVable(Base->getType())) 225*0b57cec5SDimitry Andric return UnknownRange; 226*0b57cec5SDimitry Andric 2275ffd83dbSDimitry Andric auto *PtrTy = IntegerType::getInt8PtrTy(SE.getContext()); 2285ffd83dbSDimitry Andric const SCEV *AddrExp = SE.getTruncateOrZeroExtend(SE.getSCEV(Addr), PtrTy); 2295ffd83dbSDimitry Andric const SCEV *BaseExp = SE.getTruncateOrZeroExtend(SE.getSCEV(Base), PtrTy); 2305ffd83dbSDimitry Andric const SCEV *Diff = SE.getMinusSCEV(AddrExp, BaseExp); 2315ffd83dbSDimitry Andric 2325ffd83dbSDimitry Andric ConstantRange Offset = SE.getSignedRange(Diff); 2335ffd83dbSDimitry Andric if (isUnsafe(Offset)) 2345ffd83dbSDimitry Andric return UnknownRange; 2355ffd83dbSDimitry Andric return Offset.sextOrTrunc(PointerSize); 236*0b57cec5SDimitry Andric } 237*0b57cec5SDimitry Andric 2385ffd83dbSDimitry Andric ConstantRange 2395ffd83dbSDimitry Andric StackSafetyLocalAnalysis::getAccessRange(Value *Addr, Value *Base, 2405ffd83dbSDimitry Andric const ConstantRange &SizeRange) { 2415ffd83dbSDimitry Andric // Zero-size loads and stores do not access memory. 2425ffd83dbSDimitry Andric if (SizeRange.isEmptySet()) 2435ffd83dbSDimitry Andric return ConstantRange::getEmpty(PointerSize); 2445ffd83dbSDimitry Andric assert(!isUnsafe(SizeRange)); 2455ffd83dbSDimitry Andric 2465ffd83dbSDimitry Andric ConstantRange Offsets = offsetFrom(Addr, Base); 2475ffd83dbSDimitry Andric if (isUnsafe(Offsets)) 248*0b57cec5SDimitry Andric return UnknownRange; 249*0b57cec5SDimitry Andric 2505ffd83dbSDimitry Andric Offsets = addOverflowNever(Offsets, SizeRange); 2515ffd83dbSDimitry Andric if (isUnsafe(Offsets)) 2525ffd83dbSDimitry Andric return UnknownRange; 2535ffd83dbSDimitry Andric return Offsets; 2545ffd83dbSDimitry Andric } 255*0b57cec5SDimitry Andric 2565ffd83dbSDimitry Andric ConstantRange StackSafetyLocalAnalysis::getAccessRange(Value *Addr, Value *Base, 2575ffd83dbSDimitry Andric TypeSize Size) { 2585ffd83dbSDimitry Andric if (Size.isScalable()) 2595ffd83dbSDimitry Andric return UnknownRange; 2605ffd83dbSDimitry Andric APInt APSize(PointerSize, Size.getFixedSize(), true); 2615ffd83dbSDimitry Andric if (APSize.isNegative()) 2625ffd83dbSDimitry Andric return UnknownRange; 2635ffd83dbSDimitry Andric return getAccessRange( 2645ffd83dbSDimitry Andric Addr, Base, ConstantRange(APInt::getNullValue(PointerSize), APSize)); 265*0b57cec5SDimitry Andric } 266*0b57cec5SDimitry Andric 267*0b57cec5SDimitry Andric ConstantRange StackSafetyLocalAnalysis::getMemIntrinsicAccessRange( 2685ffd83dbSDimitry Andric const MemIntrinsic *MI, const Use &U, Value *Base) { 2695ffd83dbSDimitry Andric if (const auto *MTI = dyn_cast<MemTransferInst>(MI)) { 270*0b57cec5SDimitry Andric if (MTI->getRawSource() != U && MTI->getRawDest() != U) 2715ffd83dbSDimitry Andric return ConstantRange::getEmpty(PointerSize); 272*0b57cec5SDimitry Andric } else { 273*0b57cec5SDimitry Andric if (MI->getRawDest() != U) 2745ffd83dbSDimitry Andric return ConstantRange::getEmpty(PointerSize); 275*0b57cec5SDimitry Andric } 2765ffd83dbSDimitry Andric 2775ffd83dbSDimitry Andric auto *CalculationTy = IntegerType::getIntNTy(SE.getContext(), PointerSize); 2785ffd83dbSDimitry Andric if (!SE.isSCEVable(MI->getLength()->getType())) 279*0b57cec5SDimitry Andric return UnknownRange; 2805ffd83dbSDimitry Andric 2815ffd83dbSDimitry Andric const SCEV *Expr = 2825ffd83dbSDimitry Andric SE.getTruncateOrZeroExtend(SE.getSCEV(MI->getLength()), CalculationTy); 2835ffd83dbSDimitry Andric ConstantRange Sizes = SE.getSignedRange(Expr); 2845ffd83dbSDimitry Andric if (Sizes.getUpper().isNegative() || isUnsafe(Sizes)) 2855ffd83dbSDimitry Andric return UnknownRange; 2865ffd83dbSDimitry Andric Sizes = Sizes.sextOrTrunc(PointerSize); 2875ffd83dbSDimitry Andric ConstantRange SizeRange(APInt::getNullValue(PointerSize), 2885ffd83dbSDimitry Andric Sizes.getUpper() - 1); 2895ffd83dbSDimitry Andric return getAccessRange(U, Base, SizeRange); 290*0b57cec5SDimitry Andric } 291*0b57cec5SDimitry Andric 292*0b57cec5SDimitry Andric /// The function analyzes all local uses of Ptr (alloca or argument) and 293*0b57cec5SDimitry Andric /// calculates local access range and all function calls where it was used. 2945ffd83dbSDimitry Andric bool StackSafetyLocalAnalysis::analyzeAllUses(Value *Ptr, 2955ffd83dbSDimitry Andric UseInfo<GlobalValue> &US, 2965ffd83dbSDimitry Andric const StackLifetime &SL) { 297*0b57cec5SDimitry Andric SmallPtrSet<const Value *, 16> Visited; 298*0b57cec5SDimitry Andric SmallVector<const Value *, 8> WorkList; 299*0b57cec5SDimitry Andric WorkList.push_back(Ptr); 3005ffd83dbSDimitry Andric const AllocaInst *AI = dyn_cast<AllocaInst>(Ptr); 301*0b57cec5SDimitry Andric 302*0b57cec5SDimitry Andric // A DFS search through all uses of the alloca in bitcasts/PHI/GEPs/etc. 303*0b57cec5SDimitry Andric while (!WorkList.empty()) { 304*0b57cec5SDimitry Andric const Value *V = WorkList.pop_back_val(); 305*0b57cec5SDimitry Andric for (const Use &UI : V->uses()) { 3065ffd83dbSDimitry Andric const auto *I = cast<Instruction>(UI.getUser()); 3075ffd83dbSDimitry Andric if (!SL.isReachable(I)) 3085ffd83dbSDimitry Andric continue; 3095ffd83dbSDimitry Andric 310*0b57cec5SDimitry Andric assert(V == UI.get()); 311*0b57cec5SDimitry Andric 312*0b57cec5SDimitry Andric switch (I->getOpcode()) { 313*0b57cec5SDimitry Andric case Instruction::Load: { 3145ffd83dbSDimitry Andric if (AI && !SL.isAliveAfter(AI, I)) { 3155ffd83dbSDimitry Andric US.updateRange(UnknownRange); 3165ffd83dbSDimitry Andric return false; 3175ffd83dbSDimitry Andric } 318*0b57cec5SDimitry Andric US.updateRange( 319*0b57cec5SDimitry Andric getAccessRange(UI, Ptr, DL.getTypeStoreSize(I->getType()))); 320*0b57cec5SDimitry Andric break; 321*0b57cec5SDimitry Andric } 322*0b57cec5SDimitry Andric 323*0b57cec5SDimitry Andric case Instruction::VAArg: 324*0b57cec5SDimitry Andric // "va-arg" from a pointer is safe. 325*0b57cec5SDimitry Andric break; 326*0b57cec5SDimitry Andric case Instruction::Store: { 327*0b57cec5SDimitry Andric if (V == I->getOperand(0)) { 328*0b57cec5SDimitry Andric // Stored the pointer - conservatively assume it may be unsafe. 329*0b57cec5SDimitry Andric US.updateRange(UnknownRange); 330*0b57cec5SDimitry Andric return false; 331*0b57cec5SDimitry Andric } 3325ffd83dbSDimitry Andric if (AI && !SL.isAliveAfter(AI, I)) { 3335ffd83dbSDimitry Andric US.updateRange(UnknownRange); 3345ffd83dbSDimitry Andric return false; 3355ffd83dbSDimitry Andric } 336*0b57cec5SDimitry Andric US.updateRange(getAccessRange( 337*0b57cec5SDimitry Andric UI, Ptr, DL.getTypeStoreSize(I->getOperand(0)->getType()))); 338*0b57cec5SDimitry Andric break; 339*0b57cec5SDimitry Andric } 340*0b57cec5SDimitry Andric 341*0b57cec5SDimitry Andric case Instruction::Ret: 342*0b57cec5SDimitry Andric // Information leak. 343*0b57cec5SDimitry Andric // FIXME: Process parameters correctly. This is a leak only if we return 344*0b57cec5SDimitry Andric // alloca. 345*0b57cec5SDimitry Andric US.updateRange(UnknownRange); 346*0b57cec5SDimitry Andric return false; 347*0b57cec5SDimitry Andric 348*0b57cec5SDimitry Andric case Instruction::Call: 349*0b57cec5SDimitry Andric case Instruction::Invoke: { 350*0b57cec5SDimitry Andric if (I->isLifetimeStartOrEnd()) 351*0b57cec5SDimitry Andric break; 352*0b57cec5SDimitry Andric 3535ffd83dbSDimitry Andric if (AI && !SL.isAliveAfter(AI, I)) { 3545ffd83dbSDimitry Andric US.updateRange(UnknownRange); 3555ffd83dbSDimitry Andric return false; 3565ffd83dbSDimitry Andric } 3575ffd83dbSDimitry Andric 358*0b57cec5SDimitry Andric if (const MemIntrinsic *MI = dyn_cast<MemIntrinsic>(I)) { 359*0b57cec5SDimitry Andric US.updateRange(getMemIntrinsicAccessRange(MI, UI, Ptr)); 360*0b57cec5SDimitry Andric break; 361*0b57cec5SDimitry Andric } 362*0b57cec5SDimitry Andric 3635ffd83dbSDimitry Andric const auto &CB = cast<CallBase>(*I); 3645ffd83dbSDimitry Andric if (!CB.isArgOperand(&UI)) { 3655ffd83dbSDimitry Andric US.updateRange(UnknownRange); 3665ffd83dbSDimitry Andric return false; 3675ffd83dbSDimitry Andric } 3685ffd83dbSDimitry Andric 3695ffd83dbSDimitry Andric unsigned ArgNo = CB.getArgOperandNo(&UI); 3705ffd83dbSDimitry Andric if (CB.isByValArgument(ArgNo)) { 3715ffd83dbSDimitry Andric US.updateRange(getAccessRange( 3725ffd83dbSDimitry Andric UI, Ptr, DL.getTypeStoreSize(CB.getParamByValType(ArgNo)))); 3735ffd83dbSDimitry Andric break; 3745ffd83dbSDimitry Andric } 3755ffd83dbSDimitry Andric 376*0b57cec5SDimitry Andric // FIXME: consult devirt? 377*0b57cec5SDimitry Andric // Do not follow aliases, otherwise we could inadvertently follow 378*0b57cec5SDimitry Andric // dso_preemptable aliases or aliases with interposable linkage. 3798bcb0991SDimitry Andric const GlobalValue *Callee = 3805ffd83dbSDimitry Andric dyn_cast<GlobalValue>(CB.getCalledOperand()->stripPointerCasts()); 381*0b57cec5SDimitry Andric if (!Callee) { 382*0b57cec5SDimitry Andric US.updateRange(UnknownRange); 383*0b57cec5SDimitry Andric return false; 384*0b57cec5SDimitry Andric } 385*0b57cec5SDimitry Andric 386*0b57cec5SDimitry Andric assert(isa<Function>(Callee) || isa<GlobalAlias>(Callee)); 3875ffd83dbSDimitry Andric US.Calls.emplace_back(Callee, ArgNo, offsetFrom(UI, Ptr)); 388*0b57cec5SDimitry Andric break; 389*0b57cec5SDimitry Andric } 390*0b57cec5SDimitry Andric 391*0b57cec5SDimitry Andric default: 392*0b57cec5SDimitry Andric if (Visited.insert(I).second) 393*0b57cec5SDimitry Andric WorkList.push_back(cast<const Instruction>(I)); 394*0b57cec5SDimitry Andric } 395*0b57cec5SDimitry Andric } 396*0b57cec5SDimitry Andric } 397*0b57cec5SDimitry Andric 398*0b57cec5SDimitry Andric return true; 399*0b57cec5SDimitry Andric } 400*0b57cec5SDimitry Andric 4015ffd83dbSDimitry Andric FunctionInfo<GlobalValue> StackSafetyLocalAnalysis::run() { 4025ffd83dbSDimitry Andric FunctionInfo<GlobalValue> Info; 403*0b57cec5SDimitry Andric assert(!F.isDeclaration() && 404*0b57cec5SDimitry Andric "Can't run StackSafety on a function declaration"); 405*0b57cec5SDimitry Andric 406*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "[StackSafety] " << F.getName() << "\n"); 407*0b57cec5SDimitry Andric 4085ffd83dbSDimitry Andric SmallVector<AllocaInst *, 64> Allocas; 4095ffd83dbSDimitry Andric for (auto &I : instructions(F)) 4105ffd83dbSDimitry Andric if (auto *AI = dyn_cast<AllocaInst>(&I)) 4115ffd83dbSDimitry Andric Allocas.push_back(AI); 4125ffd83dbSDimitry Andric StackLifetime SL(F, Allocas, StackLifetime::LivenessType::Must); 4135ffd83dbSDimitry Andric SL.run(); 4145ffd83dbSDimitry Andric 4155ffd83dbSDimitry Andric for (auto *AI : Allocas) { 4165ffd83dbSDimitry Andric auto &UI = Info.Allocas.emplace(AI, PointerSize).first->second; 4175ffd83dbSDimitry Andric analyzeAllUses(AI, UI, SL); 4185ffd83dbSDimitry Andric } 4195ffd83dbSDimitry Andric 4205ffd83dbSDimitry Andric for (Argument &A : make_range(F.arg_begin(), F.arg_end())) { 4215ffd83dbSDimitry Andric // Non pointers and bypass arguments are not going to be used in any global 4225ffd83dbSDimitry Andric // processing. 4235ffd83dbSDimitry Andric if (A.getType()->isPointerTy() && !A.hasByValAttr()) { 4245ffd83dbSDimitry Andric auto &UI = Info.Params.emplace(A.getArgNo(), PointerSize).first->second; 4255ffd83dbSDimitry Andric analyzeAllUses(&A, UI, SL); 426*0b57cec5SDimitry Andric } 427*0b57cec5SDimitry Andric } 428*0b57cec5SDimitry Andric 4295ffd83dbSDimitry Andric LLVM_DEBUG(Info.print(dbgs(), F.getName(), &F)); 430*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "[StackSafety] done\n"); 4315ffd83dbSDimitry Andric return Info; 432*0b57cec5SDimitry Andric } 433*0b57cec5SDimitry Andric 4345ffd83dbSDimitry Andric template <typename CalleeTy> class StackSafetyDataFlowAnalysis { 4355ffd83dbSDimitry Andric using FunctionMap = std::map<const CalleeTy *, FunctionInfo<CalleeTy>>; 436*0b57cec5SDimitry Andric 437*0b57cec5SDimitry Andric FunctionMap Functions; 438*0b57cec5SDimitry Andric const ConstantRange UnknownRange; 439*0b57cec5SDimitry Andric 4405ffd83dbSDimitry Andric // Callee-to-Caller multimap. 4415ffd83dbSDimitry Andric DenseMap<const CalleeTy *, SmallVector<const CalleeTy *, 4>> Callers; 4425ffd83dbSDimitry Andric SetVector<const CalleeTy *> WorkList; 4435ffd83dbSDimitry Andric 4445ffd83dbSDimitry Andric bool updateOneUse(UseInfo<CalleeTy> &US, bool UpdateToFullSet); 4455ffd83dbSDimitry Andric void updateOneNode(const CalleeTy *Callee, FunctionInfo<CalleeTy> &FS); 4465ffd83dbSDimitry Andric void updateOneNode(const CalleeTy *Callee) { 447*0b57cec5SDimitry Andric updateOneNode(Callee, Functions.find(Callee)->second); 448*0b57cec5SDimitry Andric } 449*0b57cec5SDimitry Andric void updateAllNodes() { 450*0b57cec5SDimitry Andric for (auto &F : Functions) 451*0b57cec5SDimitry Andric updateOneNode(F.first, F.second); 452*0b57cec5SDimitry Andric } 453*0b57cec5SDimitry Andric void runDataFlow(); 454*0b57cec5SDimitry Andric #ifndef NDEBUG 455*0b57cec5SDimitry Andric void verifyFixedPoint(); 456*0b57cec5SDimitry Andric #endif 457*0b57cec5SDimitry Andric 458*0b57cec5SDimitry Andric public: 4595ffd83dbSDimitry Andric StackSafetyDataFlowAnalysis(uint32_t PointerBitWidth, FunctionMap Functions) 4605ffd83dbSDimitry Andric : Functions(std::move(Functions)), 4615ffd83dbSDimitry Andric UnknownRange(ConstantRange::getFull(PointerBitWidth)) {} 4625ffd83dbSDimitry Andric 4635ffd83dbSDimitry Andric const FunctionMap &run(); 4645ffd83dbSDimitry Andric 4655ffd83dbSDimitry Andric ConstantRange getArgumentAccessRange(const CalleeTy *Callee, unsigned ParamNo, 4665ffd83dbSDimitry Andric const ConstantRange &Offsets) const; 467*0b57cec5SDimitry Andric }; 468*0b57cec5SDimitry Andric 4695ffd83dbSDimitry Andric template <typename CalleeTy> 4705ffd83dbSDimitry Andric ConstantRange StackSafetyDataFlowAnalysis<CalleeTy>::getArgumentAccessRange( 4715ffd83dbSDimitry Andric const CalleeTy *Callee, unsigned ParamNo, 4725ffd83dbSDimitry Andric const ConstantRange &Offsets) const { 4735ffd83dbSDimitry Andric auto FnIt = Functions.find(Callee); 474*0b57cec5SDimitry Andric // Unknown callee (outside of LTO domain or an indirect call). 4755ffd83dbSDimitry Andric if (FnIt == Functions.end()) 476*0b57cec5SDimitry Andric return UnknownRange; 4775ffd83dbSDimitry Andric auto &FS = FnIt->second; 4785ffd83dbSDimitry Andric auto ParamIt = FS.Params.find(ParamNo); 4795ffd83dbSDimitry Andric if (ParamIt == FS.Params.end()) 480*0b57cec5SDimitry Andric return UnknownRange; 4815ffd83dbSDimitry Andric auto &Access = ParamIt->second.Range; 4825ffd83dbSDimitry Andric if (Access.isEmptySet()) 4835ffd83dbSDimitry Andric return Access; 4845ffd83dbSDimitry Andric if (Access.isFullSet()) 485*0b57cec5SDimitry Andric return UnknownRange; 4865ffd83dbSDimitry Andric return addOverflowNever(Access, Offsets); 487*0b57cec5SDimitry Andric } 488*0b57cec5SDimitry Andric 4895ffd83dbSDimitry Andric template <typename CalleeTy> 4905ffd83dbSDimitry Andric bool StackSafetyDataFlowAnalysis<CalleeTy>::updateOneUse(UseInfo<CalleeTy> &US, 491*0b57cec5SDimitry Andric bool UpdateToFullSet) { 492*0b57cec5SDimitry Andric bool Changed = false; 493*0b57cec5SDimitry Andric for (auto &CS : US.Calls) { 494*0b57cec5SDimitry Andric assert(!CS.Offset.isEmptySet() && 495*0b57cec5SDimitry Andric "Param range can't be empty-set, invalid offset range"); 496*0b57cec5SDimitry Andric 4975ffd83dbSDimitry Andric ConstantRange CalleeRange = 4985ffd83dbSDimitry Andric getArgumentAccessRange(CS.Callee, CS.ParamNo, CS.Offset); 499*0b57cec5SDimitry Andric if (!US.Range.contains(CalleeRange)) { 500*0b57cec5SDimitry Andric Changed = true; 501*0b57cec5SDimitry Andric if (UpdateToFullSet) 502*0b57cec5SDimitry Andric US.Range = UnknownRange; 503*0b57cec5SDimitry Andric else 504*0b57cec5SDimitry Andric US.Range = US.Range.unionWith(CalleeRange); 505*0b57cec5SDimitry Andric } 506*0b57cec5SDimitry Andric } 507*0b57cec5SDimitry Andric return Changed; 508*0b57cec5SDimitry Andric } 509*0b57cec5SDimitry Andric 5105ffd83dbSDimitry Andric template <typename CalleeTy> 5115ffd83dbSDimitry Andric void StackSafetyDataFlowAnalysis<CalleeTy>::updateOneNode( 5125ffd83dbSDimitry Andric const CalleeTy *Callee, FunctionInfo<CalleeTy> &FS) { 513*0b57cec5SDimitry Andric bool UpdateToFullSet = FS.UpdateCount > StackSafetyMaxIterations; 514*0b57cec5SDimitry Andric bool Changed = false; 5155ffd83dbSDimitry Andric for (auto &KV : FS.Params) 5165ffd83dbSDimitry Andric Changed |= updateOneUse(KV.second, UpdateToFullSet); 517*0b57cec5SDimitry Andric 518*0b57cec5SDimitry Andric if (Changed) { 519*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "=== update [" << FS.UpdateCount 5205ffd83dbSDimitry Andric << (UpdateToFullSet ? ", full-set" : "") << "] " << &FS 5215ffd83dbSDimitry Andric << "\n"); 522*0b57cec5SDimitry Andric // Callers of this function may need updating. 523*0b57cec5SDimitry Andric for (auto &CallerID : Callers[Callee]) 524*0b57cec5SDimitry Andric WorkList.insert(CallerID); 525*0b57cec5SDimitry Andric 526*0b57cec5SDimitry Andric ++FS.UpdateCount; 527*0b57cec5SDimitry Andric } 528*0b57cec5SDimitry Andric } 529*0b57cec5SDimitry Andric 5305ffd83dbSDimitry Andric template <typename CalleeTy> 5315ffd83dbSDimitry Andric void StackSafetyDataFlowAnalysis<CalleeTy>::runDataFlow() { 5325ffd83dbSDimitry Andric SmallVector<const CalleeTy *, 16> Callees; 533*0b57cec5SDimitry Andric for (auto &F : Functions) { 534*0b57cec5SDimitry Andric Callees.clear(); 5355ffd83dbSDimitry Andric auto &FS = F.second; 5365ffd83dbSDimitry Andric for (auto &KV : FS.Params) 5375ffd83dbSDimitry Andric for (auto &CS : KV.second.Calls) 538*0b57cec5SDimitry Andric Callees.push_back(CS.Callee); 539*0b57cec5SDimitry Andric 540*0b57cec5SDimitry Andric llvm::sort(Callees); 541*0b57cec5SDimitry Andric Callees.erase(std::unique(Callees.begin(), Callees.end()), Callees.end()); 542*0b57cec5SDimitry Andric 543*0b57cec5SDimitry Andric for (auto &Callee : Callees) 544*0b57cec5SDimitry Andric Callers[Callee].push_back(F.first); 545*0b57cec5SDimitry Andric } 546*0b57cec5SDimitry Andric 547*0b57cec5SDimitry Andric updateAllNodes(); 548*0b57cec5SDimitry Andric 549*0b57cec5SDimitry Andric while (!WorkList.empty()) { 5505ffd83dbSDimitry Andric const CalleeTy *Callee = WorkList.back(); 551*0b57cec5SDimitry Andric WorkList.pop_back(); 552*0b57cec5SDimitry Andric updateOneNode(Callee); 553*0b57cec5SDimitry Andric } 554*0b57cec5SDimitry Andric } 555*0b57cec5SDimitry Andric 556*0b57cec5SDimitry Andric #ifndef NDEBUG 5575ffd83dbSDimitry Andric template <typename CalleeTy> 5585ffd83dbSDimitry Andric void StackSafetyDataFlowAnalysis<CalleeTy>::verifyFixedPoint() { 559*0b57cec5SDimitry Andric WorkList.clear(); 560*0b57cec5SDimitry Andric updateAllNodes(); 561*0b57cec5SDimitry Andric assert(WorkList.empty()); 562*0b57cec5SDimitry Andric } 563*0b57cec5SDimitry Andric #endif 564*0b57cec5SDimitry Andric 5655ffd83dbSDimitry Andric template <typename CalleeTy> 5665ffd83dbSDimitry Andric const typename StackSafetyDataFlowAnalysis<CalleeTy>::FunctionMap & 5675ffd83dbSDimitry Andric StackSafetyDataFlowAnalysis<CalleeTy>::run() { 568*0b57cec5SDimitry Andric runDataFlow(); 569*0b57cec5SDimitry Andric LLVM_DEBUG(verifyFixedPoint()); 5705ffd83dbSDimitry Andric return Functions; 5715ffd83dbSDimitry Andric } 572*0b57cec5SDimitry Andric 5735ffd83dbSDimitry Andric FunctionSummary *resolveCallee(GlobalValueSummary *S) { 5745ffd83dbSDimitry Andric while (S) { 5755ffd83dbSDimitry Andric if (!S->isLive() || !S->isDSOLocal()) 5765ffd83dbSDimitry Andric return nullptr; 5775ffd83dbSDimitry Andric if (FunctionSummary *FS = dyn_cast<FunctionSummary>(S)) 5785ffd83dbSDimitry Andric return FS; 5795ffd83dbSDimitry Andric AliasSummary *AS = dyn_cast<AliasSummary>(S); 5805ffd83dbSDimitry Andric if (!AS) 5815ffd83dbSDimitry Andric return nullptr; 5825ffd83dbSDimitry Andric S = AS->getBaseObject(); 5835ffd83dbSDimitry Andric if (S == AS) 5845ffd83dbSDimitry Andric return nullptr; 5855ffd83dbSDimitry Andric } 5865ffd83dbSDimitry Andric return nullptr; 5875ffd83dbSDimitry Andric } 5885ffd83dbSDimitry Andric 5895ffd83dbSDimitry Andric const Function *findCalleeInModule(const GlobalValue *GV) { 5905ffd83dbSDimitry Andric while (GV) { 5915ffd83dbSDimitry Andric if (GV->isDeclaration() || GV->isInterposable() || !GV->isDSOLocal()) 5925ffd83dbSDimitry Andric return nullptr; 5935ffd83dbSDimitry Andric if (const Function *F = dyn_cast<Function>(GV)) 5945ffd83dbSDimitry Andric return F; 5955ffd83dbSDimitry Andric const GlobalAlias *A = dyn_cast<GlobalAlias>(GV); 5965ffd83dbSDimitry Andric if (!A) 5975ffd83dbSDimitry Andric return nullptr; 5985ffd83dbSDimitry Andric GV = A->getBaseObject(); 5995ffd83dbSDimitry Andric if (GV == A) 6005ffd83dbSDimitry Andric return nullptr; 6015ffd83dbSDimitry Andric } 6025ffd83dbSDimitry Andric return nullptr; 6035ffd83dbSDimitry Andric } 6045ffd83dbSDimitry Andric 6055ffd83dbSDimitry Andric GlobalValueSummary *getGlobalValueSummary(const ModuleSummaryIndex *Index, 6065ffd83dbSDimitry Andric uint64_t ValueGUID) { 6075ffd83dbSDimitry Andric auto VI = Index->getValueInfo(ValueGUID); 6085ffd83dbSDimitry Andric if (!VI || VI.getSummaryList().empty()) 6095ffd83dbSDimitry Andric return nullptr; 6105ffd83dbSDimitry Andric assert(VI.getSummaryList().size() == 1); 6115ffd83dbSDimitry Andric auto &Summary = VI.getSummaryList()[0]; 6125ffd83dbSDimitry Andric return Summary.get(); 6135ffd83dbSDimitry Andric } 6145ffd83dbSDimitry Andric 6155ffd83dbSDimitry Andric const ConstantRange *findParamAccess(const FunctionSummary &FS, 6165ffd83dbSDimitry Andric uint32_t ParamNo) { 6175ffd83dbSDimitry Andric assert(FS.isLive()); 6185ffd83dbSDimitry Andric assert(FS.isDSOLocal()); 6195ffd83dbSDimitry Andric for (auto &PS : FS.paramAccesses()) 6205ffd83dbSDimitry Andric if (ParamNo == PS.ParamNo) 6215ffd83dbSDimitry Andric return &PS.Use; 6225ffd83dbSDimitry Andric return nullptr; 6235ffd83dbSDimitry Andric } 6245ffd83dbSDimitry Andric 6255ffd83dbSDimitry Andric void resolveAllCalls(UseInfo<GlobalValue> &Use, 6265ffd83dbSDimitry Andric const ModuleSummaryIndex *Index) { 6275ffd83dbSDimitry Andric ConstantRange FullSet(Use.Range.getBitWidth(), true); 6285ffd83dbSDimitry Andric for (auto &C : Use.Calls) { 6295ffd83dbSDimitry Andric const Function *F = findCalleeInModule(C.Callee); 6305ffd83dbSDimitry Andric if (F) { 6315ffd83dbSDimitry Andric C.Callee = F; 6325ffd83dbSDimitry Andric continue; 6335ffd83dbSDimitry Andric } 6345ffd83dbSDimitry Andric 6355ffd83dbSDimitry Andric if (!Index) 6365ffd83dbSDimitry Andric return Use.updateRange(FullSet); 6375ffd83dbSDimitry Andric GlobalValueSummary *GVS = getGlobalValueSummary(Index, C.Callee->getGUID()); 6385ffd83dbSDimitry Andric 6395ffd83dbSDimitry Andric FunctionSummary *FS = resolveCallee(GVS); 6405ffd83dbSDimitry Andric if (!FS) 6415ffd83dbSDimitry Andric return Use.updateRange(FullSet); 6425ffd83dbSDimitry Andric const ConstantRange *Found = findParamAccess(*FS, C.ParamNo); 6435ffd83dbSDimitry Andric if (!Found) 6445ffd83dbSDimitry Andric return Use.updateRange(FullSet); 6455ffd83dbSDimitry Andric ConstantRange Access = Found->sextOrTrunc(Use.Range.getBitWidth()); 6465ffd83dbSDimitry Andric Use.updateRange(addOverflowNever(Access, C.Offset)); 6475ffd83dbSDimitry Andric C.Callee = nullptr; 6485ffd83dbSDimitry Andric } 6495ffd83dbSDimitry Andric 6505ffd83dbSDimitry Andric Use.Calls.erase(std::remove_if(Use.Calls.begin(), Use.Calls.end(), 6515ffd83dbSDimitry Andric [](auto &T) { return !T.Callee; }), 6525ffd83dbSDimitry Andric Use.Calls.end()); 6535ffd83dbSDimitry Andric } 6545ffd83dbSDimitry Andric 6555ffd83dbSDimitry Andric GVToSSI createGlobalStackSafetyInfo( 6565ffd83dbSDimitry Andric std::map<const GlobalValue *, FunctionInfo<GlobalValue>> Functions, 6575ffd83dbSDimitry Andric const ModuleSummaryIndex *Index) { 6585ffd83dbSDimitry Andric GVToSSI SSI; 6595ffd83dbSDimitry Andric if (Functions.empty()) 660*0b57cec5SDimitry Andric return SSI; 6615ffd83dbSDimitry Andric 6625ffd83dbSDimitry Andric // FIXME: Simplify printing and remove copying here. 6635ffd83dbSDimitry Andric auto Copy = Functions; 6645ffd83dbSDimitry Andric 6655ffd83dbSDimitry Andric for (auto &FnKV : Copy) 6665ffd83dbSDimitry Andric for (auto &KV : FnKV.second.Params) 6675ffd83dbSDimitry Andric resolveAllCalls(KV.second, Index); 6685ffd83dbSDimitry Andric 6695ffd83dbSDimitry Andric uint32_t PointerSize = Copy.begin() 6705ffd83dbSDimitry Andric ->first->getParent() 6715ffd83dbSDimitry Andric ->getDataLayout() 6725ffd83dbSDimitry Andric .getMaxPointerSizeInBits(); 6735ffd83dbSDimitry Andric StackSafetyDataFlowAnalysis<GlobalValue> SSDFA(PointerSize, std::move(Copy)); 6745ffd83dbSDimitry Andric 6755ffd83dbSDimitry Andric for (auto &F : SSDFA.run()) { 6765ffd83dbSDimitry Andric auto FI = F.second; 6775ffd83dbSDimitry Andric auto &SrcF = Functions[F.first]; 6785ffd83dbSDimitry Andric for (auto &KV : FI.Allocas) { 6795ffd83dbSDimitry Andric auto &A = KV.second; 6805ffd83dbSDimitry Andric resolveAllCalls(A, Index); 6815ffd83dbSDimitry Andric for (auto &C : A.Calls) { 6825ffd83dbSDimitry Andric A.updateRange( 6835ffd83dbSDimitry Andric SSDFA.getArgumentAccessRange(C.Callee, C.ParamNo, C.Offset)); 6845ffd83dbSDimitry Andric } 6855ffd83dbSDimitry Andric // FIXME: This is needed only to preserve calls in print() results. 6865ffd83dbSDimitry Andric A.Calls = SrcF.Allocas.find(KV.first)->second.Calls; 6875ffd83dbSDimitry Andric } 6885ffd83dbSDimitry Andric for (auto &KV : FI.Params) { 6895ffd83dbSDimitry Andric auto &P = KV.second; 6905ffd83dbSDimitry Andric P.Calls = SrcF.Params.find(KV.first)->second.Calls; 6915ffd83dbSDimitry Andric } 6925ffd83dbSDimitry Andric SSI[F.first] = std::move(FI); 693*0b57cec5SDimitry Andric } 694*0b57cec5SDimitry Andric 6955ffd83dbSDimitry Andric return SSI; 696*0b57cec5SDimitry Andric } 697*0b57cec5SDimitry Andric 698*0b57cec5SDimitry Andric } // end anonymous namespace 699*0b57cec5SDimitry Andric 700*0b57cec5SDimitry Andric StackSafetyInfo::StackSafetyInfo() = default; 701*0b57cec5SDimitry Andric 7025ffd83dbSDimitry Andric StackSafetyInfo::StackSafetyInfo(Function *F, 7035ffd83dbSDimitry Andric std::function<ScalarEvolution &()> GetSE) 7045ffd83dbSDimitry Andric : F(F), GetSE(GetSE) {} 7055ffd83dbSDimitry Andric 7065ffd83dbSDimitry Andric StackSafetyInfo::StackSafetyInfo(StackSafetyInfo &&) = default; 7075ffd83dbSDimitry Andric 7085ffd83dbSDimitry Andric StackSafetyInfo &StackSafetyInfo::operator=(StackSafetyInfo &&) = default; 709*0b57cec5SDimitry Andric 710*0b57cec5SDimitry Andric StackSafetyInfo::~StackSafetyInfo() = default; 711*0b57cec5SDimitry Andric 7125ffd83dbSDimitry Andric const StackSafetyInfo::InfoTy &StackSafetyInfo::getInfo() const { 7135ffd83dbSDimitry Andric if (!Info) { 7145ffd83dbSDimitry Andric StackSafetyLocalAnalysis SSLA(*F, GetSE()); 7155ffd83dbSDimitry Andric Info.reset(new InfoTy{SSLA.run()}); 7165ffd83dbSDimitry Andric } 7175ffd83dbSDimitry Andric return *Info; 7185ffd83dbSDimitry Andric } 7195ffd83dbSDimitry Andric 7205ffd83dbSDimitry Andric void StackSafetyInfo::print(raw_ostream &O) const { 7215ffd83dbSDimitry Andric getInfo().Info.print(O, F->getName(), dyn_cast<Function>(F)); 7225ffd83dbSDimitry Andric } 7235ffd83dbSDimitry Andric 7245ffd83dbSDimitry Andric const StackSafetyGlobalInfo::InfoTy &StackSafetyGlobalInfo::getInfo() const { 7255ffd83dbSDimitry Andric if (!Info) { 7265ffd83dbSDimitry Andric std::map<const GlobalValue *, FunctionInfo<GlobalValue>> Functions; 7275ffd83dbSDimitry Andric for (auto &F : M->functions()) { 7285ffd83dbSDimitry Andric if (!F.isDeclaration()) { 7295ffd83dbSDimitry Andric auto FI = GetSSI(F).getInfo().Info; 7305ffd83dbSDimitry Andric Functions.emplace(&F, std::move(FI)); 7315ffd83dbSDimitry Andric } 7325ffd83dbSDimitry Andric } 7335ffd83dbSDimitry Andric Info.reset(new InfoTy{ 7345ffd83dbSDimitry Andric createGlobalStackSafetyInfo(std::move(Functions), Index), {}}); 7355ffd83dbSDimitry Andric for (auto &FnKV : Info->Info) { 7365ffd83dbSDimitry Andric for (auto &KV : FnKV.second.Allocas) { 7375ffd83dbSDimitry Andric ++NumAllocaTotal; 7385ffd83dbSDimitry Andric const AllocaInst *AI = KV.first; 7395ffd83dbSDimitry Andric if (getStaticAllocaSizeRange(*AI).contains(KV.second.Range)) { 7405ffd83dbSDimitry Andric Info->SafeAllocas.insert(AI); 7415ffd83dbSDimitry Andric ++NumAllocaStackSafe; 7425ffd83dbSDimitry Andric } 7435ffd83dbSDimitry Andric } 7445ffd83dbSDimitry Andric } 7455ffd83dbSDimitry Andric if (StackSafetyPrint) 7465ffd83dbSDimitry Andric print(errs()); 7475ffd83dbSDimitry Andric } 7485ffd83dbSDimitry Andric return *Info; 7495ffd83dbSDimitry Andric } 7505ffd83dbSDimitry Andric 7515ffd83dbSDimitry Andric std::vector<FunctionSummary::ParamAccess> 7525ffd83dbSDimitry Andric StackSafetyInfo::getParamAccesses() const { 7535ffd83dbSDimitry Andric // Implementation transforms internal representation of parameter information 7545ffd83dbSDimitry Andric // into FunctionSummary format. 7555ffd83dbSDimitry Andric std::vector<FunctionSummary::ParamAccess> ParamAccesses; 7565ffd83dbSDimitry Andric for (const auto &KV : getInfo().Info.Params) { 7575ffd83dbSDimitry Andric auto &PS = KV.second; 7585ffd83dbSDimitry Andric // Parameter accessed by any or unknown offset, represented as FullSet by 7595ffd83dbSDimitry Andric // StackSafety, is handled as the parameter for which we have no 7605ffd83dbSDimitry Andric // StackSafety info at all. So drop it to reduce summary size. 7615ffd83dbSDimitry Andric if (PS.Range.isFullSet()) 7625ffd83dbSDimitry Andric continue; 7635ffd83dbSDimitry Andric 7645ffd83dbSDimitry Andric ParamAccesses.emplace_back(KV.first, PS.Range); 7655ffd83dbSDimitry Andric FunctionSummary::ParamAccess &Param = ParamAccesses.back(); 7665ffd83dbSDimitry Andric 7675ffd83dbSDimitry Andric Param.Calls.reserve(PS.Calls.size()); 7685ffd83dbSDimitry Andric for (auto &C : PS.Calls) { 7695ffd83dbSDimitry Andric // Parameter forwarded into another function by any or unknown offset 7705ffd83dbSDimitry Andric // will make ParamAccess::Range as FullSet anyway. So we can drop the 7715ffd83dbSDimitry Andric // entire parameter like we did above. 7725ffd83dbSDimitry Andric // TODO(vitalybuka): Return already filtered parameters from getInfo(). 7735ffd83dbSDimitry Andric if (C.Offset.isFullSet()) { 7745ffd83dbSDimitry Andric ParamAccesses.pop_back(); 7755ffd83dbSDimitry Andric break; 7765ffd83dbSDimitry Andric } 7775ffd83dbSDimitry Andric Param.Calls.emplace_back(C.ParamNo, C.Callee->getGUID(), C.Offset); 7785ffd83dbSDimitry Andric } 7795ffd83dbSDimitry Andric } 7805ffd83dbSDimitry Andric return ParamAccesses; 7815ffd83dbSDimitry Andric } 7825ffd83dbSDimitry Andric 7835ffd83dbSDimitry Andric StackSafetyGlobalInfo::StackSafetyGlobalInfo() = default; 7845ffd83dbSDimitry Andric 7855ffd83dbSDimitry Andric StackSafetyGlobalInfo::StackSafetyGlobalInfo( 7865ffd83dbSDimitry Andric Module *M, std::function<const StackSafetyInfo &(Function &F)> GetSSI, 7875ffd83dbSDimitry Andric const ModuleSummaryIndex *Index) 7885ffd83dbSDimitry Andric : M(M), GetSSI(GetSSI), Index(Index) { 7895ffd83dbSDimitry Andric if (StackSafetyRun) 7905ffd83dbSDimitry Andric getInfo(); 7915ffd83dbSDimitry Andric } 7925ffd83dbSDimitry Andric 7935ffd83dbSDimitry Andric StackSafetyGlobalInfo::StackSafetyGlobalInfo(StackSafetyGlobalInfo &&) = 7945ffd83dbSDimitry Andric default; 7955ffd83dbSDimitry Andric 7965ffd83dbSDimitry Andric StackSafetyGlobalInfo & 7975ffd83dbSDimitry Andric StackSafetyGlobalInfo::operator=(StackSafetyGlobalInfo &&) = default; 7985ffd83dbSDimitry Andric 7995ffd83dbSDimitry Andric StackSafetyGlobalInfo::~StackSafetyGlobalInfo() = default; 8005ffd83dbSDimitry Andric 8015ffd83dbSDimitry Andric bool StackSafetyGlobalInfo::isSafe(const AllocaInst &AI) const { 8025ffd83dbSDimitry Andric const auto &Info = getInfo(); 8035ffd83dbSDimitry Andric return Info.SafeAllocas.count(&AI); 8045ffd83dbSDimitry Andric } 8055ffd83dbSDimitry Andric 8065ffd83dbSDimitry Andric void StackSafetyGlobalInfo::print(raw_ostream &O) const { 8075ffd83dbSDimitry Andric auto &SSI = getInfo().Info; 8085ffd83dbSDimitry Andric if (SSI.empty()) 8095ffd83dbSDimitry Andric return; 8105ffd83dbSDimitry Andric const Module &M = *SSI.begin()->first->getParent(); 8115ffd83dbSDimitry Andric for (auto &F : M.functions()) { 8125ffd83dbSDimitry Andric if (!F.isDeclaration()) { 8135ffd83dbSDimitry Andric SSI.find(&F)->second.print(O, F.getName(), &F); 8145ffd83dbSDimitry Andric O << "\n"; 8155ffd83dbSDimitry Andric } 8165ffd83dbSDimitry Andric } 8175ffd83dbSDimitry Andric } 8185ffd83dbSDimitry Andric 8195ffd83dbSDimitry Andric LLVM_DUMP_METHOD void StackSafetyGlobalInfo::dump() const { print(dbgs()); } 820*0b57cec5SDimitry Andric 821*0b57cec5SDimitry Andric AnalysisKey StackSafetyAnalysis::Key; 822*0b57cec5SDimitry Andric 823*0b57cec5SDimitry Andric StackSafetyInfo StackSafetyAnalysis::run(Function &F, 824*0b57cec5SDimitry Andric FunctionAnalysisManager &AM) { 8255ffd83dbSDimitry Andric return StackSafetyInfo(&F, [&AM, &F]() -> ScalarEvolution & { 8265ffd83dbSDimitry Andric return AM.getResult<ScalarEvolutionAnalysis>(F); 8275ffd83dbSDimitry Andric }); 828*0b57cec5SDimitry Andric } 829*0b57cec5SDimitry Andric 830*0b57cec5SDimitry Andric PreservedAnalyses StackSafetyPrinterPass::run(Function &F, 831*0b57cec5SDimitry Andric FunctionAnalysisManager &AM) { 832*0b57cec5SDimitry Andric OS << "'Stack Safety Local Analysis' for function '" << F.getName() << "'\n"; 833*0b57cec5SDimitry Andric AM.getResult<StackSafetyAnalysis>(F).print(OS); 834*0b57cec5SDimitry Andric return PreservedAnalyses::all(); 835*0b57cec5SDimitry Andric } 836*0b57cec5SDimitry Andric 837*0b57cec5SDimitry Andric char StackSafetyInfoWrapperPass::ID = 0; 838*0b57cec5SDimitry Andric 839*0b57cec5SDimitry Andric StackSafetyInfoWrapperPass::StackSafetyInfoWrapperPass() : FunctionPass(ID) { 840*0b57cec5SDimitry Andric initializeStackSafetyInfoWrapperPassPass(*PassRegistry::getPassRegistry()); 841*0b57cec5SDimitry Andric } 842*0b57cec5SDimitry Andric 843*0b57cec5SDimitry Andric void StackSafetyInfoWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const { 8445ffd83dbSDimitry Andric AU.addRequiredTransitive<ScalarEvolutionWrapperPass>(); 845*0b57cec5SDimitry Andric AU.setPreservesAll(); 846*0b57cec5SDimitry Andric } 847*0b57cec5SDimitry Andric 848*0b57cec5SDimitry Andric void StackSafetyInfoWrapperPass::print(raw_ostream &O, const Module *M) const { 849*0b57cec5SDimitry Andric SSI.print(O); 850*0b57cec5SDimitry Andric } 851*0b57cec5SDimitry Andric 852*0b57cec5SDimitry Andric bool StackSafetyInfoWrapperPass::runOnFunction(Function &F) { 8535ffd83dbSDimitry Andric auto *SE = &getAnalysis<ScalarEvolutionWrapperPass>().getSE(); 8545ffd83dbSDimitry Andric SSI = {&F, [SE]() -> ScalarEvolution & { return *SE; }}; 855*0b57cec5SDimitry Andric return false; 856*0b57cec5SDimitry Andric } 857*0b57cec5SDimitry Andric 858*0b57cec5SDimitry Andric AnalysisKey StackSafetyGlobalAnalysis::Key; 859*0b57cec5SDimitry Andric 860*0b57cec5SDimitry Andric StackSafetyGlobalInfo 861*0b57cec5SDimitry Andric StackSafetyGlobalAnalysis::run(Module &M, ModuleAnalysisManager &AM) { 8625ffd83dbSDimitry Andric // FIXME: Lookup Module Summary. 863*0b57cec5SDimitry Andric FunctionAnalysisManager &FAM = 864*0b57cec5SDimitry Andric AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); 8655ffd83dbSDimitry Andric return {&M, 8665ffd83dbSDimitry Andric [&FAM](Function &F) -> const StackSafetyInfo & { 867*0b57cec5SDimitry Andric return FAM.getResult<StackSafetyAnalysis>(F); 8685ffd83dbSDimitry Andric }, 8695ffd83dbSDimitry Andric nullptr}; 870*0b57cec5SDimitry Andric } 871*0b57cec5SDimitry Andric 872*0b57cec5SDimitry Andric PreservedAnalyses StackSafetyGlobalPrinterPass::run(Module &M, 873*0b57cec5SDimitry Andric ModuleAnalysisManager &AM) { 874*0b57cec5SDimitry Andric OS << "'Stack Safety Analysis' for module '" << M.getName() << "'\n"; 8755ffd83dbSDimitry Andric AM.getResult<StackSafetyGlobalAnalysis>(M).print(OS); 876*0b57cec5SDimitry Andric return PreservedAnalyses::all(); 877*0b57cec5SDimitry Andric } 878*0b57cec5SDimitry Andric 879*0b57cec5SDimitry Andric char StackSafetyGlobalInfoWrapperPass::ID = 0; 880*0b57cec5SDimitry Andric 881*0b57cec5SDimitry Andric StackSafetyGlobalInfoWrapperPass::StackSafetyGlobalInfoWrapperPass() 882*0b57cec5SDimitry Andric : ModulePass(ID) { 883*0b57cec5SDimitry Andric initializeStackSafetyGlobalInfoWrapperPassPass( 884*0b57cec5SDimitry Andric *PassRegistry::getPassRegistry()); 885*0b57cec5SDimitry Andric } 886*0b57cec5SDimitry Andric 8875ffd83dbSDimitry Andric StackSafetyGlobalInfoWrapperPass::~StackSafetyGlobalInfoWrapperPass() = default; 8885ffd83dbSDimitry Andric 889*0b57cec5SDimitry Andric void StackSafetyGlobalInfoWrapperPass::print(raw_ostream &O, 890*0b57cec5SDimitry Andric const Module *M) const { 8915ffd83dbSDimitry Andric SSGI.print(O); 892*0b57cec5SDimitry Andric } 893*0b57cec5SDimitry Andric 894*0b57cec5SDimitry Andric void StackSafetyGlobalInfoWrapperPass::getAnalysisUsage( 895*0b57cec5SDimitry Andric AnalysisUsage &AU) const { 8965ffd83dbSDimitry Andric AU.setPreservesAll(); 897*0b57cec5SDimitry Andric AU.addRequired<StackSafetyInfoWrapperPass>(); 898*0b57cec5SDimitry Andric } 899*0b57cec5SDimitry Andric 900*0b57cec5SDimitry Andric bool StackSafetyGlobalInfoWrapperPass::runOnModule(Module &M) { 9015ffd83dbSDimitry Andric const ModuleSummaryIndex *ImportSummary = nullptr; 9025ffd83dbSDimitry Andric if (auto *IndexWrapperPass = 9035ffd83dbSDimitry Andric getAnalysisIfAvailable<ImmutableModuleSummaryIndexWrapperPass>()) 9045ffd83dbSDimitry Andric ImportSummary = IndexWrapperPass->getIndex(); 9055ffd83dbSDimitry Andric 9065ffd83dbSDimitry Andric SSGI = {&M, 9075ffd83dbSDimitry Andric [this](Function &F) -> const StackSafetyInfo & { 908*0b57cec5SDimitry Andric return getAnalysis<StackSafetyInfoWrapperPass>(F).getResult(); 9095ffd83dbSDimitry Andric }, 9105ffd83dbSDimitry Andric ImportSummary}; 911*0b57cec5SDimitry Andric return false; 912*0b57cec5SDimitry Andric } 913*0b57cec5SDimitry Andric 9145ffd83dbSDimitry Andric bool llvm::needsParamAccessSummary(const Module &M) { 9155ffd83dbSDimitry Andric if (StackSafetyRun) 9165ffd83dbSDimitry Andric return true; 9175ffd83dbSDimitry Andric for (auto &F : M.functions()) 9185ffd83dbSDimitry Andric if (F.hasFnAttribute(Attribute::SanitizeMemTag)) 9195ffd83dbSDimitry Andric return true; 9205ffd83dbSDimitry Andric return false; 9215ffd83dbSDimitry Andric } 9225ffd83dbSDimitry Andric 9235ffd83dbSDimitry Andric void llvm::generateParamAccessSummary(ModuleSummaryIndex &Index) { 9245ffd83dbSDimitry Andric const ConstantRange FullSet(FunctionSummary::ParamAccess::RangeWidth, true); 9255ffd83dbSDimitry Andric std::map<const FunctionSummary *, FunctionInfo<FunctionSummary>> Functions; 9265ffd83dbSDimitry Andric 9275ffd83dbSDimitry Andric // Convert the ModuleSummaryIndex to a FunctionMap 9285ffd83dbSDimitry Andric for (auto &GVS : Index) { 9295ffd83dbSDimitry Andric for (auto &GV : GVS.second.SummaryList) { 9305ffd83dbSDimitry Andric FunctionSummary *FS = dyn_cast<FunctionSummary>(GV.get()); 9315ffd83dbSDimitry Andric if (!FS) 9325ffd83dbSDimitry Andric continue; 9335ffd83dbSDimitry Andric if (FS->isLive() && FS->isDSOLocal()) { 9345ffd83dbSDimitry Andric FunctionInfo<FunctionSummary> FI; 9355ffd83dbSDimitry Andric for (auto &PS : FS->paramAccesses()) { 9365ffd83dbSDimitry Andric auto &US = 9375ffd83dbSDimitry Andric FI.Params 9385ffd83dbSDimitry Andric .emplace(PS.ParamNo, FunctionSummary::ParamAccess::RangeWidth) 9395ffd83dbSDimitry Andric .first->second; 9405ffd83dbSDimitry Andric US.Range = PS.Use; 9415ffd83dbSDimitry Andric for (auto &Call : PS.Calls) { 9425ffd83dbSDimitry Andric assert(!Call.Offsets.isFullSet()); 9435ffd83dbSDimitry Andric FunctionSummary *S = resolveCallee( 9445ffd83dbSDimitry Andric Index.findSummaryInModule(Call.Callee, FS->modulePath())); 9455ffd83dbSDimitry Andric if (!S) { 9465ffd83dbSDimitry Andric US.Range = FullSet; 9475ffd83dbSDimitry Andric US.Calls.clear(); 9485ffd83dbSDimitry Andric break; 9495ffd83dbSDimitry Andric } 9505ffd83dbSDimitry Andric US.Calls.emplace_back(S, Call.ParamNo, Call.Offsets); 9515ffd83dbSDimitry Andric } 9525ffd83dbSDimitry Andric } 9535ffd83dbSDimitry Andric Functions.emplace(FS, std::move(FI)); 9545ffd83dbSDimitry Andric } 9555ffd83dbSDimitry Andric // Reset data for all summaries. Alive and DSO local will be set back from 9565ffd83dbSDimitry Andric // of data flow results below. Anything else will not be accessed 9575ffd83dbSDimitry Andric // by ThinLTO backend, so we can save on bitcode size. 9585ffd83dbSDimitry Andric FS->setParamAccesses({}); 9595ffd83dbSDimitry Andric } 9605ffd83dbSDimitry Andric } 9615ffd83dbSDimitry Andric StackSafetyDataFlowAnalysis<FunctionSummary> SSDFA( 9625ffd83dbSDimitry Andric FunctionSummary::ParamAccess::RangeWidth, std::move(Functions)); 9635ffd83dbSDimitry Andric for (auto &KV : SSDFA.run()) { 9645ffd83dbSDimitry Andric std::vector<FunctionSummary::ParamAccess> NewParams; 9655ffd83dbSDimitry Andric NewParams.reserve(KV.second.Params.size()); 9665ffd83dbSDimitry Andric for (auto &Param : KV.second.Params) { 9675ffd83dbSDimitry Andric NewParams.emplace_back(); 9685ffd83dbSDimitry Andric FunctionSummary::ParamAccess &New = NewParams.back(); 9695ffd83dbSDimitry Andric New.ParamNo = Param.first; 9705ffd83dbSDimitry Andric New.Use = Param.second.Range; // Only range is needed. 9715ffd83dbSDimitry Andric } 9725ffd83dbSDimitry Andric const_cast<FunctionSummary *>(KV.first)->setParamAccesses( 9735ffd83dbSDimitry Andric std::move(NewParams)); 9745ffd83dbSDimitry Andric } 9755ffd83dbSDimitry Andric } 9765ffd83dbSDimitry Andric 977*0b57cec5SDimitry Andric static const char LocalPassArg[] = "stack-safety-local"; 978*0b57cec5SDimitry Andric static const char LocalPassName[] = "Stack Safety Local Analysis"; 979*0b57cec5SDimitry Andric INITIALIZE_PASS_BEGIN(StackSafetyInfoWrapperPass, LocalPassArg, LocalPassName, 980*0b57cec5SDimitry Andric false, true) 981*0b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass) 982*0b57cec5SDimitry Andric INITIALIZE_PASS_END(StackSafetyInfoWrapperPass, LocalPassArg, LocalPassName, 983*0b57cec5SDimitry Andric false, true) 984*0b57cec5SDimitry Andric 985*0b57cec5SDimitry Andric static const char GlobalPassName[] = "Stack Safety Analysis"; 986*0b57cec5SDimitry Andric INITIALIZE_PASS_BEGIN(StackSafetyGlobalInfoWrapperPass, DEBUG_TYPE, 9875ffd83dbSDimitry Andric GlobalPassName, false, true) 988*0b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(StackSafetyInfoWrapperPass) 9895ffd83dbSDimitry Andric INITIALIZE_PASS_DEPENDENCY(ImmutableModuleSummaryIndexWrapperPass) 990*0b57cec5SDimitry Andric INITIALIZE_PASS_END(StackSafetyGlobalInfoWrapperPass, DEBUG_TYPE, 9915ffd83dbSDimitry Andric GlobalPassName, false, true) 992