blob: 111b0875388c5693c082f5157ed4468deecf1d47 [file] [log] [blame]
Derek Brueningd862c172016-04-21 21:30:22 +00001//===-- 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/Transforms/Instrumentation.h"
22#include "llvm/ADT/SmallString.h"
23#include "llvm/ADT/SmallVector.h"
24#include "llvm/ADT/Statistic.h"
25#include "llvm/ADT/StringExtras.h"
Marcin Koscielnicki3feda222016-06-18 10:10:37 +000026#include "llvm/Analysis/TargetLibraryInfo.h"
Derek Brueningd862c172016-04-21 21:30:22 +000027#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"
Qin Zhao6d3bd682016-06-02 17:30:47 +000034#include "llvm/Support/raw_ostream.h"
Derek Brueningd862c172016-04-21 21:30:22 +000035#include "llvm/Transforms/Utils/BasicBlockUtils.h"
Marcin Koscielnicki3feda222016-06-18 10:10:37 +000036#include "llvm/Transforms/Utils/Local.h"
Derek Brueningd862c172016-04-21 21:30:22 +000037#include "llvm/Transforms/Utils/ModuleUtils.h"
38
39using namespace llvm;
40
41#define DEBUG_TYPE "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.
45static cl::opt<bool>
46 ClToolCacheFrag("esan-cache-frag", cl::init(false),
47 cl::desc("Detect data cache fragmentation"), cl::Hidden);
Derek Bruening5662b932016-05-25 00:17:24 +000048static cl::opt<bool>
49 ClToolWorkingSet("esan-working-set", cl::init(false),
50 cl::desc("Measure the working set size"), cl::Hidden);
Derek Brueningd862c172016-04-21 21:30:22 +000051// Each new tool will get its own opt flag here.
52// These are converted to EfficiencySanitizerOptions for use
53// in the code.
54
55static cl::opt<bool> ClInstrumentLoadsAndStores(
56 "esan-instrument-loads-and-stores", cl::init(true),
57 cl::desc("Instrument loads and stores"), cl::Hidden);
58static cl::opt<bool> ClInstrumentMemIntrinsics(
59 "esan-instrument-memintrinsics", cl::init(true),
60 cl::desc("Instrument memintrinsics (memset/memcpy/memmove)"), cl::Hidden);
Qin Zhaod677d882016-06-10 00:48:53 +000061static cl::opt<bool> ClInstrumentFastpath(
62 "esan-instrument-fastpath", cl::init(true),
63 cl::desc("Instrument fastpath"), cl::Hidden);
Derek Brueningd862c172016-04-21 21:30:22 +000064
Derek Bruening9ef57722016-06-03 22:29:52 +000065// Experiments show that the performance difference can be 2x or more,
66// and accuracy loss is typically negligible, so we turn this on by default.
67static cl::opt<bool> ClAssumeIntraCacheLine(
68 "esan-assume-intra-cache-line", cl::init(true),
69 cl::desc("Assume each memory access touches just one cache line, for "
70 "better performance but with a potential loss of accuracy."),
71 cl::Hidden);
72
Derek Brueningd862c172016-04-21 21:30:22 +000073STATISTIC(NumInstrumentedLoads, "Number of instrumented loads");
74STATISTIC(NumInstrumentedStores, "Number of instrumented stores");
75STATISTIC(NumFastpaths, "Number of instrumented fastpaths");
76STATISTIC(NumAccessesWithIrregularSize,
77 "Number of accesses with a size outside our targeted callout sizes");
Qin Zhao6d3bd682016-06-02 17:30:47 +000078STATISTIC(NumIgnoredStructs, "Number of ignored structs");
Qin Zhaoc14c2492016-06-03 02:33:04 +000079STATISTIC(NumIgnoredGEPs, "Number of ignored GEP instructions");
80STATISTIC(NumInstrumentedGEPs, "Number of instrumented GEP instructions");
Derek Bruening9ef57722016-06-03 22:29:52 +000081STATISTIC(NumAssumedIntraCacheLine,
82 "Number of accesses assumed to be intra-cache-line");
Derek Brueningd862c172016-04-21 21:30:22 +000083
Derek Bruening0b872d92016-05-24 22:48:24 +000084static const uint64_t EsanCtorAndDtorPriority = 0;
Derek Brueningd862c172016-04-21 21:30:22 +000085static const char *const EsanModuleCtorName = "esan.module_ctor";
Derek Bruening0b872d92016-05-24 22:48:24 +000086static const char *const EsanModuleDtorName = "esan.module_dtor";
Derek Brueningd862c172016-04-21 21:30:22 +000087static const char *const EsanInitName = "__esan_init";
Derek Bruening0b872d92016-05-24 22:48:24 +000088static const char *const EsanExitName = "__esan_exit";
Derek Brueningd862c172016-04-21 21:30:22 +000089
Derek Bruening4252a162016-06-03 19:40:37 +000090// We need to specify the tool to the runtime earlier than
91// the ctor is called in some cases, so we set a global variable.
92static const char *const EsanWhichToolName = "__esan_which_tool";
93
Derek Bruening5662b932016-05-25 00:17:24 +000094// We must keep these Shadow* constants consistent with the esan runtime.
95// FIXME: Try to place these shadow constants, the names of the __esan_*
96// interface functions, and the ToolType enum into a header shared between
97// llvm and compiler-rt.
98static const uint64_t ShadowMask = 0x00000fffffffffffull;
99static const uint64_t ShadowOffs[3] = { // Indexed by scale
100 0x0000130000000000ull,
101 0x0000220000000000ull,
102 0x0000440000000000ull,
103};
104// This array is indexed by the ToolType enum.
105static const int ShadowScale[] = {
106 0, // ESAN_None.
107 2, // ESAN_CacheFrag: 4B:1B, so 4 to 1 == >>2.
108 6, // ESAN_WorkingSet: 64B:1B, so 64 to 1 == >>6.
109};
110
Qin Zhao6d3bd682016-06-02 17:30:47 +0000111// MaxStructCounterNameSize is a soft size limit to avoid insanely long
112// names for those extremely large structs.
113static const unsigned MaxStructCounterNameSize = 512;
114
Derek Brueningd862c172016-04-21 21:30:22 +0000115namespace {
116
117static EfficiencySanitizerOptions
118OverrideOptionsFromCL(EfficiencySanitizerOptions Options) {
119 if (ClToolCacheFrag)
120 Options.ToolType = EfficiencySanitizerOptions::ESAN_CacheFrag;
Derek Bruening5662b932016-05-25 00:17:24 +0000121 else if (ClToolWorkingSet)
122 Options.ToolType = EfficiencySanitizerOptions::ESAN_WorkingSet;
Derek Brueningd862c172016-04-21 21:30:22 +0000123
124 // Direct opt invocation with no params will have the default ESAN_None.
125 // We run the default tool in that case.
126 if (Options.ToolType == EfficiencySanitizerOptions::ESAN_None)
127 Options.ToolType = EfficiencySanitizerOptions::ESAN_CacheFrag;
128
129 return Options;
130}
131
Qin Zhao1762eef2016-05-31 17:14:02 +0000132// Create a constant for Str so that we can pass it to the run-time lib.
133static GlobalVariable *createPrivateGlobalForString(Module &M, StringRef Str,
134 bool AllowMerging) {
135 Constant *StrConst = ConstantDataArray::getString(M.getContext(), Str);
136 // We use private linkage for module-local strings. If they can be merged
137 // with another one, we set the unnamed_addr attribute.
138 GlobalVariable *GV =
139 new GlobalVariable(M, StrConst->getType(), true,
140 GlobalValue::PrivateLinkage, StrConst, "");
141 if (AllowMerging)
Peter Collingbourne96efdd62016-06-14 21:01:22 +0000142 GV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
Qin Zhao1762eef2016-05-31 17:14:02 +0000143 GV->setAlignment(1); // Strings may not be merged w/o setting align 1.
144 return GV;
145}
146
Derek Brueningd862c172016-04-21 21:30:22 +0000147/// EfficiencySanitizer: instrument each module to find performance issues.
Derek Brueningbc0a68e2016-05-20 20:00:05 +0000148class EfficiencySanitizer : public ModulePass {
Derek Brueningd862c172016-04-21 21:30:22 +0000149public:
150 EfficiencySanitizer(
151 const EfficiencySanitizerOptions &Opts = EfficiencySanitizerOptions())
Derek Brueningbc0a68e2016-05-20 20:00:05 +0000152 : ModulePass(ID), Options(OverrideOptionsFromCL(Opts)) {}
Derek Brueningd862c172016-04-21 21:30:22 +0000153 const char *getPassName() const override;
Marcin Koscielnicki3feda222016-06-18 10:10:37 +0000154 void getAnalysisUsage(AnalysisUsage &AU) const override;
Derek Brueningbc0a68e2016-05-20 20:00:05 +0000155 bool runOnModule(Module &M) override;
Derek Brueningd862c172016-04-21 21:30:22 +0000156 static char ID;
157
158private:
Derek Brueningbc0a68e2016-05-20 20:00:05 +0000159 bool initOnModule(Module &M);
Derek Brueningd862c172016-04-21 21:30:22 +0000160 void initializeCallbacks(Module &M);
Qin Zhao6d3bd682016-06-02 17:30:47 +0000161 bool shouldIgnoreStructType(StructType *StructTy);
162 void createStructCounterName(
163 StructType *StructTy, SmallString<MaxStructCounterNameSize> &NameStr);
Qin Zhao0b96aa72016-06-10 02:10:06 +0000164 GlobalVariable *createCacheFragInfoGV(Module &M, const DataLayout &DL,
165 Constant *UnitName);
166 Constant *createEsanInitToolInfoArg(Module &M, const DataLayout &DL);
Qin Zhao1762eef2016-05-31 17:14:02 +0000167 void createDestructor(Module &M, Constant *ToolInfoArg);
Derek Brueningbc0a68e2016-05-20 20:00:05 +0000168 bool runOnFunction(Function &F, Module &M);
Derek Brueningd862c172016-04-21 21:30:22 +0000169 bool instrumentLoadOrStore(Instruction *I, const DataLayout &DL);
170 bool instrumentMemIntrinsic(MemIntrinsic *MI);
Qin Zhaoc14c2492016-06-03 02:33:04 +0000171 bool instrumentGetElementPtr(Instruction *I, Module &M);
Qin Zhaob463c232016-07-02 03:25:37 +0000172 bool insertCounterUpdate(Instruction *I, StructType *StructTy,
173 unsigned CounterIdx);
174 unsigned getFieldCounterIdx(StructType *StructTy) {
175 return 0;
176 }
177 unsigned getArrayCounterIdx(StructType *StructTy) {
178 return StructTy->getNumElements();
179 }
180 unsigned getStructCounterSize(StructType *StructTy) {
181 // The struct counter array includes:
182 // - one counter for each struct field,
183 // - one counter for the struct access within an array.
184 return (StructTy->getNumElements()/*field*/ + 1/*array*/);
185 }
Derek Brueningd862c172016-04-21 21:30:22 +0000186 bool shouldIgnoreMemoryAccess(Instruction *I);
187 int getMemoryAccessFuncIndex(Value *Addr, const DataLayout &DL);
Derek Bruening5662b932016-05-25 00:17:24 +0000188 Value *appToShadow(Value *Shadow, IRBuilder<> &IRB);
Derek Brueningd862c172016-04-21 21:30:22 +0000189 bool instrumentFastpath(Instruction *I, const DataLayout &DL, bool IsStore,
190 Value *Addr, unsigned Alignment);
191 // Each tool has its own fastpath routine:
192 bool instrumentFastpathCacheFrag(Instruction *I, const DataLayout &DL,
193 Value *Addr, unsigned Alignment);
Derek Bruening5662b932016-05-25 00:17:24 +0000194 bool instrumentFastpathWorkingSet(Instruction *I, const DataLayout &DL,
195 Value *Addr, unsigned Alignment);
Derek Brueningd862c172016-04-21 21:30:22 +0000196
197 EfficiencySanitizerOptions Options;
198 LLVMContext *Ctx;
199 Type *IntptrTy;
200 // Our slowpath involves callouts to the runtime library.
201 // Access sizes are powers of two: 1, 2, 4, 8, 16.
202 static const size_t NumberOfAccessSizes = 5;
203 Function *EsanAlignedLoad[NumberOfAccessSizes];
204 Function *EsanAlignedStore[NumberOfAccessSizes];
205 Function *EsanUnalignedLoad[NumberOfAccessSizes];
206 Function *EsanUnalignedStore[NumberOfAccessSizes];
207 // For irregular sizes of any alignment:
208 Function *EsanUnalignedLoadN, *EsanUnalignedStoreN;
209 Function *MemmoveFn, *MemcpyFn, *MemsetFn;
210 Function *EsanCtorFunction;
Derek Bruening0b872d92016-05-24 22:48:24 +0000211 Function *EsanDtorFunction;
Qin Zhaoc14c2492016-06-03 02:33:04 +0000212 // Remember the counter variable for each struct type to avoid
213 // recomputing the variable name later during instrumentation.
214 std::map<Type *, GlobalVariable *> StructTyMap;
Derek Brueningd862c172016-04-21 21:30:22 +0000215};
216} // namespace
217
218char EfficiencySanitizer::ID = 0;
Marcin Koscielnicki3feda222016-06-18 10:10:37 +0000219INITIALIZE_PASS_BEGIN(
220 EfficiencySanitizer, "esan",
221 "EfficiencySanitizer: finds performance issues.", false, false)
222INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
223INITIALIZE_PASS_END(
224 EfficiencySanitizer, "esan",
225 "EfficiencySanitizer: finds performance issues.", false, false)
Derek Brueningd862c172016-04-21 21:30:22 +0000226
227const char *EfficiencySanitizer::getPassName() const {
228 return "EfficiencySanitizer";
229}
230
Marcin Koscielnicki3feda222016-06-18 10:10:37 +0000231void EfficiencySanitizer::getAnalysisUsage(AnalysisUsage &AU) const {
232 AU.addRequired<TargetLibraryInfoWrapperPass>();
233}
234
Derek Brueningbc0a68e2016-05-20 20:00:05 +0000235ModulePass *
Derek Brueningd862c172016-04-21 21:30:22 +0000236llvm::createEfficiencySanitizerPass(const EfficiencySanitizerOptions &Options) {
237 return new EfficiencySanitizer(Options);
238}
239
240void EfficiencySanitizer::initializeCallbacks(Module &M) {
241 IRBuilder<> IRB(M.getContext());
242 // Initialize the callbacks.
243 for (size_t Idx = 0; Idx < NumberOfAccessSizes; ++Idx) {
244 const unsigned ByteSize = 1U << Idx;
245 std::string ByteSizeStr = utostr(ByteSize);
246 // We'll inline the most common (i.e., aligned and frequent sizes)
247 // load + store instrumentation: these callouts are for the slowpath.
248 SmallString<32> AlignedLoadName("__esan_aligned_load" + ByteSizeStr);
249 EsanAlignedLoad[Idx] =
250 checkSanitizerInterfaceFunction(M.getOrInsertFunction(
251 AlignedLoadName, IRB.getVoidTy(), IRB.getInt8PtrTy(), nullptr));
252 SmallString<32> AlignedStoreName("__esan_aligned_store" + ByteSizeStr);
253 EsanAlignedStore[Idx] =
254 checkSanitizerInterfaceFunction(M.getOrInsertFunction(
255 AlignedStoreName, IRB.getVoidTy(), IRB.getInt8PtrTy(), nullptr));
256 SmallString<32> UnalignedLoadName("__esan_unaligned_load" + ByteSizeStr);
257 EsanUnalignedLoad[Idx] =
258 checkSanitizerInterfaceFunction(M.getOrInsertFunction(
259 UnalignedLoadName, IRB.getVoidTy(), IRB.getInt8PtrTy(), nullptr));
260 SmallString<32> UnalignedStoreName("__esan_unaligned_store" + ByteSizeStr);
261 EsanUnalignedStore[Idx] =
262 checkSanitizerInterfaceFunction(M.getOrInsertFunction(
263 UnalignedStoreName, IRB.getVoidTy(), IRB.getInt8PtrTy(), nullptr));
264 }
265 EsanUnalignedLoadN = checkSanitizerInterfaceFunction(
266 M.getOrInsertFunction("__esan_unaligned_loadN", IRB.getVoidTy(),
267 IRB.getInt8PtrTy(), IntptrTy, nullptr));
268 EsanUnalignedStoreN = checkSanitizerInterfaceFunction(
269 M.getOrInsertFunction("__esan_unaligned_storeN", IRB.getVoidTy(),
270 IRB.getInt8PtrTy(), IntptrTy, nullptr));
271 MemmoveFn = checkSanitizerInterfaceFunction(
272 M.getOrInsertFunction("memmove", IRB.getInt8PtrTy(), IRB.getInt8PtrTy(),
273 IRB.getInt8PtrTy(), IntptrTy, nullptr));
274 MemcpyFn = checkSanitizerInterfaceFunction(
275 M.getOrInsertFunction("memcpy", IRB.getInt8PtrTy(), IRB.getInt8PtrTy(),
276 IRB.getInt8PtrTy(), IntptrTy, nullptr));
277 MemsetFn = checkSanitizerInterfaceFunction(
278 M.getOrInsertFunction("memset", IRB.getInt8PtrTy(), IRB.getInt8PtrTy(),
279 IRB.getInt32Ty(), IntptrTy, nullptr));
280}
281
Qin Zhao6d3bd682016-06-02 17:30:47 +0000282bool EfficiencySanitizer::shouldIgnoreStructType(StructType *StructTy) {
283 if (StructTy == nullptr || StructTy->isOpaque() /* no struct body */)
284 return true;
285 return false;
286}
287
288void EfficiencySanitizer::createStructCounterName(
289 StructType *StructTy, SmallString<MaxStructCounterNameSize> &NameStr) {
290 // Append NumFields and field type ids to avoid struct conflicts
291 // with the same name but different fields.
292 if (StructTy->hasName())
293 NameStr += StructTy->getName();
294 else
295 NameStr += "struct.anon";
296 // We allow the actual size of the StructCounterName to be larger than
297 // MaxStructCounterNameSize and append #NumFields and at least one
298 // field type id.
299 // Append #NumFields.
300 NameStr += "#";
301 Twine(StructTy->getNumElements()).toVector(NameStr);
302 // Append struct field type ids in the reverse order.
303 for (int i = StructTy->getNumElements() - 1; i >= 0; --i) {
304 NameStr += "#";
305 Twine(StructTy->getElementType(i)->getTypeID()).toVector(NameStr);
306 if (NameStr.size() >= MaxStructCounterNameSize)
307 break;
308 }
309 if (StructTy->isLiteral()) {
310 // End with # for literal struct.
311 NameStr += "#";
312 }
313}
314
Qin Zhao1762eef2016-05-31 17:14:02 +0000315// Create the global variable for the cache-fragmentation tool.
316GlobalVariable *EfficiencySanitizer::createCacheFragInfoGV(
Qin Zhao0b96aa72016-06-10 02:10:06 +0000317 Module &M, const DataLayout &DL, Constant *UnitName) {
Qin Zhao1762eef2016-05-31 17:14:02 +0000318 assert(Options.ToolType == EfficiencySanitizerOptions::ESAN_CacheFrag);
319
320 auto *Int8PtrTy = Type::getInt8PtrTy(*Ctx);
321 auto *Int8PtrPtrTy = Int8PtrTy->getPointerTo();
322 auto *Int32Ty = Type::getInt32Ty(*Ctx);
Qin Zhao0b96aa72016-06-10 02:10:06 +0000323 auto *Int32PtrTy = Type::getInt32PtrTy(*Ctx);
Qin Zhao6d3bd682016-06-02 17:30:47 +0000324 auto *Int64Ty = Type::getInt64Ty(*Ctx);
Qin Zhao1762eef2016-05-31 17:14:02 +0000325 auto *Int64PtrTy = Type::getInt64PtrTy(*Ctx);
326 // This structure should be kept consistent with the StructInfo struct
327 // in the runtime library.
328 // struct StructInfo {
329 // const char *StructName;
Qin Zhao0b96aa72016-06-10 02:10:06 +0000330 // u32 Size;
Qin Zhao6d3bd682016-06-02 17:30:47 +0000331 // u32 NumFields;
Qin Zhao0b96aa72016-06-10 02:10:06 +0000332 // u32 *FieldOffsets;
Qin Zhaobb4496f2016-06-17 04:50:20 +0000333 // u32 *FieldSize;
Qin Zhao1762eef2016-05-31 17:14:02 +0000334 // const char **FieldTypeNames;
Qin Zhaob463c232016-07-02 03:25:37 +0000335 // u64 *FieldCounters;
336 // u64 *ArrayCounter;
Qin Zhao1762eef2016-05-31 17:14:02 +0000337 // };
338 auto *StructInfoTy =
Qin Zhaobb4496f2016-06-17 04:50:20 +0000339 StructType::get(Int8PtrTy, Int32Ty, Int32Ty, Int32PtrTy, Int32PtrTy,
Qin Zhaob463c232016-07-02 03:25:37 +0000340 Int8PtrPtrTy, Int64PtrTy, Int64PtrTy, nullptr);
Qin Zhao1762eef2016-05-31 17:14:02 +0000341 auto *StructInfoPtrTy = StructInfoTy->getPointerTo();
342 // This structure should be kept consistent with the CacheFragInfo struct
343 // in the runtime library.
344 // struct CacheFragInfo {
345 // const char *UnitName;
Qin Zhao6d3bd682016-06-02 17:30:47 +0000346 // u32 NumStructs;
Qin Zhao1762eef2016-05-31 17:14:02 +0000347 // StructInfo *Structs;
348 // };
349 auto *CacheFragInfoTy =
350 StructType::get(Int8PtrTy, Int32Ty, StructInfoPtrTy, nullptr);
351
352 std::vector<StructType *> Vec = M.getIdentifiedStructTypes();
Qin Zhao6d3bd682016-06-02 17:30:47 +0000353 unsigned NumStructs = 0;
354 SmallVector<Constant *, 16> Initializers;
355
356 for (auto &StructTy : Vec) {
357 if (shouldIgnoreStructType(StructTy)) {
358 ++NumIgnoredStructs;
359 continue;
360 }
361 ++NumStructs;
362
363 // StructName.
364 SmallString<MaxStructCounterNameSize> CounterNameStr;
365 createStructCounterName(StructTy, CounterNameStr);
366 GlobalVariable *StructCounterName = createPrivateGlobalForString(
367 M, CounterNameStr, /*AllowMerging*/true);
368
Qin Zhaob463c232016-07-02 03:25:37 +0000369 // Counters.
Qin Zhao6d3bd682016-06-02 17:30:47 +0000370 // We create the counter array with StructCounterName and weak linkage
371 // so that the structs with the same name and layout from different
372 // compilation units will be merged into one.
Qin Zhaob463c232016-07-02 03:25:37 +0000373 auto *CounterArrayTy = ArrayType::get(Int64Ty,
374 getStructCounterSize(StructTy));
Qin Zhao6d3bd682016-06-02 17:30:47 +0000375 GlobalVariable *Counters =
376 new GlobalVariable(M, CounterArrayTy, false,
377 GlobalVariable::WeakAnyLinkage,
378 ConstantAggregateZero::get(CounterArrayTy),
379 CounterNameStr);
380
Qin Zhaoc14c2492016-06-03 02:33:04 +0000381 // Remember the counter variable for each struct type.
382 StructTyMap.insert(std::pair<Type *, GlobalVariable *>(StructTy, Counters));
383
Qin Zhao0b96aa72016-06-10 02:10:06 +0000384 // We pass the field type name array and offset array to the runtime for
385 // better reporting.
Qin Zhao6d3bd682016-06-02 17:30:47 +0000386 // FieldTypeNames.
Qin Zhao6d3bd682016-06-02 17:30:47 +0000387 auto *TypeNameArrayTy = ArrayType::get(Int8PtrTy, StructTy->getNumElements());
Qin Zhao0b96aa72016-06-10 02:10:06 +0000388 GlobalVariable *TypeNames =
Qin Zhao6d3bd682016-06-02 17:30:47 +0000389 new GlobalVariable(M, TypeNameArrayTy, true,
390 GlobalVariable::InternalLinkage, nullptr);
391 SmallVector<Constant *, 16> TypeNameVec;
Qin Zhao0b96aa72016-06-10 02:10:06 +0000392 // FieldOffsets.
393 const StructLayout *SL = DL.getStructLayout(StructTy);
394 auto *OffsetArrayTy = ArrayType::get(Int32Ty, StructTy->getNumElements());
395 GlobalVariable *Offsets =
396 new GlobalVariable(M, OffsetArrayTy, true,
397 GlobalVariable::InternalLinkage, nullptr);
398 SmallVector<Constant *, 16> OffsetVec;
Qin Zhaobb4496f2016-06-17 04:50:20 +0000399 // FieldSize
400 auto *SizeArrayTy = ArrayType::get(Int32Ty, StructTy->getNumElements());
401 GlobalVariable *Size =
402 new GlobalVariable(M, SizeArrayTy, true,
403 GlobalVariable::InternalLinkage, nullptr);
404 SmallVector<Constant *, 16> SizeVec;
Qin Zhao6d3bd682016-06-02 17:30:47 +0000405 for (unsigned i = 0; i < StructTy->getNumElements(); ++i) {
406 Type *Ty = StructTy->getElementType(i);
407 std::string Str;
408 raw_string_ostream StrOS(Str);
409 Ty->print(StrOS);
410 TypeNameVec.push_back(
411 ConstantExpr::getPointerCast(
412 createPrivateGlobalForString(M, StrOS.str(), true),
413 Int8PtrTy));
Qin Zhao0b96aa72016-06-10 02:10:06 +0000414 OffsetVec.push_back(ConstantInt::get(Int32Ty, SL->getElementOffset(i)));
Qin Zhaobb4496f2016-06-17 04:50:20 +0000415 SizeVec.push_back(ConstantInt::get(Int32Ty,
416 DL.getTypeAllocSize(Ty)));
Qin Zhao6d3bd682016-06-02 17:30:47 +0000417 }
Qin Zhao0b96aa72016-06-10 02:10:06 +0000418 TypeNames->setInitializer(ConstantArray::get(TypeNameArrayTy, TypeNameVec));
419 Offsets->setInitializer(ConstantArray::get(OffsetArrayTy, OffsetVec));
Qin Zhaobb4496f2016-06-17 04:50:20 +0000420 Size->setInitializer(ConstantArray::get(SizeArrayTy, SizeVec));
Qin Zhao6d3bd682016-06-02 17:30:47 +0000421
Qin Zhaob463c232016-07-02 03:25:37 +0000422 Constant *FieldCounterIdx[2];
423 FieldCounterIdx[0] = ConstantInt::get(Int32Ty, 0);
424 FieldCounterIdx[1] = ConstantInt::get(Int32Ty,
425 getFieldCounterIdx(StructTy));
426 Constant *ArrayCounterIdx[2];
427 ArrayCounterIdx[0] = ConstantInt::get(Int32Ty, 0);
428 ArrayCounterIdx[1] = ConstantInt::get(Int32Ty,
429 getArrayCounterIdx(StructTy));
Qin Zhao6d3bd682016-06-02 17:30:47 +0000430 Initializers.push_back(
431 ConstantStruct::get(
432 StructInfoTy,
433 ConstantExpr::getPointerCast(StructCounterName, Int8PtrTy),
Qin Zhao0b96aa72016-06-10 02:10:06 +0000434 ConstantInt::get(Int32Ty, SL->getSizeInBytes()),
Qin Zhao6d3bd682016-06-02 17:30:47 +0000435 ConstantInt::get(Int32Ty, StructTy->getNumElements()),
Qin Zhao0b96aa72016-06-10 02:10:06 +0000436 ConstantExpr::getPointerCast(Offsets, Int32PtrTy),
Qin Zhaobb4496f2016-06-17 04:50:20 +0000437 ConstantExpr::getPointerCast(Size, Int32PtrTy),
Qin Zhao0b96aa72016-06-10 02:10:06 +0000438 ConstantExpr::getPointerCast(TypeNames, Int8PtrPtrTy),
Qin Zhaob463c232016-07-02 03:25:37 +0000439 ConstantExpr::getGetElementPtr(CounterArrayTy, Counters,
440 FieldCounterIdx),
441 ConstantExpr::getGetElementPtr(CounterArrayTy, Counters,
442 ArrayCounterIdx),
Qin Zhao6d3bd682016-06-02 17:30:47 +0000443 nullptr));
444 }
445 // Structs.
446 Constant *StructInfo;
447 if (NumStructs == 0) {
448 StructInfo = ConstantPointerNull::get(StructInfoPtrTy);
449 } else {
450 auto *StructInfoArrayTy = ArrayType::get(StructInfoTy, NumStructs);
451 StructInfo = ConstantExpr::getPointerCast(
452 new GlobalVariable(M, StructInfoArrayTy, false,
453 GlobalVariable::InternalLinkage,
454 ConstantArray::get(StructInfoArrayTy, Initializers)),
455 StructInfoPtrTy);
456 }
457
Qin Zhao1762eef2016-05-31 17:14:02 +0000458 auto *CacheFragInfoGV = new GlobalVariable(
459 M, CacheFragInfoTy, true, GlobalVariable::InternalLinkage,
460 ConstantStruct::get(CacheFragInfoTy,
461 UnitName,
Qin Zhao6d3bd682016-06-02 17:30:47 +0000462 ConstantInt::get(Int32Ty, NumStructs),
463 StructInfo,
Qin Zhao1762eef2016-05-31 17:14:02 +0000464 nullptr));
465 return CacheFragInfoGV;
Derek Bruening0b872d92016-05-24 22:48:24 +0000466}
467
Qin Zhao1762eef2016-05-31 17:14:02 +0000468// Create the tool-specific argument passed to EsanInit and EsanExit.
Qin Zhao0b96aa72016-06-10 02:10:06 +0000469Constant *EfficiencySanitizer::createEsanInitToolInfoArg(Module &M,
470 const DataLayout &DL) {
Qin Zhao1762eef2016-05-31 17:14:02 +0000471 // This structure contains tool-specific information about each compilation
472 // unit (module) and is passed to the runtime library.
473 GlobalVariable *ToolInfoGV = nullptr;
474
475 auto *Int8PtrTy = Type::getInt8PtrTy(*Ctx);
476 // Compilation unit name.
477 auto *UnitName = ConstantExpr::getPointerCast(
478 createPrivateGlobalForString(M, M.getModuleIdentifier(), true),
479 Int8PtrTy);
480
481 // Create the tool-specific variable.
482 if (Options.ToolType == EfficiencySanitizerOptions::ESAN_CacheFrag)
Qin Zhao0b96aa72016-06-10 02:10:06 +0000483 ToolInfoGV = createCacheFragInfoGV(M, DL, UnitName);
Qin Zhao1762eef2016-05-31 17:14:02 +0000484
485 if (ToolInfoGV != nullptr)
486 return ConstantExpr::getPointerCast(ToolInfoGV, Int8PtrTy);
487
488 // Create the null pointer if no tool-specific variable created.
489 return ConstantPointerNull::get(Int8PtrTy);
490}
491
492void EfficiencySanitizer::createDestructor(Module &M, Constant *ToolInfoArg) {
493 PointerType *Int8PtrTy = Type::getInt8PtrTy(*Ctx);
Derek Bruening0b872d92016-05-24 22:48:24 +0000494 EsanDtorFunction = Function::Create(FunctionType::get(Type::getVoidTy(*Ctx),
495 false),
496 GlobalValue::InternalLinkage,
497 EsanModuleDtorName, &M);
498 ReturnInst::Create(*Ctx, BasicBlock::Create(*Ctx, "", EsanDtorFunction));
499 IRBuilder<> IRB_Dtor(EsanDtorFunction->getEntryBlock().getTerminator());
500 Function *EsanExit = checkSanitizerInterfaceFunction(
501 M.getOrInsertFunction(EsanExitName, IRB_Dtor.getVoidTy(),
Qin Zhao1762eef2016-05-31 17:14:02 +0000502 Int8PtrTy, nullptr));
Derek Bruening0b872d92016-05-24 22:48:24 +0000503 EsanExit->setLinkage(Function::ExternalLinkage);
Qin Zhao1762eef2016-05-31 17:14:02 +0000504 IRB_Dtor.CreateCall(EsanExit, {ToolInfoArg});
Derek Bruening0b872d92016-05-24 22:48:24 +0000505 appendToGlobalDtors(M, EsanDtorFunction, EsanCtorAndDtorPriority);
506}
507
Derek Brueningbc0a68e2016-05-20 20:00:05 +0000508bool EfficiencySanitizer::initOnModule(Module &M) {
Derek Brueningd862c172016-04-21 21:30:22 +0000509 Ctx = &M.getContext();
510 const DataLayout &DL = M.getDataLayout();
511 IRBuilder<> IRB(M.getContext());
512 IntegerType *OrdTy = IRB.getInt32Ty();
Qin Zhao1762eef2016-05-31 17:14:02 +0000513 PointerType *Int8PtrTy = Type::getInt8PtrTy(*Ctx);
Derek Brueningd862c172016-04-21 21:30:22 +0000514 IntptrTy = DL.getIntPtrType(M.getContext());
Derek Bruening0b872d92016-05-24 22:48:24 +0000515 // Create the variable passed to EsanInit and EsanExit.
Qin Zhao0b96aa72016-06-10 02:10:06 +0000516 Constant *ToolInfoArg = createEsanInitToolInfoArg(M, DL);
Derek Bruening0b872d92016-05-24 22:48:24 +0000517 // Constructor
Derek Bruening4252a162016-06-03 19:40:37 +0000518 // We specify the tool type both in the EsanWhichToolName global
519 // and as an arg to the init routine as a sanity check.
Derek Brueningd862c172016-04-21 21:30:22 +0000520 std::tie(EsanCtorFunction, std::ignore) = createSanitizerCtorAndInitFunctions(
Qin Zhao1762eef2016-05-31 17:14:02 +0000521 M, EsanModuleCtorName, EsanInitName, /*InitArgTypes=*/{OrdTy, Int8PtrTy},
Derek Brueningd862c172016-04-21 21:30:22 +0000522 /*InitArgs=*/{
Derek Bruening0b872d92016-05-24 22:48:24 +0000523 ConstantInt::get(OrdTy, static_cast<int>(Options.ToolType)),
Qin Zhao1762eef2016-05-31 17:14:02 +0000524 ToolInfoArg});
Derek Bruening0b872d92016-05-24 22:48:24 +0000525 appendToGlobalCtors(M, EsanCtorFunction, EsanCtorAndDtorPriority);
Derek Brueningd862c172016-04-21 21:30:22 +0000526
Qin Zhao1762eef2016-05-31 17:14:02 +0000527 createDestructor(M, ToolInfoArg);
Derek Bruening4252a162016-06-03 19:40:37 +0000528
529 new GlobalVariable(M, OrdTy, true,
530 GlobalValue::WeakAnyLinkage,
531 ConstantInt::get(OrdTy,
532 static_cast<int>(Options.ToolType)),
533 EsanWhichToolName);
534
Derek Brueningd862c172016-04-21 21:30:22 +0000535 return true;
536}
537
Derek Bruening5662b932016-05-25 00:17:24 +0000538Value *EfficiencySanitizer::appToShadow(Value *Shadow, IRBuilder<> &IRB) {
539 // Shadow = ((App & Mask) + Offs) >> Scale
540 Shadow = IRB.CreateAnd(Shadow, ConstantInt::get(IntptrTy, ShadowMask));
541 uint64_t Offs;
542 int Scale = ShadowScale[Options.ToolType];
543 if (Scale <= 2)
544 Offs = ShadowOffs[Scale];
545 else
546 Offs = ShadowOffs[0] << Scale;
547 Shadow = IRB.CreateAdd(Shadow, ConstantInt::get(IntptrTy, Offs));
548 if (Scale > 0)
549 Shadow = IRB.CreateLShr(Shadow, Scale);
550 return Shadow;
551}
552
Derek Brueningd862c172016-04-21 21:30:22 +0000553bool EfficiencySanitizer::shouldIgnoreMemoryAccess(Instruction *I) {
554 if (Options.ToolType == EfficiencySanitizerOptions::ESAN_CacheFrag) {
555 // We'd like to know about cache fragmentation in vtable accesses and
556 // constant data references, so we do not currently ignore anything.
557 return false;
Derek Bruening5662b932016-05-25 00:17:24 +0000558 } else if (Options.ToolType == EfficiencySanitizerOptions::ESAN_WorkingSet) {
559 // TODO: the instrumentation disturbs the data layout on the stack, so we
560 // may want to add an option to ignore stack references (if we can
561 // distinguish them) to reduce overhead.
Derek Brueningd862c172016-04-21 21:30:22 +0000562 }
563 // TODO(bruening): future tools will be returning true for some cases.
564 return false;
565}
566
Derek Brueningbc0a68e2016-05-20 20:00:05 +0000567bool EfficiencySanitizer::runOnModule(Module &M) {
568 bool Res = initOnModule(M);
569 initializeCallbacks(M);
570 for (auto &F : M) {
571 Res |= runOnFunction(F, M);
572 }
573 return Res;
574}
575
576bool EfficiencySanitizer::runOnFunction(Function &F, Module &M) {
Derek Brueningd862c172016-04-21 21:30:22 +0000577 // This is required to prevent instrumenting the call to __esan_init from
578 // within the module constructor.
579 if (&F == EsanCtorFunction)
580 return false;
Derek Brueningd862c172016-04-21 21:30:22 +0000581 SmallVector<Instruction *, 8> LoadsAndStores;
582 SmallVector<Instruction *, 8> MemIntrinCalls;
Qin Zhaoc14c2492016-06-03 02:33:04 +0000583 SmallVector<Instruction *, 8> GetElementPtrs;
Derek Brueningd862c172016-04-21 21:30:22 +0000584 bool Res = false;
Derek Bruening0b872d92016-05-24 22:48:24 +0000585 const DataLayout &DL = M.getDataLayout();
Marcin Koscielnicki3feda222016-06-18 10:10:37 +0000586 const TargetLibraryInfo *TLI =
587 &getAnalysis<TargetLibraryInfoWrapperPass>().getTLI();
Derek Brueningd862c172016-04-21 21:30:22 +0000588
589 for (auto &BB : F) {
590 for (auto &Inst : BB) {
591 if ((isa<LoadInst>(Inst) || isa<StoreInst>(Inst) ||
592 isa<AtomicRMWInst>(Inst) || isa<AtomicCmpXchgInst>(Inst)) &&
593 !shouldIgnoreMemoryAccess(&Inst))
594 LoadsAndStores.push_back(&Inst);
595 else if (isa<MemIntrinsic>(Inst))
596 MemIntrinCalls.push_back(&Inst);
Qin Zhaoc14c2492016-06-03 02:33:04 +0000597 else if (isa<GetElementPtrInst>(Inst))
598 GetElementPtrs.push_back(&Inst);
Marcin Koscielnicki3feda222016-06-18 10:10:37 +0000599 else if (CallInst *CI = dyn_cast<CallInst>(&Inst))
600 maybeMarkSanitizerLibraryCallNoBuiltin(CI, TLI);
Derek Brueningd862c172016-04-21 21:30:22 +0000601 }
602 }
603
604 if (ClInstrumentLoadsAndStores) {
605 for (auto Inst : LoadsAndStores) {
606 Res |= instrumentLoadOrStore(Inst, DL);
607 }
608 }
609
610 if (ClInstrumentMemIntrinsics) {
611 for (auto Inst : MemIntrinCalls) {
612 Res |= instrumentMemIntrinsic(cast<MemIntrinsic>(Inst));
613 }
614 }
615
Qin Zhaoc14c2492016-06-03 02:33:04 +0000616 if (Options.ToolType == EfficiencySanitizerOptions::ESAN_CacheFrag) {
617 for (auto Inst : GetElementPtrs) {
618 Res |= instrumentGetElementPtr(Inst, M);
619 }
620 }
621
Derek Brueningd862c172016-04-21 21:30:22 +0000622 return Res;
623}
624
625bool EfficiencySanitizer::instrumentLoadOrStore(Instruction *I,
626 const DataLayout &DL) {
627 IRBuilder<> IRB(I);
628 bool IsStore;
629 Value *Addr;
630 unsigned Alignment;
631 if (LoadInst *Load = dyn_cast<LoadInst>(I)) {
632 IsStore = false;
633 Alignment = Load->getAlignment();
634 Addr = Load->getPointerOperand();
635 } else if (StoreInst *Store = dyn_cast<StoreInst>(I)) {
636 IsStore = true;
637 Alignment = Store->getAlignment();
638 Addr = Store->getPointerOperand();
639 } else if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I)) {
640 IsStore = true;
641 Alignment = 0;
642 Addr = RMW->getPointerOperand();
643 } else if (AtomicCmpXchgInst *Xchg = dyn_cast<AtomicCmpXchgInst>(I)) {
644 IsStore = true;
645 Alignment = 0;
646 Addr = Xchg->getPointerOperand();
647 } else
648 llvm_unreachable("Unsupported mem access type");
649
650 Type *OrigTy = cast<PointerType>(Addr->getType())->getElementType();
651 const uint32_t TypeSizeBytes = DL.getTypeStoreSizeInBits(OrigTy) / 8;
652 Value *OnAccessFunc = nullptr;
Derek Bruening5662b932016-05-25 00:17:24 +0000653
654 // Convert 0 to the default alignment.
655 if (Alignment == 0)
656 Alignment = DL.getPrefTypeAlignment(OrigTy);
657
Derek Brueningd862c172016-04-21 21:30:22 +0000658 if (IsStore)
659 NumInstrumentedStores++;
660 else
661 NumInstrumentedLoads++;
662 int Idx = getMemoryAccessFuncIndex(Addr, DL);
663 if (Idx < 0) {
664 OnAccessFunc = IsStore ? EsanUnalignedStoreN : EsanUnalignedLoadN;
665 IRB.CreateCall(OnAccessFunc,
666 {IRB.CreatePointerCast(Addr, IRB.getInt8PtrTy()),
667 ConstantInt::get(IntptrTy, TypeSizeBytes)});
668 } else {
Qin Zhaod677d882016-06-10 00:48:53 +0000669 if (ClInstrumentFastpath &&
670 instrumentFastpath(I, DL, IsStore, Addr, Alignment)) {
Derek Brueningd862c172016-04-21 21:30:22 +0000671 NumFastpaths++;
672 return true;
673 }
Derek Brueningd712a3c2016-07-06 20:13:53 +0000674 if (Alignment == 0 || (Alignment % TypeSizeBytes) == 0)
Derek Brueningd862c172016-04-21 21:30:22 +0000675 OnAccessFunc = IsStore ? EsanAlignedStore[Idx] : EsanAlignedLoad[Idx];
676 else
677 OnAccessFunc = IsStore ? EsanUnalignedStore[Idx] : EsanUnalignedLoad[Idx];
678 IRB.CreateCall(OnAccessFunc,
679 IRB.CreatePointerCast(Addr, IRB.getInt8PtrTy()));
680 }
681 return true;
682}
683
684// It's simplest to replace the memset/memmove/memcpy intrinsics with
685// calls that the runtime library intercepts.
686// Our pass is late enough that calls should not turn back into intrinsics.
687bool EfficiencySanitizer::instrumentMemIntrinsic(MemIntrinsic *MI) {
688 IRBuilder<> IRB(MI);
689 bool Res = false;
690 if (isa<MemSetInst>(MI)) {
691 IRB.CreateCall(
692 MemsetFn,
693 {IRB.CreatePointerCast(MI->getArgOperand(0), IRB.getInt8PtrTy()),
694 IRB.CreateIntCast(MI->getArgOperand(1), IRB.getInt32Ty(), false),
695 IRB.CreateIntCast(MI->getArgOperand(2), IntptrTy, false)});
696 MI->eraseFromParent();
697 Res = true;
698 } else if (isa<MemTransferInst>(MI)) {
699 IRB.CreateCall(
700 isa<MemCpyInst>(MI) ? MemcpyFn : MemmoveFn,
701 {IRB.CreatePointerCast(MI->getArgOperand(0), IRB.getInt8PtrTy()),
702 IRB.CreatePointerCast(MI->getArgOperand(1), IRB.getInt8PtrTy()),
703 IRB.CreateIntCast(MI->getArgOperand(2), IntptrTy, false)});
704 MI->eraseFromParent();
705 Res = true;
706 } else
707 llvm_unreachable("Unsupported mem intrinsic type");
708 return Res;
709}
710
Qin Zhaoc14c2492016-06-03 02:33:04 +0000711bool EfficiencySanitizer::instrumentGetElementPtr(Instruction *I, Module &M) {
712 GetElementPtrInst *GepInst = dyn_cast<GetElementPtrInst>(I);
Qin Zhaobc8fbea2016-06-10 22:28:55 +0000713 bool Res = false;
714 if (GepInst == nullptr || GepInst->getNumIndices() == 1) {
Qin Zhaoc14c2492016-06-03 02:33:04 +0000715 ++NumIgnoredGEPs;
716 return false;
717 }
Qin Zhaobc8fbea2016-06-10 22:28:55 +0000718 Type *SourceTy = GepInst->getSourceElementType();
Qin Zhaob463c232016-07-02 03:25:37 +0000719 StructType *StructTy;
720 ConstantInt *Idx;
721 // Check if GEP calculates address from a struct array.
722 if (isa<StructType>(SourceTy)) {
723 StructTy = cast<StructType>(SourceTy);
724 Idx = dyn_cast<ConstantInt>(GepInst->getOperand(1));
725 if ((Idx == nullptr || Idx->getSExtValue() != 0) &&
726 !shouldIgnoreStructType(StructTy) && StructTyMap.count(StructTy) != 0)
727 Res |= insertCounterUpdate(I, StructTy, getArrayCounterIdx(StructTy));
728 }
Qin Zhaobc8fbea2016-06-10 22:28:55 +0000729 // Iterate all (except the first and the last) idx within each GEP instruction
730 // for possible nested struct field address calculation.
731 for (unsigned i = 1; i < GepInst->getNumIndices(); ++i) {
732 SmallVector<Value *, 8> IdxVec(GepInst->idx_begin(),
733 GepInst->idx_begin() + i);
Qin Zhaob463c232016-07-02 03:25:37 +0000734 Type *Ty = GetElementPtrInst::getIndexedType(SourceTy, IdxVec);
735 unsigned CounterIdx = 0;
736 if (isa<ArrayType>(Ty)) {
737 ArrayType *ArrayTy = cast<ArrayType>(Ty);
738 StructTy = dyn_cast<StructType>(ArrayTy->getElementType());
739 if (shouldIgnoreStructType(StructTy) || StructTyMap.count(StructTy) == 0)
740 continue;
741 // The last counter for struct array access.
742 CounterIdx = getArrayCounterIdx(StructTy);
743 } else if (isa<StructType>(Ty)) {
744 StructTy = cast<StructType>(Ty);
745 if (shouldIgnoreStructType(StructTy) || StructTyMap.count(StructTy) == 0)
746 continue;
747 // Get the StructTy's subfield index.
748 Idx = cast<ConstantInt>(GepInst->getOperand(i+1));
749 assert(Idx->getSExtValue() >= 0 &&
750 Idx->getSExtValue() < StructTy->getNumElements());
751 CounterIdx = getFieldCounterIdx(StructTy) + Idx->getSExtValue();
752 }
753 Res |= insertCounterUpdate(I, StructTy, CounterIdx);
Qin Zhaoc14c2492016-06-03 02:33:04 +0000754 }
Qin Zhaobc8fbea2016-06-10 22:28:55 +0000755 if (Res)
756 ++NumInstrumentedGEPs;
757 else
758 ++NumIgnoredGEPs;
759 return Res;
Qin Zhaoc14c2492016-06-03 02:33:04 +0000760}
761
Qin Zhaob463c232016-07-02 03:25:37 +0000762bool EfficiencySanitizer::insertCounterUpdate(Instruction *I,
763 StructType *StructTy,
764 unsigned CounterIdx) {
765 GlobalVariable *CounterArray = StructTyMap[StructTy];
766 if (CounterArray == nullptr)
767 return false;
768 IRBuilder<> IRB(I);
769 Constant *Indices[2];
770 // Xref http://llvm.org/docs/LangRef.html#i-getelementptr and
771 // http://llvm.org/docs/GetElementPtr.html.
772 // The first index of the GEP instruction steps through the first operand,
773 // i.e., the array itself.
774 Indices[0] = ConstantInt::get(IRB.getInt32Ty(), 0);
775 // The second index is the index within the array.
776 Indices[1] = ConstantInt::get(IRB.getInt32Ty(), CounterIdx);
777 Constant *Counter =
778 ConstantExpr::getGetElementPtr(
779 ArrayType::get(IRB.getInt64Ty(), getStructCounterSize(StructTy)),
780 CounterArray, Indices);
781 Value *Load = IRB.CreateLoad(Counter);
782 IRB.CreateStore(IRB.CreateAdd(Load, ConstantInt::get(IRB.getInt64Ty(), 1)),
783 Counter);
784 return true;
785}
786
Derek Brueningd862c172016-04-21 21:30:22 +0000787int EfficiencySanitizer::getMemoryAccessFuncIndex(Value *Addr,
788 const DataLayout &DL) {
789 Type *OrigPtrTy = Addr->getType();
790 Type *OrigTy = cast<PointerType>(OrigPtrTy)->getElementType();
791 assert(OrigTy->isSized());
792 // The size is always a multiple of 8.
793 uint32_t TypeSizeBytes = DL.getTypeStoreSizeInBits(OrigTy) / 8;
794 if (TypeSizeBytes != 1 && TypeSizeBytes != 2 && TypeSizeBytes != 4 &&
795 TypeSizeBytes != 8 && TypeSizeBytes != 16) {
796 // Irregular sizes do not have per-size call targets.
797 NumAccessesWithIrregularSize++;
798 return -1;
799 }
800 size_t Idx = countTrailingZeros(TypeSizeBytes);
801 assert(Idx < NumberOfAccessSizes);
802 return Idx;
803}
804
805bool EfficiencySanitizer::instrumentFastpath(Instruction *I,
806 const DataLayout &DL, bool IsStore,
807 Value *Addr, unsigned Alignment) {
808 if (Options.ToolType == EfficiencySanitizerOptions::ESAN_CacheFrag) {
809 return instrumentFastpathCacheFrag(I, DL, Addr, Alignment);
Derek Bruening5662b932016-05-25 00:17:24 +0000810 } else if (Options.ToolType == EfficiencySanitizerOptions::ESAN_WorkingSet) {
811 return instrumentFastpathWorkingSet(I, DL, Addr, Alignment);
Derek Brueningd862c172016-04-21 21:30:22 +0000812 }
813 return false;
814}
815
816bool EfficiencySanitizer::instrumentFastpathCacheFrag(Instruction *I,
817 const DataLayout &DL,
818 Value *Addr,
819 unsigned Alignment) {
Qin Zhaod677d882016-06-10 00:48:53 +0000820 // Do nothing.
821 return true; // Return true to avoid slowpath instrumentation.
Derek Brueningd862c172016-04-21 21:30:22 +0000822}
Derek Bruening5662b932016-05-25 00:17:24 +0000823
824bool EfficiencySanitizer::instrumentFastpathWorkingSet(
825 Instruction *I, const DataLayout &DL, Value *Addr, unsigned Alignment) {
826 assert(ShadowScale[Options.ToolType] == 6); // The code below assumes this
827 IRBuilder<> IRB(I);
828 Type *OrigTy = cast<PointerType>(Addr->getType())->getElementType();
829 const uint32_t TypeSize = DL.getTypeStoreSizeInBits(OrigTy);
830 // Bail to the slowpath if the access might touch multiple cache lines.
831 // An access aligned to its size is guaranteed to be intra-cache-line.
832 // getMemoryAccessFuncIndex has already ruled out a size larger than 16
833 // and thus larger than a cache line for platforms this tool targets
834 // (and our shadow memory setup assumes 64-byte cache lines).
Derek Brueningd712a3c2016-07-06 20:13:53 +0000835 assert(TypeSize <= 128);
Derek Bruening5662b932016-05-25 00:17:24 +0000836 if (!(TypeSize == 8 ||
Derek Bruening9ef57722016-06-03 22:29:52 +0000837 (Alignment % (TypeSize / 8)) == 0)) {
838 if (ClAssumeIntraCacheLine)
839 ++NumAssumedIntraCacheLine;
840 else
841 return false;
842 }
Derek Bruening5662b932016-05-25 00:17:24 +0000843
844 // We inline instrumentation to set the corresponding shadow bits for
845 // each cache line touched by the application. Here we handle a single
846 // load or store where we've already ruled out the possibility that it
847 // might touch more than one cache line and thus we simply update the
848 // shadow memory for a single cache line.
849 // Our shadow memory model is fine with races when manipulating shadow values.
850 // We generate the following code:
851 //
852 // const char BitMask = 0x81;
853 // char *ShadowAddr = appToShadow(AppAddr);
854 // if ((*ShadowAddr & BitMask) != BitMask)
855 // *ShadowAddr |= Bitmask;
856 //
857 Value *AddrPtr = IRB.CreatePointerCast(Addr, IntptrTy);
858 Value *ShadowPtr = appToShadow(AddrPtr, IRB);
859 Type *ShadowTy = IntegerType::get(*Ctx, 8U);
860 Type *ShadowPtrTy = PointerType::get(ShadowTy, 0);
861 // The bottom bit is used for the current sampling period's working set.
862 // The top bit is used for the total working set. We set both on each
863 // memory access, if they are not already set.
864 Value *ValueMask = ConstantInt::get(ShadowTy, 0x81); // 10000001B
865
866 Value *OldValue = IRB.CreateLoad(IRB.CreateIntToPtr(ShadowPtr, ShadowPtrTy));
867 // The AND and CMP will be turned into a TEST instruction by the compiler.
868 Value *Cmp = IRB.CreateICmpNE(IRB.CreateAnd(OldValue, ValueMask), ValueMask);
869 TerminatorInst *CmpTerm = SplitBlockAndInsertIfThen(Cmp, I, false);
870 // FIXME: do I need to call SetCurrentDebugLocation?
871 IRB.SetInsertPoint(CmpTerm);
872 // We use OR to set the shadow bits to avoid corrupting the middle 6 bits,
873 // which are used by the runtime library.
874 Value *NewVal = IRB.CreateOr(OldValue, ValueMask);
875 IRB.CreateStore(NewVal, IRB.CreateIntToPtr(ShadowPtr, ShadowPtrTy));
876 IRB.SetInsertPoint(I);
877
878 return true;
879}