function that returns source line number
[c11llvm.git] / CDSPass.cpp
index 9158baef37e6d41cc8e0bb82003c08995f95a095..886621ff7f1e6ed51a15804201f9e141a1d778b0 100644 (file)
@@ -1,4 +1,4 @@
-//===-- CdsPass.cpp - xxx -------------------------------===//
+//===-- CDSPass.cpp - xxx -------------------------------===//
 //
 //                     The LLVM Compiler Infrastructure
 //
@@ -25,7 +25,6 @@
 #include "llvm/Analysis/ValueTracking.h"
 #include "llvm/Analysis/CaptureTracking.h"
 #include "llvm/IR/BasicBlock.h"
-#include "llvm/IR/CFG.h"
 #include "llvm/IR/Function.h"
 #include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/Instructions.h"
 #include "llvm/Transforms/Utils/Local.h"
 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
 #include "llvm/Transforms/IPO/PassManagerBuilder.h"
-#include <list>
 #include <vector>
-// #include "llvm/Support/MathExtras.h"
 
 #define DEBUG_TYPE "CDS"
 using namespace llvm;
 
+#include "getPosition.hpp"
+
 #define FUNCARRAYSIZE 4
 
 STATISTIC(NumInstrumentedReads, "Number of instrumented reads");
@@ -76,13 +75,17 @@ Type * Int64PtrTy;
 
 Type * VoidTy;
 
