void DSWP::insertProduce(Instruction *u, Instruction *v, DType dtype, int channel, int uthread, int vthread) { Function *fun = module->getFunction("sync_produce"); vector<Value *> args; Instruction *insPos = u->getNextNode(); if (insPos == NULL) { error("here cannot be null"); } //if (isa<BranchInst>(u)) { // error("I don't know how do deal with it"); // return; //} if (dtype == REG) { // register dep // cast the value to something that the communication guy likes CastInst *cast; if (u->getType()->isIntegerTy()) { cast = new ZExtInst(u, eleType, u->getName().str() + "_64"); } else if (u->getType()->isFloatingPointTy()) { if (u->getType()->isFloatTy()) { cout << "WARNING: float sucks?"; } cast = new BitCastInst(u, eleType, u->getName().str() + "_64"); } else if (u->getType()->isPointerTy()){ cast = new PtrToIntInst(u, eleType, u->getName().str() + "_64"); } else { error("what's the hell type"); } cast->insertBefore(insPos); args.push_back(cast); /* TODO: for true memory dependences, need to send anything or just sync? } else if (dtype == DTRUE) { // true dep error("check mem dep!!"); StoreInst *store = dyn_cast<StoreInst>(u); if (store == NULL) { error("not true dependency!"); } BitCastInst *cast = new BitCastInst(store->getOperand(0), Type::getInt8PtrTy(*context), u->getName().str() + "_ptr"); cast->insertBefore(insPos); args.push_back(cast); */ } else { // others // just send a dummy value for synchronization args.push_back(Constant::getNullValue(Type::getInt64Ty(*context))); } // channel ID args.push_back(ConstantInt::get(Type::getInt32Ty(*context), channel)); // make the actual call CallInst *call = CallInst::Create(fun, args, "", insPos); }
void Transformer4Trace::transformPthreadCondSignal(Module* module, CallInst* call, AliasAnalysis& AA) { Value * val0 = call->getArgOperand(0); Value * val1 = call->getArgOperand(1); int svIdx0 = this->getValueIndex(module, val0, AA); int svIdx1 = this->getValueIndex(module, val1, AA); if (svIdx0 == -1 && svIdx1 == -1) return; CastInst* cond = CastInst::CreatePointerCast(val0, Type::getIntNPtrTy(module->getContext(),POINTER_BIT_SIZE)); cond->insertBefore(call); CastInst* mut = CastInst::CreatePointerCast(val1, Type::getIntNPtrTy(module->getContext(),POINTER_BIT_SIZE)); mut->insertBefore(call); Value* lnval = getOtInsertLineNumberValue(module, call); this->insertCallInstBefore(call, F_prenotify, cond, mut, lnval, getOrInsertSrcFileNameValue(module, call), NULL); this->insertCallInstAfter(call, F_notify, cond, mut, lnval, getOrInsertSrcFileNameValue(module, call), NULL); }
void Transformer4Trace::transformMemCpyMov(Module* module, CallInst* call, AliasAnalysis& AA) { Value* lnval = getOtInsertLineNumberValue(module, call); Value * dst = call->getArgOperand(0); Value * src = call->getArgOperand(1); int svIdx_dst = this->getValueIndex(module, dst, AA); int svIdx_src = this->getValueIndex(module, src, AA); if (svIdx_dst == -1 && svIdx_src == -1) { return; } else if (svIdx_dst != -1 && svIdx_src != -1) { CastInst* d = CastInst::CreatePointerCast(dst, Type::getIntNPtrTy(module->getContext(),POINTER_BIT_SIZE)); d->insertBefore(call); CastInst* s = CastInst::CreatePointerCast(src, Type::getIntNPtrTy(module->getContext(),POINTER_BIT_SIZE)); s->insertBefore(call); if (svIdx_dst != svIdx_src) { insertCallInstBefore(call, F_prestore, d, lnval, getOrInsertSrcFileNameValue(module, call), NULL); insertCallInstAfter(call, F_store, d, lnval, getOrInsertSrcFileNameValue(module, call), NULL); insertCallInstBefore(call, F_preload, s, lnval, getOrInsertSrcFileNameValue(module, call), NULL); insertCallInstAfter(call, F_load, s, lnval, getOrInsertSrcFileNameValue(module, call), NULL); } else { insertCallInstBefore(call, F_prestore, d, lnval, getOrInsertSrcFileNameValue(module, call), NULL); insertCallInstAfter(call, F_store, d, lnval, getOrInsertSrcFileNameValue(module, call), NULL); } } else if (svIdx_dst != -1) { CastInst* d = CastInst::CreatePointerCast(dst, Type::getIntNPtrTy(module->getContext(),POINTER_BIT_SIZE)); d->insertBefore(call); insertCallInstBefore(call, F_prestore, d, lnval, getOrInsertSrcFileNameValue(module, call), NULL); insertCallInstAfter(call, F_store, d, lnval, getOrInsertSrcFileNameValue(module, call), NULL); } else { CastInst* s = CastInst::CreatePointerCast(src, Type::getIntNPtrTy(module->getContext(),POINTER_BIT_SIZE)); s->insertBefore(call); insertCallInstBefore(call, F_preload, s, lnval, getOrInsertSrcFileNameValue(module, call), NULL); insertCallInstAfter(call, F_load, s, lnval, getOrInsertSrcFileNameValue(module, call), NULL); } }
void Transformer4Trace::transformLoadInst(Module* module, LoadInst* inst, AliasAnalysis& AA) { Value * val = inst->getOperand(0); int svIdx = this->getValueIndex(module, val, AA); if (svIdx == -1) return; CastInst* c = CastInst::CreatePointerCast(val, Type::getIntNPtrTy(module->getContext(),POINTER_BIT_SIZE)); c->insertBefore(inst); Value* lnval = getOtInsertLineNumberValue(module, inst); this->insertCallInstBefore(inst, F_preload, c, lnval, getOrInsertSrcFileNameValue(module, inst), NULL); this->insertCallInstAfter(inst, F_load, c, lnval, getOrInsertSrcFileNameValue(module, inst), NULL); }
void Transformer4Trace::transformMemSet(Module* module, CallInst* call, AliasAnalysis& AA) { Value* lnval = getOtInsertLineNumberValue(module, call); Value * val = call->getArgOperand(0); int svIdx = this->getValueIndex(module, val, AA); if (svIdx == -1) return; CastInst* c = CastInst::CreatePointerCast(val, Type::getIntNPtrTy(module->getContext(),POINTER_BIT_SIZE)); c->insertBefore(call); insertCallInstBefore(call, F_prestore, c, lnval, getOrInsertSrcFileNameValue(module, call), NULL); insertCallInstAfter(call, F_store, c, lnval, getOrInsertSrcFileNameValue(module, call), NULL); }
void Transformer4Trace::transformOtherFunctionCalls(Module* module, CallInst* call, AliasAnalysis& AA) { Value* lnval = getOtInsertLineNumberValue(module, call); for (unsigned i = 0; i < call->getNumArgOperands(); i++) { Value * arg = call->getArgOperand(i); CastInst* c = NULL; if (arg->getType()->isPointerTy()) { c = CastInst::CreatePointerCast(arg, Type::getIntNPtrTy(module->getContext(),POINTER_BIT_SIZE)); c->insertBefore(call); } else { continue; } int svIdx = this->getValueIndex(module, arg, AA); if (svIdx != -1) { insertCallInstBefore(call, F_prestore, c, lnval, getOrInsertSrcFileNameValue(module, call), NULL); insertCallInstBefore(call, F_store, c, lnval, getOrInsertSrcFileNameValue(module, call), NULL); } } }
/** * Inserts an argument. * @param rw_newInstr rewrite rule - new instruction * @param I instruction * @param CalleeF function to be called * @param variables map of found parameters from config * @param where position of the placement of the new instruction * @return a vector of arguments for the call that is to be inserted * and a pointer to the instruction after/before the new call * is going to be inserted (it is either I or some newly added * argument) */ tuple<vector<Value *>, Instruction*> InsertArgument(InstrumentInstruction rw_newInstr, Instruction *I, Function* CalleeF, const map <string, Value*>& variables, InstrumentPlacement where) { std::vector<Value *> args; unsigned i = 0; Instruction* nI = I; for (const string& arg : rw_newInstr.parameters) { if (i == rw_newInstr.parameters.size() - 1) { break; } auto var = variables.find(arg); if (var == variables.end()) { // NOTE: in future think also about other types than ConstantInt int argInt; try { argInt = stoi(arg); LLVMContext &Context = getGlobalContext(); Value *intValue = ConstantInt::get(Type::getInt32Ty(Context), argInt); args.push_back(intValue); } catch (invalid_argument) { logger.write_error("Problem with instruction arguments: invalid argument."); } catch (out_of_range) { logger.write_error("Problem with instruction arguments: out of range."); } } else { unsigned argIndex = 0; for (Function::ArgumentListType::iterator sit=CalleeF->getArgumentList().begin(); sit != CalleeF->getArgumentList().end(); ++sit) { Value *argV = &*sit; if (i == argIndex) { if (argV->getType() != var->second->getType()) { //TODO other types? if (!var->second->getType()->isPtrOrPtrVectorTy() && !var->second->getType()->isIntegerTy()) { args.push_back(var->second); } else { CastInst *CastI; if (var->second->getType()->isPtrOrPtrVectorTy()) { CastI = CastInst::CreatePointerCast(var->second, argV->getType()); } else { CastI = CastInst::CreateIntegerCast(var->second, argV->getType(), true); //TODO do something about signed argument } if (Instruction *Inst = dyn_cast<Instruction>(var->second)) CloneMetadata(Inst, CastI); if (where == InstrumentPlacement::BEFORE) { // we want to insert before I, that is: // %c = cast ... // newInstr // I // // NOTE that we do not set nI in this case, // so that the new instruction that we will insert // is inserted before I (and after all arguments // we added here) CastI->insertBefore(I); } else { // we want to insert after I, that is: // I // %c = cast ... // newInstr // // --> we must update the nI, so that the new // instruction is inserted after the arguments CastI->insertAfter(I); nI = CastI; } args.push_back(CastI); } } else{ args.push_back(var->second); } break; } argIndex++; } } i++; } return make_tuple(args,nI); }
void DSWP::insertConsume(Instruction *u, Instruction *v, DType dtype, int channel, int uthread, int vthread) { Instruction *oldu = dyn_cast<Instruction>(newToOld[u]); Instruction *insPos = placeEquivalents[vthread][oldu]; if (insPos == NULL) { insPos = dyn_cast<Instruction>(instMap[vthread][oldu]); if (insPos == NULL) { error("can't insert nowhere"); } } // call sync_consume(channel) Function *fun = module->getFunction("sync_consume"); vector<Value *> args; args.push_back(ConstantInt::get(Type::getInt32Ty(*context), channel)); CallInst *call = CallInst::Create(fun, args, "c" + itoa(channel), insPos); if (dtype == REG) { CastInst *cast; string name = call->getName().str() + "_val"; if (u->getType()->isIntegerTy()) { cast = new TruncInst(call, u->getType(), name); } else if (u->getType()->isFloatingPointTy()) { if (u->getType()->isFloatTy()) error("cannot deal with double"); cast = new BitCastInst(call, u->getType(), name); } else if (u->getType()->isPointerTy()){ cast = new IntToPtrInst(call, u->getType(), name); } else { error("what's the hell type"); } cast->insertBefore(insPos); // replace the uses for (Instruction::use_iterator ui = oldu->use_begin(), ue = oldu->use_end(); ui != ue; ++ui) { Instruction *user = dyn_cast<Instruction>(*ui); if (user == NULL) { error("used by a non-instruction?"); } // make sure it's in the same function... if (user->getParent()->getParent() != v->getParent()->getParent()) { continue; } // call replaceUses so that it handles phi nodes map<Value *, Value *> reps; reps[oldu] = cast; replaceUses(user, reps); } } /* TODO: need to handle true memory dependences more than just syncing? else if (dtype == DTRUE) { //READ after WRITE error("check mem dep!!"); if (!isa<LoadInst>(v)) { error("not true dependency"); } BitCastInst *cast = new BitCastInst(call, v->getType(), call->getName().str() + "_ptr"); cast->insertBefore(v); // replace the v with 'cast' in v's thread: // (other thread with be dealed using dependence) for (Instruction::use_iterator ui = v->use_begin(), ue = v->use_end(); ui != ue; ui++) { Instruction *user = dyn_cast<Instruction>(*ui); if (user == NULL) { error("how could it be NULL"); } // int userthread = this->getNewInstAssigned(user); if (user->getParent()->getParent() != v->getParent()->getParent()) { continue; } for (unsigned i = 0; i < user->getNumOperands(); i++) { Value * op = user->getOperand(i); if (op == v) { user->setOperand(i, cast); } } } } */ else { // nothing to do } }
bool partition::runOnLoop(Loop* L, LPPassManager &LPM) { errs() << "*************************** Loop encountered: ************************" << '\n' << L->getHeader()->getName() << '\n'; if (function->getName() != "main") return false; IntegerType* int32Ty = Type::getInt32Ty(*context); IntegerType* int64Ty = Type::getInt64Ty(*context); PointerType* voidPtrTy = Type::getInt8PtrTy(*context); FunctionType* funcTy = FunctionType::get(int32Ty, false); Constant* func1_c; Function* func1; func1_c = module->getOrInsertFunction("func1", funcTy); func1 = cast<Function>(func1_c); Function* pro = module->getFunction("produce"); Function* con = module->getFunction("consume"); BasicBlock* func1EntryBlock = BasicBlock::Create(*context, "entry.func1", func1); AllocaInst* i_var = new AllocaInst(int32Ty, NULL, 4, "i", func1EntryBlock); Value* liveIn; BasicBlock *forCond, *forBody, *forInc; ValueToValueMapTy VMap; std::map<BasicBlock *, BasicBlock *> BlockMap; for (Loop::block_iterator BB = L->block_begin(), BBe = L->block_end(); BB != BBe; ++BB) { BasicBlock* func1Block = CloneBasicBlock(*BB, VMap, ".func1", func1); BlockMap[*BB] = func1Block; if ((*BB)->getName() == "for.cond") forCond = func1Block; if ((*BB)->getName() == "for.body") forBody = func1Block; if ((*BB)->getName() == "for.inc") forInc = func1Block; for (BasicBlock::iterator it = func1Block->begin(), ite = func1Block->end(); it != ite; ++it) { for (User::op_iterator oit = it->op_begin(), oite = it->op_end(); oit != oite; ++oit) { if (VMap[*oit] != NULL) { *oit = VMap[*oit]; } else { Constant* cons = dyn_cast<Constant>(*oit); BranchInst* br = dyn_cast<BranchInst>(it); if (cons == NULL && br == NULL) { liveIn = *oit; *oit = i_var; } } } } if ((*BB)->getName() == "for.body") { Instruction* term = (*BB)->getTerminator(); term->removeFromParent(); for (int i = 0; i < 7; i++) { (*BB)->back().eraseFromParent(); } term->insertAfter(&(*BB)->back()); (*BB)->front().eraseFromParent(); LoadInst* load = new LoadInst(liveIn, "", false, 4, term); std::vector<Value *> produce_args; CastInst* cast = CastInst::CreateIntegerCast(load, int64Ty, true); cast->insertAfter(load); produce_args.push_back(cast); ConstantInt* val = ConstantInt::get(int32Ty, (uint32_t) 3); produce_args.push_back(val); CallInst::Create(pro, ArrayRef<Value*>(produce_args), "", term); produce_args.pop_back(); val = ConstantInt::get(int32Ty, (uint32_t) 2); produce_args.push_back(val); CallInst::Create(pro, ArrayRef<Value*>(produce_args), "", term); } } // set branch instructions to restructure the CFG in created function BasicBlock* func1EndBlock = BasicBlock::Create(*context, "if.end.func1", func1); BasicBlock* garbageBB = BasicBlock::Create(*context, "garbage", func1); ConstantInt* retVal_g = ConstantInt::get(int32Ty, (uint32_t) 0); ReturnInst* ret_g = ReturnInst::Create(*context, retVal_g, garbageBB); for (Function::iterator fit = func1->begin(), fite = func1->end(); fit != fite; ++fit) { if (fit->getTerminator() == NULL || fit->getName() == "garbage") continue; BranchInst* br = dyn_cast<BranchInst>(fit->getTerminator()); int numSuccessors = br->getNumSuccessors(); for (int i = 0; i < numSuccessors; i++) { BasicBlock* successor = br->getSuccessor(i); if (BlockMap[successor] != NULL) { br->setSuccessor(i, BlockMap[successor]); } else { br->setSuccessor(i, func1EndBlock); } } /* if (fit->getName() == "for.body.func1") { for (int i = 0; i < 4; i++) { BasicBlock::iterator it = fit->begin(); it->moveBefore(ret_g); } } */ } garbageBB->eraseFromParent(); BranchInst* br = dyn_cast<BranchInst>(forBody->getTerminator()); br->setSuccessor(0, forCond); forInc->eraseFromParent(); // Create return instruction for func1EndBlock and set a branch from loop header to func1EndBlock ConstantInt* retVal = ConstantInt::get(int32Ty, (uint32_t) 0); ReturnInst* ret1 = ReturnInst::Create(*context, retVal, func1EndBlock); BasicBlock* loopHeader = BlockMap.at(L->getHeader()); BranchInst* brInst = BranchInst::Create(loopHeader, func1EntryBlock); // add produce function call std::vector<Value *> produce_args; ConstantInt* val = ConstantInt::get(int64Ty, (uint64_t) 0); produce_args.push_back(val); val = ConstantInt::get(int32Ty, (uint32_t) 5); produce_args.push_back(val); CallInst::Create(pro, ArrayRef<Value*>(produce_args), "", func1EndBlock->getTerminator()); // add consume function call int q_id = 2; for (Value::use_iterator uit = i_var->use_begin(), uite = i_var->use_end(); uit != uite; ++uit) { std::vector<Value *> consume_args; ConstantInt* val = ConstantInt::get(int32Ty, (uint32_t) q_id); consume_args.push_back(val); CallInst* call = CallInst::Create(con, ArrayRef<Value*>(consume_args)); Instruction* inst = dyn_cast<Instruction>(*uit); call->insertAfter(inst); CastInst* cast = CastInst::CreateIntegerCast(call, int32Ty, true); cast->insertAfter(call); (*uit)->replaceAllUsesWith(cast); inst->eraseFromParent(); q_id++; } i_var->eraseFromParent(); // add produce and consume function calls to main thread // transmit the function pointer to created function by a produce call BasicBlock* loopPreheader = L->getLoopPreheader(); produce_args.clear(); CastInst* cast = CastInst::CreatePointerCast(func1, int64Ty); cast->insertBefore(loopPreheader->getTerminator()); produce_args.push_back(cast); val = ConstantInt::get(int32Ty, (uint32_t) 0); produce_args.push_back(val); CallInst::Create(pro, ArrayRef<Value*>(produce_args), "", loopPreheader->getTerminator()); // transmit induction variable to created function by a produce call Instruction* load = &L->getHeader()->front(); produce_args.clear(); cast = CastInst::CreateIntegerCast(load, int64Ty, true); cast->insertAfter(load); produce_args.push_back(cast); val = ConstantInt::get(int32Ty, (uint32_t) 4); produce_args.push_back(val); CallInst::Create(pro, ArrayRef<Value*>(produce_args))->insertAfter(cast); return true; }