Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(35)

Delta Between Two Patch Sets: lib/Transforms/Instrumentation/ThreadSanitizer.cpp

Issue 6119045: ThreadSanitizer v2 atomic support (Closed) Base URL: http://llvm.org/svn/llvm-project/llvm/trunk/
Left Patch Set: - Created 12 years, 10 months ago
Right Patch Set: - Created 12 years, 10 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « no previous file | test/Instrumentation/ThreadSanitizer/atomic.ll » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 //===-- ThreadSanitizer.cpp - race detector -------------------------------===// 1 //===-- ThreadSanitizer.cpp - race detector -------------------------------===//
2 // 2 //
3 // The LLVM Compiler Infrastructure 3 // The LLVM Compiler Infrastructure
4 // 4 //
5 // This file is distributed under the University of Illinois Open Source 5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details. 6 // License. See LICENSE.TXT for details.
7 // 7 //
8 //===----------------------------------------------------------------------===// 8 //===----------------------------------------------------------------------===//
9 // 9 //
10 // This file is a part of ThreadSanitizer, a race detector. 10 // This file is a part of ThreadSanitizer, a race detector.
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
56 STATISTIC(NumInstrumentedVtableWrites, "Number of vtable ptr writes"); 56 STATISTIC(NumInstrumentedVtableWrites, "Number of vtable ptr writes");
57 STATISTIC(NumOmittedReadsFromConstantGlobals, 57 STATISTIC(NumOmittedReadsFromConstantGlobals,
58 "Number of reads from constant globals"); 58 "Number of reads from constant globals");
59 STATISTIC(NumOmittedReadsFromVtable, "Number of vtable reads"); 59 STATISTIC(NumOmittedReadsFromVtable, "Number of vtable reads");
60 60
61 namespace { 61 namespace {
62 62
63 /// ThreadSanitizer: instrument the code in module to find races. 63 /// ThreadSanitizer: instrument the code in module to find races.
64 struct ThreadSanitizer : public FunctionPass { 64 struct ThreadSanitizer : public FunctionPass {
65 ThreadSanitizer(); 65 ThreadSanitizer();
66 const char *getPassName() const;
66 bool runOnFunction(Function &F); 67 bool runOnFunction(Function &F);
67 bool doInitialization(Module &M); 68 bool doInitialization(Module &M);
68 static char ID; // Pass identification, replacement for typeid. 69 static char ID; // Pass identification, replacement for typeid.
69 70
70 private: 71 private:
71 virtual const char *getPassName() const;
glider 2012/04/24 13:46:20 This should be a public one.
dvyukov 2012/04/24 16:42:15 Done.
72 bool instrumentLoadOrStore(Instruction *I); 72 bool instrumentLoadOrStore(Instruction *I);
73 bool instrumentAtomic(Instruction *I); 73 bool instrumentAtomic(Instruction *I);
74 void choseInstructionsToInstrument(SmallVectorImpl<Instruction*> &Local, 74 void choseInstructionsToInstrument(SmallVectorImpl<Instruction*> &Local,
75 SmallVectorImpl<Instruction*> &All); 75 SmallVectorImpl<Instruction*> &All);
76 bool addrPointsToConstantData(Value *Addr); 76 bool addrPointsToConstantData(Value *Addr);
77 int getFuncIndex(Value *Addr); 77 int getMemoryAccessFuncIndex(Value *Addr);
78 78
79 TargetData *TD; 79 TargetData *TD;
80 OwningPtr<FunctionBlackList> BL; 80 OwningPtr<FunctionBlackList> BL;
81 IntegerType *OrdTy;
81 // Callbacks to run-time library are computed in doInitialization. 82 // Callbacks to run-time library are computed in doInitialization.
82 Value *TsanFuncEntry; 83 Function *TsanFuncEntry;
83 Value *TsanFuncExit; 84 Function *TsanFuncExit;
84 // Accesses sizes are powers of two: 1, 2, 4, 8, 16. 85 // Accesses sizes are powers of two: 1, 2, 4, 8, 16.
85 static const size_t kNumberOfAccessSizes = 5; 86 static const size_t kNumberOfAccessSizes = 5;
86 IntegerType *IntTy[kNumberOfAccessSizes]; 87 Function *TsanRead[kNumberOfAccessSizes];
87 IntegerType *OrdTy; 88 Function *TsanWrite[kNumberOfAccessSizes];
88 Value *TsanRead[kNumberOfAccessSizes]; 89 Function *TsanAtomicLoad[kNumberOfAccessSizes];
89 Value *TsanWrite[kNumberOfAccessSizes]; 90 Function *TsanAtomicStore[kNumberOfAccessSizes];
90 Value *TsanAtomicLoad[kNumberOfAccessSizes]; 91 Function *TsanVptrUpdate;
glider 2012/04/24 13:46:20 s/Value */Constant */ In fact you may want to che
dvyukov 2012/04/24 16:42:15 Done.
91 Value *TsanAtomicStore[kNumberOfAccessSizes];
92 Value *TsanVptrUpdate;
93 }; 92 };
94 } // namespace 93 } // namespace
95 94
96 char ThreadSanitizer::ID = 0; 95 char ThreadSanitizer::ID = 0;
97 INITIALIZE_PASS(ThreadSanitizer, "tsan", 96 INITIALIZE_PASS(ThreadSanitizer, "tsan",
98 "ThreadSanitizer: detects data races.", 97 "ThreadSanitizer: detects data races.",
99 false, false) 98 false, false)
100 99
101 const char *ThreadSanitizer::getPassName() const { 100 const char *ThreadSanitizer::getPassName() const {
102 return "ThreadSanitizer"; 101 return "ThreadSanitizer";
103 } 102 }
104 103
105 ThreadSanitizer::ThreadSanitizer() 104 ThreadSanitizer::ThreadSanitizer()
106 : FunctionPass(ID), 105 : FunctionPass(ID),
107 TD(NULL) { 106 TD(NULL) {
108 } 107 }
109 108
110 FunctionPass *llvm::createThreadSanitizerPass() { 109 FunctionPass *llvm::createThreadSanitizerPass() {
111 return new ThreadSanitizer(); 110 return new ThreadSanitizer();
111 }
112
113 static Function *checkInterfaceFunction(Constant *FuncOrBitcast) {
114 if (Function *F = dyn_cast<Function>(FuncOrBitcast))
115 return F;
116 FuncOrBitcast->dump();
117 report_fatal_error("ThreadSanitizer interface function redefined");
112 } 118 }
113 119
114 bool ThreadSanitizer::doInitialization(Module &M) { 120 bool ThreadSanitizer::doInitialization(Module &M) {
115 TD = getAnalysisIfAvailable<TargetData>(); 121 TD = getAnalysisIfAvailable<TargetData>();
116 if (!TD) 122 if (!TD)
117 return false; 123 return false;
118 BL.reset(new FunctionBlackList(ClBlackListFile)); 124 BL.reset(new FunctionBlackList(ClBlackListFile));
119 125
120 // Always insert a call to __tsan_init into the module's CTORs. 126 // Always insert a call to __tsan_init into the module's CTORs.
121 IRBuilder<> IRB(M.getContext()); 127 IRBuilder<> IRB(M.getContext());
122 Value *TsanInit = M.getOrInsertFunction("__tsan_init", 128 Value *TsanInit = M.getOrInsertFunction("__tsan_init",
123 IRB.getVoidTy(), NULL); 129 IRB.getVoidTy(), NULL);
124 appendToGlobalCtors(M, cast<Function>(TsanInit), 0); 130 appendToGlobalCtors(M, cast<Function>(TsanInit), 0);
125 131
126 // Initialize the callbacks. 132 // Initialize the callbacks.
127 TsanFuncEntry = M.getOrInsertFunction("__tsan_func_entry", IRB.getVoidTy(), 133 TsanFuncEntry = checkInterfaceFunction(M.getOrInsertFunction(
128 IRB.getInt8PtrTy(), NULL); 134 "__tsan_func_entry", IRB.getVoidTy(), IRB.getInt8PtrTy(), NULL));
129 TsanFuncExit = M.getOrInsertFunction("__tsan_func_exit", IRB.getVoidTy(), 135 TsanFuncExit = checkInterfaceFunction(M.getOrInsertFunction(
130 NULL); 136 "__tsan_func_exit", IRB.getVoidTy(), NULL));
131 IntTy[0] = IRB.getInt8Ty();
132 IntTy[1] = IRB.getInt16Ty();
133 IntTy[2] = IRB.getInt32Ty();
134 IntTy[3] = IRB.getInt64Ty();
135 IntTy[4] = Type::getIntNTy(M.getContext(), 128);
136 OrdTy = IRB.getInt32Ty(); 137 OrdTy = IRB.getInt32Ty();
glider 2012/04/24 13:46:20 I wonder if it is not better to use Int64Ty on x64
dvyukov 2012/04/24 16:42:15 Int32Ty is OK on IA-32.
137 for (size_t i = 0; i < kNumberOfAccessSizes; ++i) { 138 for (size_t i = 0; i < kNumberOfAccessSizes; ++i) {
138 SmallString<32> ReadName("__tsan_read"); 139 const size_t ByteSize = 1 << i;
139 ReadName += itostr(1 << i); 140 const size_t BitSize = ByteSize * 8;
140 TsanRead[i] = M.getOrInsertFunction(ReadName, IRB.getVoidTy(), 141 SmallString<32> ReadName("__tsan_read" + itostr(ByteSize));
141 IRB.getInt8PtrTy(), NULL); 142 TsanRead[i] = checkInterfaceFunction(M.getOrInsertFunction(
142 SmallString<32> WriteName("__tsan_write"); 143 ReadName, IRB.getVoidTy(), IRB.getInt8PtrTy(), NULL));
143 WriteName += itostr(1 << i); 144
144 TsanWrite[i] = M.getOrInsertFunction(WriteName, IRB.getVoidTy(), 145 SmallString<32> WriteName("__tsan_write" + itostr(ByteSize));
145 IRB.getInt8PtrTy(), NULL); 146 TsanWrite[i] = checkInterfaceFunction(M.getOrInsertFunction(
146 } 147 WriteName, IRB.getVoidTy(), IRB.getInt8PtrTy(), NULL));
147 for (size_t i = 0; i < kNumberOfAccessSizes; ++i) { 148
148 SmallString<32> Name("__tsan_atomic" + itostr(1 << i) + "_load"); 149 Type *Ty = Type::getIntNTy(M.getContext(), BitSize);
149 TsanAtomicLoad[i] = M.getOrInsertFunction(Name, 150 Type *PtrTy = Ty->getPointerTo();
150 IntTy[i], 151 SmallString<32> AtomicLoadName("__tsan_atomic" + itostr(BitSize) +
151 IRB.getInt8PtrTy(), 152 "_load");
152 OrdTy, NULL); 153 TsanAtomicLoad[i] = checkInterfaceFunction(M.getOrInsertFunction(
153 } 154 AtomicLoadName, Ty, PtrTy, OrdTy, NULL));
154 for (size_t i = 0; i < kNumberOfAccessSizes; ++i) { 155
155 SmallString<32> Name("__tsan_atomic" + itostr(1 << i) + "_store"); 156 SmallString<32> AtomicStoreName("__tsan_atomic" + itostr(BitSize) +
156 TsanAtomicStore[i] = M.getOrInsertFunction(Name, 157 "_store");
157 IRB.getVoidTy(), 158 TsanAtomicStore[i] = checkInterfaceFunction(M.getOrInsertFunction(
158 IRB.getInt8PtrTy(), 159 AtomicStoreName, IRB.getVoidTy(), PtrTy, Ty, OrdTy,
159 IntTy[i], 160 NULL));
160 OrdTy, NULL); 161 }
161 } 162 TsanVptrUpdate = checkInterfaceFunction(M.getOrInsertFunction(
162 TsanVptrUpdate = M.getOrInsertFunction("__tsan_vptr_update", IRB.getVoidTy(), 163 "__tsan_vptr_update", IRB.getVoidTy(), IRB.getInt8PtrTy(),
163 IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), 164 IRB.getInt8PtrTy(), NULL));
164 NULL);
165 return true; 165 return true;
166 } 166 }
167 167
168 static bool isVtableAccess(Instruction *I) { 168 static bool isVtableAccess(Instruction *I) {
169 if (MDNode *Tag = I->getMetadata(LLVMContext::MD_tbaa)) { 169 if (MDNode *Tag = I->getMetadata(LLVMContext::MD_tbaa)) {
170 if (Tag->getNumOperands() < 1) return false; 170 if (Tag->getNumOperands() < 1) return false;
171 if (MDString *Tag1 = dyn_cast<MDString>(Tag->getOperand(0))) { 171 if (MDString *Tag1 = dyn_cast<MDString>(Tag->getOperand(0))) {
172 if (Tag1->getString() == "vtable pointer") return true; 172 if (Tag1->getString() == "vtable pointer") return true;
173 } 173 }
174 } 174 }
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
229 // Addr points to some constant data -- it can not race with any writes. 229 // Addr points to some constant data -- it can not race with any writes.
230 continue; 230 continue;
231 } 231 }
232 } 232 }
233 All.push_back(I); 233 All.push_back(I);
234 } 234 }
235 Local.clear(); 235 Local.clear();
236 } 236 }
237 237
238 static bool isAtomic(Instruction *I) { 238 static bool isAtomic(Instruction *I) {
239 if (LoadInst *LI = dyn_cast<LoadInst>(I)) 239 if (LoadInst *LI = dyn_cast<LoadInst>(I))
glider 2012/04/24 13:46:20 isa<LoadInst>
dvyukov 2012/04/24 16:42:15 The style guide says: if (AllocationInst *AI = dyn
240 return LI->isAtomic() && LI->getSynchScope() == CrossThread; 240 return LI->isAtomic() && LI->getSynchScope() == CrossThread;
241 else if (StoreInst *SI = dyn_cast<StoreInst>(I)) 241 else if (StoreInst *SI = dyn_cast<StoreInst>(I))
242 return SI->isAtomic() && SI->getSynchScope() == CrossThread; 242 return SI->isAtomic() && SI->getSynchScope() == CrossThread;
243 else if (isa<AtomicRMWInst>(I)) 243 else if (isa<AtomicRMWInst>(I))
244 return true; 244 return true;
245 else if (isa<AtomicCmpXchgInst>(I)) 245 else if (isa<AtomicCmpXchgInst>(I))
246 return true; 246 return true;
247 else if (FenceInst *FI = dyn_cast<FenceInst>(I)) 247 else if (FenceInst *FI = dyn_cast<FenceInst>(I))
248 return FI->getSynchScope() == CrossThread; 248 return FI->getSynchScope() == CrossThread;
249 return false; 249 return false;
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
308 } 308 }
309 return Res; 309 return Res;
310 } 310 }
311 311
312 bool ThreadSanitizer::instrumentLoadOrStore(Instruction *I) { 312 bool ThreadSanitizer::instrumentLoadOrStore(Instruction *I) {
313 IRBuilder<> IRB(I); 313 IRBuilder<> IRB(I);
314 bool IsWrite = isa<StoreInst>(*I); 314 bool IsWrite = isa<StoreInst>(*I);
315 Value *Addr = IsWrite 315 Value *Addr = IsWrite
316 ? cast<StoreInst>(I)->getPointerOperand() 316 ? cast<StoreInst>(I)->getPointerOperand()
317 : cast<LoadInst>(I)->getPointerOperand(); 317 : cast<LoadInst>(I)->getPointerOperand();
318 int Idx = getFuncIndex(Addr); 318 int Idx = getMemoryAccessFuncIndex(Addr);
319 if (Idx < 0) 319 if (Idx < 0)
320 return false; 320 return false;
321 if (IsWrite && isVtableAccess(I)) { 321 if (IsWrite && isVtableAccess(I)) {
322 Value *StoredValue = cast<StoreInst>(I)->getValueOperand(); 322 Value *StoredValue = cast<StoreInst>(I)->getValueOperand();
323 IRB.CreateCall2(TsanVptrUpdate, 323 IRB.CreateCall2(TsanVptrUpdate,
324 IRB.CreatePointerCast(Addr, IRB.getInt8PtrTy()), 324 IRB.CreatePointerCast(Addr, IRB.getInt8PtrTy()),
325 IRB.CreatePointerCast(StoredValue, IRB.getInt8PtrTy())); 325 IRB.CreatePointerCast(StoredValue, IRB.getInt8PtrTy()));
326 NumInstrumentedVtableWrites++; 326 NumInstrumentedVtableWrites++;
327 return true; 327 return true;
328 } 328 }
329 Value *OnAccessFunc = IsWrite ? TsanWrite[Idx] : TsanRead[Idx]; 329 Value *OnAccessFunc = IsWrite ? TsanWrite[Idx] : TsanRead[Idx];
330 IRB.CreateCall(OnAccessFunc, IRB.CreatePointerCast(Addr, IRB.getInt8PtrTy())); 330 IRB.CreateCall(OnAccessFunc, IRB.CreatePointerCast(Addr, IRB.getInt8PtrTy()));
331 if (IsWrite) NumInstrumentedWrites++; 331 if (IsWrite) NumInstrumentedWrites++;
332 else NumInstrumentedReads++; 332 else NumInstrumentedReads++;
333 return true; 333 return true;
334 } 334 }
335 335
336 static ConstantInt *createOrdering(IRBuilder<> *IRB, AtomicOrdering ord) { 336 static ConstantInt *createOrdering(IRBuilder<> *IRB, AtomicOrdering ord) {
337 return IRB->getInt32(static_cast<uint32_t>(ord)); 337 uint32_t v = 0;
338 switch (ord) {
339 case NotAtomic: assert(false);
340 case Unordered: // Fall-through.
341 case Monotonic: v = 1 << 0; break;
342 // case Consume: v = 1 << 1; break; // Not specified yet.
343 case Acquire: v = 1 << 2; break;
344 case Release: v = 1 << 3; break;
345 case AcquireRelease: v = 1 << 4; break;
346 case SequentiallyConsistent: v = 1 << 5; break;
347 }
348 return IRB->getInt32(v);
338 } 349 }
339 350
340 bool ThreadSanitizer::instrumentAtomic(Instruction *I) { 351 bool ThreadSanitizer::instrumentAtomic(Instruction *I) {
341 IRBuilder<> IRB(I); 352 IRBuilder<> IRB(I);
342 if (LoadInst *LI = dyn_cast<LoadInst>(I)) { 353 if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
glider 2012/04/24 13:46:20 if (isa<LoadInst>(I)) See also http://llvm.org/do
343 Value *Addr = LI->getPointerOperand(); 354 Value *Addr = LI->getPointerOperand();
344 int Idx = getFuncIndex(Addr); 355 int Idx = getMemoryAccessFuncIndex(Addr);
345 if (Idx < 0) 356 if (Idx < 0)
346 return false; 357 return false;
347 Value *Args[] = {IRB.CreatePointerCast(Addr, IRB.getInt8PtrTy()), 358 const size_t ByteSize = 1 << Idx;
359 const size_t BitSize = ByteSize * 8;
360 Type *Ty = Type::getIntNTy(IRB.getContext(), BitSize);
361 Type *PtrTy = Ty->getPointerTo();
362 Value *Args[] = {IRB.CreatePointerCast(Addr, PtrTy),
348 createOrdering(&IRB, LI->getOrdering())}; 363 createOrdering(&IRB, LI->getOrdering())};
349 CallInst *C = CallInst::Create(TsanAtomicLoad[Idx], 364 CallInst *C = CallInst::Create(TsanAtomicLoad[Idx],
350 ArrayRef<Value*>(Args)); 365 ArrayRef<Value*>(Args));
351 ReplaceInstWithInst(I, C); 366 ReplaceInstWithInst(I, C);
352 367
353 } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) { 368 } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
354 Value *Addr = SI->getPointerOperand(); 369 Value *Addr = SI->getPointerOperand();
355 int Idx = getFuncIndex(Addr); 370 int Idx = getMemoryAccessFuncIndex(Addr);
356 if (Idx < 0) 371 if (Idx < 0)
357 return false; 372 return false;
358 Value *Args[] = {IRB.CreatePointerCast(Addr, IRB.getInt8PtrTy()), 373 const size_t ByteSize = 1 << Idx;
359 SI->getValueOperand(), 374 const size_t BitSize = ByteSize * 8;
375 Type *Ty = Type::getIntNTy(IRB.getContext(), BitSize);
376 Type *PtrTy = Ty->getPointerTo();
377 Value *Args[] = {IRB.CreatePointerCast(Addr, PtrTy),
378 IRB.CreateIntCast(SI->getValueOperand(), Ty, false),
360 createOrdering(&IRB, SI->getOrdering())}; 379 createOrdering(&IRB, SI->getOrdering())};
361 CallInst *C = CallInst::Create(TsanAtomicStore[Idx], 380 CallInst *C = CallInst::Create(TsanAtomicStore[Idx],
362 ArrayRef<Value*>(Args)); 381 ArrayRef<Value*>(Args));
363 ReplaceInstWithInst(I, C); 382 ReplaceInstWithInst(I, C);
364 } else if (AtomicRMWInst *AI = dyn_cast<AtomicRMWInst>(I)) { 383 } else if (isa<AtomicRMWInst>(I)) {
365 (void)AI; 384 // FIXME: Not yet supported.
glider 2012/04/24 13:46:20 Do you need this line?
366 } else if (AtomicCmpXchgInst *AI = dyn_cast<AtomicCmpXchgInst>(I)) { 385 } else if (isa<AtomicCmpXchgInst>(I)) {
367 (void)AI; 386 // FIXME: Not yet supported.
368 } else if (FenceInst *FI = dyn_cast<FenceInst>(I)) { 387 } else if (isa<FenceInst>(I)) {
369 (void)FI; 388 // FIXME: Not yet supported.
370 } 389 }
371 return true; 390 return true;
372 } 391 }
373 392
374 int ThreadSanitizer::getFuncIndex(Value *Addr) { 393 int ThreadSanitizer::getMemoryAccessFuncIndex(Value *Addr) {
glider 2012/04/24 13:46:20 getFuncIdx is perhaps not the best name for a func
375 Type *OrigPtrTy = Addr->getType(); 394 Type *OrigPtrTy = Addr->getType();
376 Type *OrigTy = cast<PointerType>(OrigPtrTy)->getElementType(); 395 Type *OrigTy = cast<PointerType>(OrigPtrTy)->getElementType();
377 assert(OrigTy->isSized()); 396 assert(OrigTy->isSized());
378 uint32_t TypeSize = TD->getTypeStoreSizeInBits(OrigTy); 397 uint32_t TypeSize = TD->getTypeStoreSizeInBits(OrigTy);
379 if (TypeSize != 8 && TypeSize != 16 && 398 if (TypeSize != 8 && TypeSize != 16 &&
380 TypeSize != 32 && TypeSize != 64 && TypeSize != 128) { 399 TypeSize != 32 && TypeSize != 64 && TypeSize != 128) {
381 NumAccessesWithBadSize++; 400 NumAccessesWithBadSize++;
382 // Ignore all unusual sizes. 401 // Ignore all unusual sizes.
383 return -1; 402 return -1;
384 } 403 }
385 size_t Idx = CountTrailingZeros_32(TypeSize / 8); 404 size_t Idx = CountTrailingZeros_32(TypeSize / 8);
386 assert(Idx < kNumberOfAccessSizes); 405 assert(Idx < kNumberOfAccessSizes);
387 return Idx; 406 return Idx;
388 } 407 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b