ValueToValueMapTy* MCJITHelper::generateIdentityMapping(Function* F) { ValueToValueMapTy* VMap = new ValueToValueMapTy(); // arguments for (Function::arg_iterator argIt = F->arg_begin(), argEnd = F->arg_end(); argIt != argEnd; ++argIt) { (*VMap)[argIt] = argIt; } // TODO: metadata (also in the body?) for (Function::iterator bbIt = F->begin(), bbEnd = F->end(); bbIt != bbEnd; ++bbIt) { // basic blocks (*VMap)[bbIt] = bbIt; // TODO: BB.hasAddressTaken() ? for (BasicBlock::iterator insIt = bbIt->begin(), insEnd = bbIt->end(); insIt != insEnd; ++insIt) { // instructions (*VMap)[insIt] = insIt; /** Code adapted from MapValue() called by RemapInstruction() **/ // operators for (User::op_iterator opIt = insIt->op_begin(), opEnd = insIt->op_end(); opIt != opEnd; ++opIt) { Value* v = *opIt; ValueToValueMapTy::iterator I = VMap->find(v); if (I != VMap->end() && I->second) continue; // value already exists in VMap (*VMap)[v] = v; } } } return VMap; }
/// GlobalIsNeeded - the specific global value as needed, and /// recursively mark anything that it uses as also needed. void GlobalDCE::GlobalIsNeeded(GlobalValue *G) { // If the global is already in the set, no need to reprocess it. if (!AliveGlobals.insert(G)) return; if (GlobalVariable *GV = dyn_cast<GlobalVariable>(G)) { // If this is a global variable, we must make sure to add any global values // referenced by the initializer to the alive set. if (GV->hasInitializer()) MarkUsedGlobalsAsNeeded(GV->getInitializer()); } else if (GlobalAlias *GA = dyn_cast<GlobalAlias>(G)) { // The target of a global alias is needed. MarkUsedGlobalsAsNeeded(GA->getAliasee()); } else { // Otherwise this must be a function object. We have to scan the body of // the function looking for constants and global values which are used as // operands. Any operands of these types must be processed to ensure that // any globals used will be marked as needed. Function *F = cast<Function>(G); for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) for (User::op_iterator U = I->op_begin(), E = I->op_end(); U != E; ++U) if (GlobalValue *GV = dyn_cast<GlobalValue>(*U)) GlobalIsNeeded(GV); else if (Constant *C = dyn_cast<Constant>(*U)) MarkUsedGlobalsAsNeeded(C); } }
void HeterotbbTransform::copy_function (Function* NF, Function* F) { DenseMap<const Value*, Value *> ValueMap; // Get the names of the parameters for old function for(Function::arg_iterator FI = F->arg_begin(), FE=F->arg_end(), DI=NF->arg_begin(); FE!=FI; ++FI,++DI) { DI->setName(FI->getName()); ValueMap[FI]=DI; } for (Function::const_iterator BI=F->begin(),BE = F->end(); BI != BE; ++BI) { const BasicBlock &FBB = *BI; BasicBlock *NFBB = BasicBlock::Create(FBB.getContext(), "", NF); ValueMap[&FBB] = NFBB; if (FBB.hasName()) { NFBB->setName(FBB.getName()); //DEBUG(dbgs()<<NFBB->getName()<<"\n"); } for (BasicBlock::const_iterator II = FBB.begin(), IE = FBB.end(); II != IE; ++II) { Instruction *NFInst = II->clone(/*F->getContext()*/); if (II->hasName()) NFInst->setName(II->getName()); const Instruction *FInst = &(*II); rewrite_instruction((Instruction *)FInst, NFInst, ValueMap); NFBB->getInstList().push_back(NFInst); ValueMap[II] = NFInst; } } // Remap the instructions again to take care of forward jumps for (Function::iterator BB = NF->begin(), BE=NF->end(); BB != BE; ++ BB) { for (BasicBlock::iterator II = BB->begin(); II != BB->end(); ++II) { int opIdx = 0; //DEBUG(dbgs()<<*II<<"\n"); for (User::op_iterator i = II->op_begin(), e = II->op_end(); i != e; ++i, opIdx++) { Value *V = *i; if (ValueMap[V] != NULL) { II->setOperand(opIdx, ValueMap[V]); } } } } //NF->dump(); }
void HeterotbbTransform::gen_opt_code_per_f (Function* NF, Function* F) { // Get the names of the parameters for old function Function::arg_iterator FI = F->arg_begin(); Argument *classname = &*FI; FI++; Argument *numiters = &*FI; // Set the names of the parameters for new function Function::arg_iterator DestI = NF->arg_begin(); DestI->setName(classname->getName()); Argument *class_name = &(*DestI); //second argument DestI++; DestI->setName(numiters->getName()); Argument *num_iters = &(*DestI); #ifdef EXPLICIT_REWRITE DenseMap<const Value*, Value *> ValueMap; #else ValueToValueMapTy ValueMap; #endif #if EXPLICIT_REWRITE //get the old basic block and create a new one Function::const_iterator BI = F->begin(); const BasicBlock &FB = *BI; BasicBlock *NFBB = BasicBlock::Create(FB.getContext(), "", NF); if (FB.hasName()) { NFBB->setName(FB.getName()); //DEBUG(dbgs()<<FB.getName()<<"\n"); } ValueMap[&FB] = NFBB; ValueMap[numiters] = num_iters; //must create a new instruction which casts i32* back to the class name CastInst *StrucRevCast = CastInst::Create(Instruction::BitCast, class_name, classname->getType(), classname->getName(), NFBB); ValueMap[classname] = StrucRevCast; for (BasicBlock::const_iterator II = FB.begin(), IE = FB.end(); II != IE; ++II) { Instruction *NFInst = II->clone(/*F->getContext()*/); // DEBUG(dbgs()<<*II<<"\n"); if (II->hasName()) NFInst->setName(II->getName()); const Instruction *FInst = &(*II); rewrite_instruction((Instruction *)FInst, NFInst, ValueMap); NFBB->getInstList().push_back(NFInst); ValueMap[II] = NFInst; } BI++; for (Function::const_iterator /*BI=F->begin(),*/BE = F->end(); BI != BE; ++BI) { const BasicBlock &FBB = *BI; BasicBlock *NFBB = BasicBlock::Create(FBB.getContext(), "", NF); ValueMap[&FBB] = NFBB; if (FBB.hasName()) { NFBB->setName(FBB.getName()); //DEBUG(dbgs()<<NFBB->getName()<<"\n"); } for (BasicBlock::const_iterator II = FBB.begin(), IE = FBB.end(); II != IE; ++II) { Instruction *NFInst = II->clone(/*F->getContext()*/); if (II->hasName()) NFInst->setName(II->getName()); const Instruction *FInst = &(*II); rewrite_instruction((Instruction *)FInst, NFInst, ValueMap); NFBB->getInstList().push_back(NFInst); ValueMap[II] = NFInst; } } // Remap the instructions again to take care of forward jumps for (Function::iterator BB = NF->begin(), BE=NF->end(); BB != BE; ++ BB) { for (BasicBlock::iterator II = BB->begin(); II != BB->end(); ++II) { int opIdx = 0; //DEBUG(dbgs()<<*II<<"\n"); for (User::op_iterator i = II->op_begin(), e = II->op_end(); i != e; ++i, opIdx++) { Value *V = *i; if (ValueMap[V] != NULL) { II->setOperand(opIdx, ValueMap[V]); } } } } #else Function::const_iterator BI = F->begin(); const BasicBlock &FB = *BI; BasicBlock *NFBB = BasicBlock::Create(FB.getContext(), "", NF); if (FB.hasName()) { NFBB->setName(FB.getName()); } ValueMap[&FB] = NFBB; CastInst *StrucRevCast = CastInst::Create(Instruction::BitCast, class_name, classname->getType(), classname->getName(), NFBB); ValueMap[classname] = StrucRevCast; ValueMap[numiters] = num_iters; CloneFunctionWithExistingBBInto(NF, NFBB, F, ValueMap, ""); #endif }
bool CopyMinimizationPass::runOnFunction(Function& f) { CurrentFile::set(__FILE__); bool changed = false ; if (f.isDeclaration() || f.getDFFunction() == NULL) { return changed ; } std::vector<Node<DFBasicBlock*>*> graph; //We need to start with an acyclic graph to do retiming on - //the analyzeCopyPass conveniently provides a function that returns the //blocks reachable by the sink. These are the same blocks that the //detectLoopsPass goes through, so they should be acyclical. std::map<DFBasicBlock*, bool> pipeBlocks = getPipelineBlocks(f); std::map<DFBasicBlock*,Node<DFBasicBlock*>*> nodeMap; //for each block in the DFG, create a Node for it. //this means we need to provide a weight for the block, //and we also want to save it in a map for later for(std::map<DFBasicBlock*, bool>::iterator BB = pipeBlocks.begin(); BB != pipeBlocks.end(); ++BB) { if( BB->second == false ) continue; Node<DFBasicBlock*>* node = new Node<DFBasicBlock*>(BB->first, BB->first->getPipelineLevel(), BB->first->getDelay()); nodeMap[BB->first] = node; graph.push_back(node); } //for each edge in the DFG, we need to create an Edge in the graph for(std::map<DFBasicBlock*, bool>::iterator BB = pipeBlocks.begin(); BB != pipeBlocks.end(); ++BB) { if( BB->second == false ) continue; CallInst* CI = dynamic_cast<CallInst*>(BB->first->getFirstNonPHI()); if( isROCCCFunctionCall(CI, ROCCCNames::LoadPrevious) ) continue; for(pred_iterator pred = pred_begin(BB->first); pred != pred_end(BB->first); ++pred) { assert( (*pred)->getDFBasicBlock() ); std::map<DFBasicBlock*,Node<DFBasicBlock*>*>::iterator predNode = nodeMap.find((*pred)->getDFBasicBlock()); if( predNode != nodeMap.end() ) { assert( nodeMap[BB->first] ); int weight = 0; std::map<llvm::Value*,bool> valsUsed; for(BasicBlock::iterator II = BB->first->begin(); II != BB->first->end(); ++II) { for(User::op_iterator OP = II->op_begin(); OP != II->op_end(); ++OP) { valsUsed[*OP] = true; } } for(BasicBlock::iterator PII = (*pred)->begin(); PII != (*pred)->end(); ++PII) { for(std::map<llvm::Value*,bool>::iterator VUI = valsUsed.begin(); VUI != valsUsed.end(); ++VUI) { if( isDefinition(PII, VUI->first) ) { weight += getSizeInBits(VUI->first); } } } predNode->second->flowsInto(*nodeMap[BB->first], weight); } else { INTERNAL_WARNING((*pred)->getName() << " was not found!\n"); } } } int minimum_copies = getTotalCopiedBits(graph); int num_original_copied_bits = minimum_copies; std::vector< Node<DFBasicBlock*>* > min_graph = createCopyOfGraph(graph); int iterationCount = 0; int minIterationCount = 0; LOG_MESSAGE2("Pipelining", "Register Minimization", "Bit registers needed to pipeline original graph, including both copies and pipeline boundaries: " << minimum_copies << ".\n"); while(maxTripCount(graph) < 10) { //cout << iterationCount << " - " << maxTripCount(graph) << "\n"; ++iterationCount; //display(graph); Edge< Node<DFBasicBlock*> >* largest = selectEdgeWithLargestWeight(graph); if( largest ) { //LOG_MESSAGE2("Pipelining", "Register Minimization", "Edge with most bit registers needed: " << largest->source->getData() << " -> " << largest->sink->getData() << "\n"); tightenEdge(largest); largest->tripCount++; } else { LOG_MESSAGE2("Pipelining", "Register Minimization", "Completely reduced.\n"); break; } //LOG_MESSAGE2("Pipelining", "Register Minimization", "Iteration " << iterationCount << " - total number of bits registers needed: " << getTotalCopiedBits(graph) << ".\n"); if( getTotalCopiedBits(graph) < minimum_copies ) { min_graph = createCopyOfGraph(graph); minimum_copies = getTotalCopiedBits(graph); ++minIterationCount; } } LOG_MESSAGE2("Pipelining", "Register Minimization", "Tested " << iterationCount << " total iterations of minimizing; minimum number of bit registers needed, " << minimum_copies << ", was found after " << minIterationCount << " iterations.\n"); //display(min_graph); if( minimum_copies != num_original_copied_bits ) { for(std::vector<Node<DFBasicBlock*>*>::const_iterator GI = graph.begin(); GI != graph.end(); ++GI) { int level = (*GI)->getPosition(); (*GI)->getData()->setPipelineLevel(level); (*GI)->getData()->setDataflowLevel(level); std::stringstream ss; ss << (*GI)->getData()->getName() << "_" << (*GI)->getData()->getPipelineLevel(); (*GI)->getData()->setName(ss.str()); } changed = true; } return changed ; }
/// SimplifyDivRemOfSelect - Try to fold a divide or remainder of a select /// instruction. bool InstCombiner::SimplifyDivRemOfSelect(BinaryOperator &I) { SelectInst *SI = cast<SelectInst>(I.getOperand(1)); // div/rem X, (Cond ? 0 : Y) -> div/rem X, Y int NonNullOperand = -1; if (Constant *ST = dyn_cast<Constant>(SI->getOperand(1))) if (ST->isNullValue()) NonNullOperand = 2; // div/rem X, (Cond ? Y : 0) -> div/rem X, Y if (Constant *ST = dyn_cast<Constant>(SI->getOperand(2))) if (ST->isNullValue()) NonNullOperand = 1; if (NonNullOperand == -1) return false; Value *SelectCond = SI->getOperand(0); // Change the div/rem to use 'Y' instead of the select. I.setOperand(1, SI->getOperand(NonNullOperand)); // Okay, we know we replace the operand of the div/rem with 'Y' with no // problem. However, the select, or the condition of the select may have // multiple uses. Based on our knowledge that the operand must be non-zero, // propagate the known value for the select into other uses of it, and // propagate a known value of the condition into its other users. // If the select and condition only have a single use, don't bother with this, // early exit. if (SI->use_empty() && SelectCond->hasOneUse()) return true; // Scan the current block backward, looking for other uses of SI. BasicBlock::iterator BBI = &I, BBFront = I.getParent()->begin(); while (BBI != BBFront) { --BBI; // If we found a call to a function, we can't assume it will return, so // information from below it cannot be propagated above it. if (isa<CallInst>(BBI) && !isa<IntrinsicInst>(BBI)) break; // Replace uses of the select or its condition with the known values. for (Instruction::op_iterator I = BBI->op_begin(), E = BBI->op_end(); I != E; ++I) { if (*I == SI) { *I = SI->getOperand(NonNullOperand); Worklist.Add(BBI); } else if (*I == SelectCond) { *I = NonNullOperand == 1 ? ConstantInt::getTrue(BBI->getContext()) : ConstantInt::getFalse(BBI->getContext()); Worklist.Add(BBI); } } // If we past the instruction, quit looking for it. if (&*BBI == SI) SI = 0; if (&*BBI == SelectCond) SelectCond = 0; // If we ran out of things to eliminate, break out of the loop. if (SelectCond == 0 && SI == 0) break; } return true; }
/** * Generate code for */ void HeteroOMPTransform::gen_code_per_f (Function* NF, Function* F, Instruction *max_threads){ Function::arg_iterator FI = F->arg_begin(); Argument *ctxname = &*FI; Function::arg_iterator DestI = NF->arg_begin(); DestI->setName(ctxname->getName()); Argument *ctx_name = &(*DestI); DestI++; DestI->setName("tid"); Argument *num_iters = &(*DestI); #ifdef EXPLICIT_REWRITE DenseMap<const Value*, Value *> ValueMap; #else ValueToValueMapTy ValueMap; #endif //get the old basic block and create a new one Function::const_iterator BI = F->begin(); const BasicBlock &FB = *BI; BasicBlock *NFBB = BasicBlock::Create(FB.getContext(), "", NF); if (FB.hasName()){ NFBB->setName(FB.getName()); } ValueMap[&FB] = NFBB; //ValueMap[numiters] = num_iters; ValueMap[ctxname] = ctx_name; #if EXPLICIT_REWRITE for (BasicBlock::const_iterator II = FB.begin(), IE = FB.end(); II != IE; ++II) { Instruction *NFInst = II->clone(/*F->getContext()*/); // DEBUG(dbgs()<<*II<<"\n"); if (II->hasName()) NFInst->setName(II->getName()); const Instruction *FInst = &(*II); rewrite_instruction((Instruction *)FInst, NFInst, ValueMap); NFBB->getInstList().push_back(NFInst); ValueMap[II] = NFInst; } BI++; for (Function::const_iterator /*BI=F->begin(),*/BE = F->end();BI != BE; ++BI) { const BasicBlock &FBB = *BI; BasicBlock *NFBB = BasicBlock::Create(FBB.getContext(), "", NF); ValueMap[&FBB] = NFBB; if (FBB.hasName()){ NFBB->setName(FBB.getName()); //DEBUG(dbgs()<<NFBB->getName()<<"\n"); } for (BasicBlock::const_iterator II = FBB.begin(), IE = FBB.end(); II != IE; ++II) { Instruction *NFInst = II->clone(/*F->getContext()*/); if (II->hasName()) NFInst->setName(II->getName()); const Instruction *FInst = &(*II); rewrite_instruction((Instruction *)FInst, NFInst, ValueMap); NFBB->getInstList().push_back(NFInst); ValueMap[II] = NFInst; } } // Remap the instructions again to take care of forward jumps for (Function::iterator BB = NF->begin(), BE=NF->end(); BB != BE; ++ BB) { for (BasicBlock::iterator II = BB->begin(); II != BB->end(); ++II){ int opIdx = 0; //DEBUG(dbgs()<<*II<<"\n"); for (User::op_iterator i = II->op_begin(), e = II->op_end(); i != e; ++i, opIdx++) { Value *V = *i; if (ValueMap[V] != NULL) { II->setOperand(opIdx, ValueMap[V]); } } } } #else SmallVector<ReturnInst*, 8> Returns; // Ignore returns cloned. CloneFunctionInto(NF, F, ValueMap, false, Returns, ""); #endif //max_threads->dump(); /* Remap openmp omp_num_threads() and omp_thread_num() */ /* * define internal void @_Z20initialize_variablesiPfS_.omp_fn.4(i8* nocapture %.omp_data_i) nounwind ssp { * entry: * %0 = bitcast i8* %.omp_data_i to i32* ; <i32*> [#uses=1] * %1 = load i32* %0, align 8 ; <i32> [#uses=2] * %2 = tail call i32 @omp_get_num_threads() nounwind readnone ; <i32> [#uses=2] * %3 = tail call i32 @omp_get_thread_num() nounwind readnone ; <i32> [#uses=2] %4 = sdiv i32 %1, %2 %5 = mul nsw i32 %4, %2 %6 = icmp ne i32 %5, %1 %7 = zext i1 %6 to i32 */ vector<Instruction *> toDelete; for (Function::iterator BB = NF->begin(), BE=NF->end(); BB != BE; ++ BB) { for (BasicBlock::iterator II = BB->begin(); II != BB->end(); ++II){ if (isa<CallInst>(II)) { CallSite CI(cast<Instruction>(II)); if (CI.getCalledFunction() != NULL){ string called_func_name = CI.getCalledFunction()->getName(); if (called_func_name == OMP_GET_NUM_THREADS_NAME && CI.arg_size() == 0) { II->replaceAllUsesWith(ValueMap[max_threads]); toDelete.push_back(II); } else if (called_func_name == OMP_GET_THREAD_NUM_NAME && CI.arg_size() == 0) { II->replaceAllUsesWith(num_iters); toDelete.push_back(II); } } } } } /* Delete the last branch instruction of the first basic block -- Assuming it is safe */ Function::iterator nfBB = NF->begin(); TerminatorInst *lastI = nfBB->getTerminator(); BranchInst *bI; BasicBlock *returnBlock; if ((bI = dyn_cast<BranchInst>(lastI)) && bI->isConditional() && (returnBlock = bI->getSuccessor(1)) && (returnBlock->getName() == "return")) { /* modify to a unconditional branch to next basic block and not return */ Instruction *bbI = BranchInst::Create(bI->getSuccessor(0),lastI); bbI->dump(); toDelete.push_back(lastI); } //NF->dump(); while(!toDelete.empty()) { Instruction *g = toDelete.back(); //g->replaceAllUsesWith(UndefValue::get(g->getType())); toDelete.pop_back(); g->eraseFromParent(); } //NF->dump(); }
void RegionExtractor::findInputsOutputs(ValueSet &Inputs, ValueSet &Outputs) const { for (SetVector<BasicBlock *>::const_iterator I = Blocks.begin(), E = Blocks.end(); I != E; ++I) { BasicBlock *BB = *I; // If a used value is defined outside the region, it's an input. If an // instruction is used outside the region, it's an output. for (BasicBlock::iterator II = BB->begin(), IE = BB->end(); II != IE; ++II) { for (User::op_iterator OI = II->op_begin(), OE = II->op_end(); OI != OE; ++OI) if (definedInCaller(Blocks, *OI)) Inputs.insert(*OI); #if LLVM_VERSION_MINOR == 5 for (User *U : II->users()) if (!definedInRegion(Blocks, U)) { #else for (Value::use_iterator UI = II->use_begin(), UE = II->use_end(); UI != UE; ++UI) if (!definedInRegion(Blocks, *UI)) { #endif Outputs.insert(II); break; } } } } /// severSplitPHINodes - If a PHI node has multiple inputs from outside of the /// region, we need to split the entry block of the region so that the PHI node /// is easier to deal with. void RegionExtractor::severSplitPHINodes(BasicBlock *&Header) { unsigned NumPredsFromRegion = 0; unsigned NumPredsOutsideRegion = 0; if (Header != &Header->getParent()->getEntryBlock()) { PHINode *PN = dyn_cast<PHINode>(Header->begin()); if (!PN) return; // No PHI nodes. // If the header node contains any PHI nodes, check to see if there is more // than one entry from outside the region. If so, we need to sever the // header block into two. for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) if (Blocks.count(PN->getIncomingBlock(i))) ++NumPredsFromRegion; else ++NumPredsOutsideRegion; // If there is one (or fewer) predecessor from outside the region, we don't // need to do anything special. if (NumPredsOutsideRegion <= 1) return; } // Otherwise, we need to split the header block into two pieces: one // containing PHI nodes merging values from outside of the region, and a // second that contains all of the code for the block and merges back any // incoming values from inside of the region. BasicBlock::iterator AfterPHIs = Header->getFirstNonPHI(); BasicBlock *NewBB = Header->splitBasicBlock(AfterPHIs, Header->getName()+".ce"); // We only want to code extract the second block now, and it becomes the new // header of the region. BasicBlock *OldPred = Header; Blocks.remove(OldPred); Blocks.insert(NewBB); Header = NewBB; // Okay, update dominator sets. The blocks that dominate the new one are the // blocks that dominate TIBB plus the new block itself. if (DT) DT->splitBlock(NewBB); // Okay, now we need to adjust the PHI nodes and any branches from within the // region to go to the new header block instead of the old header block. if (NumPredsFromRegion) { PHINode *PN = cast<PHINode>(OldPred->begin()); // Loop over all of the predecessors of OldPred that are in the region, // changing them to branch to NewBB instead. for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) if (Blocks.count(PN->getIncomingBlock(i))) { TerminatorInst *TI = PN->getIncomingBlock(i)->getTerminator(); TI->replaceUsesOfWith(OldPred, NewBB); } // Okay, everything within the region is now branching to the right block, we // just have to update the PHI nodes now, inserting PHI nodes into NewBB. for (AfterPHIs = OldPred->begin(); isa<PHINode>(AfterPHIs); ++AfterPHIs) { PHINode *PN = cast<PHINode>(AfterPHIs); // Create a new PHI node in the new region, which has an incoming value // from OldPred of PN. PHINode *NewPN = PHINode::Create(PN->getType(), 1 + NumPredsFromRegion, PN->getName()+".ce", NewBB->begin()); NewPN->addIncoming(PN, OldPred); // Loop over all of the incoming value in PN, moving them to NewPN if they // are from the extracted region. for (unsigned i = 0; i != PN->getNumIncomingValues(); ++i) { if (Blocks.count(PN->getIncomingBlock(i))) { NewPN->addIncoming(PN->getIncomingValue(i), PN->getIncomingBlock(i)); PN->removeIncomingValue(i); --i; } } } } }
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; }