blob: db438e78ded95b6db798bb2181801dc133f6fd53 [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
Derek Brueningd862c172016-04-21 21:30:22 +000021#include "llvm/ADT/SmallString.h"
22#include "llvm/ADT/SmallVector.h"
23#include "llvm/ADT/Statistic.h"
24#include "llvm/ADT/StringExtras.h"
Marcin Koscielnicki3feda222016-06-18 10:10:37 +000025#include "llvm/Analysis/TargetLibraryInfo.h"
David Blaikie31b98d22018-06-04 21:23:21 +000026#include "llvm/Transforms/Utils/Local.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"
Chandler Carruth6bda14b2017-06-06 11:49:48 +000035#include "llvm/Transforms/Instrumentation.h"
Derek Brueningd862c172016-04-21 21:30:22 +000036#include "llvm/Transforms/Utils/BasicBlockUtils.h"
37#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);
Qin Zhaoc35b2cb2016-07-07 03:20:16 +000064static 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);
Derek Brueningd862c172016-04-21 21:30:22 +000068
Derek Bruening9ef57722016-06-03 22:29:52 +000069// 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.
71static 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
Derek Brueningd862c172016-04-21 21:30:22 +000077STATISTIC(NumInstrumentedLoads, "Number of instrumented loads");
78STATISTIC(NumInstrumentedStores, "Number of instrumented stores");
79STATISTIC(NumFastpaths, "Number of instrumented fastpaths");
80STATISTIC(NumAccessesWithIrregularSize,
81 "Number of accesses with a size outside our targeted callout sizes");
Qin Zhao6d3bd682016-06-02 17:30:47 +000082STATISTIC(NumIgnoredStructs, "Number of ignored structs");
Qin Zhaoc14c2492016-06-03 02:33:04 +000083STATISTIC(NumIgnoredGEPs, "Number of ignored GEP instructions");
84STATISTIC(NumInstrumentedGEPs, "Number of instrumented GEP instructions");
Derek Bruening9ef57722016-06-03 22:29:52 +000085STATISTIC(NumAssumedIntraCacheLine,
86 "Number of accesses assumed to be intra-cache-line");
Derek Brueningd862c172016-04-21 21:30:22 +000087
Derek Bruening0b872d92016-05-24 22:48:24 +000088static const uint64_t EsanCtorAndDtorPriority = 0;
Derek Brueningd862c172016-04-21 21:30:22 +000089static const char *const EsanModuleCtorName = "esan.module_ctor";
Derek Bruening0b872d92016-05-24 22:48:24 +000090static const char *const EsanModuleDtorName = "esan.module_dtor";
Derek Brueningd862c172016-04-21 21:30:22 +000091static const char *const EsanInitName = "__esan_init";
Derek Bruening0b872d92016-05-24 22:48:24 +000092static const char *const EsanExitName = "__esan_exit";
Derek Brueningd862c172016-04-21 21:30:22 +000093
Derek Bruening4252a162016-06-03 19:40:37 +000094// 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.
96static const char *const EsanWhichToolName = "__esan_which_tool";
97
Derek Bruening5662b932016-05-25 00:17:24 +000098// 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.
Sagar Thakurf9292222016-10-06 09:52:06 +0000102struct ShadowMemoryParams {
103 uint64_t ShadowMask;
104 uint64_t ShadowOffs[3];
Benjamin Krameree042232016-10-18 19:39:23 +0000105};
Sagar Thakurf9292222016-10-06 09:52:06 +0000106
107static const ShadowMemoryParams ShadowParams47 = {
108 0x00000fffffffffffull,
109 {
110 0x0000130000000000ull, 0x0000220000000000ull, 0x0000440000000000ull,
111 }};
112
113static const ShadowMemoryParams ShadowParams40 = {
114 0x0fffffffffull,
115 {
116 0x1300000000ull, 0x2200000000ull, 0x4400000000ull,
117 }};
118
Derek Bruening5662b932016-05-25 00:17:24 +0000119// This array is indexed by the ToolType enum.
120static 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
Qin Zhao6d3bd682016-06-02 17:30:47 +0000126// MaxStructCounterNameSize is a soft size limit to avoid insanely long
127// names for those extremely large structs.
128static const unsigned MaxStructCounterNameSize = 512;
129
Derek Brueningd862c172016-04-21 21:30:22 +0000130namespace {
131
132static EfficiencySanitizerOptions
133OverrideOptionsFromCL(EfficiencySanitizerOptions Options) {
134 if (ClToolCacheFrag)
135 Options.ToolType = EfficiencySanitizerOptions::ESAN_CacheFrag;
Derek Bruening5662b932016-05-25 00:17:24 +0000136 else if (ClToolWorkingSet)
137 Options.ToolType = EfficiencySanitizerOptions::ESAN_WorkingSet;
Derek Brueningd862c172016-04-21 21:30:22 +0000138
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.
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)) {}
Mehdi Amini117296c2016-10-01 02:56:57 +0000153 StringRef 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 Zhaoc35b2cb2016-07-07 03:20:16 +0000164 void createCacheFragAuxGV(
165 Module &M, const DataLayout &DL, StructType *StructTy,
166 GlobalVariable *&TypeNames, GlobalVariable *&Offsets, GlobalVariable *&Size);
Qin Zhao0b96aa72016-06-10 02:10:06 +0000167 GlobalVariable *createCacheFragInfoGV(Module &M, const DataLayout &DL,
168 Constant *UnitName);
169 Constant *createEsanInitToolInfoArg(Module &M, const DataLayout &DL);
Qin Zhao1762eef2016-05-31 17:14:02 +0000170 void createDestructor(Module &M, Constant *ToolInfoArg);
Derek Brueningbc0a68e2016-05-20 20:00:05 +0000171 bool runOnFunction(Function &F, Module &M);
Derek Brueningd862c172016-04-21 21:30:22 +0000172 bool instrumentLoadOrStore(Instruction *I, const DataLayout &DL);
173 bool instrumentMemIntrinsic(MemIntrinsic *MI);
Qin Zhaoc14c2492016-06-03 02:33:04 +0000174 bool instrumentGetElementPtr(Instruction *I, Module &M);
Qin Zhaob463c232016-07-02 03:25:37 +0000175 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 }
Derek Brueningd862c172016-04-21 21:30:22 +0000189 bool shouldIgnoreMemoryAccess(Instruction *I);
190 int getMemoryAccessFuncIndex(Value *Addr, const DataLayout &DL);
Derek Bruening5662b932016-05-25 00:17:24 +0000191 Value *appToShadow(Value *Shadow, IRBuilder<> &IRB);
Derek Brueningd862c172016-04-21 21:30:22 +0000192 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);
Derek Bruening5662b932016-05-25 00:17:24 +0000197 bool instrumentFastpathWorkingSet(Instruction *I, const DataLayout &DL,
198 Value *Addr, unsigned Alignment);
Derek Brueningd862c172016-04-21 21:30:22 +0000199
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;
Derek Bruening0b872d92016-05-24 22:48:24 +0000214 Function *EsanDtorFunction;
Qin Zhaoc14c2492016-06-03 02:33:04 +0000215 // Remember the counter variable for each struct type to avoid
216 // recomputing the variable name later during instrumentation.
217 std::map<Type *, GlobalVariable *> StructTyMap;
Benjamin Krameree042232016-10-18 19:39:23 +0000218 ShadowMemoryParams ShadowParams;
Derek Brueningd862c172016-04-21 21:30:22 +0000219};
220} // namespace
221
222char EfficiencySanitizer::ID = 0;
Marcin Koscielnicki3feda222016-06-18 10:10:37 +0000223INITIALIZE_PASS_BEGIN(
224 EfficiencySanitizer, "esan",
225 "EfficiencySanitizer: finds performance issues.", false, false)
226INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
227INITIALIZE_PASS_END(
228 EfficiencySanitizer, "esan",
229 "EfficiencySanitizer: finds performance issues.", false, false)
Derek Brueningd862c172016-04-21 21:30:22 +0000230
Mehdi Amini117296c2016-10-01 02:56:57 +0000231StringRef EfficiencySanitizer::getPassName() const {
Derek Brueningd862c172016-04-21 21:30:22 +0000232 return "EfficiencySanitizer";
233}
234
Marcin Koscielnicki3feda222016-06-18 10:10:37 +0000235void EfficiencySanitizer::getAnalysisUsage(AnalysisUsage &AU) const {
236 AU.addRequired<TargetLibraryInfoWrapperPass>();
237}
238
Derek Brueningbc0a68e2016-05-20 20:00:05 +0000239ModulePass *
Derek Brueningd862c172016-04-21 21:30:22 +0000240llvm::createEfficiencySanitizerPass(const EfficiencySanitizerOptions &Options) {
241 return new EfficiencySanitizer(Options);
242}
243
244void 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(
Serge Guelton59a2d7b2017-04-11 15:01:18 +0000255 AlignedLoadName, IRB.getVoidTy(), IRB.getInt8PtrTy()));
Derek Brueningd862c172016-04-21 21:30:22 +0000256 SmallString<32> AlignedStoreName("__esan_aligned_store" + ByteSizeStr);
257 EsanAlignedStore[Idx] =
258 checkSanitizerInterfaceFunction(M.getOrInsertFunction(
Serge Guelton59a2d7b2017-04-11 15:01:18 +0000259 AlignedStoreName, IRB.getVoidTy(), IRB.getInt8PtrTy()));
Derek Brueningd862c172016-04-21 21:30:22 +0000260 SmallString<32> UnalignedLoadName("__esan_unaligned_load" + ByteSizeStr);
261 EsanUnalignedLoad[Idx] =
262 checkSanitizerInterfaceFunction(M.getOrInsertFunction(
Serge Guelton59a2d7b2017-04-11 15:01:18 +0000263 UnalignedLoadName, IRB.getVoidTy(), IRB.getInt8PtrTy()));
Derek Brueningd862c172016-04-21 21:30:22 +0000264 SmallString<32> UnalignedStoreName("__esan_unaligned_store" + ByteSizeStr);
265 EsanUnalignedStore[Idx] =
266 checkSanitizerInterfaceFunction(M.getOrInsertFunction(
Serge Guelton59a2d7b2017-04-11 15:01:18 +0000267 UnalignedStoreName, IRB.getVoidTy(), IRB.getInt8PtrTy()));
Derek Brueningd862c172016-04-21 21:30:22 +0000268 }
Mehdi Aminidb11fdf2017-04-06 20:23:57 +0000269 EsanUnalignedLoadN = checkSanitizerInterfaceFunction(
270 M.getOrInsertFunction("__esan_unaligned_loadN", IRB.getVoidTy(),
Serge Guelton59a2d7b2017-04-11 15:01:18 +0000271 IRB.getInt8PtrTy(), IntptrTy));
Derek Brueningd862c172016-04-21 21:30:22 +0000272 EsanUnalignedStoreN = checkSanitizerInterfaceFunction(
273 M.getOrInsertFunction("__esan_unaligned_storeN", IRB.getVoidTy(),
Serge Guelton59a2d7b2017-04-11 15:01:18 +0000274 IRB.getInt8PtrTy(), IntptrTy));
Derek Brueningd862c172016-04-21 21:30:22 +0000275 MemmoveFn = checkSanitizerInterfaceFunction(
276 M.getOrInsertFunction("memmove", IRB.getInt8PtrTy(), IRB.getInt8PtrTy(),
Serge Guelton59a2d7b2017-04-11 15:01:18 +0000277 IRB.getInt8PtrTy(), IntptrTy));
Derek Brueningd862c172016-04-21 21:30:22 +0000278 MemcpyFn = checkSanitizerInterfaceFunction(
279 M.getOrInsertFunction("memcpy", IRB.getInt8PtrTy(), IRB.getInt8PtrTy(),
Serge Guelton59a2d7b2017-04-11 15:01:18 +0000280 IRB.getInt8PtrTy(), IntptrTy));
Derek Brueningd862c172016-04-21 21:30:22 +0000281 MemsetFn = checkSanitizerInterfaceFunction(
282 M.getOrInsertFunction("memset", IRB.getInt8PtrTy(), IRB.getInt8PtrTy(),
Serge Guelton59a2d7b2017-04-11 15:01:18 +0000283 IRB.getInt32Ty(), IntptrTy));
Derek Brueningd862c172016-04-21 21:30:22 +0000284}
285
Qin Zhao6d3bd682016-06-02 17:30:47 +0000286bool EfficiencySanitizer::shouldIgnoreStructType(StructType *StructTy) {
287 if (StructTy == nullptr || StructTy->isOpaque() /* no struct body */)
288 return true;
289 return false;
290}
291
292void 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
Sagar Thakure74eb4e2016-09-22 08:33:06 +0000301 // MaxStructCounterNameSize and append $NumFields and at least one
Qin Zhao6d3bd682016-06-02 17:30:47 +0000302 // field type id.
Sagar Thakure74eb4e2016-09-22 08:33:06 +0000303 // Append $NumFields.
304 NameStr += "$";
Qin Zhao6d3bd682016-06-02 17:30:47 +0000305 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) {
Sagar Thakure74eb4e2016-09-22 08:33:06 +0000308 NameStr += "$";
Qin Zhao6d3bd682016-06-02 17:30:47 +0000309 Twine(StructTy->getElementType(i)->getTypeID()).toVector(NameStr);
310 if (NameStr.size() >= MaxStructCounterNameSize)
311 break;
312 }
313 if (StructTy->isLiteral()) {
Sagar Thakure74eb4e2016-09-22 08:33:06 +0000314 // End with $ for literal struct.
315 NameStr += "$";
Qin Zhao6d3bd682016-06-02 17:30:47 +0000316 }
317}
318
Qin Zhaoc35b2cb2016-07-07 03:20:16 +0000319// Create global variables with auxiliary information (e.g., struct field size,
320// offset, and type name) for better user report.
321void 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
Qin Zhao1762eef2016-05-31 17:14:02 +0000362// Create the global variable for the cache-fragmentation tool.
363GlobalVariable *EfficiencySanitizer::createCacheFragInfoGV(
Qin Zhao0b96aa72016-06-10 02:10:06 +0000364 Module &M, const DataLayout &DL, Constant *UnitName) {
Qin Zhao1762eef2016-05-31 17:14:02 +0000365 assert(Options.ToolType == EfficiencySanitizerOptions::ESAN_CacheFrag);
366
367 auto *Int8PtrTy = Type::getInt8PtrTy(*Ctx);
368 auto *Int8PtrPtrTy = Int8PtrTy->getPointerTo();
369 auto *Int32Ty = Type::getInt32Ty(*Ctx);
Qin Zhao0b96aa72016-06-10 02:10:06 +0000370 auto *Int32PtrTy = Type::getInt32PtrTy(*Ctx);
Qin Zhao6d3bd682016-06-02 17:30:47 +0000371 auto *Int64Ty = Type::getInt64Ty(*Ctx);
Qin Zhao1762eef2016-05-31 17:14:02 +0000372 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;
Qin Zhao0b96aa72016-06-10 02:10:06 +0000377 // u32 Size;
Qin Zhao6d3bd682016-06-02 17:30:47 +0000378 // u32 NumFields;
Qin Zhaoc35b2cb2016-07-07 03:20:16 +0000379 // u32 *FieldOffset; // auxiliary struct field info.
380 // u32 *FieldSize; // auxiliary struct field info.
381 // const char **FieldTypeName; // auxiliary struct field info.
Qin Zhaob463c232016-07-02 03:25:37 +0000382 // u64 *FieldCounters;
383 // u64 *ArrayCounter;
Qin Zhao1762eef2016-05-31 17:14:02 +0000384 // };
385 auto *StructInfoTy =
Serge Gueltone38003f2017-05-09 19:31:13 +0000386 StructType::get(Int8PtrTy, Int32Ty, Int32Ty, Int32PtrTy, Int32PtrTy,
387 Int8PtrPtrTy, Int64PtrTy, Int64PtrTy);
Qin Zhao1762eef2016-05-31 17:14:02 +0000388 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;
Qin Zhao6d3bd682016-06-02 17:30:47 +0000393 // u32 NumStructs;
Qin Zhao1762eef2016-05-31 17:14:02 +0000394 // StructInfo *Structs;
395 // };
Serge Gueltone38003f2017-05-09 19:31:13 +0000396 auto *CacheFragInfoTy = StructType::get(Int8PtrTy, Int32Ty, StructInfoPtrTy);
Qin Zhao1762eef2016-05-31 17:14:02 +0000397
398 std::vector<StructType *> Vec = M.getIdentifiedStructTypes();
Qin Zhao6d3bd682016-06-02 17:30:47 +0000399 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
Qin Zhaob463c232016-07-02 03:25:37 +0000415 // Counters.
Qin Zhao6d3bd682016-06-02 17:30:47 +0000416 // 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.
Qin Zhaob463c232016-07-02 03:25:37 +0000419 auto *CounterArrayTy = ArrayType::get(Int64Ty,
420 getStructCounterSize(StructTy));
Qin Zhao6d3bd682016-06-02 17:30:47 +0000421 GlobalVariable *Counters =
422 new GlobalVariable(M, CounterArrayTy, false,
423 GlobalVariable::WeakAnyLinkage,
424 ConstantAggregateZero::get(CounterArrayTy),
425 CounterNameStr);
426
Qin Zhaoc14c2492016-06-03 02:33:04 +0000427 // Remember the counter variable for each struct type.
428 StructTyMap.insert(std::pair<Type *, GlobalVariable *>(StructTy, Counters));
429
Qin Zhaoc35b2cb2016-07-07 03:20:16 +0000430 // 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);
Qin Zhao6d3bd682016-06-02 17:30:47 +0000435
Qin Zhaob463c232016-07-02 03:25:37 +0000436 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));
Serge Gueltone38003f2017-05-09 19:31:13 +0000444 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)));
Qin Zhao6d3bd682016-06-02 17:30:47 +0000461 }
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
Qin Zhao1762eef2016-05-31 17:14:02 +0000475 auto *CacheFragInfoGV = new GlobalVariable(
476 M, CacheFragInfoTy, true, GlobalVariable::InternalLinkage,
Serge Gueltone38003f2017-05-09 19:31:13 +0000477 ConstantStruct::get(CacheFragInfoTy, UnitName,
478 ConstantInt::get(Int32Ty, NumStructs), StructInfo));
Qin Zhao1762eef2016-05-31 17:14:02 +0000479 return CacheFragInfoGV;
Derek Bruening0b872d92016-05-24 22:48:24 +0000480}
481
Qin Zhao1762eef2016-05-31 17:14:02 +0000482// Create the tool-specific argument passed to EsanInit and EsanExit.
Qin Zhao0b96aa72016-06-10 02:10:06 +0000483Constant *EfficiencySanitizer::createEsanInitToolInfoArg(Module &M,
484 const DataLayout &DL) {
Qin Zhao1762eef2016-05-31 17:14:02 +0000485 // 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)
Qin Zhao0b96aa72016-06-10 02:10:06 +0000497 ToolInfoGV = createCacheFragInfoGV(M, DL, UnitName);
Qin Zhao1762eef2016-05-31 17:14:02 +0000498
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
506void EfficiencySanitizer::createDestructor(Module &M, Constant *ToolInfoArg) {
507 PointerType *Int8PtrTy = Type::getInt8PtrTy(*Ctx);
Derek Bruening0b872d92016-05-24 22:48:24 +0000508 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(
Mehdi Aminidb11fdf2017-04-06 20:23:57 +0000515 M.getOrInsertFunction(EsanExitName, IRB_Dtor.getVoidTy(),
Serge Guelton59a2d7b2017-04-11 15:01:18 +0000516 Int8PtrTy));
Derek Bruening0b872d92016-05-24 22:48:24 +0000517 EsanExit->setLinkage(Function::ExternalLinkage);
Qin Zhao1762eef2016-05-31 17:14:02 +0000518 IRB_Dtor.CreateCall(EsanExit, {ToolInfoArg});
Derek Bruening0b872d92016-05-24 22:48:24 +0000519 appendToGlobalDtors(M, EsanDtorFunction, EsanCtorAndDtorPriority);
520}
521
Derek Brueningbc0a68e2016-05-20 20:00:05 +0000522bool EfficiencySanitizer::initOnModule(Module &M) {
Sagar Thakurf9292222016-10-06 09:52:06 +0000523
524 Triple TargetTriple(M.getTargetTriple());
Alexander Richardson85e200e2018-06-25 16:49:20 +0000525 if (TargetTriple.isMIPS64())
Sagar Thakurf9292222016-10-06 09:52:06 +0000526 ShadowParams = ShadowParams40;
527 else
528 ShadowParams = ShadowParams47;
529
Derek Brueningd862c172016-04-21 21:30:22 +0000530 Ctx = &M.getContext();
531 const DataLayout &DL = M.getDataLayout();
532 IRBuilder<> IRB(M.getContext());
533 IntegerType *OrdTy = IRB.getInt32Ty();
Qin Zhao1762eef2016-05-31 17:14:02 +0000534 PointerType *Int8PtrTy = Type::getInt8PtrTy(*Ctx);
Derek Brueningd862c172016-04-21 21:30:22 +0000535 IntptrTy = DL.getIntPtrType(M.getContext());
Derek Bruening0b872d92016-05-24 22:48:24 +0000536 // Create the variable passed to EsanInit and EsanExit.
Qin Zhao0b96aa72016-06-10 02:10:06 +0000537 Constant *ToolInfoArg = createEsanInitToolInfoArg(M, DL);
Derek Bruening0b872d92016-05-24 22:48:24 +0000538 // Constructor
Derek Bruening4252a162016-06-03 19:40:37 +0000539 // We specify the tool type both in the EsanWhichToolName global
540 // and as an arg to the init routine as a sanity check.
Derek Brueningd862c172016-04-21 21:30:22 +0000541 std::tie(EsanCtorFunction, std::ignore) = createSanitizerCtorAndInitFunctions(
Qin Zhao1762eef2016-05-31 17:14:02 +0000542 M, EsanModuleCtorName, EsanInitName, /*InitArgTypes=*/{OrdTy, Int8PtrTy},
Derek Brueningd862c172016-04-21 21:30:22 +0000543 /*InitArgs=*/{
Derek Bruening0b872d92016-05-24 22:48:24 +0000544 ConstantInt::get(OrdTy, static_cast<int>(Options.ToolType)),
Qin Zhao1762eef2016-05-31 17:14:02 +0000545 ToolInfoArg});
Derek Bruening0b872d92016-05-24 22:48:24 +0000546 appendToGlobalCtors(M, EsanCtorFunction, EsanCtorAndDtorPriority);
Derek Brueningd862c172016-04-21 21:30:22 +0000547
Qin Zhao1762eef2016-05-31 17:14:02 +0000548 createDestructor(M, ToolInfoArg);
Derek Bruening4252a162016-06-03 19:40:37 +0000549
550 new GlobalVariable(M, OrdTy, true,
551 GlobalValue::WeakAnyLinkage,
552 ConstantInt::get(OrdTy,
553 static_cast<int>(Options.ToolType)),
554 EsanWhichToolName);
555
Derek Brueningd862c172016-04-21 21:30:22 +0000556 return true;
557}
558
Derek Bruening5662b932016-05-25 00:17:24 +0000559Value *EfficiencySanitizer::appToShadow(Value *Shadow, IRBuilder<> &IRB) {
560 // Shadow = ((App & Mask) + Offs) >> Scale
Sagar Thakurf9292222016-10-06 09:52:06 +0000561 Shadow = IRB.CreateAnd(Shadow, ConstantInt::get(IntptrTy, ShadowParams.ShadowMask));
Derek Bruening5662b932016-05-25 00:17:24 +0000562 uint64_t Offs;
563 int Scale = ShadowScale[Options.ToolType];
564 if (Scale <= 2)
Sagar Thakurf9292222016-10-06 09:52:06 +0000565 Offs = ShadowParams.ShadowOffs[Scale];
Derek Bruening5662b932016-05-25 00:17:24 +0000566 else
Sagar Thakurf9292222016-10-06 09:52:06 +0000567 Offs = ShadowParams.ShadowOffs[0] << Scale;
Derek Bruening5662b932016-05-25 00:17:24 +0000568 Shadow = IRB.CreateAdd(Shadow, ConstantInt::get(IntptrTy, Offs));
569 if (Scale > 0)
570 Shadow = IRB.CreateLShr(Shadow, Scale);
571 return Shadow;
572}
573
Derek Brueningd862c172016-04-21 21:30:22 +0000574bool 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;
Derek Bruening5662b932016-05-25 00:17:24 +0000579 } 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.
Derek Brueningd862c172016-04-21 21:30:22 +0000583 }
584 // TODO(bruening): future tools will be returning true for some cases.
585 return false;
586}
587
Derek Brueningbc0a68e2016-05-20 20:00:05 +0000588bool 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
597bool EfficiencySanitizer::runOnFunction(Function &F, Module &M) {
Derek Brueningd862c172016-04-21 21:30:22 +0000598 // This is required to prevent instrumenting the call to __esan_init from
599 // within the module constructor.
600 if (&F == EsanCtorFunction)
601 return false;
Derek Brueningd862c172016-04-21 21:30:22 +0000602 SmallVector<Instruction *, 8> LoadsAndStores;
603 SmallVector<Instruction *, 8> MemIntrinCalls;
Qin Zhaoc14c2492016-06-03 02:33:04 +0000604 SmallVector<Instruction *, 8> GetElementPtrs;
Derek Brueningd862c172016-04-21 21:30:22 +0000605 bool Res = false;
Derek Bruening0b872d92016-05-24 22:48:24 +0000606 const DataLayout &DL = M.getDataLayout();
Marcin Koscielnicki3feda222016-06-18 10:10:37 +0000607 const TargetLibraryInfo *TLI =
608 &getAnalysis<TargetLibraryInfoWrapperPass>().getTLI();
Derek Brueningd862c172016-04-21 21:30:22 +0000609
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);
Qin Zhaoc14c2492016-06-03 02:33:04 +0000618 else if (isa<GetElementPtrInst>(Inst))
619 GetElementPtrs.push_back(&Inst);
Marcin Koscielnicki3feda222016-06-18 10:10:37 +0000620 else if (CallInst *CI = dyn_cast<CallInst>(&Inst))
621 maybeMarkSanitizerLibraryCallNoBuiltin(CI, TLI);
Derek Brueningd862c172016-04-21 21:30:22 +0000622 }
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
Qin Zhaoc14c2492016-06-03 02:33:04 +0000637 if (Options.ToolType == EfficiencySanitizerOptions::ESAN_CacheFrag) {
638 for (auto Inst : GetElementPtrs) {
639 Res |= instrumentGetElementPtr(Inst, M);
640 }
641 }
642
Derek Brueningd862c172016-04-21 21:30:22 +0000643 return Res;
644}
645
646bool 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");
670
671 Type *OrigTy = cast<PointerType>(Addr->getType())->getElementType();
672 const uint32_t TypeSizeBytes = DL.getTypeStoreSizeInBits(OrigTy) / 8;
673 Value *OnAccessFunc = nullptr;
Derek Bruening5662b932016-05-25 00:17:24 +0000674
675 // Convert 0 to the default alignment.
676 if (Alignment == 0)
677 Alignment = DL.getPrefTypeAlignment(OrigTy);
678
Derek Brueningd862c172016-04-21 21:30:22 +0000679 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 {
Qin Zhaod677d882016-06-10 00:48:53 +0000690 if (ClInstrumentFastpath &&
691 instrumentFastpath(I, DL, IsStore, Addr, Alignment)) {
Derek Brueningd862c172016-04-21 21:30:22 +0000692 NumFastpaths++;
693 return true;
694 }
Derek Brueningd712a3c2016-07-06 20:13:53 +0000695 if (Alignment == 0 || (Alignment % TypeSizeBytes) == 0)
Derek Brueningd862c172016-04-21 21:30:22 +0000696 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.
708bool 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");
729 return Res;
730}
731
Qin Zhaoc14c2492016-06-03 02:33:04 +0000732bool EfficiencySanitizer::instrumentGetElementPtr(Instruction *I, Module &M) {
733 GetElementPtrInst *GepInst = dyn_cast<GetElementPtrInst>(I);
Qin Zhaobc8fbea2016-06-10 22:28:55 +0000734 bool Res = false;
735 if (GepInst == nullptr || GepInst->getNumIndices() == 1) {
Qin Zhaoc14c2492016-06-03 02:33:04 +0000736 ++NumIgnoredGEPs;
737 return false;
738 }
Qin Zhaobc8fbea2016-06-10 22:28:55 +0000739 Type *SourceTy = GepInst->getSourceElementType();
Vassil Vassilevc70a8f22017-03-17 20:58:08 +0000740 StructType *StructTy = nullptr;
Qin Zhaob463c232016-07-02 03:25:37 +0000741 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 }
Qin Zhaobc8fbea2016-06-10 22:28:55 +0000750 // 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);
Qin Zhaob463c232016-07-02 03:25:37 +0000755 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 &&
771 Idx->getSExtValue() < StructTy->getNumElements());
772 CounterIdx = getFieldCounterIdx(StructTy) + Idx->getSExtValue();
773 }
774 Res |= insertCounterUpdate(I, StructTy, CounterIdx);
Qin Zhaoc14c2492016-06-03 02:33:04 +0000775 }
Qin Zhaobc8fbea2016-06-10 22:28:55 +0000776 if (Res)
777 ++NumInstrumentedGEPs;
778 else
779 ++NumIgnoredGEPs;
780 return Res;
Qin Zhaoc14c2492016-06-03 02:33:04 +0000781}
782
Qin Zhaob463c232016-07-02 03:25:37 +0000783bool 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
Derek Brueningd862c172016-04-21 21:30:22 +0000808int EfficiencySanitizer::getMemoryAccessFuncIndex(Value *Addr,
809 const DataLayout &DL) {
810 Type *OrigPtrTy = Addr->getType();
811 Type *OrigTy = cast<PointerType>(OrigPtrTy)->getElementType();
812 assert(OrigTy->isSized());
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);
823 return Idx;
824}
825
826bool 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);
Derek Bruening5662b932016-05-25 00:17:24 +0000831 } else if (Options.ToolType == EfficiencySanitizerOptions::ESAN_WorkingSet) {
832 return instrumentFastpathWorkingSet(I, DL, Addr, Alignment);
Derek Brueningd862c172016-04-21 21:30:22 +0000833 }
834 return false;
835}
836
837bool EfficiencySanitizer::instrumentFastpathCacheFrag(Instruction *I,
838 const DataLayout &DL,
839 Value *Addr,
840 unsigned Alignment) {
Qin Zhaod677d882016-06-10 00:48:53 +0000841 // Do nothing.
842 return true; // Return true to avoid slowpath instrumentation.
Derek Brueningd862c172016-04-21 21:30:22 +0000843}
Derek Bruening5662b932016-05-25 00:17:24 +0000844
845bool EfficiencySanitizer::instrumentFastpathWorkingSet(
846 Instruction *I, const DataLayout &DL, Value *Addr, unsigned Alignment) {
847 assert(ShadowScale[Options.ToolType] == 6); // 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).
Derek Brueningd712a3c2016-07-06 20:13:53 +0000856 assert(TypeSize <= 128);
Derek Bruening5662b932016-05-25 00:17:24 +0000857 if (!(TypeSize == 8 ||
Derek Bruening9ef57722016-06-03 22:29:52 +0000858 (Alignment % (TypeSize / 8)) == 0)) {
859 if (ClAssumeIntraCacheLine)
860 ++NumAssumedIntraCacheLine;
861 else
862 return false;
863 }
Derek Bruening5662b932016-05-25 00:17:24 +0000864
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);
Chandler Carruth4a2d58e2018-10-15 09:34:05 +0000890 Instruction *CmpTerm = SplitBlockAndInsertIfThen(Cmp, I, false);
Derek Bruening5662b932016-05-25 00:17:24 +0000891 // 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}