void DSGraphStats::visitLoad(LoadInst &LI) { if (isNodeForValueUntyped(LI.getOperand(0), 0,LI.getParent()->getParent())) { NumUntypedMemAccesses++; } else { NumTypedMemAccesses++; } }
bool SFVInstVisitor::visitLoadInst(LoadInst &LI) { if ((Callbacks & Visit::Loads) == 0) return false; if (LatticeValue *LV = getLatticeValueForField(LI.getOperand(0))) if (LV->visitLoad(LI)) return RemoveLatticeValueAtBottom(LV); return false; }
/// Move cond_fail down if it can potentially help register promotion later. static bool sinkCondFail(SILLoop *Loop) { // Only handle innermost loops for now. if (!Loop->getSubLoops().empty()) return false; bool Changed = false; for (auto *BB : Loop->getBlocks()) { // A list of CondFails that can be moved down. SmallVector<CondFailInst*, 4> CFs; // A pair of load and store that are independent of the CondFails and // can potentially access the same memory. LoadInst *LIOfPair = nullptr; bool foundPair = false; for (auto &Inst : *BB) { if (foundPair) { // Move CFs to right before Inst. for (unsigned I = 0, E = CFs.size(); I < E; I++) { DEBUG(llvm::dbgs() << "sinking cond_fail down "); DEBUG(CFs[I]->dump()); DEBUG(llvm::dbgs() << " before "); DEBUG(Inst.dump()); CFs[I]->moveBefore(&Inst); } Changed = true; foundPair = false; LIOfPair = nullptr; } if (auto CF = dyn_cast<CondFailInst>(&Inst)) { CFs.push_back(CF); } else if (auto LI = dyn_cast<LoadInst>(&Inst)) { if (addressIndependent(LI->getOperand())) { LIOfPair = LI; } else { CFs.clear(); LIOfPair = nullptr; } } else if (auto SI = dyn_cast<StoreInst>(&Inst)) { if (addressIndependent(SI->getDest())) { if (LIOfPair && addressCanPairUp(SI->getDest(), LIOfPair->getOperand())) foundPair = true; } else { CFs.clear(); LIOfPair = nullptr; } } else if (Inst.mayHaveSideEffects()) { CFs.clear(); LIOfPair = nullptr; } } } return Changed; }
string instructionToString(Instruction* curr_Ins) { Instruction *InsOp1, *InsOp2; Value *v; string op1="'",op2="'",exprsn,opcodeName,opc; LoadInst *LD; InsOp1 = cast<Instruction>(curr_Ins->getOperand(0)); InsOp2 = cast<Instruction>(curr_Ins->getOperand(1)); opcodeName=InsOp1->getOpcodeName(); if(opcodeName=="load") { LD = cast<LoadInst>(curr_Ins->getOperand(0)); v=LD->getOperand(0); op1=v->getName().str(); } else { op1=instructionToString(InsOp1); } opcodeName=InsOp2->getOpcodeName(); if(opcodeName=="load") { LD = cast<LoadInst>(curr_Ins->getOperand(1)); v=LD->getOperand(0); op2=v->getName().str(); } else { op2=instructionToString(InsOp2); } switch(curr_Ins->getOpcode()){ case Instruction::Add: opc="+"; break; case Instruction::Sub: opc="-"; break; case 21: opc="/"; break; case Instruction::Mul: opc="*"; break;} exprsn=op1+opc+op2; return exprsn; }
bool CallAnalyzer::visitLoad(LoadInst &I) { Value *SROAArg; DenseMap<Value *, int>::iterator CostIt; if (lookupSROAArgAndCost(I.getOperand(0), SROAArg, CostIt)) { if (I.isSimple()) { accumulateSROACost(CostIt, InlineConstants::InstrCost); return true; } disableSROA(CostIt); } return false; }
void FuncTransform::visitLoadInst(LoadInst &LI) { // // Record the use of the pool handle for the pointer being dereferenced. // if (Value *PH = getPoolHandle(LI.getOperand(0))) AddPoolUse(LI, PH, PoolUses); // // If this is a volatile load, then record a use of the pool handle for the // loaded value, even if it is never used. // if (LI.isVolatile()) { if (Value *PH = getPoolHandle(&LI)) AddPoolUse (LI, PH, PoolUses); } visitInstruction(LI); }
PointerAnalysisFlow* PointerAnalysis::operation_X_Y(PointerAnalysisFlow* in, Instruction* instruction) { LoadInst* load = static_cast<LoadInst*>(instruction); PointerAnalysisFlow* f = new PointerAnalysisFlow(in); Value* Y = load->getOperand(0); //RO Value* X = load->getNextNode()->getOperand(1); //LO // X = Y // Check if X Y are pointers. if (isPointer(Y) && isPointer(X)) { if (isVariable(Y) && isVariable(X)) { //x points to what y points to PointerAnalysisFlow* ff = new PointerAnalysisFlow(); map<string, set<string> > value; value[X->getName()] = in->value[Y->getName()];; ff->value = value; PointerAnalysisFlow* tmp = static_cast<PointerAnalysisFlow*>(ff->join(f)); delete ff; delete f; f = tmp; } } return f; }
//------------------------------------------------------------------------------ void SymbolicExecution::visitLoadInst(LoadInst &loadInst) { Instruction *inst = &loadInst; Value *pointer = loadInst.getOperand(0); visitPointer(inst, pointer, loadBankConflicts, loadTransactions); }
/// DoPromotion - This method actually performs the promotion of the specified /// arguments, and returns the new function. At this point, we know that it's /// safe to do so. CallGraphNode *ArgPromotion::DoPromotion(Function *F, SmallPtrSet<Argument*, 8> &ArgsToPromote, SmallPtrSet<Argument*, 8> &ByValArgsToTransform) { // Start by computing a new prototype for the function, which is the same as // the old function, but has modified arguments. const FunctionType *FTy = F->getFunctionType(); std::vector<const Type*> Params; typedef std::set<IndicesVector> ScalarizeTable; // ScalarizedElements - If we are promoting a pointer that has elements // accessed out of it, keep track of which elements are accessed so that we // can add one argument for each. // // Arguments that are directly loaded will have a zero element value here, to // handle cases where there are both a direct load and GEP accesses. // std::map<Argument*, ScalarizeTable> ScalarizedElements; // OriginalLoads - Keep track of a representative load instruction from the // original function so that we can tell the alias analysis implementation // what the new GEP/Load instructions we are inserting look like. std::map<IndicesVector, LoadInst*> OriginalLoads; // Attributes - Keep track of the parameter attributes for the arguments // that we are *not* promoting. For the ones that we do promote, the parameter // attributes are lost SmallVector<AttributeWithIndex, 8> AttributesVec; const AttrListPtr &PAL = F->getAttributes(); // Add any return attributes. if (Attributes attrs = PAL.getRetAttributes()) AttributesVec.push_back(AttributeWithIndex::get(0, attrs)); // First, determine the new argument list unsigned ArgIndex = 1; for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E; ++I, ++ArgIndex) { if (ByValArgsToTransform.count(I)) { // Simple byval argument? Just add all the struct element types. const Type *AgTy = cast<PointerType>(I->getType())->getElementType(); const StructType *STy = cast<StructType>(AgTy); for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) Params.push_back(STy->getElementType(i)); ++NumByValArgsPromoted; } else if (!ArgsToPromote.count(I)) { // Unchanged argument Params.push_back(I->getType()); if (Attributes attrs = PAL.getParamAttributes(ArgIndex)) AttributesVec.push_back(AttributeWithIndex::get(Params.size(), attrs)); } else if (I->use_empty()) { // Dead argument (which are always marked as promotable) ++NumArgumentsDead; } else { // Okay, this is being promoted. This means that the only uses are loads // or GEPs which are only used by loads // In this table, we will track which indices are loaded from the argument // (where direct loads are tracked as no indices). ScalarizeTable &ArgIndices = ScalarizedElements[I]; for (Value::use_iterator UI = I->use_begin(), E = I->use_end(); UI != E; ++UI) { Instruction *User = cast<Instruction>(*UI); assert(isa<LoadInst>(User) || isa<GetElementPtrInst>(User)); IndicesVector Indices; Indices.reserve(User->getNumOperands() - 1); // Since loads will only have a single operand, and GEPs only a single // non-index operand, this will record direct loads without any indices, // and gep+loads with the GEP indices. for (User::op_iterator II = User->op_begin() + 1, IE = User->op_end(); II != IE; ++II) Indices.push_back(cast<ConstantInt>(*II)->getSExtValue()); // GEPs with a single 0 index can be merged with direct loads if (Indices.size() == 1 && Indices.front() == 0) Indices.clear(); ArgIndices.insert(Indices); LoadInst *OrigLoad; if (LoadInst *L = dyn_cast<LoadInst>(User)) OrigLoad = L; else // Take any load, we will use it only to update Alias Analysis OrigLoad = cast<LoadInst>(User->use_back()); OriginalLoads[Indices] = OrigLoad; } // Add a parameter to the function for each element passed in. for (ScalarizeTable::iterator SI = ArgIndices.begin(), E = ArgIndices.end(); SI != E; ++SI) { // not allowed to dereference ->begin() if size() is 0 Params.push_back(GetElementPtrInst::getIndexedType(I->getType(), SI->begin(), SI->end())); assert(Params.back()); } if (ArgIndices.size() == 1 && ArgIndices.begin()->empty()) ++NumArgumentsPromoted; else ++NumAggregatesPromoted; } } // Add any function attributes. if (Attributes attrs = PAL.getFnAttributes()) AttributesVec.push_back(AttributeWithIndex::get(~0, attrs)); const Type *RetTy = FTy->getReturnType(); // Work around LLVM bug PR56: the CWriter cannot emit varargs functions which // have zero fixed arguments. bool ExtraArgHack = false; if (Params.empty() && FTy->isVarArg()) { ExtraArgHack = true; Params.push_back(Type::getInt32Ty(F->getContext())); } // Construct the new function type using the new arguments. FunctionType *NFTy = FunctionType::get(RetTy, Params, FTy->isVarArg()); // Create the new function body and insert it into the module. Function *NF = Function::Create(NFTy, F->getLinkage(), F->getName()); NF->copyAttributesFrom(F); DEBUG(dbgs() << "ARG PROMOTION: Promoting to:" << *NF << "\n" << "From: " << *F); // Recompute the parameter attributes list based on the new arguments for // the function. NF->setAttributes(AttrListPtr::get(AttributesVec.begin(), AttributesVec.end())); AttributesVec.clear(); F->getParent()->getFunctionList().insert(F, NF); NF->takeName(F); // Get the alias analysis information that we need to update to reflect our // changes. AliasAnalysis &AA = getAnalysis<AliasAnalysis>(); // Get the callgraph information that we need to update to reflect our // changes. CallGraph &CG = getAnalysis<CallGraph>(); // Get a new callgraph node for NF. CallGraphNode *NF_CGN = CG.getOrInsertFunction(NF); // Loop over all of the callers of the function, transforming the call sites // to pass in the loaded pointers. // SmallVector<Value*, 16> Args; while (!F->use_empty()) { CallSite CS = CallSite::get(F->use_back()); assert(CS.getCalledFunction() == F); Instruction *Call = CS.getInstruction(); const AttrListPtr &CallPAL = CS.getAttributes(); // Add any return attributes. if (Attributes attrs = CallPAL.getRetAttributes()) AttributesVec.push_back(AttributeWithIndex::get(0, attrs)); // Loop over the operands, inserting GEP and loads in the caller as // appropriate. CallSite::arg_iterator AI = CS.arg_begin(); ArgIndex = 1; for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E; ++I, ++AI, ++ArgIndex) if (!ArgsToPromote.count(I) && !ByValArgsToTransform.count(I)) { Args.push_back(*AI); // Unmodified argument if (Attributes Attrs = CallPAL.getParamAttributes(ArgIndex)) AttributesVec.push_back(AttributeWithIndex::get(Args.size(), Attrs)); } else if (ByValArgsToTransform.count(I)) { // Emit a GEP and load for each element of the struct. const Type *AgTy = cast<PointerType>(I->getType())->getElementType(); const StructType *STy = cast<StructType>(AgTy); Value *Idxs[2] = { ConstantInt::get(Type::getInt32Ty(F->getContext()), 0), 0 }; for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) { Idxs[1] = ConstantInt::get(Type::getInt32Ty(F->getContext()), i); Value *Idx = GetElementPtrInst::Create(*AI, Idxs, Idxs+2, (*AI)->getName()+"."+utostr(i), Call); // TODO: Tell AA about the new values? Args.push_back(new LoadInst(Idx, Idx->getName()+".val", Call)); } } else if (!I->use_empty()) { // Non-dead argument: insert GEPs and loads as appropriate. ScalarizeTable &ArgIndices = ScalarizedElements[I]; // Store the Value* version of the indices in here, but declare it now // for reuse. std::vector<Value*> Ops; for (ScalarizeTable::iterator SI = ArgIndices.begin(), E = ArgIndices.end(); SI != E; ++SI) { Value *V = *AI; LoadInst *OrigLoad = OriginalLoads[*SI]; if (!SI->empty()) { Ops.reserve(SI->size()); const Type *ElTy = V->getType(); for (IndicesVector::const_iterator II = SI->begin(), IE = SI->end(); II != IE; ++II) { // Use i32 to index structs, and i64 for others (pointers/arrays). // This satisfies GEP constraints. const Type *IdxTy = (ElTy->isStructTy() ? Type::getInt32Ty(F->getContext()) : Type::getInt64Ty(F->getContext())); Ops.push_back(ConstantInt::get(IdxTy, *II)); // Keep track of the type we're currently indexing. ElTy = cast<CompositeType>(ElTy)->getTypeAtIndex(*II); } // And create a GEP to extract those indices. V = GetElementPtrInst::Create(V, Ops.begin(), Ops.end(), V->getName()+".idx", Call); Ops.clear(); AA.copyValue(OrigLoad->getOperand(0), V); } // Since we're replacing a load make sure we take the alignment // of the previous load. LoadInst *newLoad = new LoadInst(V, V->getName()+".val", Call); newLoad->setAlignment(OrigLoad->getAlignment()); Args.push_back(newLoad); AA.copyValue(OrigLoad, Args.back()); } } if (ExtraArgHack) Args.push_back(Constant::getNullValue(Type::getInt32Ty(F->getContext()))); // Push any varargs arguments on the list. for (; AI != CS.arg_end(); ++AI, ++ArgIndex) { Args.push_back(*AI); if (Attributes Attrs = CallPAL.getParamAttributes(ArgIndex)) AttributesVec.push_back(AttributeWithIndex::get(Args.size(), Attrs)); } // Add any function attributes. if (Attributes attrs = CallPAL.getFnAttributes()) AttributesVec.push_back(AttributeWithIndex::get(~0, attrs)); Instruction *New; if (InvokeInst *II = dyn_cast<InvokeInst>(Call)) { New = InvokeInst::Create(NF, II->getNormalDest(), II->getUnwindDest(), Args.begin(), Args.end(), "", Call); cast<InvokeInst>(New)->setCallingConv(CS.getCallingConv()); cast<InvokeInst>(New)->setAttributes(AttrListPtr::get(AttributesVec.begin(), AttributesVec.end())); } else { New = CallInst::Create(NF, Args.begin(), Args.end(), "", Call); cast<CallInst>(New)->setCallingConv(CS.getCallingConv()); cast<CallInst>(New)->setAttributes(AttrListPtr::get(AttributesVec.begin(), AttributesVec.end())); if (cast<CallInst>(Call)->isTailCall()) cast<CallInst>(New)->setTailCall(); } Args.clear(); AttributesVec.clear(); // Update the alias analysis implementation to know that we are replacing // the old call with a new one. AA.replaceWithNewValue(Call, New); // Update the callgraph to know that the callsite has been transformed. CallGraphNode *CalleeNode = CG[Call->getParent()->getParent()]; CalleeNode->replaceCallEdge(Call, New, NF_CGN); if (!Call->use_empty()) { Call->replaceAllUsesWith(New); New->takeName(Call); } // Finally, remove the old call from the program, reducing the use-count of // F. Call->eraseFromParent(); } // Since we have now created the new function, splice the body of the old // function right into the new function, leaving the old rotting hulk of the // function empty. NF->getBasicBlockList().splice(NF->begin(), F->getBasicBlockList()); // Loop over the argument list, transfering uses of the old arguments over to // the new arguments, also transfering over the names as well. // for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end(), I2 = NF->arg_begin(); I != E; ++I) { if (!ArgsToPromote.count(I) && !ByValArgsToTransform.count(I)) { // If this is an unmodified argument, move the name and users over to the // new version. I->replaceAllUsesWith(I2); I2->takeName(I); AA.replaceWithNewValue(I, I2); ++I2; continue; } if (ByValArgsToTransform.count(I)) { // In the callee, we create an alloca, and store each of the new incoming // arguments into the alloca. Instruction *InsertPt = NF->begin()->begin(); // Just add all the struct element types. const Type *AgTy = cast<PointerType>(I->getType())->getElementType(); Value *TheAlloca = new AllocaInst(AgTy, 0, "", InsertPt); const StructType *STy = cast<StructType>(AgTy); Value *Idxs[2] = { ConstantInt::get(Type::getInt32Ty(F->getContext()), 0), 0 }; for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) { Idxs[1] = ConstantInt::get(Type::getInt32Ty(F->getContext()), i); Value *Idx = GetElementPtrInst::Create(TheAlloca, Idxs, Idxs+2, TheAlloca->getName()+"."+Twine(i), InsertPt); I2->setName(I->getName()+"."+Twine(i)); new StoreInst(I2++, Idx, InsertPt); } // Anything that used the arg should now use the alloca. I->replaceAllUsesWith(TheAlloca); TheAlloca->takeName(I); AA.replaceWithNewValue(I, TheAlloca); continue; } if (I->use_empty()) { AA.deleteValue(I); continue; } // Otherwise, if we promoted this argument, then all users are load // instructions (or GEPs with only load users), and all loads should be // using the new argument that we added. ScalarizeTable &ArgIndices = ScalarizedElements[I]; while (!I->use_empty()) { if (LoadInst *LI = dyn_cast<LoadInst>(I->use_back())) { assert(ArgIndices.begin()->empty() && "Load element should sort to front!"); I2->setName(I->getName()+".val"); LI->replaceAllUsesWith(I2); AA.replaceWithNewValue(LI, I2); LI->eraseFromParent(); DEBUG(dbgs() << "*** Promoted load of argument '" << I->getName() << "' in function '" << F->getName() << "'\n"); } else { GetElementPtrInst *GEP = cast<GetElementPtrInst>(I->use_back()); IndicesVector Operands; Operands.reserve(GEP->getNumIndices()); for (User::op_iterator II = GEP->idx_begin(), IE = GEP->idx_end(); II != IE; ++II) Operands.push_back(cast<ConstantInt>(*II)->getSExtValue()); // GEPs with a single 0 index can be merged with direct loads if (Operands.size() == 1 && Operands.front() == 0) Operands.clear(); Function::arg_iterator TheArg = I2; for (ScalarizeTable::iterator It = ArgIndices.begin(); *It != Operands; ++It, ++TheArg) { assert(It != ArgIndices.end() && "GEP not handled??"); } std::string NewName = I->getName(); for (unsigned i = 0, e = Operands.size(); i != e; ++i) { NewName += "." + utostr(Operands[i]); } NewName += ".val"; TheArg->setName(NewName); DEBUG(dbgs() << "*** Promoted agg argument '" << TheArg->getName() << "' of function '" << NF->getName() << "'\n"); // All of the uses must be load instructions. Replace them all with // the argument specified by ArgNo. while (!GEP->use_empty()) { LoadInst *L = cast<LoadInst>(GEP->use_back()); L->replaceAllUsesWith(TheArg); AA.replaceWithNewValue(L, TheArg); L->eraseFromParent(); } AA.deleteValue(GEP); GEP->eraseFromParent(); } } // Increment I2 past all of the arguments added for this promoted pointer. for (unsigned i = 0, e = ArgIndices.size(); i != e; ++i) ++I2; } // Notify the alias analysis implementation that we inserted a new argument. if (ExtraArgHack) AA.copyValue(Constant::getNullValue(Type::getInt32Ty(F->getContext())), NF->arg_begin()); // Tell the alias analysis that the old function is about to disappear. AA.replaceWithNewValue(F, NF); NF_CGN->stealCalledFunctionsFrom(CG[F]); // Now that the old function is dead, delete it. If there is a dangling // reference to the CallgraphNode, just leave the dead function around for // someone else to nuke. CallGraphNode *CGN = CG[F]; if (CGN->getNumReferences() == 0) delete CG.removeFunctionFromModule(CGN); else F->setLinkage(Function::ExternalLinkage); return NF_CGN; }
bool NVPTXLowerAggrCopies::runOnFunction(Function &F) { SmallVector<LoadInst *, 4> aggrLoads; SmallVector<MemTransferInst *, 4> aggrMemcpys; SmallVector<MemSetInst *, 4> aggrMemsets; DataLayout *TD = &getAnalysis<DataLayout>(); LLVMContext &Context = F.getParent()->getContext(); // // Collect all the aggrLoads, aggrMemcpys and addrMemsets. // //const BasicBlock *firstBB = &F.front(); // first BB in F for (Function::iterator BI = F.begin(), BE = F.end(); BI != BE; ++BI) { //BasicBlock *bb = BI; for (BasicBlock::iterator II = BI->begin(), IE = BI->end(); II != IE; ++II) { if (LoadInst * load = dyn_cast<LoadInst>(II)) { if (load->hasOneUse() == false) continue; if (TD->getTypeStoreSize(load->getType()) < MaxAggrCopySize) continue; User *use = *(load->use_begin()); if (StoreInst * store = dyn_cast<StoreInst>(use)) { if (store->getOperand(0) != load) //getValueOperand continue; aggrLoads.push_back(load); } } else if (MemTransferInst * intr = dyn_cast<MemTransferInst>(II)) { Value *len = intr->getLength(); // If the number of elements being copied is greater // than MaxAggrCopySize, lower it to a loop if (ConstantInt * len_int = dyn_cast < ConstantInt > (len)) { if (len_int->getZExtValue() >= MaxAggrCopySize) { aggrMemcpys.push_back(intr); } } else { // turn variable length memcpy/memmov into loop aggrMemcpys.push_back(intr); } } else if (MemSetInst * memsetintr = dyn_cast<MemSetInst>(II)) { Value *len = memsetintr->getLength(); if (ConstantInt * len_int = dyn_cast<ConstantInt>(len)) { if (len_int->getZExtValue() >= MaxAggrCopySize) { aggrMemsets.push_back(memsetintr); } } else { // turn variable length memset into loop aggrMemsets.push_back(memsetintr); } } } } if ((aggrLoads.size() == 0) && (aggrMemcpys.size() == 0) && (aggrMemsets.size() == 0)) return false; // // Do the transformation of an aggr load/copy/set to a loop // for (unsigned i = 0, e = aggrLoads.size(); i != e; ++i) { LoadInst *load = aggrLoads[i]; StoreInst *store = dyn_cast<StoreInst>(*load->use_begin()); Value *srcAddr = load->getOperand(0); Value *dstAddr = store->getOperand(1); unsigned numLoads = TD->getTypeStoreSize(load->getType()); Value *len = ConstantInt::get(Type::getInt32Ty(Context), numLoads); convertTransferToLoop(store, srcAddr, dstAddr, len, load->isVolatile(), store->isVolatile(), Context, F); store->eraseFromParent(); load->eraseFromParent(); } for (unsigned i = 0, e = aggrMemcpys.size(); i != e; ++i) { MemTransferInst *cpy = aggrMemcpys[i]; Value *len = cpy->getLength(); // llvm 2.7 version of memcpy does not have volatile // operand yet. So always making it non-volatile // optimistically, so that we don't see unnecessary // st.volatile in ptx convertTransferToLoop(cpy, cpy->getSource(), cpy->getDest(), len, false, false, Context, F); cpy->eraseFromParent(); } for (unsigned i = 0, e = aggrMemsets.size(); i != e; ++i) { MemSetInst *memsetinst = aggrMemsets[i]; Value *len = memsetinst->getLength(); Value *val = memsetinst->getValue(); convertMemSetToLoop(memsetinst, memsetinst->getDest(), len, val, Context, F); memsetinst->eraseFromParent(); } return true; }
int qdp_jit_vec::vectorize_loads( std::vector<std::vector<Instruction*> >& load_instructions ) { DEBUG(dbgs() << "Vectorize loads, total of " << load_instructions.size() << "\n"); //std::vector<std::pair<Value*,Value*> > scalar_vector_loads; scalar_vector_pairs.clear(); if (load_instructions.empty()) return 0; int load_vec_elem = 0; for( std::vector<Instruction*>& VI : load_instructions ) { DEBUG(dbgs() << "Processing vector of loads number " << load_vec_elem++ << "\n"); assert( VI.size() == vec_len && "length of vector of loads does not match vec_len" ); int loads_consec = true; uint64_t lo,hi; bool first = true; for( Instruction* I : VI ) { GetElementPtrInst* GEP; if ((GEP = dyn_cast<GetElementPtrInst>(I->getOperand(0)))) { if (first) { ConstantInt * CI; if ((CI = dyn_cast<ConstantInt>(GEP->getOperand(1)))) { lo = CI->getZExtValue(); hi = lo+1; first=false; } else { DEBUG(dbgs() << "First load in the chain: Operand of GEP not a ConstantInt" << *GEP->getOperand(1) << "\n"); assert( 0 && "First load in the chain: Operand of GEP not a ConstantInt\n"); exit(0); } } else { ConstantInt * CI; if ((CI = dyn_cast<ConstantInt>(GEP->getOperand(1)))) { if (hi != CI->getZExtValue()) { DEBUG(dbgs() << "Loads not consecutive lo=" << lo << " hi=" << hi << " this=" << CI->getZExtValue() << "\n"); loads_consec = false; } else { hi++; } } } } else { DEBUG(dbgs() << "Operand of load not a GEP " << *I->getOperand(0) << "\n"); assert( 0 && "Operand of load not a GEP" ); exit(0); loads_consec = false; } } if (loads_consec) { DEBUG(dbgs() << "Loads consecuetive\n"); LoadInst* LI = cast<LoadInst>(VI.at(0)); GetElementPtrInst* GEP = cast<GetElementPtrInst>(LI->getOperand(0)); Instruction* GEPcl = clone_with_operands(GEP); unsigned AS = LI->getPointerAddressSpace(); VectorType *VecTy = VectorType::get( LI->getType() , vec_len ); unsigned bitwidth = LI->getType()->getPrimitiveSizeInBits(); unsigned bytewidth = bitwidth == 1 ? 1 : bitwidth/8; DEBUG(dbgs() << "bit/byte width of load instr trype: " << bitwidth << "/" << bytewidth << "\n"); //Builder->SetInsertPoint( GEP ); Value *VecPtr = Builder->CreateBitCast(GEPcl,VecTy->getPointerTo(AS)); //Value *VecLoad = Builder->CreateLoad( VecPtr ); unsigned align = lo % vec_len == 0 ? bytewidth * vec_len : bytewidth; Value *VecLoad = Builder->CreateAlignedLoad( VecPtr , align ); //DEBUG(dbgs() << "created vector load: " << *VecLoad << "\n"); //function->dump(); // unsigned AS = LI->getPointerAddressSpace(); // VectorType *VecTy = VectorType::get( LI->getType() , vec_len ); // Builder->SetInsertPoint( LI ); // Value *VecPtr = Builder->CreateBitCast(LI->getPointerOperand(),VecTy->getPointerTo(AS)); // Value *VecLoad = Builder->CreateLoad( VecPtr ); scalar_vector_pairs.push_back( std::make_pair( VI.at(0) , VecLoad ) ); } else { DEBUG(dbgs() << "Loads not consecutive:\n"); for (Value* V: VI) { DEBUG(dbgs() << *V << "\n"); } //Instruction* I = dyn_cast<Instruction>(VI.back()->getNextNode()); //DEBUG(dbgs() << *I << "\n"); //Builder->SetInsertPoint( VI.at(0) ); std::vector<Instruction*> VIcl; for( Instruction* I : VI ) { VIcl.push_back( clone_with_operands(I) ); } VectorType *VecTy = VectorType::get( VI.at(0)->getType() , vec_len ); Value *Vec = UndefValue::get(VecTy); int i=0; for( Instruction* I : VIcl ) { Vec = Builder->CreateInsertElement(Vec, I, Builder->getInt32(i++)); } scalar_vector_pairs.push_back( std::make_pair( VI.at(0) , Vec ) ); } } //vectorize_all_uses( scalar_vector_loads ); DEBUG(dbgs() << "Searching for the stores:\n"); //function->dump(); // // Vectorize all StoreInst reachable by the first load of each vector of loads // { SetVector<Instruction*> to_visit; SetVector<Instruction*> stores_processed; for( std::vector<Instruction*>& VI : load_instructions ) { to_visit.insert(VI.at(0)); } while (!to_visit.empty()) { Instruction* I = to_visit.back(); to_visit.pop_back(); DEBUG(dbgs() << "visiting " << *I << "\n"); if (StoreInst* SI = dyn_cast<StoreInst>(I)) { if (!stores_processed.count(SI)) { get_vector_version( SI ); stores_processed.insert( SI ); } } else { for (Use &U : I->uses()) { Value* V = U.getUser(); to_visit.insert(cast<Instruction>(V)); } } } } // DEBUG(dbgs() << "After vectorizing the stores\n"); // function->dump(); // // Mark all stores as being processed // SetVector<Instruction*> to_visit; for( std::vector<Instruction*>& VI : load_instructions ) { for( Instruction* I : VI ) { to_visit.insert(I); if (GetElementPtrInst* GEP = dyn_cast<GetElementPtrInst>(I->getOperand(0))) { for_erasure.insert(GEP); } } } while (!to_visit.empty()) { Instruction* I = to_visit.back(); to_visit.pop_back(); for_erasure.insert(I); if (StoreInst* SI = dyn_cast<StoreInst>(I)) { stores_processed.insert(SI); if (GetElementPtrInst* GEP = dyn_cast<GetElementPtrInst>(SI->getOperand(1))) { for_erasure.insert(GEP); } } else { for (Use &U : I->uses()) { Value* V = U.getUser(); to_visit.insert(cast<Instruction>(V)); } } } DEBUG(dbgs() << "----------------------------------------\n"); DEBUG(dbgs() << "After vectorize_loads\n"); //function->dump(); return 0; }
virtual bool runOnFunction(Function &F) { //F.dump(); bool changed = false; for (inst_iterator inst_it = inst_begin(F), _inst_end = inst_end(F); inst_it != _inst_end; ++inst_it) { LoadInst *li = dyn_cast<LoadInst>(&*inst_it); if (!li) continue; ConstantExpr *ce = dyn_cast<ConstantExpr>(li->getOperand(0)); // Not 100% sure what the isGEPWithNoNotionalOverIndexing() means, but // at least it checks if it's a gep: if (ce && ce->isGEPWithNoNotionalOverIndexing() && ce->getOperand(0)->getType() == g.llvm_flavor_type_ptr) { changed = handleFlavor(li, ce); } GlobalVariable *gv = dyn_cast<GlobalVariable>(li->getOperand(0)); if (!gv) continue; llvm::Type* gv_t = gv->getType(); if (gv_t == g.llvm_bool_type_ptr->getPointerTo()) { changed = handleBool(li, gv) || changed; continue; } if (gv_t == g.llvm_class_type_ptr->getPointerTo()) { changed = handleCls(li, gv) || changed; continue; } } return changed; }
// // Method: runOnModule() // // Description: // Entry point for this LLVM pass. Search for insert/extractvalue instructions // that can be simplified. // // Inputs: // M - A reference to the LLVM module to transform. // // Outputs: // M - The transformed LLVM module. // // Return value: // true - The module was modified. // false - The module was not modified. // bool SimplifyLoad::runOnModule(Module& M) { // Repeat till no change bool changed; do { changed = false; for (Module::iterator F = M.begin(); F != M.end(); ++F) { for (Function::iterator B = F->begin(), FE = F->end(); B != FE; ++B) { for (BasicBlock::iterator I = B->begin(), BE = B->end(); I != BE;) { LoadInst *LI = dyn_cast<LoadInst>(I++); if(!LI) continue; if(LI->hasOneUse()) { if(CastInst *CI = dyn_cast<CastInst>(*(LI->use_begin()))) { if(LI->getType()->isPointerTy()) { if(ConstantExpr *CE = dyn_cast<ConstantExpr>(LI->getOperand(0))) { if(const PointerType *PTy = dyn_cast<PointerType>(CE->getOperand(0)->getType())) if(PTy->getElementType() == CI->getType()) { LoadInst *LINew = new LoadInst(CE->getOperand(0), "", LI); CI->replaceAllUsesWith(LINew); } } } } } } } } } while(changed); return (numErased > 0); }