#include "llvm/ADT/SmallString.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/Analysis/CaptureTracking.h"
+#include "llvm/Analysis/LoopInfo.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/EscapeEnumerator.h"
-// #include "llvm/Transforms/Utils/ModuleUtils.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include <vector>
using namespace llvm;
+#define CDS_DEBUG
#define DEBUG_TYPE "CDS"
#include <llvm/IR/DebugLoc.h>
-Value *getPosition( Instruction * I, IRBuilder <> IRB, bool print = false)
+Value *getPosition( Instruction * I, IRBuilder <> &IRB, bool print = false)
{
const DebugLoc & debug_location = I->getDebugLoc ();
std::string position_string;
return IRB.CreateGlobalStringPtr (position_string);
}
+static inline bool checkSignature(Function * func, Value * args[]) {
+ FunctionType * FType = func->getFunctionType();
+ for (unsigned i = 0 ; i < FType->getNumParams(); i++) {
+ if (FType->getParamType(i) != args[i]->getType()) {
+#ifdef CDS_DEBUG
+ errs() << "expects: " << *FType->getParamType(i)
+ << "\tbut receives: " << *args[i]->getType() << "\n";
+#endif
+ return false;
+ }
+ }
+
+ return true;
+}
+
STATISTIC(NumInstrumentedReads, "Number of instrumented reads");
STATISTIC(NumInstrumentedWrites, "Number of instrumented writes");
STATISTIC(NumOmittedReadsBeforeWrite,
switch (order) {
case AtomicOrdering::Monotonic:
return (int)AtomicOrderingCABI::relaxed;
- // case AtomicOrdering::Consume: // not specified yet
- // return AtomicOrderingCABI::consume;
+ //case AtomicOrdering::Consume: // not specified yet
+ // return AtomicOrderingCABI::consume;
case AtomicOrdering::Acquire:
return (int)AtomicOrderingCABI::acquire;
case AtomicOrdering::Release:
/* The original function checkSanitizerInterfaceFunction was defined
* in llvm/Transforms/Utils/ModuleUtils.h
*/
-static Function * checkCDSPassInterfaceFunction(Constant *FuncOrBitcast) {
+static Function * checkCDSPassInterfaceFunction(Value *FuncOrBitcast) {
if (isa<Function>(FuncOrBitcast))
return cast<Function>(FuncOrBitcast);
FuncOrBitcast->print(errs());
- errs() << '\n';
+ errs() << "\n";
std::string Err;
raw_string_ostream Stream(Err);
Stream << "CDSPass interface function redefined: " << *FuncOrBitcast;
bool instrumentLoadOrStore(Instruction *I, const DataLayout &DL);
bool instrumentVolatile(Instruction *I, const DataLayout &DL);
bool instrumentMemIntrinsic(Instruction *I);
- bool isAtomicCall(Instruction *I);
bool instrumentAtomic(Instruction *I, const DataLayout &DL);
- bool instrumentAtomicCall(CallInst *CI, const DataLayout &DL);
+ bool shouldInstrumentBeforeAtomics(Instruction *I);
void chooseInstructionsToInstrument(SmallVectorImpl<Instruction *> &Local,
SmallVectorImpl<Instruction *> &All,
const DataLayout &DL);
CDSFuncEntry = checkCDSPassInterfaceFunction(
M.getOrInsertFunction("cds_func_entry",
- Attr, VoidTy, Int8PtrTy));
+ Attr, VoidTy, Int8PtrTy).getCallee());
CDSFuncExit = checkCDSPassInterfaceFunction(
M.getOrInsertFunction("cds_func_exit",
- Attr, VoidTy, Int8PtrTy));
+ Attr, VoidTy, Int8PtrTy).getCallee());
// Get the function to call from our untime library.
for (unsigned i = 0; i < kNumberOfAccessSizes; i++) {
SmallString<32> AtomicStoreName("cds_atomic_store" + BitSizeStr);
CDSLoad[i] = checkCDSPassInterfaceFunction(
- M.getOrInsertFunction(LoadName, Attr, VoidTy, PtrTy));
+ M.getOrInsertFunction(LoadName, Attr, VoidTy, Int8PtrTy).getCallee());
CDSStore[i] = checkCDSPassInterfaceFunction(
- M.getOrInsertFunction(StoreName, Attr, VoidTy, PtrTy));
+ M.getOrInsertFunction(StoreName, Attr, VoidTy, Int8PtrTy).getCallee());
CDSVolatileLoad[i] = checkCDSPassInterfaceFunction(
M.getOrInsertFunction(VolatileLoadName,
- Attr, Ty, PtrTy, Int8PtrTy));
+ Attr, Ty, PtrTy, Int8PtrTy).getCallee());
CDSVolatileStore[i] = checkCDSPassInterfaceFunction(
M.getOrInsertFunction(VolatileStoreName,
- Attr, VoidTy, PtrTy, Ty, Int8PtrTy));
+ Attr, VoidTy, PtrTy, Ty, Int8PtrTy).getCallee());
CDSAtomicInit[i] = checkCDSPassInterfaceFunction(
M.getOrInsertFunction(AtomicInitName,
- Attr, VoidTy, PtrTy, Ty, Int8PtrTy));
+ Attr, VoidTy, PtrTy, Ty, Int8PtrTy).getCallee());
CDSAtomicLoad[i] = checkCDSPassInterfaceFunction(
M.getOrInsertFunction(AtomicLoadName,
- Attr, Ty, PtrTy, OrdTy, Int8PtrTy));
+ Attr, Ty, PtrTy, OrdTy, Int8PtrTy).getCallee());
CDSAtomicStore[i] = checkCDSPassInterfaceFunction(
M.getOrInsertFunction(AtomicStoreName,
- Attr, VoidTy, PtrTy, Ty, OrdTy, Int8PtrTy));
+ Attr, VoidTy, PtrTy, Ty, OrdTy, Int8PtrTy).getCallee());
- for (int op = AtomicRMWInst::FIRST_BINOP;
+ for (unsigned op = AtomicRMWInst::FIRST_BINOP;
op <= AtomicRMWInst::LAST_BINOP; ++op) {
CDSAtomicRMW[op][i] = nullptr;
std::string NamePart;
SmallString<32> AtomicRMWName("cds_atomic" + NamePart + BitSizeStr);
CDSAtomicRMW[op][i] = checkCDSPassInterfaceFunction(
M.getOrInsertFunction(AtomicRMWName,
- Attr, Ty, PtrTy, Ty, OrdTy, Int8PtrTy));
+ Attr, Ty, PtrTy, Ty, OrdTy, Int8PtrTy).getCallee());
}
// only supportes strong version
SmallString<32> AtomicCASName_V2("cds_atomic_compare_exchange" + BitSizeStr + "_v2");
CDSAtomicCAS_V1[i] = checkCDSPassInterfaceFunction(
M.getOrInsertFunction(AtomicCASName_V1,
- Attr, Ty, PtrTy, Ty, Ty, OrdTy, OrdTy, Int8PtrTy));
+ Attr, Ty, PtrTy, Ty, Ty, OrdTy, OrdTy, Int8PtrTy).getCallee());
CDSAtomicCAS_V2[i] = checkCDSPassInterfaceFunction(
M.getOrInsertFunction(AtomicCASName_V2,
- Attr, Int1Ty, PtrTy, PtrTy, Ty, OrdTy, OrdTy, Int8PtrTy));
+ Attr, Int1Ty, PtrTy, PtrTy, Ty, OrdTy, OrdTy, Int8PtrTy).getCallee());
}
CDSAtomicThreadFence = checkCDSPassInterfaceFunction(
- M.getOrInsertFunction("cds_atomic_thread_fence", Attr, VoidTy, OrdTy, Int8PtrTy));
+ M.getOrInsertFunction("cds_atomic_thread_fence", Attr, VoidTy, OrdTy, Int8PtrTy).getCallee());
MemmoveFn = checkCDSPassInterfaceFunction(
M.getOrInsertFunction("memmove", Attr, Int8PtrTy, Int8PtrTy,
- Int8PtrTy, IntPtrTy));
+ Int8PtrTy, IntPtrTy).getCallee());
MemcpyFn = checkCDSPassInterfaceFunction(
M.getOrInsertFunction("memcpy", Attr, Int8PtrTy, Int8PtrTy,
- Int8PtrTy, IntPtrTy));
+ Int8PtrTy, IntPtrTy).getCallee());
MemsetFn = checkCDSPassInterfaceFunction(
M.getOrInsertFunction("memset", Attr, Int8PtrTy, Int8PtrTy,
- Int32Ty, IntPtrTy));
+ Int32Ty, IntPtrTy).getCallee());
}
bool CDSPass::doInitialization(Module &M) {
return false;
}
+bool CDSPass::shouldInstrumentBeforeAtomics(Instruction * Inst) {
+ if (LoadInst *LI = dyn_cast<LoadInst>(Inst)) {
+ AtomicOrdering ordering = LI->getOrdering();
+ if ( isAtLeastOrStrongerThan(ordering, AtomicOrdering::Acquire) )
+ return true;
+ } else if (StoreInst *SI = dyn_cast<StoreInst>(Inst)) {
+ AtomicOrdering ordering = SI->getOrdering();
+ if ( isAtLeastOrStrongerThan(ordering, AtomicOrdering::Acquire) )
+ return true;
+ } else if (AtomicRMWInst *RMWI = dyn_cast<AtomicRMWInst>(Inst)) {
+ AtomicOrdering ordering = RMWI->getOrdering();
+ if ( isAtLeastOrStrongerThan(ordering, AtomicOrdering::Acquire) )
+ return true;
+ } else if (AtomicCmpXchgInst *CASI = dyn_cast<AtomicCmpXchgInst>(Inst)) {
+ AtomicOrdering ordering = CASI->getSuccessOrdering();
+ if ( isAtLeastOrStrongerThan(ordering, AtomicOrdering::Acquire) )
+ return true;
+ } else if (FenceInst *FI = dyn_cast<FenceInst>(Inst)) {
+ AtomicOrdering ordering = FI->getOrdering();
+ if ( isAtLeastOrStrongerThan(ordering, AtomicOrdering::Acquire) )
+ return true;
+ }
+
+ return false;
+}
+
void CDSPass::chooseInstructionsToInstrument(
SmallVectorImpl<Instruction *> &Local, SmallVectorImpl<Instruction *> &All,
const DataLayout &DL) {
Value *Addr = isa<StoreInst>(*I)
? cast<StoreInst>(I)->getPointerOperand()
: cast<LoadInst>(I)->getPointerOperand();
- if (isa<AllocaInst>(GetUnderlyingObject(Addr, DL)) &&
+ if (isa<AllocaInst>(getUnderlyingObject(Addr)) &&
!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
}*/
bool CDSPass::runOnFunction(Function &F) {
- if (F.getName() == "main") {
- F.setName("user_main");
- errs() << "main replaced by user_main\n";
- }
-
initializeCallbacks( *F.getParent() );
SmallVector<Instruction*, 8> AllLoadsAndStores;
SmallVector<Instruction*, 8> LocalLoadsAndStores;
for (auto &BB : F) {
for (auto &Inst : BB) {
- if ( (&Inst)->isAtomic() || isAtomicCall(&Inst) ) {
+ if ( (&Inst)->isAtomic() ) {
AtomicAccesses.push_back(&Inst);
HasAtomic = true;
+
+ if (shouldInstrumentBeforeAtomics(&Inst)) {
+ chooseInstructionsToInstrument(LocalLoadsAndStores, AllLoadsAndStores,
+ DL);
+ }
} else if (isa<LoadInst>(Inst) || isa<StoreInst>(Inst)) {
LoadInst *LI = dyn_cast<LoadInst>(&Inst);
StoreInst *SI = dyn_cast<StoreInst>(&Inst);
Res |= instrumentMemIntrinsic(Inst);
}
- // Only instrument functions that contain atomics or volatiles
+ // Instrument function entry and exit for functions containing atomics or volatiles
if (Res && ( HasAtomic || HasVolatile) ) {
IRBuilder<> IRB(F.getEntryBlock().getFirstNonPHI());
/* Unused for now
// 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;
+ return false;
int Idx = getMemoryAccessFuncIndex(Addr, DL);
if (Idx < 0)
return false;
-// 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 (IsWrite && isVtableAccess(I)) {
+ /* TODO
+ 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 ( ArgType != Int8PtrTy && ArgType != Int16PtrTy &&
- ArgType != Int32PtrTy && ArgType != Int64PtrTy ) {
- // if other types of load or stores are passed in
- return false;
+ if (!IsWrite && isVtableAccess(I)) {
+ /* TODO
+ IRB.CreateCall(TsanVptrLoad,
+ IRB.CreatePointerCast(Addr, IRB.getInt8PtrTy()));
+ NumInstrumentedVtableReads++;
+ */
+ return true;
}
- IRB.CreateCall(OnAccessFunc, IRB.CreatePointerCast(Addr, Addr->getType()));
+ // TODO: unaligned reads and writes
+ FunctionCallee OnAccessFunc = nullptr;
+ OnAccessFunc = IsWrite ? CDSStore[Idx] : CDSLoad[Idx];
+ IRB.CreateCall(OnAccessFunc, IRB.CreatePointerCast(Addr, IRB.getInt8PtrTy()));
if (IsWrite) NumInstrumentedWrites++;
else NumInstrumentedReads++;
return true;
Value *position = getPosition(I, IRB);
if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
- assert( LI->isVolatile() );
Value *Addr = LI->getPointerOperand();
int Idx=getMemoryAccessFuncIndex(Addr, DL);
if (Idx < 0)
return false;
+ const unsigned ByteSize = 1U << Idx;
+ const unsigned BitSize = ByteSize * 8;
+ Type *Ty = Type::getIntNTy(IRB.getContext(), BitSize);
+ Type *PtrTy = Ty->getPointerTo();
+ Value *Args[] = {IRB.CreatePointerCast(Addr, PtrTy), position};
- Value *args[] = {Addr, position};
- Instruction* funcInst = CallInst::Create(CDSVolatileLoad[Idx], args);
- ReplaceInstWithInst(LI, funcInst);
+ Type *OrigTy = cast<PointerType>(Addr->getType())->getElementType();
+ Value *C = IRB.CreateCall(CDSVolatileLoad[Idx], Args);
+ Value *Cast = IRB.CreateBitOrPointerCast(C, OrigTy);
+ I->replaceAllUsesWith(Cast);
} else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
- assert( SI->isVolatile() );
Value *Addr = SI->getPointerOperand();
int Idx=getMemoryAccessFuncIndex(Addr, DL);
if (Idx < 0)
return false;
-
- Value *val = SI->getValueOperand();
- Value *args[] = {Addr, val, position};
- Instruction* funcInst = CallInst::Create(CDSVolatileStore[Idx], args);
- ReplaceInstWithInst(SI, funcInst);
+ const unsigned ByteSize = 1U << Idx;
+ const unsigned BitSize = ByteSize * 8;
+ Type *Ty = Type::getIntNTy(IRB.getContext(), BitSize);
+ Type *PtrTy = Ty->getPointerTo();
+ Value *Args[] = {IRB.CreatePointerCast(Addr, PtrTy),
+ IRB.CreateBitOrPointerCast(SI->getValueOperand(), Ty),
+ position};
+ CallInst *C = CallInst::Create(CDSVolatileStore[Idx], Args);
+ ReplaceInstWithInst(I, C);
} else {
return false;
}
bool CDSPass::instrumentAtomic(Instruction * I, const DataLayout &DL) {
IRBuilder<> IRB(I);
- 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);
+ 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 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);
+ 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 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);
+ 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);
return true;
}
-bool CDSPass::isAtomicCall(Instruction *I) {
- if ( auto *CI = dyn_cast<CallInst>(I) ) {
- Function *fun = CI->getCalledFunction();
- if (fun == NULL)
- return false;
-
- StringRef funName = fun->getName();
-
- // TODO: come up with better rules for function name checking
- for (StringRef name : AtomicFuncNames) {
- if ( funName.contains(name) )
- return true;
- }
-
- for (StringRef PartialName : PartialAtomicFuncNames) {
- if (funName.contains(PartialName) &&
- funName.contains("atomic") )
- return true;
- }
- }
-
- return false;
-}
-
-bool CDSPass::instrumentAtomicCall(CallInst *CI, const DataLayout &DL) {
- IRBuilder<> IRB(CI);
- Function *fun = CI->getCalledFunction();
- StringRef funName = fun->getName();
- std::vector<Value *> parameters;
-
- User::op_iterator begin = CI->arg_begin();
- User::op_iterator end = CI->arg_end();
- for (User::op_iterator it = begin; it != end; ++it) {
- Value *param = *it;
- parameters.push_back(param);
- }
-
- // obtain source line number of the CallInst
- Value *position = getPosition(CI, IRB);
-
- // the pointer to the address is always the first argument
- Value *OrigPtr = parameters[0];
-
- int Idx = getMemoryAccessFuncIndex(OrigPtr, DL);
- if (Idx < 0)
- return false;
-
- const unsigned ByteSize = 1U << Idx;
- const unsigned BitSize = ByteSize * 8;
- Type *Ty = Type::getIntNTy(IRB.getContext(), BitSize);
- Type *PtrTy = Ty->getPointerTo();
-
- // atomic_init; args = {obj, order}
- if (funName.contains("atomic_init")) {
- Value *OrigVal = parameters[1];
-
- Value *ptr = IRB.CreatePointerCast(OrigPtr, PtrTy);
- Value *val;
- if (OrigVal->getType()->isPtrOrPtrVectorTy())
- val = IRB.CreatePointerCast(OrigVal, Ty);
- else
- val = IRB.CreateIntCast(OrigVal, Ty, true);
-
- Value *args[] = {ptr, val, position};
-
- Instruction* funcInst = CallInst::Create(CDSAtomicInit[Idx], args);
- ReplaceInstWithInst(CI, funcInst);
-
- return true;
- }
-
- // atomic_load; args = {obj, order}
- if (funName.contains("atomic_load")) {
- bool isExplicit = funName.contains("atomic_load_explicit");
-
- Value *ptr = IRB.CreatePointerCast(OrigPtr, PtrTy);
- Value *order;
- if (isExplicit)
- order = IRB.CreateBitOrPointerCast(parameters[1], OrdTy);
- else
- order = ConstantInt::get(OrdTy,
- (int) AtomicOrderingCABI::seq_cst);
- Value *args[] = {ptr, order, position};
-
- Instruction* funcInst = CallInst::Create(CDSAtomicLoad[Idx], args);
- ReplaceInstWithInst(CI, funcInst);
-
- return true;
- } else if (funName.contains("atomic") &&
- funName.contains("load") ) {
- // does this version of call always have an atomic order as an argument?
- Value *ptr = IRB.CreatePointerCast(OrigPtr, PtrTy);
- Value *order = IRB.CreateBitOrPointerCast(parameters[1], OrdTy);
- Value *args[] = {ptr, order, position};
-
- if (!CI->getType()->isPointerTy()) {
- return false;
- }
-
- CallInst *funcInst = IRB.CreateCall(CDSAtomicLoad[Idx], args);
- Value *RetVal = IRB.CreateIntToPtr(funcInst, CI->getType());
-
- CI->replaceAllUsesWith(RetVal);
- CI->eraseFromParent();
-
- return true;
- }
-
- // atomic_store; args = {obj, val, order}
- if (funName.contains("atomic_store")) {
- bool isExplicit = funName.contains("atomic_store_explicit");
- Value *OrigVal = parameters[1];
-
- Value *ptr = IRB.CreatePointerCast(OrigPtr, PtrTy);
- Value *val = IRB.CreatePointerCast(OrigVal, Ty);
- Value *order;
- if (isExplicit)
- order = IRB.CreateBitOrPointerCast(parameters[2], OrdTy);
- else
- order = ConstantInt::get(OrdTy,
- (int) AtomicOrderingCABI::seq_cst);
- Value *args[] = {ptr, val, order, position};
-
- Instruction* funcInst = CallInst::Create(CDSAtomicStore[Idx], args);
- ReplaceInstWithInst(CI, funcInst);
-
- return true;
- } else if (funName.contains("atomic") &&
- funName.contains("store") ) {
- // does this version of call always have an atomic order as an argument?
- Value *OrigVal = parameters[1];
-
- Value *ptr = IRB.CreatePointerCast(OrigPtr, PtrTy);
- Value *val;
- if (OrigVal->getType()->isPtrOrPtrVectorTy())
- val = IRB.CreatePointerCast(OrigVal, Ty);
- else
- val = IRB.CreateIntCast(OrigVal, Ty, true);
-
- Value *order = IRB.CreateBitOrPointerCast(parameters[2], OrdTy);
- Value *args[] = {ptr, val, order, position};
-
- Instruction* funcInst = CallInst::Create(CDSAtomicStore[Idx], args);
- ReplaceInstWithInst(CI, funcInst);
-
- return true;
- }
-
- // atomic_fetch_*; args = {obj, val, order}
- if (funName.contains("atomic_fetch_") ||
- funName.contains("atomic_exchange")) {
-
- /* TODO: implement stricter function name checking */
- if (funName.contains("non"))
- return false;
-
- bool isExplicit = funName.contains("_explicit");
- Value *OrigVal = parameters[1];
-
- int op;
- if ( funName.contains("_fetch_add") )
- op = AtomicRMWInst::Add;
- else if ( funName.contains("_fetch_sub") )
- op = AtomicRMWInst::Sub;
- else if ( funName.contains("_fetch_and") )
- op = AtomicRMWInst::And;
- else if ( funName.contains("_fetch_or") )
- op = AtomicRMWInst::Or;
- else if ( funName.contains("_fetch_xor") )
- op = AtomicRMWInst::Xor;
- else if ( funName.contains("atomic_exchange") )
- op = AtomicRMWInst::Xchg;
- else {
- errs() << "Unknown atomic read-modify-write operation\n";
- return false;
- }
-
- Value *ptr = IRB.CreatePointerCast(OrigPtr, PtrTy);
- Value *val;
- if (OrigVal->getType()->isPtrOrPtrVectorTy())
- val = IRB.CreatePointerCast(OrigVal, Ty);
- else
- val = IRB.CreateIntCast(OrigVal, Ty, true);
-
- Value *order;
- if (isExplicit)
- order = IRB.CreateBitOrPointerCast(parameters[2], OrdTy);
- else
- order = ConstantInt::get(OrdTy,
- (int) AtomicOrderingCABI::seq_cst);
- Value *args[] = {ptr, val, order, position};
-
- Instruction* funcInst = CallInst::Create(CDSAtomicRMW[op][Idx], args);
- ReplaceInstWithInst(CI, funcInst);
-
- return true;
- } else if (funName.contains("fetch")) {
- errs() << "atomic fetch captured. Not implemented yet. ";
- errs() << "See source file :";
- getPosition(CI, IRB, true);
- return false;
- } else if (funName.contains("exchange") &&
- !funName.contains("compare_exchange") ) {
- if (CI->getType()->isPointerTy()) {
- // Can not deal with this now
- errs() << "atomic exchange captured. Not implemented yet. ";
- errs() << "See source file :";
- getPosition(CI, IRB, true);
-
- return false;
- }
-
- Value *OrigVal = parameters[1];
-
- Value *ptr = IRB.CreatePointerCast(OrigPtr, PtrTy);
- Value *val;
- if (OrigVal->getType()->isPtrOrPtrVectorTy())
- val = IRB.CreatePointerCast(OrigVal, Ty);
- else
- val = IRB.CreateIntCast(OrigVal, Ty, true);
-
- Value *order = IRB.CreateBitOrPointerCast(parameters[2], OrdTy);
- Value *args[] = {ptr, val, order, position};
- int op = AtomicRMWInst::Xchg;
-
- Instruction* funcInst = CallInst::Create(CDSAtomicRMW[op][Idx], args);
- ReplaceInstWithInst(CI, funcInst);
- }
-
- /* atomic_compare_exchange_*;
- args = {obj, expected, new value, order1, order2}
- */
- if ( funName.contains("atomic_compare_exchange_") ) {
- bool isExplicit = funName.contains("_explicit");
-
- Value *Addr = IRB.CreatePointerCast(OrigPtr, PtrTy);
- Value *CmpOperand = IRB.CreatePointerCast(parameters[1], PtrTy);
- Value *NewOperand = IRB.CreateBitOrPointerCast(parameters[2], Ty);
-
- Value *order_succ, *order_fail;
- if (isExplicit) {
- order_succ = IRB.CreateBitOrPointerCast(parameters[3], OrdTy);
-
- if (parameters.size() > 4) {
- order_fail = IRB.CreateBitOrPointerCast(parameters[4], OrdTy);
- } else {
- /* The failure order is not provided */
- order_fail = order_succ;
- ConstantInt * order_succ_cast = dyn_cast<ConstantInt>(order_succ);
- int index = order_succ_cast->getSExtValue();
-
- order_fail = ConstantInt::get(OrdTy,
- AtomicCasFailureOrderIndex(index));
- }
- } else {
- order_succ = ConstantInt::get(OrdTy,
- (int) AtomicOrderingCABI::seq_cst);
- order_fail = ConstantInt::get(OrdTy,
- (int) AtomicOrderingCABI::seq_cst);
- }
-
- Value *args[] = {Addr, CmpOperand, NewOperand,
- order_succ, order_fail, position};
-
- Instruction* funcInst = CallInst::Create(CDSAtomicCAS_V2[Idx], args);
- ReplaceInstWithInst(CI, funcInst);
-
- return true;
- } else if ( funName.contains("compare_exchange_strong") ||
- funName.contains("compare_exchange_weak") ) {
- Value *Addr = IRB.CreatePointerCast(OrigPtr, PtrTy);
- Value *CmpOperand = IRB.CreatePointerCast(parameters[1], PtrTy);
- Value *NewOperand = IRB.CreateBitOrPointerCast(parameters[2], Ty);
-
- Value *order_succ, *order_fail;
- order_succ = IRB.CreateBitOrPointerCast(parameters[3], OrdTy);
-
- if (parameters.size() > 4) {
- order_fail = IRB.CreateBitOrPointerCast(parameters[4], OrdTy);
- } else {
- /* The failure order is not provided */
- order_fail = order_succ;
- ConstantInt * order_succ_cast = dyn_cast<ConstantInt>(order_succ);
- int index = order_succ_cast->getSExtValue();
-
- order_fail = ConstantInt::get(OrdTy,
- AtomicCasFailureOrderIndex(index));
- }
-
- Value *args[] = {Addr, CmpOperand, NewOperand,
- order_succ, order_fail, position};
- Instruction* funcInst = CallInst::Create(CDSAtomicCAS_V2[Idx], args);
- ReplaceInstWithInst(CI, funcInst);
-
- return true;
- }
-
- return false;
-}
-
int CDSPass::getMemoryAccessFuncIndex(Value *Addr,
const DataLayout &DL) {
Type *OrigPtrTy = Addr->getType();
return Idx;
}
-
char CDSPass::ID = 0;
// Automatically enable the pass.