-static bool shouldInstrumentReadWriteFromAddress(const Module *M, Value *Addr) {
- // Peel off GEPs and BitCasts.
- Addr = Addr->stripInBoundsOffsets();
-
- if (GlobalVariable *GV = dyn_cast<GlobalVariable>(Addr)) {
- if (GV->hasSection()) {
- StringRef SectionName = GV->getSection();
- // Check if the global is in the PGO counters section.
- auto OF = Triple(M->getTargetTriple()).getObjectFormat();
- if (SectionName.endswith(
- getInstrProfSectionName(IPSK_cnts, OF, /*AddSegmentInfo=*/false)))
- return false;
- }
-
- // Check if the global is private gcov data.
- if (GV->getName().startswith("__llvm_gcov") ||
- GV->getName().startswith("__llvm_gcda"))
- return false;
- }
-
- // Do not instrument acesses from different address spaces; we cannot deal
- // with them.
- if (Addr) {
- Type *PtrTy = cast<PointerType>(Addr->getType()->getScalarType());
- if (PtrTy->getPointerAddressSpace() != 0)
- return false;
- }
-
- return true;
-}
-
-bool CDSPass::addrPointsToConstantData(Value *Addr) {
- // If this is a GEP, just analyze its pointer operand.
- if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(Addr))
- Addr = GEP->getPointerOperand();
-
- if (GlobalVariable *GV = dyn_cast<GlobalVariable>(Addr)) {
- if (GV->isConstant()) {
- // Reads from constant globals can not race with any writes.
- NumOmittedReadsFromConstantGlobals++;
- return true;
- }
- } else if (LoadInst *L = dyn_cast<LoadInst>(Addr)) {
- if (isVtableAccess(L)) {
- // Reads from a vtable pointer can not race with any writes.
- NumOmittedReadsFromVtable++;
- return true;
- }
- }
- return false;
-}
-
-bool CDSPass::runOnFunction(Function &F) {
- if (F.getName() == "main") {
- F.setName("user_main");
- errs() << "main replaced by user_main\n";
- }
-
- if (true) {
- initializeCallbacks( *F.getParent() );
-
- SmallVector<Instruction*, 8> AllLoadsAndStores;
- SmallVector<Instruction*, 8> LocalLoadsAndStores;
- SmallVector<Instruction*, 8> AtomicAccesses;
-
- std::vector<Instruction *> worklist;
-
- bool Res = false;
- const DataLayout &DL = F.getParent()->getDataLayout();
-
- errs() << "--- " << F.getName() << "---\n";
-
- for (auto &B : F) {
- for (auto &I : B) {
- if ( (&I)->isAtomic() || isAtomicCall(&I) ) {
- AtomicAccesses.push_back(&I);
- } else if (isa<LoadInst>(I) || isa<StoreInst>(I)) {
- LocalLoadsAndStores.push_back(&I);
- } else if (isa<CallInst>(I) || isa<InvokeInst>(I)) {
- // not implemented yet
- }
- }
-
- chooseInstructionsToInstrument(LocalLoadsAndStores, AllLoadsAndStores, DL);
- }
-
- for (auto Inst : AllLoadsAndStores) {
-// Res |= instrumentLoadOrStore(Inst, DL);
-// errs() << "load and store are replaced\n";
- }
-
- for (auto Inst : AtomicAccesses) {
- Res |= instrumentAtomic(Inst, DL);
- }
-
- if (F.getName() == "user_main") {
- // F.dump();
- }
-
- }
-
- return false;
-}
-
-void CDSPass::chooseInstructionsToInstrument(
- SmallVectorImpl<Instruction *> &Local, SmallVectorImpl<Instruction *> &All,
- const DataLayout &DL) {
- SmallPtrSet<Value*, 8> WriteTargets;
- // Iterate from the end.
- for (Instruction *I : reverse(Local)) {
- if (StoreInst *Store = dyn_cast<StoreInst>(I)) {
- Value *Addr = Store->getPointerOperand();
- if (!shouldInstrumentReadWriteFromAddress(I->getModule(), Addr))
- continue;
- WriteTargets.insert(Addr);
- } else {
- LoadInst *Load = cast<LoadInst>(I);
- Value *Addr = Load->getPointerOperand();
- if (!shouldInstrumentReadWriteFromAddress(I->getModule(), Addr))
- continue;
- if (WriteTargets.count(Addr)) {
- // We will write to this temp, so no reason to analyze the read.
- NumOmittedReadsBeforeWrite++;
- continue;
- }
- if (addrPointsToConstantData(Addr)) {
- // Addr points to some constant data -- it can not race with any writes.
- continue;
- }
- }
- Value *Addr = isa<StoreInst>(*I)
- ? cast<StoreInst>(I)->getPointerOperand()
- : cast<LoadInst>(I)->getPointerOperand();
- if (isa<AllocaInst>(GetUnderlyingObject(Addr, DL)) &&
- !PointerMayBeCaptured(Addr, true, true)) {
- // The variable is addressable but not captured, so it cannot be
- // referenced from a different thread and participate in a data race
- // (see llvm/Analysis/CaptureTracking.h for details).
- NumOmittedNonCaptured++;
- continue;
- }
- All.push_back(I);
- }
- Local.clear();
-}
-
-
-bool CDSPass::instrumentLoadOrStore(Instruction *I,
- const DataLayout &DL) {
- IRBuilder<> IRB(I);
- bool IsWrite = isa<StoreInst>(*I);
- Value *Addr = IsWrite
- ? cast<StoreInst>(I)->getPointerOperand()
- : cast<LoadInst>(I)->getPointerOperand();
-
- // swifterror memory addresses are mem2reg promoted by instruction selection.
- // As such they cannot have regular uses like an instrumentation function and
- // it makes no sense to track them as memory.
- if (Addr->isSwiftError())
- return false;
-
- int Idx = getMemoryAccessFuncIndex(Addr, DL);
-
-
-// not supported by CDS yet
-/* if (IsWrite && isVtableAccess(I)) {
- LLVM_DEBUG(dbgs() << " VPTR : " << *I << "\n");
- Value *StoredValue = cast<StoreInst>(I)->getValueOperand();
- // StoredValue may be a vector type if we are storing several vptrs at once.
- // In this case, just take the first element of the vector since this is
- // enough to find vptr races.
- if (isa<VectorType>(StoredValue->getType()))
- StoredValue = IRB.CreateExtractElement(
- StoredValue, ConstantInt::get(IRB.getInt32Ty(), 0));
- if (StoredValue->getType()->isIntegerTy())
- StoredValue = IRB.CreateIntToPtr(StoredValue, IRB.getInt8PtrTy());
- // Call TsanVptrUpdate.
- IRB.CreateCall(TsanVptrUpdate,
- {IRB.CreatePointerCast(Addr, IRB.getInt8PtrTy()),
- IRB.CreatePointerCast(StoredValue, IRB.getInt8PtrTy())});
- NumInstrumentedVtableWrites++;
- return true;
- }
-
- if (!IsWrite && isVtableAccess(I)) {
- IRB.CreateCall(TsanVptrLoad,
- IRB.CreatePointerCast(Addr, IRB.getInt8PtrTy()));
- NumInstrumentedVtableReads++;
- return true;
- }
-*/
-
- Value *OnAccessFunc = nullptr;
- OnAccessFunc = IsWrite ? CDSStore[Idx] : CDSLoad[Idx];
-
- Type *ArgType = IRB.CreatePointerCast(Addr, Addr->getType())->getType();
-
- if ( ArgType != Int8PtrTy && ArgType != Int16PtrTy &&
- ArgType != Int32PtrTy && ArgType != Int64PtrTy ) {
- //errs() << "A load or store of type ";
- //errs() << *ArgType;
- //errs() << " is passed in\n";
- return false; // if other types of load or stores are passed in
- }
- IRB.CreateCall(OnAccessFunc, IRB.CreatePointerCast(Addr, Addr->getType()));
- if (IsWrite) NumInstrumentedWrites++;
- else NumInstrumentedReads++;
- return true;
-}
-
-bool CDSPass::instrumentAtomic(Instruction * I, const DataLayout &DL) {
- IRBuilder<> IRB(I);
- // LLVMContext &Ctx = IRB.getContext();
-
- if (auto *CI = dyn_cast<CallInst>(I)) {
- return instrumentAtomicCall(CI, DL);
- }
-
- Value *position = getPosition(I, IRB);
-
- if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
- Value *Addr = LI->getPointerOperand();
- int Idx=getMemoryAccessFuncIndex(Addr, DL);
- int atomic_order_index = getAtomicOrderIndex(LI->getOrdering());
- Value *order = ConstantInt::get(OrdTy, atomic_order_index);
- Value *args[] = {Addr, order, position};
- Instruction* funcInst=CallInst::Create(CDSAtomicLoad[Idx], args);
- ReplaceInstWithInst(LI, funcInst);
- } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
- Value *Addr = SI->getPointerOperand();
- int Idx=getMemoryAccessFuncIndex(Addr, DL);
- int atomic_order_index = getAtomicOrderIndex(SI->getOrdering());
- Value *val = SI->getValueOperand();
- Value *order = ConstantInt::get(OrdTy, atomic_order_index);
- Value *args[] = {Addr, val, order, position};
- Instruction* funcInst=CallInst::Create(CDSAtomicStore[Idx], args);
- ReplaceInstWithInst(SI, funcInst);
- } else if (AtomicRMWInst *RMWI = dyn_cast<AtomicRMWInst>(I)) {
- Value *Addr = RMWI->getPointerOperand();
- int Idx=getMemoryAccessFuncIndex(Addr, DL);
- int atomic_order_index = getAtomicOrderIndex(RMWI->getOrdering());
- Value *val = RMWI->getValOperand();
- Value *order = ConstantInt::get(OrdTy, atomic_order_index);
- Value *args[] = {Addr, val, order, position};
- Instruction* funcInst = CallInst::Create(CDSAtomicRMW[RMWI->getOperation()][Idx], args);
- ReplaceInstWithInst(RMWI, funcInst);
- } else if (AtomicCmpXchgInst *CASI = dyn_cast<AtomicCmpXchgInst>(I)) {
- IRBuilder<> IRB(CASI);
-
- Value *Addr = CASI->getPointerOperand();
- int Idx=getMemoryAccessFuncIndex(Addr, DL);
-
- const unsigned ByteSize = 1U << Idx;
- const unsigned BitSize = ByteSize * 8;
- Type *Ty = Type::getIntNTy(IRB.getContext(), BitSize);
- Type *PtrTy = Ty->getPointerTo();
-
- Value *CmpOperand = IRB.CreateBitOrPointerCast(CASI->getCompareOperand(), Ty);
- Value *NewOperand = IRB.CreateBitOrPointerCast(CASI->getNewValOperand(), Ty);
-
- int atomic_order_index_succ = getAtomicOrderIndex(CASI->getSuccessOrdering());
- int atomic_order_index_fail = getAtomicOrderIndex(CASI->getFailureOrdering());
- Value *order_succ = ConstantInt::get(OrdTy, atomic_order_index_succ);
- Value *order_fail = ConstantInt::get(OrdTy, atomic_order_index_fail);
-
- Value *Args[] = {IRB.CreatePointerCast(Addr, PtrTy),
- CmpOperand, NewOperand,
- order_succ, order_fail, position};
-
- CallInst *funcInst = IRB.CreateCall(CDSAtomicCAS_V1[Idx], Args);
- Value *Success = IRB.CreateICmpEQ(funcInst, CmpOperand);
-
- Value *OldVal = funcInst;
- Type *OrigOldValTy = CASI->getNewValOperand()->getType();
- if (Ty != OrigOldValTy) {
- // The value is a pointer, so we need to cast the return value.
- OldVal = IRB.CreateIntToPtr(funcInst, OrigOldValTy);
- }
-
- Value *Res =
- IRB.CreateInsertValue(UndefValue::get(CASI->getType()), OldVal, 0);
- Res = IRB.CreateInsertValue(Res, Success, 1);
-
- I->replaceAllUsesWith(Res);
- I->eraseFromParent();
- } else if (FenceInst *FI = dyn_cast<FenceInst>(I)) {
- int atomic_order_index = getAtomicOrderIndex(FI->getOrdering());
- Value *order = ConstantInt::get(OrdTy, atomic_order_index);
- Value *Args[] = {order, position};
-
- CallInst *funcInst = CallInst::Create(CDSAtomicThreadFence, Args);
- ReplaceInstWithInst(FI, funcInst);
-// errs() << "Thread Fences replaced\n";
- }
- return true;
-}
-