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