| File: | build/source/llvm/lib/Analysis/StackSafetyAnalysis.cpp |
| Warning: | line 183, column 37 Value assigned to field 'UpdateCount' in implicit constructor is garbage or undefined |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | //===- StackSafetyAnalysis.cpp - Stack memory safety analysis -------------===// | |||
| 2 | // | |||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |||
| 4 | // See https://llvm.org/LICENSE.txt for license information. | |||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |||
| 6 | // | |||
| 7 | //===----------------------------------------------------------------------===// | |||
| 8 | // | |||
| 9 | //===----------------------------------------------------------------------===// | |||
| 10 | ||||
| 11 | #include "llvm/Analysis/StackSafetyAnalysis.h" | |||
| 12 | #include "llvm/ADT/APInt.h" | |||
| 13 | #include "llvm/ADT/SmallPtrSet.h" | |||
| 14 | #include "llvm/ADT/SmallVector.h" | |||
| 15 | #include "llvm/ADT/Statistic.h" | |||
| 16 | #include "llvm/Analysis/ModuleSummaryAnalysis.h" | |||
| 17 | #include "llvm/Analysis/ScalarEvolution.h" | |||
| 18 | #include "llvm/Analysis/StackLifetime.h" | |||
| 19 | #include "llvm/IR/ConstantRange.h" | |||
| 20 | #include "llvm/IR/DerivedTypes.h" | |||
| 21 | #include "llvm/IR/GlobalValue.h" | |||
| 22 | #include "llvm/IR/InstIterator.h" | |||
| 23 | #include "llvm/IR/Instruction.h" | |||
| 24 | #include "llvm/IR/Instructions.h" | |||
| 25 | #include "llvm/IR/IntrinsicInst.h" | |||
| 26 | #include "llvm/IR/ModuleSummaryIndex.h" | |||
| 27 | #include "llvm/InitializePasses.h" | |||
| 28 | #include "llvm/Support/Casting.h" | |||
| 29 | #include "llvm/Support/CommandLine.h" | |||
| 30 | #include "llvm/Support/FormatVariadic.h" | |||
| 31 | #include "llvm/Support/raw_ostream.h" | |||
| 32 | #include <algorithm> | |||
| 33 | #include <memory> | |||
| 34 | #include <tuple> | |||
| 35 | ||||
| 36 | using namespace llvm; | |||
| 37 | ||||
| 38 | #define DEBUG_TYPE"stack-safety" "stack-safety" | |||
| 39 | ||||
| 40 | STATISTIC(NumAllocaStackSafe, "Number of safe allocas")static llvm::Statistic NumAllocaStackSafe = {"stack-safety", "NumAllocaStackSafe" , "Number of safe allocas"}; | |||
| 41 | STATISTIC(NumAllocaTotal, "Number of total allocas")static llvm::Statistic NumAllocaTotal = {"stack-safety", "NumAllocaTotal" , "Number of total allocas"}; | |||
| 42 | ||||
| 43 | STATISTIC(NumCombinedCalleeLookupTotal,static llvm::Statistic NumCombinedCalleeLookupTotal = {"stack-safety" , "NumCombinedCalleeLookupTotal", "Number of total callee lookups on combined index." } | |||
| 44 | "Number of total callee lookups on combined index.")static llvm::Statistic NumCombinedCalleeLookupTotal = {"stack-safety" , "NumCombinedCalleeLookupTotal", "Number of total callee lookups on combined index." }; | |||
| 45 | STATISTIC(NumCombinedCalleeLookupFailed,static llvm::Statistic NumCombinedCalleeLookupFailed = {"stack-safety" , "NumCombinedCalleeLookupFailed", "Number of failed callee lookups on combined index." } | |||
| 46 | "Number of failed callee lookups on combined index.")static llvm::Statistic NumCombinedCalleeLookupFailed = {"stack-safety" , "NumCombinedCalleeLookupFailed", "Number of failed callee lookups on combined index." }; | |||
| 47 | STATISTIC(NumModuleCalleeLookupTotal,static llvm::Statistic NumModuleCalleeLookupTotal = {"stack-safety" , "NumModuleCalleeLookupTotal", "Number of total callee lookups on module index." } | |||
| 48 | "Number of total callee lookups on module index.")static llvm::Statistic NumModuleCalleeLookupTotal = {"stack-safety" , "NumModuleCalleeLookupTotal", "Number of total callee lookups on module index." }; | |||
| 49 | STATISTIC(NumModuleCalleeLookupFailed,static llvm::Statistic NumModuleCalleeLookupFailed = {"stack-safety" , "NumModuleCalleeLookupFailed", "Number of failed callee lookups on module index." } | |||
| 50 | "Number of failed callee lookups on module index.")static llvm::Statistic NumModuleCalleeLookupFailed = {"stack-safety" , "NumModuleCalleeLookupFailed", "Number of failed callee lookups on module index." }; | |||
| 51 | STATISTIC(NumCombinedParamAccessesBefore,static llvm::Statistic NumCombinedParamAccessesBefore = {"stack-safety" , "NumCombinedParamAccessesBefore", "Number of total param accesses before generateParamAccessSummary." } | |||
| 52 | "Number of total param accesses before generateParamAccessSummary.")static llvm::Statistic NumCombinedParamAccessesBefore = {"stack-safety" , "NumCombinedParamAccessesBefore", "Number of total param accesses before generateParamAccessSummary." }; | |||
| 53 | STATISTIC(NumCombinedParamAccessesAfter,static llvm::Statistic NumCombinedParamAccessesAfter = {"stack-safety" , "NumCombinedParamAccessesAfter", "Number of total param accesses after generateParamAccessSummary." } | |||
| 54 | "Number of total param accesses after generateParamAccessSummary.")static llvm::Statistic NumCombinedParamAccessesAfter = {"stack-safety" , "NumCombinedParamAccessesAfter", "Number of total param accesses after generateParamAccessSummary." }; | |||
| 55 | STATISTIC(NumCombinedDataFlowNodes,static llvm::Statistic NumCombinedDataFlowNodes = {"stack-safety" , "NumCombinedDataFlowNodes", "Number of total nodes in combined index for dataflow processing." } | |||
| 56 | "Number of total nodes in combined index for dataflow processing.")static llvm::Statistic NumCombinedDataFlowNodes = {"stack-safety" , "NumCombinedDataFlowNodes", "Number of total nodes in combined index for dataflow processing." }; | |||
| 57 | STATISTIC(NumIndexCalleeUnhandled, "Number of index callee which are unhandled.")static llvm::Statistic NumIndexCalleeUnhandled = {"stack-safety" , "NumIndexCalleeUnhandled", "Number of index callee which are unhandled." }; | |||
| 58 | STATISTIC(NumIndexCalleeMultipleWeak, "Number of index callee non-unique weak.")static llvm::Statistic NumIndexCalleeMultipleWeak = {"stack-safety" , "NumIndexCalleeMultipleWeak", "Number of index callee non-unique weak." }; | |||
| 59 | STATISTIC(NumIndexCalleeMultipleExternal, "Number of index callee non-unique external.")static llvm::Statistic NumIndexCalleeMultipleExternal = {"stack-safety" , "NumIndexCalleeMultipleExternal", "Number of index callee non-unique external." }; | |||
| 60 | ||||
| 61 | ||||
| 62 | static cl::opt<int> StackSafetyMaxIterations("stack-safety-max-iterations", | |||
| 63 | cl::init(20), cl::Hidden); | |||
| 64 | ||||
| 65 | static cl::opt<bool> StackSafetyPrint("stack-safety-print", cl::init(false), | |||
| 66 | cl::Hidden); | |||
| 67 | ||||
| 68 | static cl::opt<bool> StackSafetyRun("stack-safety-run", cl::init(false), | |||
| 69 | cl::Hidden); | |||
| 70 | ||||
| 71 | namespace { | |||
| 72 | ||||
| 73 | // Check if we should bailout for such ranges. | |||
| 74 | bool isUnsafe(const ConstantRange &R) { | |||
| 75 | return R.isEmptySet() || R.isFullSet() || R.isUpperSignWrapped(); | |||
| 76 | } | |||
| 77 | ||||
| 78 | ConstantRange addOverflowNever(const ConstantRange &L, const ConstantRange &R) { | |||
| 79 | assert(!L.isSignWrappedSet())(static_cast <bool> (!L.isSignWrappedSet()) ? void (0) : __assert_fail ("!L.isSignWrappedSet()", "llvm/lib/Analysis/StackSafetyAnalysis.cpp" , 79, __extension__ __PRETTY_FUNCTION__)); | |||
| 80 | assert(!R.isSignWrappedSet())(static_cast <bool> (!R.isSignWrappedSet()) ? void (0) : __assert_fail ("!R.isSignWrappedSet()", "llvm/lib/Analysis/StackSafetyAnalysis.cpp" , 80, __extension__ __PRETTY_FUNCTION__)); | |||
| 81 | if (L.signedAddMayOverflow(R) != | |||
| 82 | ConstantRange::OverflowResult::NeverOverflows) | |||
| 83 | return ConstantRange::getFull(L.getBitWidth()); | |||
| 84 | ConstantRange Result = L.add(R); | |||
| 85 | assert(!Result.isSignWrappedSet())(static_cast <bool> (!Result.isSignWrappedSet()) ? void (0) : __assert_fail ("!Result.isSignWrappedSet()", "llvm/lib/Analysis/StackSafetyAnalysis.cpp" , 85, __extension__ __PRETTY_FUNCTION__)); | |||
| 86 | return Result; | |||
| 87 | } | |||
| 88 | ||||
| 89 | ConstantRange unionNoWrap(const ConstantRange &L, const ConstantRange &R) { | |||
| 90 | assert(!L.isSignWrappedSet())(static_cast <bool> (!L.isSignWrappedSet()) ? void (0) : __assert_fail ("!L.isSignWrappedSet()", "llvm/lib/Analysis/StackSafetyAnalysis.cpp" , 90, __extension__ __PRETTY_FUNCTION__)); | |||
| 91 | assert(!R.isSignWrappedSet())(static_cast <bool> (!R.isSignWrappedSet()) ? void (0) : __assert_fail ("!R.isSignWrappedSet()", "llvm/lib/Analysis/StackSafetyAnalysis.cpp" , 91, __extension__ __PRETTY_FUNCTION__)); | |||
| 92 | auto Result = L.unionWith(R); | |||
| 93 | // Two non-wrapped sets can produce wrapped. | |||
| 94 | if (Result.isSignWrappedSet()) | |||
| 95 | Result = ConstantRange::getFull(Result.getBitWidth()); | |||
| 96 | return Result; | |||
| 97 | } | |||
| 98 | ||||
| 99 | /// Describes use of address in as a function call argument. | |||
| 100 | template <typename CalleeTy> struct CallInfo { | |||
| 101 | /// Function being called. | |||
| 102 | const CalleeTy *Callee = nullptr; | |||
| 103 | /// Index of argument which pass address. | |||
| 104 | size_t ParamNo = 0; | |||
| 105 | ||||
| 106 | CallInfo(const CalleeTy *Callee, size_t ParamNo) | |||
| 107 | : Callee(Callee), ParamNo(ParamNo) {} | |||
| 108 | ||||
| 109 | struct Less { | |||
| 110 | bool operator()(const CallInfo &L, const CallInfo &R) const { | |||
| 111 | return std::tie(L.ParamNo, L.Callee) < std::tie(R.ParamNo, R.Callee); | |||
| 112 | } | |||
| 113 | }; | |||
| 114 | }; | |||
| 115 | ||||
| 116 | /// Describe uses of address (alloca or parameter) inside of the function. | |||
| 117 | template <typename CalleeTy> struct UseInfo { | |||
| 118 | // Access range if the address (alloca or parameters). | |||
| 119 | // It is allowed to be empty-set when there are no known accesses. | |||
| 120 | ConstantRange Range; | |||
| 121 | std::set<const Instruction *> UnsafeAccesses; | |||
| 122 | ||||
| 123 | // List of calls which pass address as an argument. | |||
| 124 | // Value is offset range of address from base address (alloca or calling | |||
| 125 | // function argument). Range should never set to empty-set, that is an invalid | |||
| 126 | // access range that can cause empty-set to be propagated with | |||
| 127 | // ConstantRange::add | |||
| 128 | using CallsTy = std::map<CallInfo<CalleeTy>, ConstantRange, | |||
| 129 | typename CallInfo<CalleeTy>::Less>; | |||
| 130 | CallsTy Calls; | |||
| 131 | ||||
| 132 | UseInfo(unsigned PointerSize) : Range{PointerSize, false} {} | |||
| 133 | ||||
| 134 | void updateRange(const ConstantRange &R) { Range = unionNoWrap(Range, R); } | |||
| 135 | void addRange(const Instruction *I, const ConstantRange &R, bool IsSafe) { | |||
| 136 | if (!IsSafe) | |||
| 137 | UnsafeAccesses.insert(I); | |||
| 138 | updateRange(R); | |||
| 139 | } | |||
| 140 | }; | |||
| 141 | ||||
| 142 | template <typename CalleeTy> | |||
| 143 | raw_ostream &operator<<(raw_ostream &OS, const UseInfo<CalleeTy> &U) { | |||
| 144 | OS << U.Range; | |||
| 145 | for (auto &Call : U.Calls) | |||
| 146 | OS << ", " | |||
| 147 | << "@" << Call.first.Callee->getName() << "(arg" << Call.first.ParamNo | |||
| 148 | << ", " << Call.second << ")"; | |||
| 149 | return OS; | |||
| 150 | } | |||
| 151 | ||||
| 152 | /// Calculate the allocation size of a given alloca. Returns empty range | |||
| 153 | // in case of confution. | |||
| 154 | ConstantRange getStaticAllocaSizeRange(const AllocaInst &AI) { | |||
| 155 | const DataLayout &DL = AI.getModule()->getDataLayout(); | |||
| 156 | TypeSize TS = DL.getTypeAllocSize(AI.getAllocatedType()); | |||
| 157 | unsigned PointerSize = DL.getPointerTypeSizeInBits(AI.getType()); | |||
| 158 | // Fallback to empty range for alloca size. | |||
| 159 | ConstantRange R = ConstantRange::getEmpty(PointerSize); | |||
| 160 | if (TS.isScalable()) | |||
| 161 | return R; | |||
| 162 | APInt APSize(PointerSize, TS.getFixedValue(), true); | |||
| 163 | if (APSize.isNonPositive()) | |||
| 164 | return R; | |||
| 165 | if (AI.isArrayAllocation()) { | |||
| 166 | const auto *C = dyn_cast<ConstantInt>(AI.getArraySize()); | |||
| 167 | if (!C) | |||
| 168 | return R; | |||
| 169 | bool Overflow = false; | |||
| 170 | APInt Mul = C->getValue(); | |||
| 171 | if (Mul.isNonPositive()) | |||
| 172 | return R; | |||
| 173 | Mul = Mul.sextOrTrunc(PointerSize); | |||
| 174 | APSize = APSize.smul_ov(Mul, Overflow); | |||
| 175 | if (Overflow) | |||
| 176 | return R; | |||
| 177 | } | |||
| 178 | R = ConstantRange(APInt::getZero(PointerSize), APSize); | |||
| 179 | assert(!isUnsafe(R))(static_cast <bool> (!isUnsafe(R)) ? void (0) : __assert_fail ("!isUnsafe(R)", "llvm/lib/Analysis/StackSafetyAnalysis.cpp" , 179, __extension__ __PRETTY_FUNCTION__)); | |||
| 180 | return R; | |||
| 181 | } | |||
| 182 | ||||
| 183 | template <typename CalleeTy> struct FunctionInfo { | |||
| ||||
| 184 | std::map<const AllocaInst *, UseInfo<CalleeTy>> Allocas; | |||
| 185 | std::map<uint32_t, UseInfo<CalleeTy>> Params; | |||
| 186 | // TODO: describe return value as depending on one or more of its arguments. | |||
| 187 | ||||
| 188 | // StackSafetyDataFlowAnalysis counter stored here for faster access. | |||
| 189 | int UpdateCount = 0; | |||
| 190 | ||||
| 191 | void print(raw_ostream &O, StringRef Name, const Function *F) const { | |||
| 192 | // TODO: Consider different printout format after | |||
| 193 | // StackSafetyDataFlowAnalysis. Calls and parameters are irrelevant then. | |||
| 194 | O << " @" << Name << ((F && F->isDSOLocal()) ? "" : " dso_preemptable") | |||
| 195 | << ((F && F->isInterposable()) ? " interposable" : "") << "\n"; | |||
| 196 | ||||
| 197 | O << " args uses:\n"; | |||
| 198 | for (auto &KV : Params) { | |||
| 199 | O << " "; | |||
| 200 | if (F) | |||
| 201 | O << F->getArg(KV.first)->getName(); | |||
| 202 | else | |||
| 203 | O << formatv("arg{0}", KV.first); | |||
| 204 | O << "[]: " << KV.second << "\n"; | |||
| 205 | } | |||
| 206 | ||||
| 207 | O << " allocas uses:\n"; | |||
| 208 | if (F) { | |||
| 209 | for (const auto &I : instructions(F)) { | |||
| 210 | if (const AllocaInst *AI = dyn_cast<AllocaInst>(&I)) { | |||
| 211 | auto &AS = Allocas.find(AI)->second; | |||
| 212 | O << " " << AI->getName() << "[" | |||
| 213 | << getStaticAllocaSizeRange(*AI).getUpper() << "]: " << AS << "\n"; | |||
| 214 | } | |||
| 215 | } | |||
| 216 | } else { | |||
| 217 | assert(Allocas.empty())(static_cast <bool> (Allocas.empty()) ? void (0) : __assert_fail ("Allocas.empty()", "llvm/lib/Analysis/StackSafetyAnalysis.cpp" , 217, __extension__ __PRETTY_FUNCTION__)); | |||
| 218 | } | |||
| 219 | } | |||
| 220 | }; | |||
| 221 | ||||
| 222 | using GVToSSI = std::map<const GlobalValue *, FunctionInfo<GlobalValue>>; | |||
| 223 | ||||
| 224 | } // namespace | |||
| 225 | ||||
| 226 | struct StackSafetyInfo::InfoTy { | |||
| 227 | FunctionInfo<GlobalValue> Info; | |||
| 228 | }; | |||
| 229 | ||||
| 230 | struct StackSafetyGlobalInfo::InfoTy { | |||
| 231 | GVToSSI Info; | |||
| 232 | SmallPtrSet<const AllocaInst *, 8> SafeAllocas; | |||
| 233 | std::set<const Instruction *> UnsafeAccesses; | |||
| 234 | }; | |||
| 235 | ||||
| 236 | namespace { | |||
| 237 | ||||
| 238 | class StackSafetyLocalAnalysis { | |||
| 239 | Function &F; | |||
| 240 | const DataLayout &DL; | |||
| 241 | ScalarEvolution &SE; | |||
| 242 | unsigned PointerSize = 0; | |||
| 243 | ||||
| 244 | const ConstantRange UnknownRange; | |||
| 245 | ||||
| 246 | ConstantRange offsetFrom(Value *Addr, Value *Base); | |||
| 247 | ConstantRange getAccessRange(Value *Addr, Value *Base, | |||
| 248 | const ConstantRange &SizeRange); | |||
| 249 | ConstantRange getAccessRange(Value *Addr, Value *Base, TypeSize Size); | |||
| 250 | ConstantRange getMemIntrinsicAccessRange(const MemIntrinsic *MI, const Use &U, | |||
| 251 | Value *Base); | |||
| 252 | ||||
| 253 | void analyzeAllUses(Value *Ptr, UseInfo<GlobalValue> &AS, | |||
| 254 | const StackLifetime &SL); | |||
| 255 | ||||
| 256 | ||||
| 257 | bool isSafeAccess(const Use &U, AllocaInst *AI, const SCEV *AccessSize); | |||
| 258 | bool isSafeAccess(const Use &U, AllocaInst *AI, Value *V); | |||
| 259 | bool isSafeAccess(const Use &U, AllocaInst *AI, TypeSize AccessSize); | |||
| 260 | ||||
| 261 | public: | |||
| 262 | StackSafetyLocalAnalysis(Function &F, ScalarEvolution &SE) | |||
| 263 | : F(F), DL(F.getParent()->getDataLayout()), SE(SE), | |||
| 264 | PointerSize(DL.getPointerSizeInBits()), | |||
| 265 | UnknownRange(PointerSize, true) {} | |||
| 266 | ||||
| 267 | // Run the transformation on the associated function. | |||
| 268 | FunctionInfo<GlobalValue> run(); | |||
| 269 | }; | |||
| 270 | ||||
| 271 | ConstantRange StackSafetyLocalAnalysis::offsetFrom(Value *Addr, Value *Base) { | |||
| 272 | if (!SE.isSCEVable(Addr->getType()) || !SE.isSCEVable(Base->getType())) | |||
| 273 | return UnknownRange; | |||
| 274 | ||||
| 275 | auto *PtrTy = IntegerType::getInt8PtrTy(SE.getContext()); | |||
| 276 | const SCEV *AddrExp = SE.getTruncateOrZeroExtend(SE.getSCEV(Addr), PtrTy); | |||
| 277 | const SCEV *BaseExp = SE.getTruncateOrZeroExtend(SE.getSCEV(Base), PtrTy); | |||
| 278 | const SCEV *Diff = SE.getMinusSCEV(AddrExp, BaseExp); | |||
| 279 | if (isa<SCEVCouldNotCompute>(Diff)) | |||
| 280 | return UnknownRange; | |||
| 281 | ||||
| 282 | ConstantRange Offset = SE.getSignedRange(Diff); | |||
| 283 | if (isUnsafe(Offset)) | |||
| 284 | return UnknownRange; | |||
| 285 | return Offset.sextOrTrunc(PointerSize); | |||
| 286 | } | |||
| 287 | ||||
| 288 | ConstantRange | |||
| 289 | StackSafetyLocalAnalysis::getAccessRange(Value *Addr, Value *Base, | |||
| 290 | const ConstantRange &SizeRange) { | |||
| 291 | // Zero-size loads and stores do not access memory. | |||
| 292 | if (SizeRange.isEmptySet()) | |||
| 293 | return ConstantRange::getEmpty(PointerSize); | |||
| 294 | assert(!isUnsafe(SizeRange))(static_cast <bool> (!isUnsafe(SizeRange)) ? void (0) : __assert_fail ("!isUnsafe(SizeRange)", "llvm/lib/Analysis/StackSafetyAnalysis.cpp" , 294, __extension__ __PRETTY_FUNCTION__)); | |||
| 295 | ||||
| 296 | ConstantRange Offsets = offsetFrom(Addr, Base); | |||
| 297 | if (isUnsafe(Offsets)) | |||
| 298 | return UnknownRange; | |||
| 299 | ||||
| 300 | Offsets = addOverflowNever(Offsets, SizeRange); | |||
| 301 | if (isUnsafe(Offsets)) | |||
| 302 | return UnknownRange; | |||
| 303 | return Offsets; | |||
| 304 | } | |||
| 305 | ||||
| 306 | ConstantRange StackSafetyLocalAnalysis::getAccessRange(Value *Addr, Value *Base, | |||
| 307 | TypeSize Size) { | |||
| 308 | if (Size.isScalable()) | |||
| 309 | return UnknownRange; | |||
| 310 | APInt APSize(PointerSize, Size.getFixedValue(), true); | |||
| 311 | if (APSize.isNegative()) | |||
| 312 | return UnknownRange; | |||
| 313 | return getAccessRange(Addr, Base, | |||
| 314 | ConstantRange(APInt::getZero(PointerSize), APSize)); | |||
| 315 | } | |||
| 316 | ||||
| 317 | ConstantRange StackSafetyLocalAnalysis::getMemIntrinsicAccessRange( | |||
| 318 | const MemIntrinsic *MI, const Use &U, Value *Base) { | |||
| 319 | if (const auto *MTI = dyn_cast<MemTransferInst>(MI)) { | |||
| 320 | if (MTI->getRawSource() != U && MTI->getRawDest() != U) | |||
| 321 | return ConstantRange::getEmpty(PointerSize); | |||
| 322 | } else { | |||
| 323 | if (MI->getRawDest() != U) | |||
| 324 | return ConstantRange::getEmpty(PointerSize); | |||
| 325 | } | |||
| 326 | ||||
| 327 | auto *CalculationTy = IntegerType::getIntNTy(SE.getContext(), PointerSize); | |||
| 328 | if (!SE.isSCEVable(MI->getLength()->getType())) | |||
| 329 | return UnknownRange; | |||
| 330 | ||||
| 331 | const SCEV *Expr = | |||
| 332 | SE.getTruncateOrZeroExtend(SE.getSCEV(MI->getLength()), CalculationTy); | |||
| 333 | ConstantRange Sizes = SE.getSignedRange(Expr); | |||
| 334 | if (Sizes.getUpper().isNegative() || isUnsafe(Sizes)) | |||
| 335 | return UnknownRange; | |||
| 336 | Sizes = Sizes.sextOrTrunc(PointerSize); | |||
| 337 | ConstantRange SizeRange(APInt::getZero(PointerSize), Sizes.getUpper() - 1); | |||
| 338 | return getAccessRange(U, Base, SizeRange); | |||
| 339 | } | |||
| 340 | ||||
| 341 | bool StackSafetyLocalAnalysis::isSafeAccess(const Use &U, AllocaInst *AI, | |||
| 342 | Value *V) { | |||
| 343 | return isSafeAccess(U, AI, SE.getSCEV(V)); | |||
| 344 | } | |||
| 345 | ||||
| 346 | bool StackSafetyLocalAnalysis::isSafeAccess(const Use &U, AllocaInst *AI, | |||
| 347 | TypeSize TS) { | |||
| 348 | if (TS.isScalable()) | |||
| 349 | return false; | |||
| 350 | auto *CalculationTy = IntegerType::getIntNTy(SE.getContext(), PointerSize); | |||
| 351 | const SCEV *SV = SE.getConstant(CalculationTy, TS.getFixedValue()); | |||
| 352 | return isSafeAccess(U, AI, SV); | |||
| 353 | } | |||
| 354 | ||||
| 355 | bool StackSafetyLocalAnalysis::isSafeAccess(const Use &U, AllocaInst *AI, | |||
| 356 | const SCEV *AccessSize) { | |||
| 357 | ||||
| 358 | if (!AI) | |||
| 359 | return true; | |||
| 360 | if (isa<SCEVCouldNotCompute>(AccessSize)) | |||
| 361 | return false; | |||
| 362 | ||||
| 363 | const auto *I = cast<Instruction>(U.getUser()); | |||
| 364 | ||||
| 365 | auto ToCharPtr = [&](const SCEV *V) { | |||
| 366 | auto *PtrTy = IntegerType::getInt8PtrTy(SE.getContext()); | |||
| 367 | return SE.getTruncateOrZeroExtend(V, PtrTy); | |||
| 368 | }; | |||
| 369 | ||||
| 370 | const SCEV *AddrExp = ToCharPtr(SE.getSCEV(U.get())); | |||
| 371 | const SCEV *BaseExp = ToCharPtr(SE.getSCEV(AI)); | |||
| 372 | const SCEV *Diff = SE.getMinusSCEV(AddrExp, BaseExp); | |||
| 373 | if (isa<SCEVCouldNotCompute>(Diff)) | |||
| 374 | return false; | |||
| 375 | ||||
| 376 | auto Size = getStaticAllocaSizeRange(*AI); | |||
| 377 | ||||
| 378 | auto *CalculationTy = IntegerType::getIntNTy(SE.getContext(), PointerSize); | |||
| 379 | auto ToDiffTy = [&](const SCEV *V) { | |||
| 380 | return SE.getTruncateOrZeroExtend(V, CalculationTy); | |||
| 381 | }; | |||
| 382 | const SCEV *Min = ToDiffTy(SE.getConstant(Size.getLower())); | |||
| 383 | const SCEV *Max = SE.getMinusSCEV(ToDiffTy(SE.getConstant(Size.getUpper())), | |||
| 384 | ToDiffTy(AccessSize)); | |||
| 385 | return SE.evaluatePredicateAt(ICmpInst::Predicate::ICMP_SGE, Diff, Min, I) | |||
| 386 | .value_or(false) && | |||
| 387 | SE.evaluatePredicateAt(ICmpInst::Predicate::ICMP_SLE, Diff, Max, I) | |||
| 388 | .value_or(false); | |||
| 389 | } | |||
| 390 | ||||
| 391 | /// The function analyzes all local uses of Ptr (alloca or argument) and | |||
| 392 | /// calculates local access range and all function calls where it was used. | |||
| 393 | void StackSafetyLocalAnalysis::analyzeAllUses(Value *Ptr, | |||
| 394 | UseInfo<GlobalValue> &US, | |||
| 395 | const StackLifetime &SL) { | |||
| 396 | SmallPtrSet<const Value *, 16> Visited; | |||
| 397 | SmallVector<const Value *, 8> WorkList; | |||
| 398 | WorkList.push_back(Ptr); | |||
| 399 | AllocaInst *AI = dyn_cast<AllocaInst>(Ptr); | |||
| 400 | ||||
| 401 | // A DFS search through all uses of the alloca in bitcasts/PHI/GEPs/etc. | |||
| 402 | while (!WorkList.empty()) { | |||
| 403 | const Value *V = WorkList.pop_back_val(); | |||
| 404 | for (const Use &UI : V->uses()) { | |||
| 405 | const auto *I = cast<Instruction>(UI.getUser()); | |||
| 406 | if (!SL.isReachable(I)) | |||
| 407 | continue; | |||
| 408 | ||||
| 409 | assert(V == UI.get())(static_cast <bool> (V == UI.get()) ? void (0) : __assert_fail ("V == UI.get()", "llvm/lib/Analysis/StackSafetyAnalysis.cpp" , 409, __extension__ __PRETTY_FUNCTION__)); | |||
| 410 | ||||
| 411 | switch (I->getOpcode()) { | |||
| 412 | case Instruction::Load: { | |||
| 413 | if (AI && !SL.isAliveAfter(AI, I)) { | |||
| 414 | US.addRange(I, UnknownRange, /*IsSafe=*/false); | |||
| 415 | break; | |||
| 416 | } | |||
| 417 | auto TypeSize = DL.getTypeStoreSize(I->getType()); | |||
| 418 | auto AccessRange = getAccessRange(UI, Ptr, TypeSize); | |||
| 419 | bool Safe = isSafeAccess(UI, AI, TypeSize); | |||
| 420 | US.addRange(I, AccessRange, Safe); | |||
| 421 | break; | |||
| 422 | } | |||
| 423 | ||||
| 424 | case Instruction::VAArg: | |||
| 425 | // "va-arg" from a pointer is safe. | |||
| 426 | break; | |||
| 427 | case Instruction::Store: { | |||
| 428 | if (V == I->getOperand(0)) { | |||
| 429 | // Stored the pointer - conservatively assume it may be unsafe. | |||
| 430 | US.addRange(I, UnknownRange, /*IsSafe=*/false); | |||
| 431 | break; | |||
| 432 | } | |||
| 433 | if (AI && !SL.isAliveAfter(AI, I)) { | |||
| 434 | US.addRange(I, UnknownRange, /*IsSafe=*/false); | |||
| 435 | break; | |||
| 436 | } | |||
| 437 | auto TypeSize = DL.getTypeStoreSize(I->getOperand(0)->getType()); | |||
| 438 | auto AccessRange = getAccessRange(UI, Ptr, TypeSize); | |||
| 439 | bool Safe = isSafeAccess(UI, AI, TypeSize); | |||
| 440 | US.addRange(I, AccessRange, Safe); | |||
| 441 | break; | |||
| 442 | } | |||
| 443 | ||||
| 444 | case Instruction::Ret: | |||
| 445 | // Information leak. | |||
| 446 | // FIXME: Process parameters correctly. This is a leak only if we return | |||
| 447 | // alloca. | |||
| 448 | US.addRange(I, UnknownRange, /*IsSafe=*/false); | |||
| 449 | break; | |||
| 450 | ||||
| 451 | case Instruction::Call: | |||
| 452 | case Instruction::Invoke: { | |||
| 453 | if (I->isLifetimeStartOrEnd()) | |||
| 454 | break; | |||
| 455 | ||||
| 456 | if (AI && !SL.isAliveAfter(AI, I)) { | |||
| 457 | US.addRange(I, UnknownRange, /*IsSafe=*/false); | |||
| 458 | break; | |||
| 459 | } | |||
| 460 | if (const MemIntrinsic *MI = dyn_cast<MemIntrinsic>(I)) { | |||
| 461 | auto AccessRange = getMemIntrinsicAccessRange(MI, UI, Ptr); | |||
| 462 | bool Safe = false; | |||
| 463 | if (const auto *MTI = dyn_cast<MemTransferInst>(MI)) { | |||
| 464 | if (MTI->getRawSource() != UI && MTI->getRawDest() != UI) | |||
| 465 | Safe = true; | |||
| 466 | } else if (MI->getRawDest() != UI) { | |||
| 467 | Safe = true; | |||
| 468 | } | |||
| 469 | Safe = Safe || isSafeAccess(UI, AI, MI->getLength()); | |||
| 470 | US.addRange(I, AccessRange, Safe); | |||
| 471 | break; | |||
| 472 | } | |||
| 473 | ||||
| 474 | const auto &CB = cast<CallBase>(*I); | |||
| 475 | if (CB.getReturnedArgOperand() == V) { | |||
| 476 | if (Visited.insert(I).second) | |||
| 477 | WorkList.push_back(cast<const Instruction>(I)); | |||
| 478 | } | |||
| 479 | ||||
| 480 | if (!CB.isArgOperand(&UI)) { | |||
| 481 | US.addRange(I, UnknownRange, /*IsSafe=*/false); | |||
| 482 | break; | |||
| 483 | } | |||
| 484 | ||||
| 485 | unsigned ArgNo = CB.getArgOperandNo(&UI); | |||
| 486 | if (CB.isByValArgument(ArgNo)) { | |||
| 487 | auto TypeSize = DL.getTypeStoreSize(CB.getParamByValType(ArgNo)); | |||
| 488 | auto AccessRange = getAccessRange(UI, Ptr, TypeSize); | |||
| 489 | bool Safe = isSafeAccess(UI, AI, TypeSize); | |||
| 490 | US.addRange(I, AccessRange, Safe); | |||
| 491 | break; | |||
| 492 | } | |||
| 493 | ||||
| 494 | // FIXME: consult devirt? | |||
| 495 | // Do not follow aliases, otherwise we could inadvertently follow | |||
| 496 | // dso_preemptable aliases or aliases with interposable linkage. | |||
| 497 | const GlobalValue *Callee = | |||
| 498 | dyn_cast<GlobalValue>(CB.getCalledOperand()->stripPointerCasts()); | |||
| 499 | if (!Callee) { | |||
| 500 | US.addRange(I, UnknownRange, /*IsSafe=*/false); | |||
| 501 | break; | |||
| 502 | } | |||
| 503 | ||||
| 504 | assert(isa<Function>(Callee) || isa<GlobalAlias>(Callee))(static_cast <bool> (isa<Function>(Callee) || isa <GlobalAlias>(Callee)) ? void (0) : __assert_fail ("isa<Function>(Callee) || isa<GlobalAlias>(Callee)" , "llvm/lib/Analysis/StackSafetyAnalysis.cpp", 504, __extension__ __PRETTY_FUNCTION__)); | |||
| 505 | ConstantRange Offsets = offsetFrom(UI, Ptr); | |||
| 506 | auto Insert = | |||
| 507 | US.Calls.emplace(CallInfo<GlobalValue>(Callee, ArgNo), Offsets); | |||
| 508 | if (!Insert.second) | |||
| 509 | Insert.first->second = Insert.first->second.unionWith(Offsets); | |||
| 510 | break; | |||
| 511 | } | |||
| 512 | ||||
| 513 | default: | |||
| 514 | if (Visited.insert(I).second) | |||
| 515 | WorkList.push_back(cast<const Instruction>(I)); | |||
| 516 | } | |||
| 517 | } | |||
| 518 | } | |||
| 519 | } | |||
| 520 | ||||
| 521 | FunctionInfo<GlobalValue> StackSafetyLocalAnalysis::run() { | |||
| 522 | FunctionInfo<GlobalValue> Info; | |||
| 523 | assert(!F.isDeclaration() &&(static_cast <bool> (!F.isDeclaration() && "Can't run StackSafety on a function declaration" ) ? void (0) : __assert_fail ("!F.isDeclaration() && \"Can't run StackSafety on a function declaration\"" , "llvm/lib/Analysis/StackSafetyAnalysis.cpp", 524, __extension__ __PRETTY_FUNCTION__)) | |||
| 524 | "Can't run StackSafety on a function declaration")(static_cast <bool> (!F.isDeclaration() && "Can't run StackSafety on a function declaration" ) ? void (0) : __assert_fail ("!F.isDeclaration() && \"Can't run StackSafety on a function declaration\"" , "llvm/lib/Analysis/StackSafetyAnalysis.cpp", 524, __extension__ __PRETTY_FUNCTION__)); | |||
| 525 | ||||
| 526 | LLVM_DEBUG(dbgs() << "[StackSafety] " << F.getName() << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("stack-safety")) { dbgs() << "[StackSafety] " << F.getName() << "\n"; } } while (false); | |||
| 527 | ||||
| 528 | SmallVector<AllocaInst *, 64> Allocas; | |||
| 529 | for (auto &I : instructions(F)) | |||
| 530 | if (auto *AI = dyn_cast<AllocaInst>(&I)) | |||
| 531 | Allocas.push_back(AI); | |||
| 532 | StackLifetime SL(F, Allocas, StackLifetime::LivenessType::Must); | |||
| 533 | SL.run(); | |||
| 534 | ||||
| 535 | for (auto *AI : Allocas) { | |||
| 536 | auto &UI = Info.Allocas.emplace(AI, PointerSize).first->second; | |||
| 537 | analyzeAllUses(AI, UI, SL); | |||
| 538 | } | |||
| 539 | ||||
| 540 | for (Argument &A : F.args()) { | |||
| 541 | // Non pointers and bypass arguments are not going to be used in any global | |||
| 542 | // processing. | |||
| 543 | if (A.getType()->isPointerTy() && !A.hasByValAttr()) { | |||
| 544 | auto &UI = Info.Params.emplace(A.getArgNo(), PointerSize).first->second; | |||
| 545 | analyzeAllUses(&A, UI, SL); | |||
| 546 | } | |||
| 547 | } | |||
| 548 | ||||
| 549 | LLVM_DEBUG(Info.print(dbgs(), F.getName(), &F))do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("stack-safety")) { Info.print(dbgs(), F.getName(), &F); } } while (false); | |||
| 550 | LLVM_DEBUG(dbgs() << "\n[StackSafety] done\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("stack-safety")) { dbgs() << "\n[StackSafety] done\n"; } } while (false); | |||
| 551 | return Info; | |||
| 552 | } | |||
| 553 | ||||
| 554 | template <typename CalleeTy> class StackSafetyDataFlowAnalysis { | |||
| 555 | using FunctionMap = std::map<const CalleeTy *, FunctionInfo<CalleeTy>>; | |||
| 556 | ||||
| 557 | FunctionMap Functions; | |||
| 558 | const ConstantRange UnknownRange; | |||
| 559 | ||||
| 560 | // Callee-to-Caller multimap. | |||
| 561 | DenseMap<const CalleeTy *, SmallVector<const CalleeTy *, 4>> Callers; | |||
| 562 | SetVector<const CalleeTy *> WorkList; | |||
| 563 | ||||
| 564 | bool updateOneUse(UseInfo<CalleeTy> &US, bool UpdateToFullSet); | |||
| 565 | void updateOneNode(const CalleeTy *Callee, FunctionInfo<CalleeTy> &FS); | |||
| 566 | void updateOneNode(const CalleeTy *Callee) { | |||
| 567 | updateOneNode(Callee, Functions.find(Callee)->second); | |||
| 568 | } | |||
| 569 | void updateAllNodes() { | |||
| 570 | for (auto &F : Functions) | |||
| 571 | updateOneNode(F.first, F.second); | |||
| 572 | } | |||
| 573 | void runDataFlow(); | |||
| 574 | #ifndef NDEBUG | |||
| 575 | void verifyFixedPoint(); | |||
| 576 | #endif | |||
| 577 | ||||
| 578 | public: | |||
| 579 | StackSafetyDataFlowAnalysis(uint32_t PointerBitWidth, FunctionMap Functions) | |||
| 580 | : Functions(std::move(Functions)), | |||
| 581 | UnknownRange(ConstantRange::getFull(PointerBitWidth)) {} | |||
| 582 | ||||
| 583 | const FunctionMap &run(); | |||
| 584 | ||||
| 585 | ConstantRange getArgumentAccessRange(const CalleeTy *Callee, unsigned ParamNo, | |||
| 586 | const ConstantRange &Offsets) const; | |||
| 587 | }; | |||
| 588 | ||||
| 589 | template <typename CalleeTy> | |||
| 590 | ConstantRange StackSafetyDataFlowAnalysis<CalleeTy>::getArgumentAccessRange( | |||
| 591 | const CalleeTy *Callee, unsigned ParamNo, | |||
| 592 | const ConstantRange &Offsets) const { | |||
| 593 | auto FnIt = Functions.find(Callee); | |||
| 594 | // Unknown callee (outside of LTO domain or an indirect call). | |||
| 595 | if (FnIt == Functions.end()) | |||
| 596 | return UnknownRange; | |||
| 597 | auto &FS = FnIt->second; | |||
| 598 | auto ParamIt = FS.Params.find(ParamNo); | |||
| 599 | if (ParamIt == FS.Params.end()) | |||
| 600 | return UnknownRange; | |||
| 601 | auto &Access = ParamIt->second.Range; | |||
| 602 | if (Access.isEmptySet()) | |||
| 603 | return Access; | |||
| 604 | if (Access.isFullSet()) | |||
| 605 | return UnknownRange; | |||
| 606 | return addOverflowNever(Access, Offsets); | |||
| 607 | } | |||
| 608 | ||||
| 609 | template <typename CalleeTy> | |||
| 610 | bool StackSafetyDataFlowAnalysis<CalleeTy>::updateOneUse(UseInfo<CalleeTy> &US, | |||
| 611 | bool UpdateToFullSet) { | |||
| 612 | bool Changed = false; | |||
| 613 | for (auto &KV : US.Calls) { | |||
| 614 | assert(!KV.second.isEmptySet() &&(static_cast <bool> (!KV.second.isEmptySet() && "Param range can't be empty-set, invalid offset range") ? void (0) : __assert_fail ("!KV.second.isEmptySet() && \"Param range can't be empty-set, invalid offset range\"" , "llvm/lib/Analysis/StackSafetyAnalysis.cpp", 615, __extension__ __PRETTY_FUNCTION__)) | |||
| 615 | "Param range can't be empty-set, invalid offset range")(static_cast <bool> (!KV.second.isEmptySet() && "Param range can't be empty-set, invalid offset range") ? void (0) : __assert_fail ("!KV.second.isEmptySet() && \"Param range can't be empty-set, invalid offset range\"" , "llvm/lib/Analysis/StackSafetyAnalysis.cpp", 615, __extension__ __PRETTY_FUNCTION__)); | |||
| 616 | ||||
| 617 | ConstantRange CalleeRange = | |||
| 618 | getArgumentAccessRange(KV.first.Callee, KV.first.ParamNo, KV.second); | |||
| 619 | if (!US.Range.contains(CalleeRange)) { | |||
| 620 | Changed = true; | |||
| 621 | if (UpdateToFullSet) | |||
| 622 | US.Range = UnknownRange; | |||
| 623 | else | |||
| 624 | US.updateRange(CalleeRange); | |||
| 625 | } | |||
| 626 | } | |||
| 627 | return Changed; | |||
| 628 | } | |||
| 629 | ||||
| 630 | template <typename CalleeTy> | |||
| 631 | void StackSafetyDataFlowAnalysis<CalleeTy>::updateOneNode( | |||
| 632 | const CalleeTy *Callee, FunctionInfo<CalleeTy> &FS) { | |||
| 633 | bool UpdateToFullSet = FS.UpdateCount > StackSafetyMaxIterations; | |||
| 634 | bool Changed = false; | |||
| 635 | for (auto &KV : FS.Params) | |||
| 636 | Changed |= updateOneUse(KV.second, UpdateToFullSet); | |||
| 637 | ||||
| 638 | if (Changed) { | |||
| 639 | LLVM_DEBUG(dbgs() << "=== update [" << FS.UpdateCountdo { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("stack-safety")) { dbgs() << "=== update [" << FS .UpdateCount << (UpdateToFullSet ? ", full-set" : "") << "] " << &FS << "\n"; } } while (false) | |||
| 640 | << (UpdateToFullSet ? ", full-set" : "") << "] " << &FSdo { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("stack-safety")) { dbgs() << "=== update [" << FS .UpdateCount << (UpdateToFullSet ? ", full-set" : "") << "] " << &FS << "\n"; } } while (false) | |||
| 641 | << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("stack-safety")) { dbgs() << "=== update [" << FS .UpdateCount << (UpdateToFullSet ? ", full-set" : "") << "] " << &FS << "\n"; } } while (false); | |||
| 642 | // Callers of this function may need updating. | |||
| 643 | for (auto &CallerID : Callers[Callee]) | |||
| 644 | WorkList.insert(CallerID); | |||
| 645 | ||||
| 646 | ++FS.UpdateCount; | |||
| 647 | } | |||
| 648 | } | |||
| 649 | ||||
| 650 | template <typename CalleeTy> | |||
| 651 | void StackSafetyDataFlowAnalysis<CalleeTy>::runDataFlow() { | |||
| 652 | SmallVector<const CalleeTy *, 16> Callees; | |||
| 653 | for (auto &F : Functions) { | |||
| 654 | Callees.clear(); | |||
| 655 | auto &FS = F.second; | |||
| 656 | for (auto &KV : FS.Params) | |||
| 657 | for (auto &CS : KV.second.Calls) | |||
| 658 | Callees.push_back(CS.first.Callee); | |||
| 659 | ||||
| 660 | llvm::sort(Callees); | |||
| 661 | Callees.erase(std::unique(Callees.begin(), Callees.end()), Callees.end()); | |||
| 662 | ||||
| 663 | for (auto &Callee : Callees) | |||
| 664 | Callers[Callee].push_back(F.first); | |||
| 665 | } | |||
| 666 | ||||
| 667 | updateAllNodes(); | |||
| 668 | ||||
| 669 | while (!WorkList.empty()) { | |||
| 670 | const CalleeTy *Callee = WorkList.pop_back_val(); | |||
| 671 | updateOneNode(Callee); | |||
| 672 | } | |||
| 673 | } | |||
| 674 | ||||
| 675 | #ifndef NDEBUG | |||
| 676 | template <typename CalleeTy> | |||
| 677 | void StackSafetyDataFlowAnalysis<CalleeTy>::verifyFixedPoint() { | |||
| 678 | WorkList.clear(); | |||
| 679 | updateAllNodes(); | |||
| 680 | assert(WorkList.empty())(static_cast <bool> (WorkList.empty()) ? void (0) : __assert_fail ("WorkList.empty()", "llvm/lib/Analysis/StackSafetyAnalysis.cpp" , 680, __extension__ __PRETTY_FUNCTION__)); | |||
| 681 | } | |||
| 682 | #endif | |||
| 683 | ||||
| 684 | template <typename CalleeTy> | |||
| 685 | const typename StackSafetyDataFlowAnalysis<CalleeTy>::FunctionMap & | |||
| 686 | StackSafetyDataFlowAnalysis<CalleeTy>::run() { | |||
| 687 | runDataFlow(); | |||
| 688 | LLVM_DEBUG(verifyFixedPoint())do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("stack-safety")) { verifyFixedPoint(); } } while (false); | |||
| 689 | return Functions; | |||
| 690 | } | |||
| 691 | ||||
| 692 | FunctionSummary *findCalleeFunctionSummary(ValueInfo VI, StringRef ModuleId) { | |||
| 693 | if (!VI) | |||
| 694 | return nullptr; | |||
| 695 | auto SummaryList = VI.getSummaryList(); | |||
| 696 | GlobalValueSummary* S = nullptr; | |||
| 697 | for (const auto& GVS : SummaryList) { | |||
| 698 | if (!GVS->isLive()) | |||
| 699 | continue; | |||
| 700 | if (const AliasSummary *AS = dyn_cast<AliasSummary>(GVS.get())) | |||
| 701 | if (!AS->hasAliasee()) | |||
| 702 | continue; | |||
| 703 | if (!isa<FunctionSummary>(GVS->getBaseObject())) | |||
| 704 | continue; | |||
| 705 | if (GlobalValue::isLocalLinkage(GVS->linkage())) { | |||
| 706 | if (GVS->modulePath() == ModuleId) { | |||
| 707 | S = GVS.get(); | |||
| 708 | break; | |||
| 709 | } | |||
| 710 | } else if (GlobalValue::isExternalLinkage(GVS->linkage())) { | |||
| 711 | if (S) { | |||
| 712 | ++NumIndexCalleeMultipleExternal; | |||
| 713 | return nullptr; | |||
| 714 | } | |||
| 715 | S = GVS.get(); | |||
| 716 | } else if (GlobalValue::isWeakLinkage(GVS->linkage())) { | |||
| 717 | if (S) { | |||
| 718 | ++NumIndexCalleeMultipleWeak; | |||
| 719 | return nullptr; | |||
| 720 | } | |||
| 721 | S = GVS.get(); | |||
| 722 | } else if (GlobalValue::isAvailableExternallyLinkage(GVS->linkage()) || | |||
| 723 | GlobalValue::isLinkOnceLinkage(GVS->linkage())) { | |||
| 724 | if (SummaryList.size() == 1) | |||
| 725 | S = GVS.get(); | |||
| 726 | // According thinLTOResolvePrevailingGUID these are unlikely prevailing. | |||
| 727 | } else { | |||
| 728 | ++NumIndexCalleeUnhandled; | |||
| 729 | } | |||
| 730 | }; | |||
| 731 | while (S) { | |||
| 732 | if (!S->isLive() || !S->isDSOLocal()) | |||
| 733 | return nullptr; | |||
| 734 | if (FunctionSummary *FS = dyn_cast<FunctionSummary>(S)) | |||
| 735 | return FS; | |||
| 736 | AliasSummary *AS = dyn_cast<AliasSummary>(S); | |||
| 737 | if (!AS || !AS->hasAliasee()) | |||
| 738 | return nullptr; | |||
| 739 | S = AS->getBaseObject(); | |||
| 740 | if (S == AS) | |||
| 741 | return nullptr; | |||
| 742 | } | |||
| 743 | return nullptr; | |||
| 744 | } | |||
| 745 | ||||
| 746 | const Function *findCalleeInModule(const GlobalValue *GV) { | |||
| 747 | while (GV) { | |||
| 748 | if (GV->isDeclaration() || GV->isInterposable() || !GV->isDSOLocal()) | |||
| 749 | return nullptr; | |||
| 750 | if (const Function *F = dyn_cast<Function>(GV)) | |||
| 751 | return F; | |||
| 752 | const GlobalAlias *A = dyn_cast<GlobalAlias>(GV); | |||
| 753 | if (!A) | |||
| 754 | return nullptr; | |||
| 755 | GV = A->getAliaseeObject(); | |||
| 756 | if (GV == A) | |||
| 757 | return nullptr; | |||
| 758 | } | |||
| 759 | return nullptr; | |||
| 760 | } | |||
| 761 | ||||
| 762 | const ConstantRange *findParamAccess(const FunctionSummary &FS, | |||
| 763 | uint32_t ParamNo) { | |||
| 764 | assert(FS.isLive())(static_cast <bool> (FS.isLive()) ? void (0) : __assert_fail ("FS.isLive()", "llvm/lib/Analysis/StackSafetyAnalysis.cpp", 764, __extension__ __PRETTY_FUNCTION__)); | |||
| 765 | assert(FS.isDSOLocal())(static_cast <bool> (FS.isDSOLocal()) ? void (0) : __assert_fail ("FS.isDSOLocal()", "llvm/lib/Analysis/StackSafetyAnalysis.cpp" , 765, __extension__ __PRETTY_FUNCTION__)); | |||
| 766 | for (const auto &PS : FS.paramAccesses()) | |||
| 767 | if (ParamNo == PS.ParamNo) | |||
| 768 | return &PS.Use; | |||
| 769 | return nullptr; | |||
| 770 | } | |||
| 771 | ||||
| 772 | void resolveAllCalls(UseInfo<GlobalValue> &Use, | |||
| 773 | const ModuleSummaryIndex *Index) { | |||
| 774 | ConstantRange FullSet(Use.Range.getBitWidth(), true); | |||
| 775 | // Move Use.Calls to a temp storage and repopulate - don't use std::move as it | |||
| 776 | // leaves Use.Calls in an undefined state. | |||
| 777 | UseInfo<GlobalValue>::CallsTy TmpCalls; | |||
| 778 | std::swap(TmpCalls, Use.Calls); | |||
| 779 | for (const auto &C : TmpCalls) { | |||
| 780 | const Function *F = findCalleeInModule(C.first.Callee); | |||
| 781 | if (F) { | |||
| 782 | Use.Calls.emplace(CallInfo<GlobalValue>(F, C.first.ParamNo), C.second); | |||
| 783 | continue; | |||
| 784 | } | |||
| 785 | ||||
| 786 | if (!Index) | |||
| 787 | return Use.updateRange(FullSet); | |||
| 788 | FunctionSummary *FS = | |||
| 789 | findCalleeFunctionSummary(Index->getValueInfo(C.first.Callee->getGUID()), | |||
| 790 | C.first.Callee->getParent()->getModuleIdentifier()); | |||
| 791 | ++NumModuleCalleeLookupTotal; | |||
| 792 | if (!FS) { | |||
| 793 | ++NumModuleCalleeLookupFailed; | |||
| 794 | return Use.updateRange(FullSet); | |||
| 795 | } | |||
| 796 | const ConstantRange *Found = findParamAccess(*FS, C.first.ParamNo); | |||
| 797 | if (!Found || Found->isFullSet()) | |||
| 798 | return Use.updateRange(FullSet); | |||
| 799 | ConstantRange Access = Found->sextOrTrunc(Use.Range.getBitWidth()); | |||
| 800 | if (!Access.isEmptySet()) | |||
| 801 | Use.updateRange(addOverflowNever(Access, C.second)); | |||
| 802 | } | |||
| 803 | } | |||
| 804 | ||||
| 805 | GVToSSI createGlobalStackSafetyInfo( | |||
| 806 | std::map<const GlobalValue *, FunctionInfo<GlobalValue>> Functions, | |||
| 807 | const ModuleSummaryIndex *Index) { | |||
| 808 | GVToSSI SSI; | |||
| 809 | if (Functions.empty()) | |||
| 810 | return SSI; | |||
| 811 | ||||
| 812 | // FIXME: Simplify printing and remove copying here. | |||
| 813 | auto Copy = Functions; | |||
| 814 | ||||
| 815 | for (auto &FnKV : Copy) | |||
| 816 | for (auto &KV : FnKV.second.Params) { | |||
| 817 | resolveAllCalls(KV.second, Index); | |||
| 818 | if (KV.second.Range.isFullSet()) | |||
| 819 | KV.second.Calls.clear(); | |||
| 820 | } | |||
| 821 | ||||
| 822 | uint32_t PointerSize = | |||
| 823 | Copy.begin()->first->getParent()->getDataLayout().getPointerSizeInBits(); | |||
| 824 | StackSafetyDataFlowAnalysis<GlobalValue> SSDFA(PointerSize, std::move(Copy)); | |||
| 825 | ||||
| 826 | for (const auto &F : SSDFA.run()) { | |||
| 827 | auto FI = F.second; | |||
| 828 | auto &SrcF = Functions[F.first]; | |||
| 829 | for (auto &KV : FI.Allocas) { | |||
| 830 | auto &A = KV.second; | |||
| 831 | resolveAllCalls(A, Index); | |||
| 832 | for (auto &C : A.Calls) { | |||
| 833 | A.updateRange(SSDFA.getArgumentAccessRange(C.first.Callee, | |||
| 834 | C.first.ParamNo, C.second)); | |||
| 835 | } | |||
| 836 | // FIXME: This is needed only to preserve calls in print() results. | |||
| 837 | A.Calls = SrcF.Allocas.find(KV.first)->second.Calls; | |||
| 838 | } | |||
| 839 | for (auto &KV : FI.Params) { | |||
| 840 | auto &P = KV.second; | |||
| 841 | P.Calls = SrcF.Params.find(KV.first)->second.Calls; | |||
| 842 | } | |||
| 843 | SSI[F.first] = std::move(FI); | |||
| 844 | } | |||
| 845 | ||||
| 846 | return SSI; | |||
| 847 | } | |||
| 848 | ||||
| 849 | } // end anonymous namespace | |||
| 850 | ||||
| 851 | StackSafetyInfo::StackSafetyInfo() = default; | |||
| 852 | ||||
| 853 | StackSafetyInfo::StackSafetyInfo(Function *F, | |||
| 854 | std::function<ScalarEvolution &()> GetSE) | |||
| 855 | : F(F), GetSE(GetSE) {} | |||
| 856 | ||||
| 857 | StackSafetyInfo::StackSafetyInfo(StackSafetyInfo &&) = default; | |||
| 858 | ||||
| 859 | StackSafetyInfo &StackSafetyInfo::operator=(StackSafetyInfo &&) = default; | |||
| 860 | ||||
| 861 | StackSafetyInfo::~StackSafetyInfo() = default; | |||
| 862 | ||||
| 863 | const StackSafetyInfo::InfoTy &StackSafetyInfo::getInfo() const { | |||
| 864 | if (!Info) { | |||
| 865 | StackSafetyLocalAnalysis SSLA(*F, GetSE()); | |||
| 866 | Info.reset(new InfoTy{SSLA.run()}); | |||
| 867 | } | |||
| 868 | return *Info; | |||
| 869 | } | |||
| 870 | ||||
| 871 | void StackSafetyInfo::print(raw_ostream &O) const { | |||
| 872 | getInfo().Info.print(O, F->getName(), dyn_cast<Function>(F)); | |||
| 873 | O << "\n"; | |||
| 874 | } | |||
| 875 | ||||
| 876 | const StackSafetyGlobalInfo::InfoTy &StackSafetyGlobalInfo::getInfo() const { | |||
| 877 | if (!Info) { | |||
| 878 | std::map<const GlobalValue *, FunctionInfo<GlobalValue>> Functions; | |||
| 879 | for (auto &F : M->functions()) { | |||
| 880 | if (!F.isDeclaration()) { | |||
| 881 | auto FI = GetSSI(F).getInfo().Info; | |||
| 882 | Functions.emplace(&F, std::move(FI)); | |||
| 883 | } | |||
| 884 | } | |||
| 885 | Info.reset(new InfoTy{ | |||
| 886 | createGlobalStackSafetyInfo(std::move(Functions), Index), {}, {}}); | |||
| 887 | ||||
| 888 | for (auto &FnKV : Info->Info) { | |||
| 889 | for (auto &KV : FnKV.second.Allocas) { | |||
| 890 | ++NumAllocaTotal; | |||
| 891 | const AllocaInst *AI = KV.first; | |||
| 892 | auto AIRange = getStaticAllocaSizeRange(*AI); | |||
| 893 | if (AIRange.contains(KV.second.Range)) { | |||
| 894 | Info->SafeAllocas.insert(AI); | |||
| 895 | ++NumAllocaStackSafe; | |||
| 896 | } | |||
| 897 | Info->UnsafeAccesses.insert(KV.second.UnsafeAccesses.begin(), | |||
| 898 | KV.second.UnsafeAccesses.end()); | |||
| 899 | } | |||
| 900 | } | |||
| 901 | ||||
| 902 | if (StackSafetyPrint) | |||
| 903 | print(errs()); | |||
| 904 | } | |||
| 905 | return *Info; | |||
| 906 | } | |||
| 907 | ||||
| 908 | std::vector<FunctionSummary::ParamAccess> | |||
| 909 | StackSafetyInfo::getParamAccesses(ModuleSummaryIndex &Index) const { | |||
| 910 | // Implementation transforms internal representation of parameter information | |||
| 911 | // into FunctionSummary format. | |||
| 912 | std::vector<FunctionSummary::ParamAccess> ParamAccesses; | |||
| 913 | for (const auto &KV : getInfo().Info.Params) { | |||
| 914 | auto &PS = KV.second; | |||
| 915 | // Parameter accessed by any or unknown offset, represented as FullSet by | |||
| 916 | // StackSafety, is handled as the parameter for which we have no | |||
| 917 | // StackSafety info at all. So drop it to reduce summary size. | |||
| 918 | if (PS.Range.isFullSet()) | |||
| 919 | continue; | |||
| 920 | ||||
| 921 | ParamAccesses.emplace_back(KV.first, PS.Range); | |||
| 922 | FunctionSummary::ParamAccess &Param = ParamAccesses.back(); | |||
| 923 | ||||
| 924 | Param.Calls.reserve(PS.Calls.size()); | |||
| 925 | for (const auto &C : PS.Calls) { | |||
| 926 | // Parameter forwarded into another function by any or unknown offset | |||
| 927 | // will make ParamAccess::Range as FullSet anyway. So we can drop the | |||
| 928 | // entire parameter like we did above. | |||
| 929 | // TODO(vitalybuka): Return already filtered parameters from getInfo(). | |||
| 930 | if (C.second.isFullSet()) { | |||
| 931 | ParamAccesses.pop_back(); | |||
| 932 | break; | |||
| 933 | } | |||
| 934 | Param.Calls.emplace_back(C.first.ParamNo, | |||
| 935 | Index.getOrInsertValueInfo(C.first.Callee), | |||
| 936 | C.second); | |||
| 937 | } | |||
| 938 | } | |||
| 939 | for (FunctionSummary::ParamAccess &Param : ParamAccesses) { | |||
| 940 | sort(Param.Calls, [](const FunctionSummary::ParamAccess::Call &L, | |||
| 941 | const FunctionSummary::ParamAccess::Call &R) { | |||
| 942 | return std::tie(L.ParamNo, L.Callee) < std::tie(R.ParamNo, R.Callee); | |||
| 943 | }); | |||
| 944 | } | |||
| 945 | return ParamAccesses; | |||
| 946 | } | |||
| 947 | ||||
| 948 | StackSafetyGlobalInfo::StackSafetyGlobalInfo() = default; | |||
| 949 | ||||
| 950 | StackSafetyGlobalInfo::StackSafetyGlobalInfo( | |||
| 951 | Module *M, std::function<const StackSafetyInfo &(Function &F)> GetSSI, | |||
| 952 | const ModuleSummaryIndex *Index) | |||
| 953 | : M(M), GetSSI(GetSSI), Index(Index) { | |||
| 954 | if (StackSafetyRun) | |||
| 955 | getInfo(); | |||
| 956 | } | |||
| 957 | ||||
| 958 | StackSafetyGlobalInfo::StackSafetyGlobalInfo(StackSafetyGlobalInfo &&) = | |||
| 959 | default; | |||
| 960 | ||||
| 961 | StackSafetyGlobalInfo & | |||
| 962 | StackSafetyGlobalInfo::operator=(StackSafetyGlobalInfo &&) = default; | |||
| 963 | ||||
| 964 | StackSafetyGlobalInfo::~StackSafetyGlobalInfo() = default; | |||
| 965 | ||||
| 966 | bool StackSafetyGlobalInfo::isSafe(const AllocaInst &AI) const { | |||
| 967 | const auto &Info = getInfo(); | |||
| 968 | return Info.SafeAllocas.count(&AI); | |||
| 969 | } | |||
| 970 | ||||
| 971 | bool StackSafetyGlobalInfo::stackAccessIsSafe(const Instruction &I) const { | |||
| 972 | const auto &Info = getInfo(); | |||
| 973 | return Info.UnsafeAccesses.find(&I) == Info.UnsafeAccesses.end(); | |||
| 974 | } | |||
| 975 | ||||
| 976 | void StackSafetyGlobalInfo::print(raw_ostream &O) const { | |||
| 977 | auto &SSI = getInfo().Info; | |||
| 978 | if (SSI.empty()) | |||
| 979 | return; | |||
| 980 | const Module &M = *SSI.begin()->first->getParent(); | |||
| 981 | for (const auto &F : M.functions()) { | |||
| 982 | if (!F.isDeclaration()) { | |||
| 983 | SSI.find(&F)->second.print(O, F.getName(), &F); | |||
| 984 | O << " safe accesses:" | |||
| 985 | << "\n"; | |||
| 986 | for (const auto &I : instructions(F)) { | |||
| 987 | const CallInst *Call = dyn_cast<CallInst>(&I); | |||
| 988 | if ((isa<StoreInst>(I) || isa<LoadInst>(I) || isa<MemIntrinsic>(I) || | |||
| 989 | (Call && Call->hasByValArgument())) && | |||
| 990 | stackAccessIsSafe(I)) { | |||
| 991 | O << " " << I << "\n"; | |||
| 992 | } | |||
| 993 | } | |||
| 994 | O << "\n"; | |||
| 995 | } | |||
| 996 | } | |||
| 997 | } | |||
| 998 | ||||
| 999 | LLVM_DUMP_METHOD__attribute__((noinline)) __attribute__((__used__)) void StackSafetyGlobalInfo::dump() const { print(dbgs()); } | |||
| 1000 | ||||
| 1001 | AnalysisKey StackSafetyAnalysis::Key; | |||
| 1002 | ||||
| 1003 | StackSafetyInfo StackSafetyAnalysis::run(Function &F, | |||
| 1004 | FunctionAnalysisManager &AM) { | |||
| 1005 | return StackSafetyInfo(&F, [&AM, &F]() -> ScalarEvolution & { | |||
| 1006 | return AM.getResult<ScalarEvolutionAnalysis>(F); | |||
| 1007 | }); | |||
| 1008 | } | |||
| 1009 | ||||
| 1010 | PreservedAnalyses StackSafetyPrinterPass::run(Function &F, | |||
| 1011 | FunctionAnalysisManager &AM) { | |||
| 1012 | OS << "'Stack Safety Local Analysis' for function '" << F.getName() << "'\n"; | |||
| 1013 | AM.getResult<StackSafetyAnalysis>(F).print(OS); | |||
| 1014 | return PreservedAnalyses::all(); | |||
| 1015 | } | |||
| 1016 | ||||
| 1017 | char StackSafetyInfoWrapperPass::ID = 0; | |||
| 1018 | ||||
| 1019 | StackSafetyInfoWrapperPass::StackSafetyInfoWrapperPass() : FunctionPass(ID) { | |||
| 1020 | initializeStackSafetyInfoWrapperPassPass(*PassRegistry::getPassRegistry()); | |||
| 1021 | } | |||
| 1022 | ||||
| 1023 | void StackSafetyInfoWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const { | |||
| 1024 | AU.addRequiredTransitive<ScalarEvolutionWrapperPass>(); | |||
| 1025 | AU.setPreservesAll(); | |||
| 1026 | } | |||
| 1027 | ||||
| 1028 | void StackSafetyInfoWrapperPass::print(raw_ostream &O, const Module *M) const { | |||
| 1029 | SSI.print(O); | |||
| 1030 | } | |||
| 1031 | ||||
| 1032 | bool StackSafetyInfoWrapperPass::runOnFunction(Function &F) { | |||
| 1033 | auto *SE = &getAnalysis<ScalarEvolutionWrapperPass>().getSE(); | |||
| 1034 | SSI = {&F, [SE]() -> ScalarEvolution & { return *SE; }}; | |||
| 1035 | return false; | |||
| 1036 | } | |||
| 1037 | ||||
| 1038 | AnalysisKey StackSafetyGlobalAnalysis::Key; | |||
| 1039 | ||||
| 1040 | StackSafetyGlobalInfo | |||
| 1041 | StackSafetyGlobalAnalysis::run(Module &M, ModuleAnalysisManager &AM) { | |||
| 1042 | // FIXME: Lookup Module Summary. | |||
| 1043 | FunctionAnalysisManager &FAM = | |||
| 1044 | AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); | |||
| 1045 | return {&M, | |||
| 1046 | [&FAM](Function &F) -> const StackSafetyInfo & { | |||
| 1047 | return FAM.getResult<StackSafetyAnalysis>(F); | |||
| 1048 | }, | |||
| 1049 | nullptr}; | |||
| 1050 | } | |||
| 1051 | ||||
| 1052 | PreservedAnalyses StackSafetyGlobalPrinterPass::run(Module &M, | |||
| 1053 | ModuleAnalysisManager &AM) { | |||
| 1054 | OS << "'Stack Safety Analysis' for module '" << M.getName() << "'\n"; | |||
| 1055 | AM.getResult<StackSafetyGlobalAnalysis>(M).print(OS); | |||
| 1056 | return PreservedAnalyses::all(); | |||
| 1057 | } | |||
| 1058 | ||||
| 1059 | char StackSafetyGlobalInfoWrapperPass::ID = 0; | |||
| 1060 | ||||
| 1061 | StackSafetyGlobalInfoWrapperPass::StackSafetyGlobalInfoWrapperPass() | |||
| 1062 | : ModulePass(ID) { | |||
| 1063 | initializeStackSafetyGlobalInfoWrapperPassPass( | |||
| 1064 | *PassRegistry::getPassRegistry()); | |||
| 1065 | } | |||
| 1066 | ||||
| 1067 | StackSafetyGlobalInfoWrapperPass::~StackSafetyGlobalInfoWrapperPass() = default; | |||
| 1068 | ||||
| 1069 | void StackSafetyGlobalInfoWrapperPass::print(raw_ostream &O, | |||
| 1070 | const Module *M) const { | |||
| 1071 | SSGI.print(O); | |||
| 1072 | } | |||
| 1073 | ||||
| 1074 | void StackSafetyGlobalInfoWrapperPass::getAnalysisUsage( | |||
| 1075 | AnalysisUsage &AU) const { | |||
| 1076 | AU.setPreservesAll(); | |||
| 1077 | AU.addRequired<StackSafetyInfoWrapperPass>(); | |||
| 1078 | } | |||
| 1079 | ||||
| 1080 | bool StackSafetyGlobalInfoWrapperPass::runOnModule(Module &M) { | |||
| 1081 | const ModuleSummaryIndex *ImportSummary = nullptr; | |||
| 1082 | if (auto *IndexWrapperPass
| |||
| ||||
| 1083 | getAnalysisIfAvailable<ImmutableModuleSummaryIndexWrapperPass>()) | |||
| 1084 | ImportSummary = IndexWrapperPass->getIndex(); | |||
| 1085 | ||||
| 1086 | SSGI = {&M, | |||
| 1087 | [this](Function &F) -> const StackSafetyInfo & { | |||
| 1088 | return getAnalysis<StackSafetyInfoWrapperPass>(F).getResult(); | |||
| 1089 | }, | |||
| 1090 | ImportSummary}; | |||
| 1091 | return false; | |||
| 1092 | } | |||
| 1093 | ||||
| 1094 | bool llvm::needsParamAccessSummary(const Module &M) { | |||
| 1095 | if (StackSafetyRun) | |||
| 1096 | return true; | |||
| 1097 | for (const auto &F : M.functions()) | |||
| 1098 | if (F.hasFnAttribute(Attribute::SanitizeMemTag)) | |||
| 1099 | return true; | |||
| 1100 | return false; | |||
| 1101 | } | |||
| 1102 | ||||
| 1103 | void llvm::generateParamAccessSummary(ModuleSummaryIndex &Index) { | |||
| 1104 | if (!Index.hasParamAccess()) | |||
| 1105 | return; | |||
| 1106 | const ConstantRange FullSet(FunctionSummary::ParamAccess::RangeWidth, true); | |||
| 1107 | ||||
| 1108 | auto CountParamAccesses = [&](auto &Stat) { | |||
| 1109 | if (!AreStatisticsEnabled()) | |||
| 1110 | return; | |||
| 1111 | for (auto &GVS : Index) | |||
| 1112 | for (auto &GV : GVS.second.SummaryList) | |||
| 1113 | if (FunctionSummary *FS = dyn_cast<FunctionSummary>(GV.get())) | |||
| 1114 | Stat += FS->paramAccesses().size(); | |||
| 1115 | }; | |||
| 1116 | ||||
| 1117 | CountParamAccesses(NumCombinedParamAccessesBefore); | |||
| 1118 | ||||
| 1119 | std::map<const FunctionSummary *, FunctionInfo<FunctionSummary>> Functions; | |||
| 1120 | ||||
| 1121 | // Convert the ModuleSummaryIndex to a FunctionMap | |||
| 1122 | for (auto &GVS : Index) { | |||
| 1123 | for (auto &GV : GVS.second.SummaryList) { | |||
| 1124 | FunctionSummary *FS = dyn_cast<FunctionSummary>(GV.get()); | |||
| 1125 | if (!FS || FS->paramAccesses().empty()) | |||
| 1126 | continue; | |||
| 1127 | if (FS->isLive() && FS->isDSOLocal()) { | |||
| 1128 | FunctionInfo<FunctionSummary> FI; | |||
| 1129 | for (const auto &PS : FS->paramAccesses()) { | |||
| 1130 | auto &US = | |||
| 1131 | FI.Params | |||
| 1132 | .emplace(PS.ParamNo, FunctionSummary::ParamAccess::RangeWidth) | |||
| 1133 | .first->second; | |||
| 1134 | US.Range = PS.Use; | |||
| 1135 | for (const auto &Call : PS.Calls) { | |||
| 1136 | assert(!Call.Offsets.isFullSet())(static_cast <bool> (!Call.Offsets.isFullSet()) ? void ( 0) : __assert_fail ("!Call.Offsets.isFullSet()", "llvm/lib/Analysis/StackSafetyAnalysis.cpp" , 1136, __extension__ __PRETTY_FUNCTION__)); | |||
| 1137 | FunctionSummary *S = | |||
| 1138 | findCalleeFunctionSummary(Call.Callee, FS->modulePath()); | |||
| 1139 | ++NumCombinedCalleeLookupTotal; | |||
| 1140 | if (!S) { | |||
| 1141 | ++NumCombinedCalleeLookupFailed; | |||
| 1142 | US.Range = FullSet; | |||
| 1143 | US.Calls.clear(); | |||
| 1144 | break; | |||
| 1145 | } | |||
| 1146 | US.Calls.emplace(CallInfo<FunctionSummary>(S, Call.ParamNo), | |||
| 1147 | Call.Offsets); | |||
| 1148 | } | |||
| 1149 | } | |||
| 1150 | Functions.emplace(FS, std::move(FI)); | |||
| 1151 | } | |||
| 1152 | // Reset data for all summaries. Alive and DSO local will be set back from | |||
| 1153 | // of data flow results below. Anything else will not be accessed | |||
| 1154 | // by ThinLTO backend, so we can save on bitcode size. | |||
| 1155 | FS->setParamAccesses({}); | |||
| 1156 | } | |||
| 1157 | } | |||
| 1158 | NumCombinedDataFlowNodes += Functions.size(); | |||
| 1159 | StackSafetyDataFlowAnalysis<FunctionSummary> SSDFA( | |||
| 1160 | FunctionSummary::ParamAccess::RangeWidth, std::move(Functions)); | |||
| 1161 | for (const auto &KV : SSDFA.run()) { | |||
| 1162 | std::vector<FunctionSummary::ParamAccess> NewParams; | |||
| 1163 | NewParams.reserve(KV.second.Params.size()); | |||
| 1164 | for (const auto &Param : KV.second.Params) { | |||
| 1165 | // It's not needed as FullSet is processed the same as a missing value. | |||
| 1166 | if (Param.second.Range.isFullSet()) | |||
| 1167 | continue; | |||
| 1168 | NewParams.emplace_back(); | |||
| 1169 | FunctionSummary::ParamAccess &New = NewParams.back(); | |||
| 1170 | New.ParamNo = Param.first; | |||
| 1171 | New.Use = Param.second.Range; // Only range is needed. | |||
| 1172 | } | |||
| 1173 | const_cast<FunctionSummary *>(KV.first)->setParamAccesses( | |||
| 1174 | std::move(NewParams)); | |||
| 1175 | } | |||
| 1176 | ||||
| 1177 | CountParamAccesses(NumCombinedParamAccessesAfter); | |||
| 1178 | } | |||
| 1179 | ||||
| 1180 | static const char LocalPassArg[] = "stack-safety-local"; | |||
| 1181 | static const char LocalPassName[] = "Stack Safety Local Analysis"; | |||
| 1182 | INITIALIZE_PASS_BEGIN(StackSafetyInfoWrapperPass, LocalPassArg, LocalPassName,static void *initializeStackSafetyInfoWrapperPassPassOnce(PassRegistry &Registry) { | |||
| 1183 | false, true)static void *initializeStackSafetyInfoWrapperPassPassOnce(PassRegistry &Registry) { | |||
| 1184 | INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass)initializeScalarEvolutionWrapperPassPass(Registry); | |||
| 1185 | INITIALIZE_PASS_END(StackSafetyInfoWrapperPass, LocalPassArg, LocalPassName,PassInfo *PI = new PassInfo( LocalPassName, LocalPassArg, & StackSafetyInfoWrapperPass::ID, PassInfo::NormalCtor_t(callDefaultCtor <StackSafetyInfoWrapperPass>), false, true); Registry.registerPass (*PI, true); return PI; } static llvm::once_flag InitializeStackSafetyInfoWrapperPassPassFlag ; void llvm::initializeStackSafetyInfoWrapperPassPass(PassRegistry &Registry) { llvm::call_once(InitializeStackSafetyInfoWrapperPassPassFlag , initializeStackSafetyInfoWrapperPassPassOnce, std::ref(Registry )); } | |||
| 1186 | false, true)PassInfo *PI = new PassInfo( LocalPassName, LocalPassArg, & StackSafetyInfoWrapperPass::ID, PassInfo::NormalCtor_t(callDefaultCtor <StackSafetyInfoWrapperPass>), false, true); Registry.registerPass (*PI, true); return PI; } static llvm::once_flag InitializeStackSafetyInfoWrapperPassPassFlag ; void llvm::initializeStackSafetyInfoWrapperPassPass(PassRegistry &Registry) { llvm::call_once(InitializeStackSafetyInfoWrapperPassPassFlag , initializeStackSafetyInfoWrapperPassPassOnce, std::ref(Registry )); } | |||
| 1187 | ||||
| 1188 | static const char GlobalPassName[] = "Stack Safety Analysis"; | |||
| 1189 | INITIALIZE_PASS_BEGIN(StackSafetyGlobalInfoWrapperPass, DEBUG_TYPE,static void *initializeStackSafetyGlobalInfoWrapperPassPassOnce (PassRegistry &Registry) { | |||
| 1190 | GlobalPassName, false, true)static void *initializeStackSafetyGlobalInfoWrapperPassPassOnce (PassRegistry &Registry) { | |||
| 1191 | INITIALIZE_PASS_DEPENDENCY(StackSafetyInfoWrapperPass)initializeStackSafetyInfoWrapperPassPass(Registry); | |||
| 1192 | INITIALIZE_PASS_DEPENDENCY(ImmutableModuleSummaryIndexWrapperPass)initializeImmutableModuleSummaryIndexWrapperPassPass(Registry ); | |||
| 1193 | INITIALIZE_PASS_END(StackSafetyGlobalInfoWrapperPass, DEBUG_TYPE,PassInfo *PI = new PassInfo( GlobalPassName, "stack-safety", & StackSafetyGlobalInfoWrapperPass::ID, PassInfo::NormalCtor_t( callDefaultCtor<StackSafetyGlobalInfoWrapperPass>), false , true); Registry.registerPass(*PI, true); return PI; } static llvm::once_flag InitializeStackSafetyGlobalInfoWrapperPassPassFlag ; void llvm::initializeStackSafetyGlobalInfoWrapperPassPass(PassRegistry &Registry) { llvm::call_once(InitializeStackSafetyGlobalInfoWrapperPassPassFlag , initializeStackSafetyGlobalInfoWrapperPassPassOnce, std::ref (Registry)); } | |||
| 1194 | GlobalPassName, false, true)PassInfo *PI = new PassInfo( GlobalPassName, "stack-safety", & StackSafetyGlobalInfoWrapperPass::ID, PassInfo::NormalCtor_t( callDefaultCtor<StackSafetyGlobalInfoWrapperPass>), false , true); Registry.registerPass(*PI, true); return PI; } static llvm::once_flag InitializeStackSafetyGlobalInfoWrapperPassPassFlag ; void llvm::initializeStackSafetyGlobalInfoWrapperPassPass(PassRegistry &Registry) { llvm::call_once(InitializeStackSafetyGlobalInfoWrapperPassPassFlag , initializeStackSafetyGlobalInfoWrapperPassPassOnce, std::ref (Registry)); } |