void DuettoNativeRewriter::rewriteConstructorImplementation(Module& M, Function& F) { //Copy the code in a function with the right signature Function* newFunc=getReturningConstructor(M, &F); if(!newFunc->empty()) return; //Visit each instruction and take note of the ones that needs to be replaced Function::const_iterator B=F.begin(); Function::const_iterator BE=F.end(); ValueToValueMapTy valueMap; CallInst* lowerConstructor = NULL; const CallInst* oldLowerConstructor = NULL; for(;B!=BE;++B) { BasicBlock::const_iterator I=B->begin(); BasicBlock::const_iterator IE=B->end(); for(;I!=IE;++I) { if(I->getOpcode()!=Instruction::Call) continue; const CallInst* callInst=cast<CallInst>(&(*I)); Function* f=callInst->getCalledFunction(); if(!f) continue; const char* startOfType; const char* endOfType; if(!DuettoNativeRewriter::isBuiltinConstructor(f->getName().data(), startOfType, endOfType)) continue; //Check that the constructor is for 'this' if(callInst->getOperand(0)!=F.arg_begin()) continue; //If this is another constructor for the same type, change it to a //returning constructor and use it as the 'this' argument Function* newFunc = getReturningConstructor(M, f); llvm::SmallVector<Value*, 4> newArgs; for(unsigned i=1;i<callInst->getNumArgOperands();i++) newArgs.push_back(callInst->getArgOperand(i)); lowerConstructor = CallInst::Create(newFunc, newArgs); oldLowerConstructor = callInst; break; } if(lowerConstructor) break; } //Clone the linkage first newFunc->setLinkage(F.getLinkage()); Function::arg_iterator origArg=++F.arg_begin(); Function::arg_iterator newArg=newFunc->arg_begin(); valueMap.insert(make_pair(F.arg_begin(), lowerConstructor)); for(unsigned i=1;i<F.arg_size();i++) { valueMap.insert(make_pair(&(*origArg), &(*newArg))); ++origArg; ++newArg; } SmallVector<ReturnInst*, 4> returns; CloneFunctionInto(newFunc, &F, valueMap, false, returns); //Find the right place to add the base construtor call assert(lowerConstructor->getNumArgOperands()<=1 && "Native constructors with multiple args are not supported"); Instruction* callPred = NULL; if (lowerConstructor->getNumArgOperands()==1 && Instruction::classof(lowerConstructor->getArgOperand(0))) { //Switch the argument to the one in the new func lowerConstructor->setArgOperand(0, valueMap[lowerConstructor->getArgOperand(0)]); callPred = cast<Instruction>(lowerConstructor->getArgOperand(0)); } else callPred = &newFunc->getEntryBlock().front(); //Add add it lowerConstructor->insertAfter(callPred); //Override the returs values for(unsigned i=0;i<returns.size();i++) { Instruction* newInst = ReturnInst::Create(M.getContext(),lowerConstructor); newInst->insertBefore(returns[i]); returns[i]->removeFromParent(); } //Recursively move all the users of the lower constructor after the call itself Instruction* insertPoint = lowerConstructor->getNextNode(); SmallVector<Value*, 4> usersQueue(lowerConstructor->getNumUses()); unsigned int i; Value::use_iterator it; for(i=usersQueue.size()-1,it=lowerConstructor->use_begin();it!=lowerConstructor->use_end();++it,i--) usersQueue[i]=it->getUser(); SmallSet<Instruction*, 4> movedInstructions; while(!usersQueue.empty()) { Instruction* cur=dyn_cast<Instruction>(usersQueue.pop_back_val()); if(!cur) continue; if(movedInstructions.count(cur)) continue; movedInstructions.insert(cur); cur->moveBefore(insertPoint); //Add users of this instrucution as well usersQueue.resize(usersQueue.size()+cur->getNumUses()); for(i=usersQueue.size()-1,it=cur->use_begin();it!=cur->use_end();++it,i--) usersQueue[i]=it->getUser(); } cast<Instruction>(valueMap[oldLowerConstructor])->eraseFromParent(); }
// Replace "packW" and "unpackW" intrinsics by insert/extract operations and // update the uses accordingly. void FunctionVectorizer::generatePackUnpackCode(Function* f, const WFVInfo& info) { assert (f); SmallVector<CallInst*, 16> eraseVec; for (auto &BB : *f) { Instruction* allocPos = BB.getFirstInsertionPt(); for (auto &I : BB) { Instruction* inst = &I; if (isUnpackWFunctionCall(inst)) { DEBUG_WFV( outs() << "generateUnpackCode(" << *inst << " )\n"; ); CallInst* unpackCall = cast<CallInst>(inst); Value* value = unpackCall->getArgOperand(0); Value* indexVal = unpackCall->getArgOperand(1); // Extract scalar values. Value* extract = generateHorizontalExtract(value, indexVal, unpackCall->getName(), allocPos, unpackCall, info); // If the type only matches structurally, create an additional bitcast. Type* oldType = unpackCall->getType(); Type* newType = extract->getType(); if (oldType != newType) { assert (newType->canLosslesslyBitCastTo(oldType) || WFV::typesMatch(oldType, newType)); Instruction* bc = new BitCastInst(extract, oldType, "", unpackCall); // Copy properties from unpackCall. WFV::copyMetadata(bc, *unpackCall); extract = bc; } // Rewire the use. assert (unpackCall->getNumUses() == 1); Value* use = *unpackCall->use_begin(); assert (isa<Instruction>(use)); Instruction* scalarUse = cast<Instruction>(use); scalarUse->replaceUsesOfWith(unpackCall, extract); // Erase now unused unpack call. eraseVec.push_back(unpackCall); // If the returned extract operation is an alloca, we have to // make sure that all changes to that memory location are // correctly written back to the original memory from which // the sub-element was extracted. // This means we have to insert merge and store operations // after every use of this value (including "forwarded" uses // via casts, phis, and GEPs). // However, we must only merge back those values that were // modified. This is not only for efficiency, but also for // correctness, since there may be uninitialized pointers in // a structure, which we must not load/store from/to (see // test_struct_extra05 with all analyses disabled). if (isa<AllocaInst>(extract) || (isa<BitCastInst>(extract) && isa<AllocaInst>(cast<BitCastInst>(extract)->getOperand(0)))) { generateWriteBackOperations(cast<Instruction>(extract), cast<Instruction>(extract), value, indexVal, info); } } else if (isPackWFunctionCall(inst)) { DEBUG_WFV( outs() << "generatePackCode(" << *inst << " )\n"; ); CallInst* packCall = cast<CallInst>(inst); assert (WFV::isVectorizedType(*packCall->getType()) && "packCall should have vector return type after inst vectorization!"); SmallVector<Value*, 8> scalarVals(info.mVectorizationFactor); // Get scalar results for merge. for (unsigned i=0; i<info.mVectorizationFactor; ++i) { scalarVals[i] = packCall->getArgOperand(i); } // Merge scalar results. Instruction* merge = generateHorizontalMerge(scalarVals, packCall->getType(), "", packCall, info); // Rewire the uses. packCall->replaceAllUsesWith(merge); // Copy properties from packCall. WFV::copyMetadata(merge, *packCall); // Erase now unused pack call. eraseVec.push_back(packCall); }