1 //===-- CDSPass.cpp - xxx -------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 // This file is distributed under the University of Illinois Open Source
7 // License. See LICENSE.TXT for details.
9 //===----------------------------------------------------------------------===//
11 // This file is a modified version of ThreadSanitizer.cpp, a part of a race detector.
13 // The tool is under development, for the details about previous versions see
14 // http://code.google.com/p/data-race-test
16 // The instrumentation phase is quite simple:
17 // - Insert calls to run-time library before every memory access.
18 // - Optimizations may apply to avoid instrumenting some of the accesses.
19 // - Insert calls at function entry/exit.
20 // The rest is handled by the run-time library.
21 //===----------------------------------------------------------------------===//
23 #include "llvm/ADT/Statistic.h"
24 #include "llvm/ADT/StringExtras.h"
25 #include "llvm/ADT/SmallString.h"
26 #include "llvm/Analysis/ValueTracking.h"
27 #include "llvm/Analysis/CaptureTracking.h"
28 #include "llvm/IR/BasicBlock.h"
29 #include "llvm/IR/Function.h"
30 #include "llvm/IR/IRBuilder.h"
31 #include "llvm/IR/Instructions.h"
32 #include "llvm/IR/LLVMContext.h"
33 #include "llvm/IR/LegacyPassManager.h"
34 #include "llvm/IR/Module.h"
35 #include "llvm/IR/PassManager.h"
36 #include "llvm/Pass.h"
37 #include "llvm/ProfileData/InstrProf.h"
38 #include "llvm/Support/raw_ostream.h"
39 #include "llvm/Support/AtomicOrdering.h"
40 #include "llvm/Support/Debug.h"
41 #include "llvm/Transforms/Scalar.h"
42 #include "llvm/Transforms/Utils/Local.h"
43 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
44 #include "llvm/Transforms/IPO/PassManagerBuilder.h"
45 #include "llvm/Transforms/Utils/EscapeEnumerator.h"
50 #define DEBUG_TYPE "CDS"
51 #include <llvm/IR/DebugLoc.h>
53 Value *getPosition( Instruction * I, IRBuilder <> IRB, bool print = false)
55 const DebugLoc & debug_location = I->getDebugLoc ();
56 std::string position_string;
58 llvm::raw_string_ostream position_stream (position_string);
59 debug_location . print (position_stream);
63 errs() << position_string << "\n";
66 return IRB.CreateGlobalStringPtr (position_string);
69 STATISTIC(NumInstrumentedReads, "Number of instrumented reads");
70 STATISTIC(NumInstrumentedWrites, "Number of instrumented writes");
71 STATISTIC(NumAccessesWithBadSize, "Number of accesses with bad size");
72 // STATISTIC(NumInstrumentedVtableWrites, "Number of vtable ptr writes");
73 // STATISTIC(NumInstrumentedVtableReads, "Number of vtable ptr reads");
75 STATISTIC(NumOmittedReadsBeforeWrite,
76 "Number of reads ignored due to following writes");
77 STATISTIC(NumOmittedReadsFromConstantGlobals,
78 "Number of reads from constant globals");
79 STATISTIC(NumOmittedReadsFromVtable, "Number of vtable reads");
80 STATISTIC(NumOmittedNonCaptured, "Number of accesses ignored due to capturing");
91 static const size_t kNumberOfAccessSizes = 4;
92 static const int volatile_order = 6;
94 int getAtomicOrderIndex(AtomicOrdering order){
96 case AtomicOrdering::Monotonic:
97 return (int)AtomicOrderingCABI::relaxed;
98 // case AtomicOrdering::Consume: // not specified yet
99 // return AtomicOrderingCABI::consume;
100 case AtomicOrdering::Acquire:
101 return (int)AtomicOrderingCABI::acquire;
102 case AtomicOrdering::Release:
103 return (int)AtomicOrderingCABI::release;
104 case AtomicOrdering::AcquireRelease:
105 return (int)AtomicOrderingCABI::acq_rel;
106 case AtomicOrdering::SequentiallyConsistent:
107 return (int)AtomicOrderingCABI::seq_cst;
109 // unordered or Not Atomic
115 struct CDSPass : public FunctionPass {
117 CDSPass() : FunctionPass(ID) {}
118 bool runOnFunction(Function &F) override;
121 void initializeCallbacks(Module &M);
122 bool instrumentLoadOrStore(Instruction *I, const DataLayout &DL);
123 bool instrumentVolatile(Instruction *I, const DataLayout &DL);
124 bool isAtomicCall(Instruction *I);
125 bool instrumentAtomic(Instruction *I, const DataLayout &DL);
126 bool instrumentAtomicCall(CallInst *CI, const DataLayout &DL);
127 void chooseInstructionsToInstrument(SmallVectorImpl<Instruction *> &Local,
128 SmallVectorImpl<Instruction *> &All,
129 const DataLayout &DL);
130 bool addrPointsToConstantData(Value *Addr);
131 int getMemoryAccessFuncIndex(Value *Addr, const DataLayout &DL);
133 // Callbacks to run-time library are computed in doInitialization.
134 Constant * CDSFuncEntry;
135 Constant * CDSFuncExit;
137 Constant * CDSLoad[kNumberOfAccessSizes];
138 Constant * CDSStore[kNumberOfAccessSizes];
139 Constant * CDSVolatileLoad[kNumberOfAccessSizes];
140 Constant * CDSVolatileStore[kNumberOfAccessSizes];
141 Constant * CDSAtomicInit[kNumberOfAccessSizes];
142 Constant * CDSAtomicLoad[kNumberOfAccessSizes];
143 Constant * CDSAtomicStore[kNumberOfAccessSizes];
144 Constant * CDSAtomicRMW[AtomicRMWInst::LAST_BINOP + 1][kNumberOfAccessSizes];
145 Constant * CDSAtomicCAS_V1[kNumberOfAccessSizes];
146 Constant * CDSAtomicCAS_V2[kNumberOfAccessSizes];
147 Constant * CDSAtomicThreadFence;
149 std::vector<StringRef> AtomicFuncNames;
150 std::vector<StringRef> PartialAtomicFuncNames;
154 static bool isVtableAccess(Instruction *I) {
155 if (MDNode *Tag = I->getMetadata(LLVMContext::MD_tbaa))
156 return Tag->isTBAAVtableAccess();
160 void CDSPass::initializeCallbacks(Module &M) {
161 LLVMContext &Ctx = M.getContext();
163 Type * Int1Ty = Type::getInt1Ty(Ctx);
164 OrdTy = Type::getInt32Ty(Ctx);
166 Int8PtrTy = Type::getInt8PtrTy(Ctx);
167 Int16PtrTy = Type::getInt16PtrTy(Ctx);
168 Int32PtrTy = Type::getInt32PtrTy(Ctx);
169 Int64PtrTy = Type::getInt64PtrTy(Ctx);
171 VoidTy = Type::getVoidTy(Ctx);
173 CDSFuncEntry = M.getOrInsertFunction("cds_func_entry",
175 CDSFuncExit = M.getOrInsertFunction("cds_func_exit",
178 // Get the function to call from our untime library.
179 for (unsigned i = 0; i < kNumberOfAccessSizes; i++) {
180 const unsigned ByteSize = 1U << i;
181 const unsigned BitSize = ByteSize * 8;
183 std::string ByteSizeStr = utostr(ByteSize);
184 std::string BitSizeStr = utostr(BitSize);
186 Type *Ty = Type::getIntNTy(Ctx, BitSize);
187 Type *PtrTy = Ty->getPointerTo();
189 // uint8_t cds_atomic_load8 (void * obj, int atomic_index)
190 // void cds_atomic_store8 (void * obj, int atomic_index, uint8_t val)
191 SmallString<32> LoadName("cds_load" + BitSizeStr);
192 SmallString<32> StoreName("cds_store" + BitSizeStr);
193 SmallString<32> VolatileLoadName("cds_volatile_load" + BitSizeStr);
194 SmallString<32> VolatileStoreName("cds_volatile_store" + BitSizeStr);
195 SmallString<32> AtomicInitName("cds_atomic_init" + BitSizeStr);
196 SmallString<32> AtomicLoadName("cds_atomic_load" + BitSizeStr);
197 SmallString<32> AtomicStoreName("cds_atomic_store" + BitSizeStr);
199 CDSLoad[i] = M.getOrInsertFunction(LoadName, VoidTy, PtrTy);
200 CDSStore[i] = M.getOrInsertFunction(StoreName, VoidTy, PtrTy);
201 CDSVolatileLoad[i] = M.getOrInsertFunction(VolatileLoadName,
202 Ty, PtrTy, OrdTy, Int8PtrTy);
203 CDSVolatileStore[i] = M.getOrInsertFunction(VolatileStoreName,
204 VoidTy, PtrTy, Ty, OrdTy, Int8PtrTy);
205 CDSAtomicInit[i] = M.getOrInsertFunction(AtomicInitName,
206 VoidTy, PtrTy, Ty, Int8PtrTy);
207 CDSAtomicLoad[i] = M.getOrInsertFunction(AtomicLoadName,
208 Ty, PtrTy, OrdTy, Int8PtrTy);
209 CDSAtomicStore[i] = M.getOrInsertFunction(AtomicStoreName,
210 VoidTy, PtrTy, Ty, OrdTy, Int8PtrTy);
212 for (int op = AtomicRMWInst::FIRST_BINOP;
213 op <= AtomicRMWInst::LAST_BINOP; ++op) {
214 CDSAtomicRMW[op][i] = nullptr;
215 std::string NamePart;
217 if (op == AtomicRMWInst::Xchg)
218 NamePart = "_exchange";
219 else if (op == AtomicRMWInst::Add)
220 NamePart = "_fetch_add";
221 else if (op == AtomicRMWInst::Sub)
222 NamePart = "_fetch_sub";
223 else if (op == AtomicRMWInst::And)
224 NamePart = "_fetch_and";
225 else if (op == AtomicRMWInst::Or)
226 NamePart = "_fetch_or";
227 else if (op == AtomicRMWInst::Xor)
228 NamePart = "_fetch_xor";
232 SmallString<32> AtomicRMWName("cds_atomic" + NamePart + BitSizeStr);
233 CDSAtomicRMW[op][i] = M.getOrInsertFunction(AtomicRMWName,
234 Ty, PtrTy, Ty, OrdTy, Int8PtrTy);
237 // only supportes strong version
238 SmallString<32> AtomicCASName_V1("cds_atomic_compare_exchange" + BitSizeStr + "_v1");
239 SmallString<32> AtomicCASName_V2("cds_atomic_compare_exchange" + BitSizeStr + "_v2");
240 CDSAtomicCAS_V1[i] = M.getOrInsertFunction(AtomicCASName_V1,
241 Ty, PtrTy, Ty, Ty, OrdTy, OrdTy, Int8PtrTy);
242 CDSAtomicCAS_V2[i] = M.getOrInsertFunction(AtomicCASName_V2,
243 Int1Ty, PtrTy, PtrTy, Ty, OrdTy, OrdTy, Int8PtrTy);
246 CDSAtomicThreadFence = M.getOrInsertFunction("cds_atomic_thread_fence",
247 VoidTy, OrdTy, Int8PtrTy);
250 static bool shouldInstrumentReadWriteFromAddress(const Module *M, Value *Addr) {
251 // Peel off GEPs and BitCasts.
252 Addr = Addr->stripInBoundsOffsets();
254 if (GlobalVariable *GV = dyn_cast<GlobalVariable>(Addr)) {
255 if (GV->hasSection()) {
256 StringRef SectionName = GV->getSection();
257 // Check if the global is in the PGO counters section.
258 auto OF = Triple(M->getTargetTriple()).getObjectFormat();
259 if (SectionName.endswith(
260 getInstrProfSectionName(IPSK_cnts, OF, /*AddSegmentInfo=*/false)))
264 // Check if the global is private gcov data.
265 if (GV->getName().startswith("__llvm_gcov") ||
266 GV->getName().startswith("__llvm_gcda"))
270 // Do not instrument acesses from different address spaces; we cannot deal
273 Type *PtrTy = cast<PointerType>(Addr->getType()->getScalarType());
274 if (PtrTy->getPointerAddressSpace() != 0)
281 bool CDSPass::addrPointsToConstantData(Value *Addr) {
282 // If this is a GEP, just analyze its pointer operand.
283 if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(Addr))
284 Addr = GEP->getPointerOperand();
286 if (GlobalVariable *GV = dyn_cast<GlobalVariable>(Addr)) {
287 if (GV->isConstant()) {
288 // Reads from constant globals can not race with any writes.
289 NumOmittedReadsFromConstantGlobals++;
292 } else if (LoadInst *L = dyn_cast<LoadInst>(Addr)) {
293 if (isVtableAccess(L)) {
294 // Reads from a vtable pointer can not race with any writes.
295 NumOmittedReadsFromVtable++;
302 bool CDSPass::runOnFunction(Function &F) {
303 if (F.getName() == "main") {
304 F.setName("user_main");
305 errs() << "main replaced by user_main\n";
309 initializeCallbacks( *F.getParent() );
313 "atomic_init", "atomic_load", "atomic_store",
314 "atomic_fetch_", "atomic_exchange", "atomic_compare_exchange_"
317 PartialAtomicFuncNames =
319 "load", "store", "fetch", "exchange", "compare_exchange_"
322 SmallVector<Instruction*, 8> AllLoadsAndStores;
323 SmallVector<Instruction*, 8> LocalLoadsAndStores;
324 SmallVector<Instruction*, 8> VolatileLoadsAndStores;
325 SmallVector<Instruction*, 8> AtomicAccesses;
327 std::vector<Instruction *> worklist;
330 bool HasAtomic = false;
331 const DataLayout &DL = F.getParent()->getDataLayout();
333 // errs() << "--- " << F.getName() << "---\n";
337 if ( (&I)->isAtomic() || isAtomicCall(&I) ) {
338 AtomicAccesses.push_back(&I);
340 } else if (isa<LoadInst>(I) || isa<StoreInst>(I)) {
341 LoadInst *LI = dyn_cast<LoadInst>(&I);
342 StoreInst *SI = dyn_cast<StoreInst>(&I);
343 bool isVolatile = ( LI ? LI->isVolatile() : SI->isVolatile() );
346 VolatileLoadsAndStores.push_back(&I);
348 LocalLoadsAndStores.push_back(&I);
349 } else if (isa<CallInst>(I) || isa<InvokeInst>(I)) {
350 // not implemented yet
354 chooseInstructionsToInstrument(LocalLoadsAndStores, AllLoadsAndStores, DL);
357 for (auto Inst : AllLoadsAndStores) {
358 Res |= instrumentLoadOrStore(Inst, DL);
361 for (auto Inst : VolatileLoadsAndStores) {
362 Res |= instrumentVolatile(Inst, DL);
365 for (auto Inst : AtomicAccesses) {
366 Res |= instrumentAtomic(Inst, DL);
369 // only instrument functions that contain atomics
370 if (Res && HasAtomic) {
371 IRBuilder<> IRB(F.getEntryBlock().getFirstNonPHI());
373 Value *ReturnAddress = IRB.CreateCall(
374 Intrinsic::getDeclaration(F.getParent(), Intrinsic::returnaddress),
378 Value * FuncName = IRB.CreateGlobalStringPtr(F.getName());
379 IRB.CreateCall(CDSFuncEntry, FuncName);
381 EscapeEnumerator EE(F, "cds_cleanup", true);
382 while (IRBuilder<> *AtExit = EE.Next()) {
383 AtExit->CreateCall(CDSFuncExit, FuncName);
393 void CDSPass::chooseInstructionsToInstrument(
394 SmallVectorImpl<Instruction *> &Local, SmallVectorImpl<Instruction *> &All,
395 const DataLayout &DL) {
396 SmallPtrSet<Value*, 8> WriteTargets;
397 // Iterate from the end.
398 for (Instruction *I : reverse(Local)) {
399 if (StoreInst *Store = dyn_cast<StoreInst>(I)) {
400 Value *Addr = Store->getPointerOperand();
401 if (!shouldInstrumentReadWriteFromAddress(I->getModule(), Addr))
403 WriteTargets.insert(Addr);
405 LoadInst *Load = cast<LoadInst>(I);
406 Value *Addr = Load->getPointerOperand();
407 if (!shouldInstrumentReadWriteFromAddress(I->getModule(), Addr))
409 if (WriteTargets.count(Addr)) {
410 // We will write to this temp, so no reason to analyze the read.
411 NumOmittedReadsBeforeWrite++;
414 if (addrPointsToConstantData(Addr)) {
415 // Addr points to some constant data -- it can not race with any writes.
419 Value *Addr = isa<StoreInst>(*I)
420 ? cast<StoreInst>(I)->getPointerOperand()
421 : cast<LoadInst>(I)->getPointerOperand();
422 if (isa<AllocaInst>(GetUnderlyingObject(Addr, DL)) &&
423 !PointerMayBeCaptured(Addr, true, true)) {
424 // The variable is addressable but not captured, so it cannot be
425 // referenced from a different thread and participate in a data race
426 // (see llvm/Analysis/CaptureTracking.h for details).
427 NumOmittedNonCaptured++;
436 bool CDSPass::instrumentLoadOrStore(Instruction *I,
437 const DataLayout &DL) {
439 bool IsWrite = isa<StoreInst>(*I);
440 Value *Addr = IsWrite
441 ? cast<StoreInst>(I)->getPointerOperand()
442 : cast<LoadInst>(I)->getPointerOperand();
444 // swifterror memory addresses are mem2reg promoted by instruction selection.
445 // As such they cannot have regular uses like an instrumentation function and
446 // it makes no sense to track them as memory.
447 if (Addr->isSwiftError())
450 int Idx = getMemoryAccessFuncIndex(Addr, DL);
454 // not supported by CDS yet
455 /* if (IsWrite && isVtableAccess(I)) {
456 LLVM_DEBUG(dbgs() << " VPTR : " << *I << "\n");
457 Value *StoredValue = cast<StoreInst>(I)->getValueOperand();
458 // StoredValue may be a vector type if we are storing several vptrs at once.
459 // In this case, just take the first element of the vector since this is
460 // enough to find vptr races.
461 if (isa<VectorType>(StoredValue->getType()))
462 StoredValue = IRB.CreateExtractElement(
463 StoredValue, ConstantInt::get(IRB.getInt32Ty(), 0));
464 if (StoredValue->getType()->isIntegerTy())
465 StoredValue = IRB.CreateIntToPtr(StoredValue, IRB.getInt8PtrTy());
466 // Call TsanVptrUpdate.
467 IRB.CreateCall(TsanVptrUpdate,
468 {IRB.CreatePointerCast(Addr, IRB.getInt8PtrTy()),
469 IRB.CreatePointerCast(StoredValue, IRB.getInt8PtrTy())});
470 NumInstrumentedVtableWrites++;
474 if (!IsWrite && isVtableAccess(I)) {
475 IRB.CreateCall(TsanVptrLoad,
476 IRB.CreatePointerCast(Addr, IRB.getInt8PtrTy()));
477 NumInstrumentedVtableReads++;
482 Value *OnAccessFunc = nullptr;
483 OnAccessFunc = IsWrite ? CDSStore[Idx] : CDSLoad[Idx];
485 Type *ArgType = IRB.CreatePointerCast(Addr, Addr->getType())->getType();
487 if ( ArgType != Int8PtrTy && ArgType != Int16PtrTy &&
488 ArgType != Int32PtrTy && ArgType != Int64PtrTy ) {
489 // if other types of load or stores are passed in
492 IRB.CreateCall(OnAccessFunc, IRB.CreatePointerCast(Addr, Addr->getType()));
493 if (IsWrite) NumInstrumentedWrites++;
494 else NumInstrumentedReads++;
498 bool CDSPass::instrumentVolatile(Instruction * I, const DataLayout &DL) {
500 Value *position = getPosition(I, IRB);
502 if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
503 assert( LI->isVolatile() );
504 Value *Addr = LI->getPointerOperand();
505 int Idx=getMemoryAccessFuncIndex(Addr, DL);
509 Value *order = ConstantInt::get(OrdTy, volatile_order);
510 Value *args[] = {Addr, order, position};
511 Instruction* funcInst=CallInst::Create(CDSVolatileLoad[Idx], args);
512 ReplaceInstWithInst(LI, funcInst);
513 } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
514 assert( SI->isVolatile() );
515 Value *Addr = SI->getPointerOperand();
516 int Idx=getMemoryAccessFuncIndex(Addr, DL);
520 Value *val = SI->getValueOperand();
521 Value *order = ConstantInt::get(OrdTy, volatile_order);
522 Value *args[] = {Addr, val, order, position};
523 Instruction* funcInst=CallInst::Create(CDSVolatileStore[Idx], args);
524 ReplaceInstWithInst(SI, funcInst);
532 bool CDSPass::instrumentAtomic(Instruction * I, const DataLayout &DL) {
535 if (auto *CI = dyn_cast<CallInst>(I)) {
536 return instrumentAtomicCall(CI, DL);
539 Value *position = getPosition(I, IRB);
541 if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
542 Value *Addr = LI->getPointerOperand();
543 int Idx=getMemoryAccessFuncIndex(Addr, DL);
547 int atomic_order_index = getAtomicOrderIndex(LI->getOrdering());
548 Value *order = ConstantInt::get(OrdTy, atomic_order_index);
549 Value *args[] = {Addr, order, position};
550 Instruction* funcInst=CallInst::Create(CDSAtomicLoad[Idx], args);
551 ReplaceInstWithInst(LI, funcInst);
552 } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
553 Value *Addr = SI->getPointerOperand();
554 int Idx=getMemoryAccessFuncIndex(Addr, DL);
558 int atomic_order_index = getAtomicOrderIndex(SI->getOrdering());
559 Value *val = SI->getValueOperand();
560 Value *order = ConstantInt::get(OrdTy, atomic_order_index);
561 Value *args[] = {Addr, val, order, position};
562 Instruction* funcInst=CallInst::Create(CDSAtomicStore[Idx], args);
563 ReplaceInstWithInst(SI, funcInst);
564 } else if (AtomicRMWInst *RMWI = dyn_cast<AtomicRMWInst>(I)) {
565 Value *Addr = RMWI->getPointerOperand();
566 int Idx=getMemoryAccessFuncIndex(Addr, DL);
570 int atomic_order_index = getAtomicOrderIndex(RMWI->getOrdering());
571 Value *val = RMWI->getValOperand();
572 Value *order = ConstantInt::get(OrdTy, atomic_order_index);
573 Value *args[] = {Addr, val, order, position};
574 Instruction* funcInst = CallInst::Create(CDSAtomicRMW[RMWI->getOperation()][Idx], args);
575 ReplaceInstWithInst(RMWI, funcInst);
576 } else if (AtomicCmpXchgInst *CASI = dyn_cast<AtomicCmpXchgInst>(I)) {
577 IRBuilder<> IRB(CASI);
579 Value *Addr = CASI->getPointerOperand();
580 int Idx=getMemoryAccessFuncIndex(Addr, DL);
584 const unsigned ByteSize = 1U << Idx;
585 const unsigned BitSize = ByteSize * 8;
586 Type *Ty = Type::getIntNTy(IRB.getContext(), BitSize);
587 Type *PtrTy = Ty->getPointerTo();
589 Value *CmpOperand = IRB.CreateBitOrPointerCast(CASI->getCompareOperand(), Ty);
590 Value *NewOperand = IRB.CreateBitOrPointerCast(CASI->getNewValOperand(), Ty);
592 int atomic_order_index_succ = getAtomicOrderIndex(CASI->getSuccessOrdering());
593 int atomic_order_index_fail = getAtomicOrderIndex(CASI->getFailureOrdering());
594 Value *order_succ = ConstantInt::get(OrdTy, atomic_order_index_succ);
595 Value *order_fail = ConstantInt::get(OrdTy, atomic_order_index_fail);
597 Value *Args[] = {IRB.CreatePointerCast(Addr, PtrTy),
598 CmpOperand, NewOperand,
599 order_succ, order_fail, position};
601 CallInst *funcInst = IRB.CreateCall(CDSAtomicCAS_V1[Idx], Args);
602 Value *Success = IRB.CreateICmpEQ(funcInst, CmpOperand);
604 Value *OldVal = funcInst;
605 Type *OrigOldValTy = CASI->getNewValOperand()->getType();
606 if (Ty != OrigOldValTy) {
607 // The value is a pointer, so we need to cast the return value.
608 OldVal = IRB.CreateIntToPtr(funcInst, OrigOldValTy);
612 IRB.CreateInsertValue(UndefValue::get(CASI->getType()), OldVal, 0);
613 Res = IRB.CreateInsertValue(Res, Success, 1);
615 I->replaceAllUsesWith(Res);
616 I->eraseFromParent();
617 } else if (FenceInst *FI = dyn_cast<FenceInst>(I)) {
618 int atomic_order_index = getAtomicOrderIndex(FI->getOrdering());
619 Value *order = ConstantInt::get(OrdTy, atomic_order_index);
620 Value *Args[] = {order, position};
622 CallInst *funcInst = CallInst::Create(CDSAtomicThreadFence, Args);
623 ReplaceInstWithInst(FI, funcInst);
624 // errs() << "Thread Fences replaced\n";
629 bool CDSPass::isAtomicCall(Instruction *I) {
630 if ( auto *CI = dyn_cast<CallInst>(I) ) {
631 Function *fun = CI->getCalledFunction();
635 StringRef funName = fun->getName();
637 // todo: come up with better rules for function name checking
638 for (StringRef name : AtomicFuncNames) {
639 if ( funName.contains(name) )
643 for (StringRef PartialName : PartialAtomicFuncNames) {
644 if (funName.contains(PartialName) &&
645 funName.contains("atomic") )
653 bool CDSPass::instrumentAtomicCall(CallInst *CI, const DataLayout &DL) {
655 Function *fun = CI->getCalledFunction();
656 StringRef funName = fun->getName();
657 std::vector<Value *> parameters;
659 User::op_iterator begin = CI->arg_begin();
660 User::op_iterator end = CI->arg_end();
661 for (User::op_iterator it = begin; it != end; ++it) {
663 parameters.push_back(param);
666 // obtain source line number of the CallInst
667 Value *position = getPosition(CI, IRB);
669 // the pointer to the address is always the first argument
670 Value *OrigPtr = parameters[0];
672 int Idx = getMemoryAccessFuncIndex(OrigPtr, DL);
676 const unsigned ByteSize = 1U << Idx;
677 const unsigned BitSize = ByteSize * 8;
678 Type *Ty = Type::getIntNTy(IRB.getContext(), BitSize);
679 Type *PtrTy = Ty->getPointerTo();
681 // atomic_init; args = {obj, order}
682 if (funName.contains("atomic_init")) {
683 Value *ptr = IRB.CreatePointerCast(OrigPtr, PtrTy);
684 Value *val = IRB.CreateBitOrPointerCast(parameters[1], Ty);
685 Value *args[] = {ptr, val, position};
687 Instruction* funcInst = CallInst::Create(CDSAtomicInit[Idx], args);
688 ReplaceInstWithInst(CI, funcInst);
693 // atomic_load; args = {obj, order}
694 if (funName.contains("atomic_load")) {
695 bool isExplicit = funName.contains("atomic_load_explicit");
697 Value *ptr = IRB.CreatePointerCast(OrigPtr, PtrTy);
700 order = IRB.CreateBitOrPointerCast(parameters[1], OrdTy);
702 order = ConstantInt::get(OrdTy,
703 (int) AtomicOrderingCABI::seq_cst);
704 Value *args[] = {ptr, order, position};
706 Instruction* funcInst = CallInst::Create(CDSAtomicLoad[Idx], args);
707 ReplaceInstWithInst(CI, funcInst);
710 } else if (funName.contains("atomic") &&
711 funName.contains("load") ) {
712 // does this version of call always have an atomic order as an argument?
713 Value *ptr = IRB.CreatePointerCast(OrigPtr, PtrTy);
714 Value *order = IRB.CreateBitOrPointerCast(parameters[1], OrdTy);
715 Value *args[] = {ptr, order, position};
717 if (!CI->getType()->isPointerTy()) {
721 CallInst *funcInst = IRB.CreateCall(CDSAtomicLoad[Idx], args);
722 Value *RetVal = IRB.CreateIntToPtr(funcInst, CI->getType());
724 CI->replaceAllUsesWith(RetVal);
725 CI->eraseFromParent();
730 // atomic_store; args = {obj, val, order}
731 if (funName.contains("atomic_store")) {
732 bool isExplicit = funName.contains("atomic_store_explicit");
733 Value *OrigVal = parameters[1];
735 Value *ptr = IRB.CreatePointerCast(OrigPtr, PtrTy);
736 Value *val = IRB.CreatePointerCast(OrigVal, Ty);
739 order = IRB.CreateBitOrPointerCast(parameters[2], OrdTy);
741 order = ConstantInt::get(OrdTy,
742 (int) AtomicOrderingCABI::seq_cst);
743 Value *args[] = {ptr, val, order, position};
745 Instruction* funcInst = CallInst::Create(CDSAtomicStore[Idx], args);
746 ReplaceInstWithInst(CI, funcInst);
749 } else if (funName.contains("atomic") &&
750 funName.contains("EEEE5store") ) {
751 // does this version of call always have an atomic order as an argument?
752 Value *OrigVal = parameters[1];
754 Value *ptr = IRB.CreatePointerCast(OrigPtr, PtrTy);
755 Value *val = IRB.CreatePointerCast(OrigVal, Ty);
756 Value *order = IRB.CreateBitOrPointerCast(parameters[2], OrdTy);
757 Value *args[] = {ptr, val, order, position};
759 Instruction* funcInst = CallInst::Create(CDSAtomicStore[Idx], args);
760 ReplaceInstWithInst(CI, funcInst);
765 // atomic_fetch_*; args = {obj, val, order}
766 if (funName.contains("atomic_fetch_") ||
767 funName.contains("atomic_exchange") ) {
768 bool isExplicit = funName.contains("_explicit");
769 Value *OrigVal = parameters[1];
772 if ( funName.contains("_fetch_add") )
773 op = AtomicRMWInst::Add;
774 else if ( funName.contains("_fetch_sub") )
775 op = AtomicRMWInst::Sub;
776 else if ( funName.contains("_fetch_and") )
777 op = AtomicRMWInst::And;
778 else if ( funName.contains("_fetch_or") )
779 op = AtomicRMWInst::Or;
780 else if ( funName.contains("_fetch_xor") )
781 op = AtomicRMWInst::Xor;
782 else if ( funName.contains("atomic_exchange") )
783 op = AtomicRMWInst::Xchg;
785 errs() << "Unknown atomic read-modify-write operation\n";
789 Value *ptr = IRB.CreatePointerCast(OrigPtr, PtrTy);
790 Value *val = IRB.CreatePointerCast(OrigVal, Ty);
793 order = IRB.CreateBitOrPointerCast(parameters[2], OrdTy);
795 order = ConstantInt::get(OrdTy,
796 (int) AtomicOrderingCABI::seq_cst);
797 Value *args[] = {ptr, val, order, position};
799 Instruction* funcInst = CallInst::Create(CDSAtomicRMW[op][Idx], args);
800 ReplaceInstWithInst(CI, funcInst);
803 } else if (funName.contains("fetch")) {
804 errs() << "atomic exchange captured. Not implemented yet. ";
805 errs() << "See source file :";
806 getPosition(CI, IRB, true);
807 } else if (funName.contains("exchange") &&
808 !funName.contains("compare_exchange") ) {
809 errs() << "atomic exchange captured. Not implemented yet. ";
810 errs() << "See source file :";
811 getPosition(CI, IRB, true);
814 /* atomic_compare_exchange_*;
815 args = {obj, expected, new value, order1, order2}
817 if ( funName.contains("atomic_compare_exchange_") ) {
818 bool isExplicit = funName.contains("_explicit");
820 Value *Addr = IRB.CreatePointerCast(OrigPtr, PtrTy);
821 Value *CmpOperand = IRB.CreatePointerCast(parameters[1], PtrTy);
822 Value *NewOperand = IRB.CreateBitOrPointerCast(parameters[2], Ty);
824 Value *order_succ, *order_fail;
826 order_succ = IRB.CreateBitOrPointerCast(parameters[3], OrdTy);
827 order_fail = IRB.CreateBitOrPointerCast(parameters[4], OrdTy);
829 order_succ = ConstantInt::get(OrdTy,
830 (int) AtomicOrderingCABI::seq_cst);
831 order_fail = ConstantInt::get(OrdTy,
832 (int) AtomicOrderingCABI::seq_cst);
835 Value *args[] = {Addr, CmpOperand, NewOperand,
836 order_succ, order_fail, position};
838 Instruction* funcInst = CallInst::Create(CDSAtomicCAS_V2[Idx], args);
839 ReplaceInstWithInst(CI, funcInst);
842 } else if ( funName.contains("compare_exchange_strong") ||
843 funName.contains("compare_exchange_weak") ) {
844 Value *Addr = IRB.CreatePointerCast(OrigPtr, PtrTy);
845 Value *CmpOperand = IRB.CreatePointerCast(parameters[1], PtrTy);
846 Value *NewOperand = IRB.CreateBitOrPointerCast(parameters[2], Ty);
848 Value *order_succ, *order_fail;
849 order_succ = IRB.CreateBitOrPointerCast(parameters[3], OrdTy);
850 order_fail = IRB.CreateBitOrPointerCast(parameters[4], OrdTy);
852 Value *args[] = {Addr, CmpOperand, NewOperand,
853 order_succ, order_fail, position};
854 Instruction* funcInst = CallInst::Create(CDSAtomicCAS_V2[Idx], args);
855 ReplaceInstWithInst(CI, funcInst);
863 int CDSPass::getMemoryAccessFuncIndex(Value *Addr,
864 const DataLayout &DL) {
865 Type *OrigPtrTy = Addr->getType();
866 Type *OrigTy = cast<PointerType>(OrigPtrTy)->getElementType();
867 assert(OrigTy->isSized());
868 uint32_t TypeSize = DL.getTypeStoreSizeInBits(OrigTy);
869 if (TypeSize != 8 && TypeSize != 16 &&
870 TypeSize != 32 && TypeSize != 64 && TypeSize != 128) {
871 NumAccessesWithBadSize++;
872 // Ignore all unusual sizes.
875 size_t Idx = countTrailingZeros(TypeSize / 8);
876 //assert(Idx < kNumberOfAccessSizes);
877 if (Idx >= kNumberOfAccessSizes) {
884 char CDSPass::ID = 0;
886 // Automatically enable the pass.
887 static void registerCDSPass(const PassManagerBuilder &,
888 legacy::PassManagerBase &PM) {
889 PM.add(new CDSPass());
892 /* Enable the pass when opt level is greater than 0 */
893 static RegisterStandardPasses
894 RegisterMyPass1(PassManagerBuilder::EP_OptimizerLast,
897 /* Enable the pass when opt level is 0 */
898 static RegisterStandardPasses
899 RegisterMyPass2(PassManagerBuilder::EP_EnabledOnOptLevel0,