-bool CdsPass::instrumentAtomic(Instruction * I) {
- IRBuilder<> IRB(I);
- // LLVMContext &Ctx = IRB.getContext();
-
- if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
- int atomic_order_index = getAtomicOrderIndex(SI->getOrdering());
-
- Value *val = SI->getValueOperand();
- Value *ptr = SI->getPointerOperand();
- Value *order = ConstantInt::get(OrdTy, atomic_order_index);
- Value *args[] = {ptr, order, val};
-
- int size=getTypeSize(ptr->getType());
- int index=sizetoindex(size);
-
- Instruction* funcInst=CallInst::Create(CdsAtomicStore[index], args,"");
- ReplaceInstWithInst(SI, funcInst);
- errs() << "Store replaced\n";
- } else if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
- int atomic_order_index = getAtomicOrderIndex(LI->getOrdering());
-
- Value *ptr = LI->getPointerOperand();
- Value *order = ConstantInt::get(OrdTy, atomic_order_index);
- Value *args[] = {ptr, order};
-
- int size=getTypeSize(ptr->getType());
- int index=sizetoindex(size);
-
- Instruction* funcInst=CallInst::Create(CdsAtomicLoad[index], args, "");
- ReplaceInstWithInst(LI, funcInst);
- errs() << "Load Replaced\n";
- } else if (AtomicRMWInst *RMWI = dyn_cast<AtomicRMWInst>(I)) {
- int atomic_order_index = getAtomicOrderIndex(RMWI->getOrdering());
-
- Value *val = RMWI->getValOperand();
- Value *ptr = RMWI->getPointerOperand();
- Value *order = ConstantInt::get(OrdTy, atomic_order_index);
- Value *args[] = {ptr, order, val};
-
- int size = getTypeSize(ptr->getType());
- int index = sizetoindex(size);
-
- Instruction* funcInst = CallInst::Create(CdsAtomicRMW[RMWI->getOperation()][index], args, "");
- ReplaceInstWithInst(RMWI, funcInst);
- errs() << RMWI->getOperationName(RMWI->getOperation());
- errs() << " replaced\n";
- } else if (AtomicCmpXchgInst *CASI = dyn_cast<AtomicCmpXchgInst>(I)) {
- IRBuilder<> IRB(CASI);
-
- Value *Addr = CASI->getPointerOperand();
-
- int size = getTypeSize(Addr->getType());
- int index = sizetoindex(size);
- const unsigned ByteSize = 1U << index;
- 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};
-
- CallInst *funcInst = IRB.CreateCall(CdsAtomicCAS[index], 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};
-
- CallInst *funcInst = CallInst::Create(CdsAtomicThreadFence, Args);
- ReplaceInstWithInst(FI, funcInst);
- errs() << "Thread Fences replaced\n";
- }
- return true;
+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()) {
+ /**
+ * TODO: instrument the following case
+ * mcs-lock.h
+ * std::atomic<struct T *> m_tail;
+ * struct T * me;
+ * struct T * pred = m_tail.exchange(me, memory_order_*);
+ */
+ 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);
+
+ return true;
+ }
+
+ /* 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;