-Constant * CdsLoad[FUNCARRAYSIZE];
-Constant * CdsStore[FUNCARRAYSIZE];
-Constant * CdsAtomicLoad[FUNCARRAYSIZE];
-Constant * CdsAtomicStore[FUNCARRAYSIZE];
-Constant * CdsAtomicRMW[AtomicRMWInst::LAST_BINOP + 1][FUNCARRAYSIZE];
-Constant * CdsAtomicCAS[FUNCARRAYSIZE];
-Constant * CdsAtomicThreadFence;
+Constant * CDSLoad[FUNCARRAYSIZE];
+Constant * CDSStore[FUNCARRAYSIZE];
+Constant * CDSAtomicInit[FUNCARRAYSIZE];
+Constant * CDSAtomicLoad[FUNCARRAYSIZE];
+Constant * CDSAtomicStore[FUNCARRAYSIZE];
+Constant * CDSAtomicRMW[AtomicRMWInst::LAST_BINOP + 1][FUNCARRAYSIZE];
+Constant * CDSAtomicCAS_V1[FUNCARRAYSIZE];
+Constant * CDSAtomicCAS_V2[FUNCARRAYSIZE];
+Constant * CDSAtomicThreadFence;
+
+bool start = false;
 
 int getAtomicOrderIndex(AtomicOrdering order){
   switch (order) {
@@ -105,13 +108,13 @@ int getAtomicOrderIndex(AtomicOrdering order){
 }
 
 int getTypeSize(Type* type) {
-  if (type==Int32PtrTy) {
-    return sizeof(int)*8;
-  } else if (type==Int8PtrTy) {
+  if (type == Int8PtrTy) {
     return sizeof(char)*8;
-  } else if (type==Int16PtrTy) {
+  } else if (type == Int16PtrTy) {
     return sizeof(short)*8;
-  } else if (type==Int64PtrTy) {
+  } else if (type == Int32PtrTy) {
+    return sizeof(int)*8;
+  } else if (type == Int64PtrTy) {
     return sizeof(long long int)*8;
   } else {
     return sizeof(void*)*8;
@@ -131,101 +134,34 @@ static int sizetoindex(int size) {
 }
 
 namespace {
-  struct CdsPass : public FunctionPass {
+  struct CDSPass : public FunctionPass {
     static char ID;
-    CdsPass() : FunctionPass(ID) {}
+    CDSPass() : FunctionPass(ID) {}
     bool runOnFunction(Function &F) override; 
 
   private:
     void initializeCallbacks(Module &M);
     bool instrumentLoadOrStore(Instruction *I, const DataLayout &DL);
-    bool instrumentAtomic(Instruction *I);
+    bool instrumentAtomic(Instruction *I, const DataLayout &DL);
+    bool instrumentAtomicCall(CallInst *CI, const DataLayout &DL);
     void chooseInstructionsToInstrument(SmallVectorImpl<Instruction *> &Local,
                                       SmallVectorImpl<Instruction *> &All,
                                       const DataLayout &DL);
     bool addrPointsToConstantData(Value *Addr);
+    int getMemoryAccessFuncIndex(Value *Addr, const DataLayout &DL);
   };
 }
 
-void CdsPass::initializeCallbacks(Module &M) {
-  LLVMContext &Ctx = M.getContext();
-
-  Int8Ty  = Type::getInt8Ty(Ctx);
-  Int16Ty = Type::getInt16Ty(Ctx);
-  Int32Ty = Type::getInt32Ty(Ctx);
-  Int64Ty = Type::getInt64Ty(Ctx);
-  OrdTy = Type::getInt32Ty(Ctx);
-
-  Int8PtrTy  = Type::getInt8PtrTy(Ctx);
-  Int16PtrTy = Type::getInt16PtrTy(Ctx);
-  Int32PtrTy = Type::getInt32PtrTy(Ctx);
-  Int64PtrTy = Type::getInt64PtrTy(Ctx);
-
-  VoidTy = Type::getVoidTy(Ctx);
-  
-
-  // Get the function to call from our untime library.
-  for (unsigned i = 0; i < FUNCARRAYSIZE; i++) {
-    const unsigned ByteSize = 1U << i;
-    const unsigned BitSize = ByteSize * 8;
-//    errs() << BitSize << "\n";
-    std::string ByteSizeStr = utostr(ByteSize);
-    std::string BitSizeStr = utostr(BitSize);
-
-    Type *Ty = Type::getIntNTy(Ctx, BitSize);
-    Type *PtrTy = Ty->getPointerTo();
-
-    // uint8_t cds_atomic_load8 (void * obj, int atomic_index)
-    // void cds_atomic_store8 (void * obj, int atomic_index, uint8_t val)
-    SmallString<32> LoadName("cds_load" + BitSizeStr);
-    SmallString<32> StoreName("cds_store" + BitSizeStr);
-    SmallString<32> AtomicLoadName("cds_atomic_load" + BitSizeStr);
-    SmallString<32> AtomicStoreName("cds_atomic_store" + BitSizeStr);
-
-//    CdsLoad[i]  = M.getOrInsertFunction(LoadName, Ty, PtrTy);
-//    CdsStore[i] = M.getOrInsertFunction(StoreName, VoidTy, PtrTy, Ty);
-    CdsLoad[i]  = M.getOrInsertFunction(LoadName, VoidTy, PtrTy);
-    CdsStore[i] = M.getOrInsertFunction(StoreName, VoidTy, PtrTy);
-    CdsAtomicLoad[i]  = M.getOrInsertFunction(AtomicLoadName, Ty, PtrTy, OrdTy);
-    CdsAtomicStore[i] = M.getOrInsertFunction(AtomicStoreName, VoidTy, PtrTy, OrdTy, Ty);
-
-    for (int op = AtomicRMWInst::FIRST_BINOP; op <= AtomicRMWInst::LAST_BINOP; ++op) {
-      CdsAtomicRMW[op][i] = nullptr;
-      std::string NamePart;
-
-      if (op == AtomicRMWInst::Xchg)
-        NamePart = "_exchange";
-      else if (op == AtomicRMWInst::Add) 
-        NamePart = "_fetch_add";
-      else if (op == AtomicRMWInst::Sub)
-        NamePart = "_fetch_sub";
-      else if (op == AtomicRMWInst::And)
-        NamePart = "_fetch_and";
-      else if (op == AtomicRMWInst::Or)
-        NamePart = "_fetch_or";
-      else if (op == AtomicRMWInst::Xor)
-        NamePart = "_fetch_xor";
-      else
-        continue;
-
-      SmallString<32> AtomicRMWName("cds_atomic" + NamePart + BitSizeStr);
-      CdsAtomicRMW[op][i] = M.getOrInsertFunction(AtomicRMWName, Ty, PtrTy, OrdTy, Ty);
-    }
-
-    // only supportes strong version
-    SmallString<32> AtomicCASName("cds_atomic_compare_exchange" + BitSizeStr);    
-    CdsAtomicCAS[i]   = M.getOrInsertFunction(AtomicCASName, Ty, PtrTy, Ty, Ty, OrdTy, OrdTy);
-  }
-
-  CdsAtomicThreadFence = M.getOrInsertFunction("cds_atomic_thread_fence", VoidTy, OrdTy);
-}
-
 static bool isVtableAccess(Instruction *I) {
   if (MDNode *Tag = I->getMetadata(LLVMContext::MD_tbaa))
     return Tag->isTBAAVtableAccess();
   return false;
 }
 
+#include "initializeCallbacks.hpp"
+#include "isAtomicCall.hpp"
+#include "instrumentAtomicCall.hpp"
+
 static bool shouldInstrumentReadWriteFromAddress(const Module *M, Value *Addr) {
   // Peel off GEPs and BitCasts.
   Addr = Addr->stripInBoundsOffsets();
@@ -257,7 +193,7 @@ static bool shouldInstrumentReadWriteFromAddress(const Module *M, Value *Addr) {
   return true;
 }
 
-bool CdsPass::addrPointsToConstantData(Value *Addr) {
+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();
@@ -278,50 +214,59 @@ bool CdsPass::addrPointsToConstantData(Value *Addr) {
   return false;
 }
 
-bool CdsPass::runOnFunction(Function &F) {
-  if (F.getName() == "main") 
+bool CDSPass::runOnFunction(Function &F) {
+  if (F.getName() == "main") {
     F.setName("user_main");
+    errs() << "main replaced by user_main\n";
+  }
 
-  initializeCallbacks( *F.getParent() );
+  if (true) {
+    initializeCallbacks( *F.getParent() );
 
-  SmallVector<Instruction*, 8> AllLoadsAndStores;
-  SmallVector<Instruction*, 8> LocalLoadsAndStores;
-  SmallVector<Instruction*, 8> AtomicAccesses;
+    SmallVector<Instruction*, 8> AllLoadsAndStores;
+    SmallVector<Instruction*, 8> LocalLoadsAndStores;
+    SmallVector<Instruction*, 8> AtomicAccesses;
 
-  std::vector<Instruction *> worklist;
+    std::vector<Instruction *> worklist;
 
-  bool Res = false;
-  const DataLayout &DL = F.getParent()->getDataLayout();
-  
-  errs() << "Before\n";
-  F.dump();
-
-  for (auto &B : F) {
-    for (auto &I : B) {
-      if ( (&I)->isAtomic() ) {
-        AtomicAccesses.push_back(&I);
-      } else if (isa<LoadInst>(I) || isa<StoreInst>(I)) {
-        LocalLoadsAndStores.push_back(&I);
+    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);
     }
-    chooseInstructionsToInstrument(LocalLoadsAndStores, AllLoadsAndStores, DL);
-  }
 
-  for (auto Inst : AllLoadsAndStores) {
-    Res |= instrumentLoadOrStore(Inst, DL);
-  }
+    for (auto Inst : AllLoadsAndStores) {
+//      Res |= instrumentLoadOrStore(Inst, DL);
+//      errs() << "load and store are replaced\n";
+    }
 
-  for (auto Inst : AtomicAccesses) {
-    Res |= instrumentAtomic(Inst);
-  } 
+    for (auto Inst : AtomicAccesses) {
+      Res |= instrumentAtomic(Inst, DL);
+    }
+
+    if (F.getName() == "user_main") {
+      // F.dump();
+    }
+
+  }
 
-  errs() << "After\n";
-  F.dump();
-  
   return false;
 }
 
-void CdsPass::chooseInstructionsToInstrument(
+void CDSPass::chooseInstructionsToInstrument(
     SmallVectorImpl<Instruction *> &Local, SmallVectorImpl<Instruction *> &All,
     const DataLayout &DL) {
   SmallPtrSet<Value*, 8> WriteTargets;
@@ -364,7 +309,7 @@ void CdsPass::chooseInstructionsToInstrument(
 }
 
 
-bool CdsPass::instrumentLoadOrStore(Instruction *I,
+bool CDSPass::instrumentLoadOrStore(Instruction *I,
                                             const DataLayout &DL) {
   IRBuilder<> IRB(I);
   bool IsWrite = isa<StoreInst>(*I);
@@ -381,7 +326,7 @@ bool CdsPass::instrumentLoadOrStore(Instruction *I,
   int size = getTypeSize(Addr->getType());
   int index = sizetoindex(size);
 
-//  not supported by Cds yet
+//  not supported by CDS yet
 /*  if (IsWrite && isVtableAccess(I)) {
     LLVM_DEBUG(dbgs() << "  VPTR : " << *I << "\n");
     Value *StoredValue = cast<StoreInst>(I)->getValueOperand();
@@ -410,61 +355,76 @@ bool CdsPass::instrumentLoadOrStore(Instruction *I,
 */
 
   Value *OnAccessFunc = nullptr;
-  OnAccessFunc = IsWrite ? CdsStore[index] : CdsLoad[index];
-
+  OnAccessFunc = IsWrite ? CDSStore[index] : CDSLoad[index];
+  
+  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) {
+// todo: replace getTypeSize with the getMemoryAccessFuncIndex
+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 (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};
+    Value *args[] = {ptr, val, order, position};
 
     int size=getTypeSize(ptr->getType());
     int index=sizetoindex(size);
 
-    Instruction* funcInst=CallInst::Create(CdsAtomicStore[index], args,"");
+    Instruction* funcInst=CallInst::Create(CDSAtomicStore[index], args);
     ReplaceInstWithInst(SI, funcInst);
-    errs() << "Store replaced\n";
+//    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};
+    Value *args[] = {ptr, order, position};
 
     int size=getTypeSize(ptr->getType());
     int index=sizetoindex(size);
 
-    Instruction* funcInst=CallInst::Create(CdsAtomicLoad[index], args, "");
+    Instruction* funcInst=CallInst::Create(CDSAtomicLoad[index], args);
     ReplaceInstWithInst(LI, funcInst);
-    errs() << "Load Replaced\n";
+//    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};
+    Value *args[] = {ptr, val, order, position};
 
     int size = getTypeSize(ptr->getType());
     int index = sizetoindex(size);
 
-    Instruction* funcInst = CallInst::Create(CdsAtomicRMW[RMWI->getOperation()][index], args, "");
+    Instruction* funcInst = CallInst::Create(CDSAtomicRMW[RMWI->getOperation()][index], args);
     ReplaceInstWithInst(RMWI, funcInst);
-    errs() << RMWI->getOperationName(RMWI->getOperation());
-    errs() << " replaced\n";
+//    errs() << RMWI->getOperationName(RMWI->getOperation());
+//    errs() << " replaced\n";
   } else if (AtomicCmpXchgInst *CASI = dyn_cast<AtomicCmpXchgInst>(I)) {
     IRBuilder<> IRB(CASI);
 
@@ -487,9 +447,9 @@ bool CdsPass::instrumentAtomic(Instruction * I) {
 
     Value *Args[] = {IRB.CreatePointerCast(Addr, PtrTy),
                      CmpOperand, NewOperand,
-                     order_succ, order_fail};
+                     order_succ, order_fail, position};
 
-    CallInst *funcInst = IRB.CreateCall(CdsAtomicCAS[index], Args);
+    CallInst *funcInst = IRB.CreateCall(CDSAtomicCAS_V1[index], Args);
     Value *Success = IRB.CreateICmpEQ(funcInst, CmpOperand);
 
     Value *OldVal = funcInst;
@@ -508,25 +468,40 @@ bool CdsPass::instrumentAtomic(Instruction * I) {
   } 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};
+    Value *Args[] = {order, position};
 
-    CallInst *funcInst = CallInst::Create(CdsAtomicThreadFence, Args);
+    CallInst *funcInst = CallInst::Create(CDSAtomicThreadFence, Args);
     ReplaceInstWithInst(FI, funcInst);
-    errs() << "Thread Fences replaced\n";
+//    errs() << "Thread Fences replaced\n";
   }
   return true;
 }
 
+int CDSPass::getMemoryAccessFuncIndex(Value *Addr,
+                                              const DataLayout &DL) {
+  Type *OrigPtrTy = Addr->getType();
+  Type *OrigTy = cast<PointerType>(OrigPtrTy)->getElementType();
+  assert(OrigTy->isSized());
+  uint32_t TypeSize = DL.getTypeStoreSizeInBits(OrigTy);
+  if (TypeSize != 8  && TypeSize != 16 &&
+      TypeSize != 32 && TypeSize != 64 && TypeSize != 128) {
+    // NumAccessesWithBadSize++;
+    // Ignore all unusual sizes.
+    return -1;
+  }
+  size_t Idx = countTrailingZeros(TypeSize / 8);
+  // assert(Idx < FUNCARRAYSIZE);
+  return Idx;
+}
 
 
-char CdsPass::ID = 0;
+char CDSPass::ID = 0;
 
 // Automatically enable the pass.
-// http://adriansampson.net/blog/clangpass.html
-static void registerCdsPass(const PassManagerBuilder &,
+static void registerCDSPass(const PassManagerBuilder &,
                          legacy::PassManagerBase &PM) {
-  PM.add(new CdsPass());
+  PM.add(new CDSPass());
 }
 static RegisterStandardPasses 
-       RegisterMyPass(PassManagerBuilder::EP_EarlyAsPossible,
-registerCdsPass);
\ No newline at end of file
+       RegisterMyPass(PassManagerBuilder::EP_OptimizerLast,
+registerCDSPass);