File: | lib/Transforms/Instrumentation/EfficiencySanitizer.cpp |
Warning: | line 187, column 13 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===-- EfficiencySanitizer.cpp - performance tuner -----------------------===// | |||
2 | // | |||
3 | // The LLVM Compiler Infrastructure | |||
4 | // | |||
5 | // This file is distributed under the University of Illinois Open Source | |||
6 | // License. See LICENSE.TXT for details. | |||
7 | // | |||
8 | //===----------------------------------------------------------------------===// | |||
9 | // | |||
10 | // This file is a part of EfficiencySanitizer, a family of performance tuners | |||
11 | // that detects multiple performance issues via separate sub-tools. | |||
12 | // | |||
13 | // The instrumentation phase is straightforward: | |||
14 | // - Take action on every memory access: either inlined instrumentation, | |||
15 | // or Inserted calls to our run-time library. | |||
16 | // - Optimizations may apply to avoid instrumenting some of the accesses. | |||
17 | // - Turn mem{set,cpy,move} instrinsics into library calls. | |||
18 | // The rest is handled by the run-time library. | |||
19 | //===----------------------------------------------------------------------===// | |||
20 | ||||
21 | #include "llvm/ADT/SmallString.h" | |||
22 | #include "llvm/ADT/SmallVector.h" | |||
23 | #include "llvm/ADT/Statistic.h" | |||
24 | #include "llvm/ADT/StringExtras.h" | |||
25 | #include "llvm/Analysis/TargetLibraryInfo.h" | |||
26 | #include "llvm/Transforms/Utils/Local.h" | |||
27 | #include "llvm/IR/Function.h" | |||
28 | #include "llvm/IR/IRBuilder.h" | |||
29 | #include "llvm/IR/IntrinsicInst.h" | |||
30 | #include "llvm/IR/Module.h" | |||
31 | #include "llvm/IR/Type.h" | |||
32 | #include "llvm/Support/CommandLine.h" | |||
33 | #include "llvm/Support/Debug.h" | |||
34 | #include "llvm/Support/raw_ostream.h" | |||
35 | #include "llvm/Transforms/Instrumentation.h" | |||
36 | #include "llvm/Transforms/Utils/BasicBlockUtils.h" | |||
37 | #include "llvm/Transforms/Utils/ModuleUtils.h" | |||
38 | ||||
39 | using namespace llvm; | |||
40 | ||||
41 | #define DEBUG_TYPE"esan" "esan" | |||
42 | ||||
43 | // The tool type must be just one of these ClTool* options, as the tools | |||
44 | // cannot be combined due to shadow memory constraints. | |||
45 | static cl::opt<bool> | |||
46 | ClToolCacheFrag("esan-cache-frag", cl::init(false), | |||
47 | cl::desc("Detect data cache fragmentation"), cl::Hidden); | |||
48 | static cl::opt<bool> | |||
49 | ClToolWorkingSet("esan-working-set", cl::init(false), | |||
50 | cl::desc("Measure the working set size"), cl::Hidden); | |||
51 | // Each new tool will get its own opt flag here. | |||
52 | // These are converted to EfficiencySanitizerOptions for use | |||
53 | // in the code. | |||
54 | ||||
55 | static cl::opt<bool> ClInstrumentLoadsAndStores( | |||
56 | "esan-instrument-loads-and-stores", cl::init(true), | |||
57 | cl::desc("Instrument loads and stores"), cl::Hidden); | |||
58 | static cl::opt<bool> ClInstrumentMemIntrinsics( | |||
59 | "esan-instrument-memintrinsics", cl::init(true), | |||
60 | cl::desc("Instrument memintrinsics (memset/memcpy/memmove)"), cl::Hidden); | |||
61 | static cl::opt<bool> ClInstrumentFastpath( | |||
62 | "esan-instrument-fastpath", cl::init(true), | |||
63 | cl::desc("Instrument fastpath"), cl::Hidden); | |||
64 | static cl::opt<bool> ClAuxFieldInfo( | |||
65 | "esan-aux-field-info", cl::init(true), | |||
66 | cl::desc("Generate binary with auxiliary struct field information"), | |||
67 | cl::Hidden); | |||
68 | ||||
69 | // Experiments show that the performance difference can be 2x or more, | |||
70 | // and accuracy loss is typically negligible, so we turn this on by default. | |||
71 | static cl::opt<bool> ClAssumeIntraCacheLine( | |||
72 | "esan-assume-intra-cache-line", cl::init(true), | |||
73 | cl::desc("Assume each memory access touches just one cache line, for " | |||
74 | "better performance but with a potential loss of accuracy."), | |||
75 | cl::Hidden); | |||
76 | ||||
77 | STATISTIC(NumInstrumentedLoads, "Number of instrumented loads")static llvm::Statistic NumInstrumentedLoads = {"esan", "NumInstrumentedLoads" , "Number of instrumented loads", {0}, {false}}; | |||
78 | STATISTIC(NumInstrumentedStores, "Number of instrumented stores")static llvm::Statistic NumInstrumentedStores = {"esan", "NumInstrumentedStores" , "Number of instrumented stores", {0}, {false}}; | |||
79 | STATISTIC(NumFastpaths, "Number of instrumented fastpaths")static llvm::Statistic NumFastpaths = {"esan", "NumFastpaths" , "Number of instrumented fastpaths", {0}, {false}}; | |||
80 | STATISTIC(NumAccessesWithIrregularSize,static llvm::Statistic NumAccessesWithIrregularSize = {"esan" , "NumAccessesWithIrregularSize", "Number of accesses with a size outside our targeted callout sizes" , {0}, {false}} | |||
81 | "Number of accesses with a size outside our targeted callout sizes")static llvm::Statistic NumAccessesWithIrregularSize = {"esan" , "NumAccessesWithIrregularSize", "Number of accesses with a size outside our targeted callout sizes" , {0}, {false}}; | |||
82 | STATISTIC(NumIgnoredStructs, "Number of ignored structs")static llvm::Statistic NumIgnoredStructs = {"esan", "NumIgnoredStructs" , "Number of ignored structs", {0}, {false}}; | |||
83 | STATISTIC(NumIgnoredGEPs, "Number of ignored GEP instructions")static llvm::Statistic NumIgnoredGEPs = {"esan", "NumIgnoredGEPs" , "Number of ignored GEP instructions", {0}, {false}}; | |||
84 | STATISTIC(NumInstrumentedGEPs, "Number of instrumented GEP instructions")static llvm::Statistic NumInstrumentedGEPs = {"esan", "NumInstrumentedGEPs" , "Number of instrumented GEP instructions", {0}, {false}}; | |||
85 | STATISTIC(NumAssumedIntraCacheLine,static llvm::Statistic NumAssumedIntraCacheLine = {"esan", "NumAssumedIntraCacheLine" , "Number of accesses assumed to be intra-cache-line", {0}, { false}} | |||
86 | "Number of accesses assumed to be intra-cache-line")static llvm::Statistic NumAssumedIntraCacheLine = {"esan", "NumAssumedIntraCacheLine" , "Number of accesses assumed to be intra-cache-line", {0}, { false}}; | |||
87 | ||||
88 | static const uint64_t EsanCtorAndDtorPriority = 0; | |||
89 | static const char *const EsanModuleCtorName = "esan.module_ctor"; | |||
90 | static const char *const EsanModuleDtorName = "esan.module_dtor"; | |||
91 | static const char *const EsanInitName = "__esan_init"; | |||
92 | static const char *const EsanExitName = "__esan_exit"; | |||
93 | ||||
94 | // We need to specify the tool to the runtime earlier than | |||
95 | // the ctor is called in some cases, so we set a global variable. | |||
96 | static const char *const EsanWhichToolName = "__esan_which_tool"; | |||
97 | ||||
98 | // We must keep these Shadow* constants consistent with the esan runtime. | |||
99 | // FIXME: Try to place these shadow constants, the names of the __esan_* | |||
100 | // interface functions, and the ToolType enum into a header shared between | |||
101 | // llvm and compiler-rt. | |||
102 | struct ShadowMemoryParams { | |||
103 | uint64_t ShadowMask; | |||
104 | uint64_t ShadowOffs[3]; | |||
105 | }; | |||
106 | ||||
107 | static const ShadowMemoryParams ShadowParams47 = { | |||
108 | 0x00000fffffffffffull, | |||
109 | { | |||
110 | 0x0000130000000000ull, 0x0000220000000000ull, 0x0000440000000000ull, | |||
111 | }}; | |||
112 | ||||
113 | static const ShadowMemoryParams ShadowParams40 = { | |||
114 | 0x0fffffffffull, | |||
115 | { | |||
116 | 0x1300000000ull, 0x2200000000ull, 0x4400000000ull, | |||
117 | }}; | |||
118 | ||||
119 | // This array is indexed by the ToolType enum. | |||
120 | static const int ShadowScale[] = { | |||
121 | 0, // ESAN_None. | |||
122 | 2, // ESAN_CacheFrag: 4B:1B, so 4 to 1 == >>2. | |||
123 | 6, // ESAN_WorkingSet: 64B:1B, so 64 to 1 == >>6. | |||
124 | }; | |||
125 | ||||
126 | // MaxStructCounterNameSize is a soft size limit to avoid insanely long | |||
127 | // names for those extremely large structs. | |||
128 | static const unsigned MaxStructCounterNameSize = 512; | |||
129 | ||||
130 | namespace { | |||
131 | ||||
132 | static EfficiencySanitizerOptions | |||
133 | OverrideOptionsFromCL(EfficiencySanitizerOptions Options) { | |||
134 | if (ClToolCacheFrag) | |||
135 | Options.ToolType = EfficiencySanitizerOptions::ESAN_CacheFrag; | |||
136 | else if (ClToolWorkingSet) | |||
137 | Options.ToolType = EfficiencySanitizerOptions::ESAN_WorkingSet; | |||
138 | ||||
139 | // Direct opt invocation with no params will have the default ESAN_None. | |||
140 | // We run the default tool in that case. | |||
141 | if (Options.ToolType == EfficiencySanitizerOptions::ESAN_None) | |||
142 | Options.ToolType = EfficiencySanitizerOptions::ESAN_CacheFrag; | |||
143 | ||||
144 | return Options; | |||
145 | } | |||
146 | ||||
147 | /// EfficiencySanitizer: instrument each module to find performance issues. | |||
148 | class EfficiencySanitizer : public ModulePass { | |||
149 | public: | |||
150 | EfficiencySanitizer( | |||
151 | const EfficiencySanitizerOptions &Opts = EfficiencySanitizerOptions()) | |||
152 | : ModulePass(ID), Options(OverrideOptionsFromCL(Opts)) {} | |||
153 | StringRef getPassName() const override; | |||
154 | void getAnalysisUsage(AnalysisUsage &AU) const override; | |||
155 | bool runOnModule(Module &M) override; | |||
156 | static char ID; | |||
157 | ||||
158 | private: | |||
159 | bool initOnModule(Module &M); | |||
160 | void initializeCallbacks(Module &M); | |||
161 | bool shouldIgnoreStructType(StructType *StructTy); | |||
162 | void createStructCounterName( | |||
163 | StructType *StructTy, SmallString<MaxStructCounterNameSize> &NameStr); | |||
164 | void createCacheFragAuxGV( | |||
165 | Module &M, const DataLayout &DL, StructType *StructTy, | |||
166 | GlobalVariable *&TypeNames, GlobalVariable *&Offsets, GlobalVariable *&Size); | |||
167 | GlobalVariable *createCacheFragInfoGV(Module &M, const DataLayout &DL, | |||
168 | Constant *UnitName); | |||
169 | Constant *createEsanInitToolInfoArg(Module &M, const DataLayout &DL); | |||
170 | void createDestructor(Module &M, Constant *ToolInfoArg); | |||
171 | bool runOnFunction(Function &F, Module &M); | |||
172 | bool instrumentLoadOrStore(Instruction *I, const DataLayout &DL); | |||
173 | bool instrumentMemIntrinsic(MemIntrinsic *MI); | |||
174 | bool instrumentGetElementPtr(Instruction *I, Module &M); | |||
175 | bool insertCounterUpdate(Instruction *I, StructType *StructTy, | |||
176 | unsigned CounterIdx); | |||
177 | unsigned getFieldCounterIdx(StructType *StructTy) { | |||
178 | return 0; | |||
179 | } | |||
180 | unsigned getArrayCounterIdx(StructType *StructTy) { | |||
181 | return StructTy->getNumElements(); | |||
182 | } | |||
183 | unsigned getStructCounterSize(StructType *StructTy) { | |||
184 | // The struct counter array includes: | |||
185 | // - one counter for each struct field, | |||
186 | // - one counter for the struct access within an array. | |||
187 | return (StructTy->getNumElements()/*field*/ + 1/*array*/); | |||
| ||||
188 | } | |||
189 | bool shouldIgnoreMemoryAccess(Instruction *I); | |||
190 | int getMemoryAccessFuncIndex(Value *Addr, const DataLayout &DL); | |||
191 | Value *appToShadow(Value *Shadow, IRBuilder<> &IRB); | |||
192 | bool instrumentFastpath(Instruction *I, const DataLayout &DL, bool IsStore, | |||
193 | Value *Addr, unsigned Alignment); | |||
194 | // Each tool has its own fastpath routine: | |||
195 | bool instrumentFastpathCacheFrag(Instruction *I, const DataLayout &DL, | |||
196 | Value *Addr, unsigned Alignment); | |||
197 | bool instrumentFastpathWorkingSet(Instruction *I, const DataLayout &DL, | |||
198 | Value *Addr, unsigned Alignment); | |||
199 | ||||
200 | EfficiencySanitizerOptions Options; | |||
201 | LLVMContext *Ctx; | |||
202 | Type *IntptrTy; | |||
203 | // Our slowpath involves callouts to the runtime library. | |||
204 | // Access sizes are powers of two: 1, 2, 4, 8, 16. | |||
205 | static const size_t NumberOfAccessSizes = 5; | |||
206 | Function *EsanAlignedLoad[NumberOfAccessSizes]; | |||
207 | Function *EsanAlignedStore[NumberOfAccessSizes]; | |||
208 | Function *EsanUnalignedLoad[NumberOfAccessSizes]; | |||
209 | Function *EsanUnalignedStore[NumberOfAccessSizes]; | |||
210 | // For irregular sizes of any alignment: | |||
211 | Function *EsanUnalignedLoadN, *EsanUnalignedStoreN; | |||
212 | Function *MemmoveFn, *MemcpyFn, *MemsetFn; | |||
213 | Function *EsanCtorFunction; | |||
214 | Function *EsanDtorFunction; | |||
215 | // Remember the counter variable for each struct type to avoid | |||
216 | // recomputing the variable name later during instrumentation. | |||
217 | std::map<Type *, GlobalVariable *> StructTyMap; | |||
218 | ShadowMemoryParams ShadowParams; | |||
219 | }; | |||
220 | } // namespace | |||
221 | ||||
222 | char EfficiencySanitizer::ID = 0; | |||
223 | INITIALIZE_PASS_BEGIN(static void *initializeEfficiencySanitizerPassOnce(PassRegistry &Registry) { | |||
224 | EfficiencySanitizer, "esan",static void *initializeEfficiencySanitizerPassOnce(PassRegistry &Registry) { | |||
225 | "EfficiencySanitizer: finds performance issues.", false, false)static void *initializeEfficiencySanitizerPassOnce(PassRegistry &Registry) { | |||
226 | INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)initializeTargetLibraryInfoWrapperPassPass(Registry); | |||
227 | INITIALIZE_PASS_END(PassInfo *PI = new PassInfo( "EfficiencySanitizer: finds performance issues." , "esan", &EfficiencySanitizer::ID, PassInfo::NormalCtor_t (callDefaultCtor<EfficiencySanitizer>), false, false); Registry .registerPass(*PI, true); return PI; } static llvm::once_flag InitializeEfficiencySanitizerPassFlag; void llvm::initializeEfficiencySanitizerPass (PassRegistry &Registry) { llvm::call_once(InitializeEfficiencySanitizerPassFlag , initializeEfficiencySanitizerPassOnce, std::ref(Registry)); } | |||
228 | EfficiencySanitizer, "esan",PassInfo *PI = new PassInfo( "EfficiencySanitizer: finds performance issues." , "esan", &EfficiencySanitizer::ID, PassInfo::NormalCtor_t (callDefaultCtor<EfficiencySanitizer>), false, false); Registry .registerPass(*PI, true); return PI; } static llvm::once_flag InitializeEfficiencySanitizerPassFlag; void llvm::initializeEfficiencySanitizerPass (PassRegistry &Registry) { llvm::call_once(InitializeEfficiencySanitizerPassFlag , initializeEfficiencySanitizerPassOnce, std::ref(Registry)); } | |||
229 | "EfficiencySanitizer: finds performance issues.", false, false)PassInfo *PI = new PassInfo( "EfficiencySanitizer: finds performance issues." , "esan", &EfficiencySanitizer::ID, PassInfo::NormalCtor_t (callDefaultCtor<EfficiencySanitizer>), false, false); Registry .registerPass(*PI, true); return PI; } static llvm::once_flag InitializeEfficiencySanitizerPassFlag; void llvm::initializeEfficiencySanitizerPass (PassRegistry &Registry) { llvm::call_once(InitializeEfficiencySanitizerPassFlag , initializeEfficiencySanitizerPassOnce, std::ref(Registry)); } | |||
230 | ||||
231 | StringRef EfficiencySanitizer::getPassName() const { | |||
232 | return "EfficiencySanitizer"; | |||
233 | } | |||
234 | ||||
235 | void EfficiencySanitizer::getAnalysisUsage(AnalysisUsage &AU) const { | |||
236 | AU.addRequired<TargetLibraryInfoWrapperPass>(); | |||
237 | } | |||
238 | ||||
239 | ModulePass * | |||
240 | llvm::createEfficiencySanitizerPass(const EfficiencySanitizerOptions &Options) { | |||
241 | return new EfficiencySanitizer(Options); | |||
242 | } | |||
243 | ||||
244 | void EfficiencySanitizer::initializeCallbacks(Module &M) { | |||
245 | IRBuilder<> IRB(M.getContext()); | |||
246 | // Initialize the callbacks. | |||
247 | for (size_t Idx = 0; Idx < NumberOfAccessSizes; ++Idx) { | |||
248 | const unsigned ByteSize = 1U << Idx; | |||
249 | std::string ByteSizeStr = utostr(ByteSize); | |||
250 | // We'll inline the most common (i.e., aligned and frequent sizes) | |||
251 | // load + store instrumentation: these callouts are for the slowpath. | |||
252 | SmallString<32> AlignedLoadName("__esan_aligned_load" + ByteSizeStr); | |||
253 | EsanAlignedLoad[Idx] = | |||
254 | checkSanitizerInterfaceFunction(M.getOrInsertFunction( | |||
255 | AlignedLoadName, IRB.getVoidTy(), IRB.getInt8PtrTy())); | |||
256 | SmallString<32> AlignedStoreName("__esan_aligned_store" + ByteSizeStr); | |||
257 | EsanAlignedStore[Idx] = | |||
258 | checkSanitizerInterfaceFunction(M.getOrInsertFunction( | |||
259 | AlignedStoreName, IRB.getVoidTy(), IRB.getInt8PtrTy())); | |||
260 | SmallString<32> UnalignedLoadName("__esan_unaligned_load" + ByteSizeStr); | |||
261 | EsanUnalignedLoad[Idx] = | |||
262 | checkSanitizerInterfaceFunction(M.getOrInsertFunction( | |||
263 | UnalignedLoadName, IRB.getVoidTy(), IRB.getInt8PtrTy())); | |||
264 | SmallString<32> UnalignedStoreName("__esan_unaligned_store" + ByteSizeStr); | |||
265 | EsanUnalignedStore[Idx] = | |||
266 | checkSanitizerInterfaceFunction(M.getOrInsertFunction( | |||
267 | UnalignedStoreName, IRB.getVoidTy(), IRB.getInt8PtrTy())); | |||
268 | } | |||
269 | EsanUnalignedLoadN = checkSanitizerInterfaceFunction( | |||
270 | M.getOrInsertFunction("__esan_unaligned_loadN", IRB.getVoidTy(), | |||
271 | IRB.getInt8PtrTy(), IntptrTy)); | |||
272 | EsanUnalignedStoreN = checkSanitizerInterfaceFunction( | |||
273 | M.getOrInsertFunction("__esan_unaligned_storeN", IRB.getVoidTy(), | |||
274 | IRB.getInt8PtrTy(), IntptrTy)); | |||
275 | MemmoveFn = checkSanitizerInterfaceFunction( | |||
276 | M.getOrInsertFunction("memmove", IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), | |||
277 | IRB.getInt8PtrTy(), IntptrTy)); | |||
278 | MemcpyFn = checkSanitizerInterfaceFunction( | |||
279 | M.getOrInsertFunction("memcpy", IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), | |||
280 | IRB.getInt8PtrTy(), IntptrTy)); | |||
281 | MemsetFn = checkSanitizerInterfaceFunction( | |||
282 | M.getOrInsertFunction("memset", IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), | |||
283 | IRB.getInt32Ty(), IntptrTy)); | |||
284 | } | |||
285 | ||||
286 | bool EfficiencySanitizer::shouldIgnoreStructType(StructType *StructTy) { | |||
287 | if (StructTy == nullptr || StructTy->isOpaque() /* no struct body */) | |||
288 | return true; | |||
289 | return false; | |||
290 | } | |||
291 | ||||
292 | void EfficiencySanitizer::createStructCounterName( | |||
293 | StructType *StructTy, SmallString<MaxStructCounterNameSize> &NameStr) { | |||
294 | // Append NumFields and field type ids to avoid struct conflicts | |||
295 | // with the same name but different fields. | |||
296 | if (StructTy->hasName()) | |||
297 | NameStr += StructTy->getName(); | |||
298 | else | |||
299 | NameStr += "struct.anon"; | |||
300 | // We allow the actual size of the StructCounterName to be larger than | |||
301 | // MaxStructCounterNameSize and append $NumFields and at least one | |||
302 | // field type id. | |||
303 | // Append $NumFields. | |||
304 | NameStr += "$"; | |||
305 | Twine(StructTy->getNumElements()).toVector(NameStr); | |||
306 | // Append struct field type ids in the reverse order. | |||
307 | for (int i = StructTy->getNumElements() - 1; i >= 0; --i) { | |||
308 | NameStr += "$"; | |||
309 | Twine(StructTy->getElementType(i)->getTypeID()).toVector(NameStr); | |||
310 | if (NameStr.size() >= MaxStructCounterNameSize) | |||
311 | break; | |||
312 | } | |||
313 | if (StructTy->isLiteral()) { | |||
314 | // End with $ for literal struct. | |||
315 | NameStr += "$"; | |||
316 | } | |||
317 | } | |||
318 | ||||
319 | // Create global variables with auxiliary information (e.g., struct field size, | |||
320 | // offset, and type name) for better user report. | |||
321 | void EfficiencySanitizer::createCacheFragAuxGV( | |||
322 | Module &M, const DataLayout &DL, StructType *StructTy, | |||
323 | GlobalVariable *&TypeName, GlobalVariable *&Offset, | |||
324 | GlobalVariable *&Size) { | |||
325 | auto *Int8PtrTy = Type::getInt8PtrTy(*Ctx); | |||
326 | auto *Int32Ty = Type::getInt32Ty(*Ctx); | |||
327 | // FieldTypeName. | |||
328 | auto *TypeNameArrayTy = ArrayType::get(Int8PtrTy, StructTy->getNumElements()); | |||
329 | TypeName = new GlobalVariable(M, TypeNameArrayTy, true, | |||
330 | GlobalVariable::InternalLinkage, nullptr); | |||
331 | SmallVector<Constant *, 16> TypeNameVec; | |||
332 | // FieldOffset. | |||
333 | auto *OffsetArrayTy = ArrayType::get(Int32Ty, StructTy->getNumElements()); | |||
334 | Offset = new GlobalVariable(M, OffsetArrayTy, true, | |||
335 | GlobalVariable::InternalLinkage, nullptr); | |||
336 | SmallVector<Constant *, 16> OffsetVec; | |||
337 | // FieldSize | |||
338 | auto *SizeArrayTy = ArrayType::get(Int32Ty, StructTy->getNumElements()); | |||
339 | Size = new GlobalVariable(M, SizeArrayTy, true, | |||
340 | GlobalVariable::InternalLinkage, nullptr); | |||
341 | SmallVector<Constant *, 16> SizeVec; | |||
342 | for (unsigned i = 0; i < StructTy->getNumElements(); ++i) { | |||
343 | Type *Ty = StructTy->getElementType(i); | |||
344 | std::string Str; | |||
345 | raw_string_ostream StrOS(Str); | |||
346 | Ty->print(StrOS); | |||
347 | TypeNameVec.push_back( | |||
348 | ConstantExpr::getPointerCast( | |||
349 | createPrivateGlobalForString(M, StrOS.str(), true), | |||
350 | Int8PtrTy)); | |||
351 | OffsetVec.push_back( | |||
352 | ConstantInt::get(Int32Ty, | |||
353 | DL.getStructLayout(StructTy)->getElementOffset(i))); | |||
354 | SizeVec.push_back(ConstantInt::get(Int32Ty, | |||
355 | DL.getTypeAllocSize(Ty))); | |||
356 | } | |||
357 | TypeName->setInitializer(ConstantArray::get(TypeNameArrayTy, TypeNameVec)); | |||
358 | Offset->setInitializer(ConstantArray::get(OffsetArrayTy, OffsetVec)); | |||
359 | Size->setInitializer(ConstantArray::get(SizeArrayTy, SizeVec)); | |||
360 | } | |||
361 | ||||
362 | // Create the global variable for the cache-fragmentation tool. | |||
363 | GlobalVariable *EfficiencySanitizer::createCacheFragInfoGV( | |||
364 | Module &M, const DataLayout &DL, Constant *UnitName) { | |||
365 | assert(Options.ToolType == EfficiencySanitizerOptions::ESAN_CacheFrag)((Options.ToolType == EfficiencySanitizerOptions::ESAN_CacheFrag ) ? static_cast<void> (0) : __assert_fail ("Options.ToolType == EfficiencySanitizerOptions::ESAN_CacheFrag" , "/build/llvm-toolchain-snapshot-8~svn350071/lib/Transforms/Instrumentation/EfficiencySanitizer.cpp" , 365, __PRETTY_FUNCTION__)); | |||
366 | ||||
367 | auto *Int8PtrTy = Type::getInt8PtrTy(*Ctx); | |||
368 | auto *Int8PtrPtrTy = Int8PtrTy->getPointerTo(); | |||
369 | auto *Int32Ty = Type::getInt32Ty(*Ctx); | |||
370 | auto *Int32PtrTy = Type::getInt32PtrTy(*Ctx); | |||
371 | auto *Int64Ty = Type::getInt64Ty(*Ctx); | |||
372 | auto *Int64PtrTy = Type::getInt64PtrTy(*Ctx); | |||
373 | // This structure should be kept consistent with the StructInfo struct | |||
374 | // in the runtime library. | |||
375 | // struct StructInfo { | |||
376 | // const char *StructName; | |||
377 | // u32 Size; | |||
378 | // u32 NumFields; | |||
379 | // u32 *FieldOffset; // auxiliary struct field info. | |||
380 | // u32 *FieldSize; // auxiliary struct field info. | |||
381 | // const char **FieldTypeName; // auxiliary struct field info. | |||
382 | // u64 *FieldCounters; | |||
383 | // u64 *ArrayCounter; | |||
384 | // }; | |||
385 | auto *StructInfoTy = | |||
386 | StructType::get(Int8PtrTy, Int32Ty, Int32Ty, Int32PtrTy, Int32PtrTy, | |||
387 | Int8PtrPtrTy, Int64PtrTy, Int64PtrTy); | |||
388 | auto *StructInfoPtrTy = StructInfoTy->getPointerTo(); | |||
389 | // This structure should be kept consistent with the CacheFragInfo struct | |||
390 | // in the runtime library. | |||
391 | // struct CacheFragInfo { | |||
392 | // const char *UnitName; | |||
393 | // u32 NumStructs; | |||
394 | // StructInfo *Structs; | |||
395 | // }; | |||
396 | auto *CacheFragInfoTy = StructType::get(Int8PtrTy, Int32Ty, StructInfoPtrTy); | |||
397 | ||||
398 | std::vector<StructType *> Vec = M.getIdentifiedStructTypes(); | |||
399 | unsigned NumStructs = 0; | |||
400 | SmallVector<Constant *, 16> Initializers; | |||
401 | ||||
402 | for (auto &StructTy : Vec) { | |||
403 | if (shouldIgnoreStructType(StructTy)) { | |||
404 | ++NumIgnoredStructs; | |||
405 | continue; | |||
406 | } | |||
407 | ++NumStructs; | |||
408 | ||||
409 | // StructName. | |||
410 | SmallString<MaxStructCounterNameSize> CounterNameStr; | |||
411 | createStructCounterName(StructTy, CounterNameStr); | |||
412 | GlobalVariable *StructCounterName = createPrivateGlobalForString( | |||
413 | M, CounterNameStr, /*AllowMerging*/true); | |||
414 | ||||
415 | // Counters. | |||
416 | // We create the counter array with StructCounterName and weak linkage | |||
417 | // so that the structs with the same name and layout from different | |||
418 | // compilation units will be merged into one. | |||
419 | auto *CounterArrayTy = ArrayType::get(Int64Ty, | |||
420 | getStructCounterSize(StructTy)); | |||
421 | GlobalVariable *Counters = | |||
422 | new GlobalVariable(M, CounterArrayTy, false, | |||
423 | GlobalVariable::WeakAnyLinkage, | |||
424 | ConstantAggregateZero::get(CounterArrayTy), | |||
425 | CounterNameStr); | |||
426 | ||||
427 | // Remember the counter variable for each struct type. | |||
428 | StructTyMap.insert(std::pair<Type *, GlobalVariable *>(StructTy, Counters)); | |||
429 | ||||
430 | // We pass the field type name array, offset array, and size array to | |||
431 | // the runtime for better reporting. | |||
432 | GlobalVariable *TypeName = nullptr, *Offset = nullptr, *Size = nullptr; | |||
433 | if (ClAuxFieldInfo) | |||
434 | createCacheFragAuxGV(M, DL, StructTy, TypeName, Offset, Size); | |||
435 | ||||
436 | Constant *FieldCounterIdx[2]; | |||
437 | FieldCounterIdx[0] = ConstantInt::get(Int32Ty, 0); | |||
438 | FieldCounterIdx[1] = ConstantInt::get(Int32Ty, | |||
439 | getFieldCounterIdx(StructTy)); | |||
440 | Constant *ArrayCounterIdx[2]; | |||
441 | ArrayCounterIdx[0] = ConstantInt::get(Int32Ty, 0); | |||
442 | ArrayCounterIdx[1] = ConstantInt::get(Int32Ty, | |||
443 | getArrayCounterIdx(StructTy)); | |||
444 | Initializers.push_back(ConstantStruct::get( | |||
445 | StructInfoTy, | |||
446 | ConstantExpr::getPointerCast(StructCounterName, Int8PtrTy), | |||
447 | ConstantInt::get(Int32Ty, | |||
448 | DL.getStructLayout(StructTy)->getSizeInBytes()), | |||
449 | ConstantInt::get(Int32Ty, StructTy->getNumElements()), | |||
450 | Offset == nullptr ? ConstantPointerNull::get(Int32PtrTy) | |||
451 | : ConstantExpr::getPointerCast(Offset, Int32PtrTy), | |||
452 | Size == nullptr ? ConstantPointerNull::get(Int32PtrTy) | |||
453 | : ConstantExpr::getPointerCast(Size, Int32PtrTy), | |||
454 | TypeName == nullptr | |||
455 | ? ConstantPointerNull::get(Int8PtrPtrTy) | |||
456 | : ConstantExpr::getPointerCast(TypeName, Int8PtrPtrTy), | |||
457 | ConstantExpr::getGetElementPtr(CounterArrayTy, Counters, | |||
458 | FieldCounterIdx), | |||
459 | ConstantExpr::getGetElementPtr(CounterArrayTy, Counters, | |||
460 | ArrayCounterIdx))); | |||
461 | } | |||
462 | // Structs. | |||
463 | Constant *StructInfo; | |||
464 | if (NumStructs == 0) { | |||
465 | StructInfo = ConstantPointerNull::get(StructInfoPtrTy); | |||
466 | } else { | |||
467 | auto *StructInfoArrayTy = ArrayType::get(StructInfoTy, NumStructs); | |||
468 | StructInfo = ConstantExpr::getPointerCast( | |||
469 | new GlobalVariable(M, StructInfoArrayTy, false, | |||
470 | GlobalVariable::InternalLinkage, | |||
471 | ConstantArray::get(StructInfoArrayTy, Initializers)), | |||
472 | StructInfoPtrTy); | |||
473 | } | |||
474 | ||||
475 | auto *CacheFragInfoGV = new GlobalVariable( | |||
476 | M, CacheFragInfoTy, true, GlobalVariable::InternalLinkage, | |||
477 | ConstantStruct::get(CacheFragInfoTy, UnitName, | |||
478 | ConstantInt::get(Int32Ty, NumStructs), StructInfo)); | |||
479 | return CacheFragInfoGV; | |||
480 | } | |||
481 | ||||
482 | // Create the tool-specific argument passed to EsanInit and EsanExit. | |||
483 | Constant *EfficiencySanitizer::createEsanInitToolInfoArg(Module &M, | |||
484 | const DataLayout &DL) { | |||
485 | // This structure contains tool-specific information about each compilation | |||
486 | // unit (module) and is passed to the runtime library. | |||
487 | GlobalVariable *ToolInfoGV = nullptr; | |||
488 | ||||
489 | auto *Int8PtrTy = Type::getInt8PtrTy(*Ctx); | |||
490 | // Compilation unit name. | |||
491 | auto *UnitName = ConstantExpr::getPointerCast( | |||
492 | createPrivateGlobalForString(M, M.getModuleIdentifier(), true), | |||
493 | Int8PtrTy); | |||
494 | ||||
495 | // Create the tool-specific variable. | |||
496 | if (Options.ToolType == EfficiencySanitizerOptions::ESAN_CacheFrag) | |||
497 | ToolInfoGV = createCacheFragInfoGV(M, DL, UnitName); | |||
498 | ||||
499 | if (ToolInfoGV != nullptr) | |||
500 | return ConstantExpr::getPointerCast(ToolInfoGV, Int8PtrTy); | |||
501 | ||||
502 | // Create the null pointer if no tool-specific variable created. | |||
503 | return ConstantPointerNull::get(Int8PtrTy); | |||
504 | } | |||
505 | ||||
506 | void EfficiencySanitizer::createDestructor(Module &M, Constant *ToolInfoArg) { | |||
507 | PointerType *Int8PtrTy = Type::getInt8PtrTy(*Ctx); | |||
508 | EsanDtorFunction = Function::Create(FunctionType::get(Type::getVoidTy(*Ctx), | |||
509 | false), | |||
510 | GlobalValue::InternalLinkage, | |||
511 | EsanModuleDtorName, &M); | |||
512 | ReturnInst::Create(*Ctx, BasicBlock::Create(*Ctx, "", EsanDtorFunction)); | |||
513 | IRBuilder<> IRB_Dtor(EsanDtorFunction->getEntryBlock().getTerminator()); | |||
514 | Function *EsanExit = checkSanitizerInterfaceFunction( | |||
515 | M.getOrInsertFunction(EsanExitName, IRB_Dtor.getVoidTy(), | |||
516 | Int8PtrTy)); | |||
517 | EsanExit->setLinkage(Function::ExternalLinkage); | |||
518 | IRB_Dtor.CreateCall(EsanExit, {ToolInfoArg}); | |||
519 | appendToGlobalDtors(M, EsanDtorFunction, EsanCtorAndDtorPriority); | |||
520 | } | |||
521 | ||||
522 | bool EfficiencySanitizer::initOnModule(Module &M) { | |||
523 | ||||
524 | Triple TargetTriple(M.getTargetTriple()); | |||
525 | if (TargetTriple.isMIPS64()) | |||
526 | ShadowParams = ShadowParams40; | |||
527 | else | |||
528 | ShadowParams = ShadowParams47; | |||
529 | ||||
530 | Ctx = &M.getContext(); | |||
531 | const DataLayout &DL = M.getDataLayout(); | |||
532 | IRBuilder<> IRB(M.getContext()); | |||
533 | IntegerType *OrdTy = IRB.getInt32Ty(); | |||
534 | PointerType *Int8PtrTy = Type::getInt8PtrTy(*Ctx); | |||
535 | IntptrTy = DL.getIntPtrType(M.getContext()); | |||
536 | // Create the variable passed to EsanInit and EsanExit. | |||
537 | Constant *ToolInfoArg = createEsanInitToolInfoArg(M, DL); | |||
538 | // Constructor | |||
539 | // We specify the tool type both in the EsanWhichToolName global | |||
540 | // and as an arg to the init routine as a sanity check. | |||
541 | std::tie(EsanCtorFunction, std::ignore) = createSanitizerCtorAndInitFunctions( | |||
542 | M, EsanModuleCtorName, EsanInitName, /*InitArgTypes=*/{OrdTy, Int8PtrTy}, | |||
543 | /*InitArgs=*/{ | |||
544 | ConstantInt::get(OrdTy, static_cast<int>(Options.ToolType)), | |||
545 | ToolInfoArg}); | |||
546 | appendToGlobalCtors(M, EsanCtorFunction, EsanCtorAndDtorPriority); | |||
547 | ||||
548 | createDestructor(M, ToolInfoArg); | |||
549 | ||||
550 | new GlobalVariable(M, OrdTy, true, | |||
551 | GlobalValue::WeakAnyLinkage, | |||
552 | ConstantInt::get(OrdTy, | |||
553 | static_cast<int>(Options.ToolType)), | |||
554 | EsanWhichToolName); | |||
555 | ||||
556 | return true; | |||
557 | } | |||
558 | ||||
559 | Value *EfficiencySanitizer::appToShadow(Value *Shadow, IRBuilder<> &IRB) { | |||
560 | // Shadow = ((App & Mask) + Offs) >> Scale | |||
561 | Shadow = IRB.CreateAnd(Shadow, ConstantInt::get(IntptrTy, ShadowParams.ShadowMask)); | |||
562 | uint64_t Offs; | |||
563 | int Scale = ShadowScale[Options.ToolType]; | |||
564 | if (Scale <= 2) | |||
565 | Offs = ShadowParams.ShadowOffs[Scale]; | |||
566 | else | |||
567 | Offs = ShadowParams.ShadowOffs[0] << Scale; | |||
568 | Shadow = IRB.CreateAdd(Shadow, ConstantInt::get(IntptrTy, Offs)); | |||
569 | if (Scale > 0) | |||
570 | Shadow = IRB.CreateLShr(Shadow, Scale); | |||
571 | return Shadow; | |||
572 | } | |||
573 | ||||
574 | bool EfficiencySanitizer::shouldIgnoreMemoryAccess(Instruction *I) { | |||
575 | if (Options.ToolType == EfficiencySanitizerOptions::ESAN_CacheFrag) { | |||
576 | // We'd like to know about cache fragmentation in vtable accesses and | |||
577 | // constant data references, so we do not currently ignore anything. | |||
578 | return false; | |||
579 | } else if (Options.ToolType == EfficiencySanitizerOptions::ESAN_WorkingSet) { | |||
580 | // TODO: the instrumentation disturbs the data layout on the stack, so we | |||
581 | // may want to add an option to ignore stack references (if we can | |||
582 | // distinguish them) to reduce overhead. | |||
583 | } | |||
584 | // TODO(bruening): future tools will be returning true for some cases. | |||
585 | return false; | |||
586 | } | |||
587 | ||||
588 | bool EfficiencySanitizer::runOnModule(Module &M) { | |||
589 | bool Res = initOnModule(M); | |||
590 | initializeCallbacks(M); | |||
591 | for (auto &F : M) { | |||
592 | Res |= runOnFunction(F, M); | |||
593 | } | |||
594 | return Res; | |||
595 | } | |||
596 | ||||
597 | bool EfficiencySanitizer::runOnFunction(Function &F, Module &M) { | |||
598 | // This is required to prevent instrumenting the call to __esan_init from | |||
599 | // within the module constructor. | |||
600 | if (&F == EsanCtorFunction) | |||
| ||||
601 | return false; | |||
602 | SmallVector<Instruction *, 8> LoadsAndStores; | |||
603 | SmallVector<Instruction *, 8> MemIntrinCalls; | |||
604 | SmallVector<Instruction *, 8> GetElementPtrs; | |||
605 | bool Res = false; | |||
606 | const DataLayout &DL = M.getDataLayout(); | |||
607 | const TargetLibraryInfo *TLI = | |||
608 | &getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(); | |||
609 | ||||
610 | for (auto &BB : F) { | |||
611 | for (auto &Inst : BB) { | |||
612 | if ((isa<LoadInst>(Inst) || isa<StoreInst>(Inst) || | |||
613 | isa<AtomicRMWInst>(Inst) || isa<AtomicCmpXchgInst>(Inst)) && | |||
614 | !shouldIgnoreMemoryAccess(&Inst)) | |||
615 | LoadsAndStores.push_back(&Inst); | |||
616 | else if (isa<MemIntrinsic>(Inst)) | |||
617 | MemIntrinCalls.push_back(&Inst); | |||
618 | else if (isa<GetElementPtrInst>(Inst)) | |||
619 | GetElementPtrs.push_back(&Inst); | |||
620 | else if (CallInst *CI = dyn_cast<CallInst>(&Inst)) | |||
621 | maybeMarkSanitizerLibraryCallNoBuiltin(CI, TLI); | |||
622 | } | |||
623 | } | |||
624 | ||||
625 | if (ClInstrumentLoadsAndStores) { | |||
626 | for (auto Inst : LoadsAndStores) { | |||
627 | Res |= instrumentLoadOrStore(Inst, DL); | |||
628 | } | |||
629 | } | |||
630 | ||||
631 | if (ClInstrumentMemIntrinsics) { | |||
632 | for (auto Inst : MemIntrinCalls) { | |||
633 | Res |= instrumentMemIntrinsic(cast<MemIntrinsic>(Inst)); | |||
634 | } | |||
635 | } | |||
636 | ||||
637 | if (Options.ToolType == EfficiencySanitizerOptions::ESAN_CacheFrag) { | |||
638 | for (auto Inst : GetElementPtrs) { | |||
639 | Res |= instrumentGetElementPtr(Inst, M); | |||
640 | } | |||
641 | } | |||
642 | ||||
643 | return Res; | |||
644 | } | |||
645 | ||||
646 | bool EfficiencySanitizer::instrumentLoadOrStore(Instruction *I, | |||
647 | const DataLayout &DL) { | |||
648 | IRBuilder<> IRB(I); | |||
649 | bool IsStore; | |||
650 | Value *Addr; | |||
651 | unsigned Alignment; | |||
652 | if (LoadInst *Load = dyn_cast<LoadInst>(I)) { | |||
653 | IsStore = false; | |||
654 | Alignment = Load->getAlignment(); | |||
655 | Addr = Load->getPointerOperand(); | |||
656 | } else if (StoreInst *Store = dyn_cast<StoreInst>(I)) { | |||
657 | IsStore = true; | |||
658 | Alignment = Store->getAlignment(); | |||
659 | Addr = Store->getPointerOperand(); | |||
660 | } else if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I)) { | |||
661 | IsStore = true; | |||
662 | Alignment = 0; | |||
663 | Addr = RMW->getPointerOperand(); | |||
664 | } else if (AtomicCmpXchgInst *Xchg = dyn_cast<AtomicCmpXchgInst>(I)) { | |||
665 | IsStore = true; | |||
666 | Alignment = 0; | |||
667 | Addr = Xchg->getPointerOperand(); | |||
668 | } else | |||
669 | llvm_unreachable("Unsupported mem access type")::llvm::llvm_unreachable_internal("Unsupported mem access type" , "/build/llvm-toolchain-snapshot-8~svn350071/lib/Transforms/Instrumentation/EfficiencySanitizer.cpp" , 669); | |||
670 | ||||
671 | Type *OrigTy = cast<PointerType>(Addr->getType())->getElementType(); | |||
672 | const uint32_t TypeSizeBytes = DL.getTypeStoreSizeInBits(OrigTy) / 8; | |||
673 | Value *OnAccessFunc = nullptr; | |||
674 | ||||
675 | // Convert 0 to the default alignment. | |||
676 | if (Alignment == 0) | |||
677 | Alignment = DL.getPrefTypeAlignment(OrigTy); | |||
678 | ||||
679 | if (IsStore) | |||
680 | NumInstrumentedStores++; | |||
681 | else | |||
682 | NumInstrumentedLoads++; | |||
683 | int Idx = getMemoryAccessFuncIndex(Addr, DL); | |||
684 | if (Idx < 0) { | |||
685 | OnAccessFunc = IsStore ? EsanUnalignedStoreN : EsanUnalignedLoadN; | |||
686 | IRB.CreateCall(OnAccessFunc, | |||
687 | {IRB.CreatePointerCast(Addr, IRB.getInt8PtrTy()), | |||
688 | ConstantInt::get(IntptrTy, TypeSizeBytes)}); | |||
689 | } else { | |||
690 | if (ClInstrumentFastpath && | |||
691 | instrumentFastpath(I, DL, IsStore, Addr, Alignment)) { | |||
692 | NumFastpaths++; | |||
693 | return true; | |||
694 | } | |||
695 | if (Alignment == 0 || (Alignment % TypeSizeBytes) == 0) | |||
696 | OnAccessFunc = IsStore ? EsanAlignedStore[Idx] : EsanAlignedLoad[Idx]; | |||
697 | else | |||
698 | OnAccessFunc = IsStore ? EsanUnalignedStore[Idx] : EsanUnalignedLoad[Idx]; | |||
699 | IRB.CreateCall(OnAccessFunc, | |||
700 | IRB.CreatePointerCast(Addr, IRB.getInt8PtrTy())); | |||
701 | } | |||
702 | return true; | |||
703 | } | |||
704 | ||||
705 | // It's simplest to replace the memset/memmove/memcpy intrinsics with | |||
706 | // calls that the runtime library intercepts. | |||
707 | // Our pass is late enough that calls should not turn back into intrinsics. | |||
708 | bool EfficiencySanitizer::instrumentMemIntrinsic(MemIntrinsic *MI) { | |||
709 | IRBuilder<> IRB(MI); | |||
710 | bool Res = false; | |||
711 | if (isa<MemSetInst>(MI)) { | |||
712 | IRB.CreateCall( | |||
713 | MemsetFn, | |||
714 | {IRB.CreatePointerCast(MI->getArgOperand(0), IRB.getInt8PtrTy()), | |||
715 | IRB.CreateIntCast(MI->getArgOperand(1), IRB.getInt32Ty(), false), | |||
716 | IRB.CreateIntCast(MI->getArgOperand(2), IntptrTy, false)}); | |||
717 | MI->eraseFromParent(); | |||
718 | Res = true; | |||
719 | } else if (isa<MemTransferInst>(MI)) { | |||
720 | IRB.CreateCall( | |||
721 | isa<MemCpyInst>(MI) ? MemcpyFn : MemmoveFn, | |||
722 | {IRB.CreatePointerCast(MI->getArgOperand(0), IRB.getInt8PtrTy()), | |||
723 | IRB.CreatePointerCast(MI->getArgOperand(1), IRB.getInt8PtrTy()), | |||
724 | IRB.CreateIntCast(MI->getArgOperand(2), IntptrTy, false)}); | |||
725 | MI->eraseFromParent(); | |||
726 | Res = true; | |||
727 | } else | |||
728 | llvm_unreachable("Unsupported mem intrinsic type")::llvm::llvm_unreachable_internal("Unsupported mem intrinsic type" , "/build/llvm-toolchain-snapshot-8~svn350071/lib/Transforms/Instrumentation/EfficiencySanitizer.cpp" , 728); | |||
729 | return Res; | |||
730 | } | |||
731 | ||||
732 | bool EfficiencySanitizer::instrumentGetElementPtr(Instruction *I, Module &M) { | |||
733 | GetElementPtrInst *GepInst = dyn_cast<GetElementPtrInst>(I); | |||
734 | bool Res = false; | |||
735 | if (GepInst == nullptr || GepInst->getNumIndices() == 1) { | |||
736 | ++NumIgnoredGEPs; | |||
737 | return false; | |||
738 | } | |||
739 | Type *SourceTy = GepInst->getSourceElementType(); | |||
740 | StructType *StructTy = nullptr; | |||
741 | ConstantInt *Idx; | |||
742 | // Check if GEP calculates address from a struct array. | |||
743 | if (isa<StructType>(SourceTy)) { | |||
744 | StructTy = cast<StructType>(SourceTy); | |||
745 | Idx = dyn_cast<ConstantInt>(GepInst->getOperand(1)); | |||
746 | if ((Idx == nullptr || Idx->getSExtValue() != 0) && | |||
747 | !shouldIgnoreStructType(StructTy) && StructTyMap.count(StructTy) != 0) | |||
748 | Res |= insertCounterUpdate(I, StructTy, getArrayCounterIdx(StructTy)); | |||
749 | } | |||
750 | // Iterate all (except the first and the last) idx within each GEP instruction | |||
751 | // for possible nested struct field address calculation. | |||
752 | for (unsigned i = 1; i < GepInst->getNumIndices(); ++i) { | |||
753 | SmallVector<Value *, 8> IdxVec(GepInst->idx_begin(), | |||
754 | GepInst->idx_begin() + i); | |||
755 | Type *Ty = GetElementPtrInst::getIndexedType(SourceTy, IdxVec); | |||
756 | unsigned CounterIdx = 0; | |||
757 | if (isa<ArrayType>(Ty)) { | |||
758 | ArrayType *ArrayTy = cast<ArrayType>(Ty); | |||
759 | StructTy = dyn_cast<StructType>(ArrayTy->getElementType()); | |||
760 | if (shouldIgnoreStructType(StructTy) || StructTyMap.count(StructTy) == 0) | |||
761 | continue; | |||
762 | // The last counter for struct array access. | |||
763 | CounterIdx = getArrayCounterIdx(StructTy); | |||
764 | } else if (isa<StructType>(Ty)) { | |||
765 | StructTy = cast<StructType>(Ty); | |||
766 | if (shouldIgnoreStructType(StructTy) || StructTyMap.count(StructTy) == 0) | |||
767 | continue; | |||
768 | // Get the StructTy's subfield index. | |||
769 | Idx = cast<ConstantInt>(GepInst->getOperand(i+1)); | |||
770 | assert(Idx->getSExtValue() >= 0 &&((Idx->getSExtValue() >= 0 && Idx->getSExtValue () < StructTy->getNumElements()) ? static_cast<void> (0) : __assert_fail ("Idx->getSExtValue() >= 0 && Idx->getSExtValue() < StructTy->getNumElements()" , "/build/llvm-toolchain-snapshot-8~svn350071/lib/Transforms/Instrumentation/EfficiencySanitizer.cpp" , 771, __PRETTY_FUNCTION__)) | |||
771 | Idx->getSExtValue() < StructTy->getNumElements())((Idx->getSExtValue() >= 0 && Idx->getSExtValue () < StructTy->getNumElements()) ? static_cast<void> (0) : __assert_fail ("Idx->getSExtValue() >= 0 && Idx->getSExtValue() < StructTy->getNumElements()" , "/build/llvm-toolchain-snapshot-8~svn350071/lib/Transforms/Instrumentation/EfficiencySanitizer.cpp" , 771, __PRETTY_FUNCTION__)); | |||
772 | CounterIdx = getFieldCounterIdx(StructTy) + Idx->getSExtValue(); | |||
773 | } | |||
774 | Res |= insertCounterUpdate(I, StructTy, CounterIdx); | |||
775 | } | |||
776 | if (Res) | |||
777 | ++NumInstrumentedGEPs; | |||
778 | else | |||
779 | ++NumIgnoredGEPs; | |||
780 | return Res; | |||
781 | } | |||
782 | ||||
783 | bool EfficiencySanitizer::insertCounterUpdate(Instruction *I, | |||
784 | StructType *StructTy, | |||
785 | unsigned CounterIdx) { | |||
786 | GlobalVariable *CounterArray = StructTyMap[StructTy]; | |||
787 | if (CounterArray == nullptr) | |||
788 | return false; | |||
789 | IRBuilder<> IRB(I); | |||
790 | Constant *Indices[2]; | |||
791 | // Xref http://llvm.org/docs/LangRef.html#i-getelementptr and | |||
792 | // http://llvm.org/docs/GetElementPtr.html. | |||
793 | // The first index of the GEP instruction steps through the first operand, | |||
794 | // i.e., the array itself. | |||
795 | Indices[0] = ConstantInt::get(IRB.getInt32Ty(), 0); | |||
796 | // The second index is the index within the array. | |||
797 | Indices[1] = ConstantInt::get(IRB.getInt32Ty(), CounterIdx); | |||
798 | Constant *Counter = | |||
799 | ConstantExpr::getGetElementPtr( | |||
800 | ArrayType::get(IRB.getInt64Ty(), getStructCounterSize(StructTy)), | |||
801 | CounterArray, Indices); | |||
802 | Value *Load = IRB.CreateLoad(Counter); | |||
803 | IRB.CreateStore(IRB.CreateAdd(Load, ConstantInt::get(IRB.getInt64Ty(), 1)), | |||
804 | Counter); | |||
805 | return true; | |||
806 | } | |||
807 | ||||
808 | int EfficiencySanitizer::getMemoryAccessFuncIndex(Value *Addr, | |||
809 | const DataLayout &DL) { | |||
810 | Type *OrigPtrTy = Addr->getType(); | |||
811 | Type *OrigTy = cast<PointerType>(OrigPtrTy)->getElementType(); | |||
812 | assert(OrigTy->isSized())((OrigTy->isSized()) ? static_cast<void> (0) : __assert_fail ("OrigTy->isSized()", "/build/llvm-toolchain-snapshot-8~svn350071/lib/Transforms/Instrumentation/EfficiencySanitizer.cpp" , 812, __PRETTY_FUNCTION__)); | |||
813 | // The size is always a multiple of 8. | |||
814 | uint32_t TypeSizeBytes = DL.getTypeStoreSizeInBits(OrigTy) / 8; | |||
815 | if (TypeSizeBytes != 1 && TypeSizeBytes != 2 && TypeSizeBytes != 4 && | |||
816 | TypeSizeBytes != 8 && TypeSizeBytes != 16) { | |||
817 | // Irregular sizes do not have per-size call targets. | |||
818 | NumAccessesWithIrregularSize++; | |||
819 | return -1; | |||
820 | } | |||
821 | size_t Idx = countTrailingZeros(TypeSizeBytes); | |||
822 | assert(Idx < NumberOfAccessSizes)((Idx < NumberOfAccessSizes) ? static_cast<void> (0) : __assert_fail ("Idx < NumberOfAccessSizes", "/build/llvm-toolchain-snapshot-8~svn350071/lib/Transforms/Instrumentation/EfficiencySanitizer.cpp" , 822, __PRETTY_FUNCTION__)); | |||
823 | return Idx; | |||
824 | } | |||
825 | ||||
826 | bool EfficiencySanitizer::instrumentFastpath(Instruction *I, | |||
827 | const DataLayout &DL, bool IsStore, | |||
828 | Value *Addr, unsigned Alignment) { | |||
829 | if (Options.ToolType == EfficiencySanitizerOptions::ESAN_CacheFrag) { | |||
830 | return instrumentFastpathCacheFrag(I, DL, Addr, Alignment); | |||
831 | } else if (Options.ToolType == EfficiencySanitizerOptions::ESAN_WorkingSet) { | |||
832 | return instrumentFastpathWorkingSet(I, DL, Addr, Alignment); | |||
833 | } | |||
834 | return false; | |||
835 | } | |||
836 | ||||
837 | bool EfficiencySanitizer::instrumentFastpathCacheFrag(Instruction *I, | |||
838 | const DataLayout &DL, | |||
839 | Value *Addr, | |||
840 | unsigned Alignment) { | |||
841 | // Do nothing. | |||
842 | return true; // Return true to avoid slowpath instrumentation. | |||
843 | } | |||
844 | ||||
845 | bool EfficiencySanitizer::instrumentFastpathWorkingSet( | |||
846 | Instruction *I, const DataLayout &DL, Value *Addr, unsigned Alignment) { | |||
847 | assert(ShadowScale[Options.ToolType] == 6)((ShadowScale[Options.ToolType] == 6) ? static_cast<void> (0) : __assert_fail ("ShadowScale[Options.ToolType] == 6", "/build/llvm-toolchain-snapshot-8~svn350071/lib/Transforms/Instrumentation/EfficiencySanitizer.cpp" , 847, __PRETTY_FUNCTION__)); // The code below assumes this | |||
848 | IRBuilder<> IRB(I); | |||
849 | Type *OrigTy = cast<PointerType>(Addr->getType())->getElementType(); | |||
850 | const uint32_t TypeSize = DL.getTypeStoreSizeInBits(OrigTy); | |||
851 | // Bail to the slowpath if the access might touch multiple cache lines. | |||
852 | // An access aligned to its size is guaranteed to be intra-cache-line. | |||
853 | // getMemoryAccessFuncIndex has already ruled out a size larger than 16 | |||
854 | // and thus larger than a cache line for platforms this tool targets | |||
855 | // (and our shadow memory setup assumes 64-byte cache lines). | |||
856 | assert(TypeSize <= 128)((TypeSize <= 128) ? static_cast<void> (0) : __assert_fail ("TypeSize <= 128", "/build/llvm-toolchain-snapshot-8~svn350071/lib/Transforms/Instrumentation/EfficiencySanitizer.cpp" , 856, __PRETTY_FUNCTION__)); | |||
857 | if (!(TypeSize == 8 || | |||
858 | (Alignment % (TypeSize / 8)) == 0)) { | |||
859 | if (ClAssumeIntraCacheLine) | |||
860 | ++NumAssumedIntraCacheLine; | |||
861 | else | |||
862 | return false; | |||
863 | } | |||
864 | ||||
865 | // We inline instrumentation to set the corresponding shadow bits for | |||
866 | // each cache line touched by the application. Here we handle a single | |||
867 | // load or store where we've already ruled out the possibility that it | |||
868 | // might touch more than one cache line and thus we simply update the | |||
869 | // shadow memory for a single cache line. | |||
870 | // Our shadow memory model is fine with races when manipulating shadow values. | |||
871 | // We generate the following code: | |||
872 | // | |||
873 | // const char BitMask = 0x81; | |||
874 | // char *ShadowAddr = appToShadow(AppAddr); | |||
875 | // if ((*ShadowAddr & BitMask) != BitMask) | |||
876 | // *ShadowAddr |= Bitmask; | |||
877 | // | |||
878 | Value *AddrPtr = IRB.CreatePointerCast(Addr, IntptrTy); | |||
879 | Value *ShadowPtr = appToShadow(AddrPtr, IRB); | |||
880 | Type *ShadowTy = IntegerType::get(*Ctx, 8U); | |||
881 | Type *ShadowPtrTy = PointerType::get(ShadowTy, 0); | |||
882 | // The bottom bit is used for the current sampling period's working set. | |||
883 | // The top bit is used for the total working set. We set both on each | |||
884 | // memory access, if they are not already set. | |||
885 | Value *ValueMask = ConstantInt::get(ShadowTy, 0x81); // 10000001B | |||
886 | ||||
887 | Value *OldValue = IRB.CreateLoad(IRB.CreateIntToPtr(ShadowPtr, ShadowPtrTy)); | |||
888 | // The AND and CMP will be turned into a TEST instruction by the compiler. | |||
889 | Value *Cmp = IRB.CreateICmpNE(IRB.CreateAnd(OldValue, ValueMask), ValueMask); | |||
890 | Instruction *CmpTerm = SplitBlockAndInsertIfThen(Cmp, I, false); | |||
891 | // FIXME: do I need to call SetCurrentDebugLocation? | |||
892 | IRB.SetInsertPoint(CmpTerm); | |||
893 | // We use OR to set the shadow bits to avoid corrupting the middle 6 bits, | |||
894 | // which are used by the runtime library. | |||
895 | Value *NewVal = IRB.CreateOr(OldValue, ValueMask); | |||
896 | IRB.CreateStore(NewVal, IRB.CreateIntToPtr(ShadowPtr, ShadowPtrTy)); | |||
897 | IRB.SetInsertPoint(I); | |||
898 | ||||
899 | return true; | |||
900 | } |