1 | //===- StackSafetyAnalysis.h - Stack memory safety analysis -----*- C++ -*-===// |
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 | // Stack Safety Analysis detects allocas and arguments with safe access. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #ifndef LLVM_ANALYSIS_STACKSAFETYANALYSIS_H |
14 | #define LLVM_ANALYSIS_STACKSAFETYANALYSIS_H |
15 | |
16 | #include "llvm/IR/ModuleSummaryIndex.h" |
17 | #include "llvm/IR/PassManager.h" |
18 | #include "llvm/Pass.h" |
19 | |
20 | namespace llvm { |
21 | |
22 | class AllocaInst; |
23 | class ScalarEvolution; |
24 | |
25 | /// Interface to access stack safety analysis results for single function. |
26 | class StackSafetyInfo { |
27 | public: |
28 | struct InfoTy; |
29 | |
30 | private: |
31 | Function *F = nullptr; |
32 | std::function<ScalarEvolution &()> GetSE; |
33 | mutable std::unique_ptr<InfoTy> Info; |
34 | |
35 | public: |
36 | StackSafetyInfo(); |
37 | StackSafetyInfo(Function *F, std::function<ScalarEvolution &()> GetSE); |
38 | StackSafetyInfo(StackSafetyInfo &&); |
39 | StackSafetyInfo &operator=(StackSafetyInfo &&); |
40 | ~StackSafetyInfo(); |
41 | |
42 | const InfoTy &getInfo() const; |
43 | |
44 | // TODO: Add useful for client methods. |
45 | void print(raw_ostream &O) const; |
46 | |
47 | /// Parameters use for a FunctionSummary. |
48 | /// Function collects access information of all pointer parameters. |
49 | /// Information includes a range of direct access of parameters by the |
50 | /// functions and all call sites accepting the parameter. |
51 | /// StackSafety assumes that missing parameter information means possibility |
52 | /// of access to the parameter with any offset, so we can correctly link |
53 | /// code without StackSafety information, e.g. non-ThinLTO. |
54 | std::vector<FunctionSummary::ParamAccess> |
55 | getParamAccesses(ModuleSummaryIndex &Index) const; |
56 | }; |
57 | |
58 | class StackSafetyGlobalInfo { |
59 | public: |
60 | struct InfoTy; |
61 | |
62 | private: |
63 | Module *M = nullptr; |
64 | std::function<const StackSafetyInfo &(Function &F)> GetSSI; |
65 | const ModuleSummaryIndex *Index = nullptr; |
66 | mutable std::unique_ptr<InfoTy> Info; |
67 | const InfoTy &getInfo() const; |
68 | |
69 | public: |
70 | StackSafetyGlobalInfo(); |
71 | StackSafetyGlobalInfo( |
72 | Module *M, std::function<const StackSafetyInfo &(Function &F)> GetSSI, |
73 | const ModuleSummaryIndex *Index); |
74 | StackSafetyGlobalInfo(StackSafetyGlobalInfo &&); |
75 | StackSafetyGlobalInfo &operator=(StackSafetyGlobalInfo &&); |
76 | ~StackSafetyGlobalInfo(); |
77 | |
78 | // Whether we can prove that all accesses to this Alloca are in-range and |
79 | // during its lifetime. |
80 | bool isSafe(const AllocaInst &AI) const; |
81 | |
82 | // Returns true if the instruction can be proven to do only two types of |
83 | // memory accesses: |
84 | // (1) live stack locations in-bounds or |
85 | // (2) non-stack locations. |
86 | bool stackAccessIsSafe(const Instruction &I) const; |
87 | void print(raw_ostream &O) const; |
88 | void dump() const; |
89 | }; |
90 | |
91 | /// StackSafetyInfo wrapper for the new pass manager. |
92 | class StackSafetyAnalysis : public AnalysisInfoMixin<StackSafetyAnalysis> { |
93 | friend AnalysisInfoMixin<StackSafetyAnalysis>; |
94 | static AnalysisKey Key; |
95 | |
96 | public: |
97 | using Result = StackSafetyInfo; |
98 | StackSafetyInfo run(Function &F, FunctionAnalysisManager &AM); |
99 | }; |
100 | |
101 | /// Printer pass for the \c StackSafetyAnalysis results. |
102 | class StackSafetyPrinterPass : public PassInfoMixin<StackSafetyPrinterPass> { |
103 | raw_ostream &OS; |
104 | |
105 | public: |
106 | explicit StackSafetyPrinterPass(raw_ostream &OS) : OS(OS) {} |
107 | PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); |
108 | static bool isRequired() { return true; } |
109 | }; |
110 | |
111 | /// StackSafetyInfo wrapper for the legacy pass manager |
112 | class StackSafetyInfoWrapperPass : public FunctionPass { |
113 | StackSafetyInfo SSI; |
114 | |
115 | public: |
116 | static char ID; |
117 | StackSafetyInfoWrapperPass(); |
118 | |
119 | const StackSafetyInfo &getResult() const { return SSI; } |
120 | |
121 | void print(raw_ostream &O, const Module *M) const override; |
122 | void getAnalysisUsage(AnalysisUsage &AU) const override; |
123 | |
124 | bool runOnFunction(Function &F) override; |
125 | }; |
126 | |
127 | /// This pass performs the global (interprocedural) stack safety analysis (new |
128 | /// pass manager). |
129 | class StackSafetyGlobalAnalysis |
130 | : public AnalysisInfoMixin<StackSafetyGlobalAnalysis> { |
131 | friend AnalysisInfoMixin<StackSafetyGlobalAnalysis>; |
132 | static AnalysisKey Key; |
133 | |
134 | public: |
135 | using Result = StackSafetyGlobalInfo; |
136 | Result run(Module &M, ModuleAnalysisManager &AM); |
137 | }; |
138 | |
139 | /// Printer pass for the \c StackSafetyGlobalAnalysis results. |
140 | class StackSafetyGlobalPrinterPass |
141 | : public PassInfoMixin<StackSafetyGlobalPrinterPass> { |
142 | raw_ostream &OS; |
143 | |
144 | public: |
145 | explicit StackSafetyGlobalPrinterPass(raw_ostream &OS) : OS(OS) {} |
146 | PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); |
147 | static bool isRequired() { return true; } |
148 | }; |
149 | |
150 | /// This pass performs the global (interprocedural) stack safety analysis |
151 | /// (legacy pass manager). |
152 | class StackSafetyGlobalInfoWrapperPass : public ModulePass { |
153 | StackSafetyGlobalInfo SSGI; |
154 | |
155 | public: |
156 | static char ID; |
157 | |
158 | StackSafetyGlobalInfoWrapperPass(); |
159 | ~StackSafetyGlobalInfoWrapperPass(); |
160 | |
161 | const StackSafetyGlobalInfo &getResult() const { return SSGI; } |
162 | |
163 | void print(raw_ostream &O, const Module *M) const override; |
164 | void getAnalysisUsage(AnalysisUsage &AU) const override; |
165 | |
166 | bool runOnModule(Module &M) override; |
167 | }; |
168 | |
169 | bool needsParamAccessSummary(const Module &M); |
170 | |
171 | void generateParamAccessSummary(ModuleSummaryIndex &Index); |
172 | |
173 | } // end namespace llvm |
174 | |
175 | #endif // LLVM_ANALYSIS_STACKSAFETYANALYSIS_H |
176 | |