void Aa::LowerConstantExpr::process(Instruction *inst) { if(isa<llvm::CallInst>(inst)) { CallInst* ci = dyn_cast<CallInst>(inst); for(int idx = 0; idx < ci->getNumArgOperands(); idx++) { llvm::Value *opnd = ci->getArgOperand(idx); if (ConstantExpr *ce = dyn_cast<ConstantExpr>(opnd)) { lower(ce, inst); } } } else { for (unsigned oi = 0, oe = inst->getNumOperands(); oi != oe; oi++) { llvm::Value *opnd = inst->getOperand(oi); if (ConstantExpr *ce = dyn_cast<ConstantExpr>(opnd)) { lower(ce, inst); } } } }
/// \brief Check call has a unary float signature /// It checks following: /// a) call should have a single argument /// b) argument type should be floating point type /// c) call instruction type and argument type should be same /// d) call should only reads memory. /// If all these condition is met then return ValidIntrinsicID /// else return not_intrinsic. Intrinsic::ID llvm::checkUnaryFloatSignature(const CallInst &I, Intrinsic::ID ValidIntrinsicID) { if (I.getNumArgOperands() != 1 || !I.getArgOperand(0)->getType()->isFloatingPointTy() || I.getType() != I.getArgOperand(0)->getType() || !I.onlyReadsMemory()) return Intrinsic::not_intrinsic; return ValidIntrinsicID; }
bool EncoderPass::isAtoiFunction(Instruction *I) { if(I->getOpcode()==Instruction::Add && I->getName().substr(0, 1) == "_") { CallInst *call = dyn_cast<CallInst>(I->getOperand(0)); if(call && call->getNumArgOperands()==1) { Function *F = call->getCalledFunction(); if (F && F->getName()=="atoi") { return true; } } } return false; }
/// AddCatchInfo - Extract the personality and type infos from an eh.selector /// call, and add them to the specified machine basic block. void llvm::AddCatchInfo(const CallInst &I, MachineModuleInfo *MMI, MachineBasicBlock *MBB) { // Inform the MachineModuleInfo of the personality for this landing pad. const ConstantExpr *CE = cast<ConstantExpr>(I.getArgOperand(1)); assert(CE->getOpcode() == Instruction::BitCast && isa<Function>(CE->getOperand(0)) && "Personality should be a function"); MMI->addPersonality(MBB, cast<Function>(CE->getOperand(0))); // Gather all the type infos for this landing pad and pass them along to // MachineModuleInfo. std::vector<const GlobalVariable *> TyInfo; unsigned N = I.getNumArgOperands(); for (unsigned i = N - 1; i > 1; --i) { if (const ConstantInt *CI = dyn_cast<ConstantInt>(I.getArgOperand(i))) { unsigned FilterLength = CI->getZExtValue(); unsigned FirstCatch = i + FilterLength + !FilterLength; assert(FirstCatch <= N && "Invalid filter length"); if (FirstCatch < N) { TyInfo.reserve(N - FirstCatch); for (unsigned j = FirstCatch; j < N; ++j) TyInfo.push_back(ExtractTypeInfo(I.getArgOperand(j))); MMI->addCatchTypeInfo(MBB, TyInfo); TyInfo.clear(); } if (!FilterLength) { // Cleanup. MMI->addCleanup(MBB); } else { // Filter. TyInfo.reserve(FilterLength - 1); for (unsigned j = i + 1; j < FirstCatch; ++j) TyInfo.push_back(ExtractTypeInfo(I.getArgOperand(j))); MMI->addFilterTypeInfo(MBB, TyInfo); TyInfo.clear(); } N = i; } } if (N > 2) { TyInfo.reserve(N - 2); for (unsigned j = 2; j < N; ++j) TyInfo.push_back(ExtractTypeInfo(I.getArgOperand(j))); MMI->addCatchTypeInfo(MBB, TyInfo); } }
void llvm::computeUsesVAFloatArgument(const CallInst &I, MachineModuleInfo &MMI) { FunctionType *FT = cast<FunctionType>(I.getCalledValue()->getType()->getContainedType(0)); if (FT->isVarArg() && !MMI.usesVAFloatArgument()) { for (unsigned i = 0, e = I.getNumArgOperands(); i != e; ++i) { Type *T = I.getArgOperand(i)->getType(); for (auto i : post_order(T)) { if (i->isFloatingPointTy()) { MMI.setUsesVAFloatArgument(true); return; } } } } }
/// ComputeUsesVAFloatArgument - Determine if any floating-point values are /// being passed to this variadic function, and set the MachineModuleInfo's /// usesVAFloatArgument flag if so. This flag is used to emit an undefined /// reference to _fltused on Windows, which will link in MSVCRT's /// floating-point support. void llvm::ComputeUsesVAFloatArgument(const CallInst &I, MachineModuleInfo *MMI) { FunctionType *FT = cast<FunctionType>( I.getCalledValue()->getType()->getContainedType(0)); if (FT->isVarArg() && !MMI->usesVAFloatArgument()) { for (unsigned i = 0, e = I.getNumArgOperands(); i != e; ++i) { Type* T = I.getArgOperand(i)->getType(); for (po_iterator<Type*> i = po_begin(T), e = po_end(T); i != e; ++i) { if (i->isFloatingPointTy()) { MMI->setUsesVAFloatArgument(true); return; } } } } }
void ExtractContracts::validateAnnotation(CallInst &I) { assert(I.getCalledFunction() && "Unexpected virtual function."); assert(I.getNumArgOperands() == 1 && "Unexpected operands."); auto B = I.getParent(); auto F = B->getParent(); auto& DT = getAnalysis<DominatorTreeWrapperPass>(*F).getDomTree(); auto& LI = getAnalysis<LoopInfoWrapperPass>(*F).getLoopInfo(); if (I.getCalledFunction()->getName() == Naming::CONTRACT_INVARIANT) { auto L = LI[B]; if (!L) { llvm_unreachable("Loop invariants must occur inside loops."); } } else { for (auto L : LI) { auto& J = L->getHeader()->getInstList().front(); if (DT.dominates(&J, &I)) { llvm_unreachable("Procedure specifications must occur before loops."); } } } }
void RuntimeHelperFixupPass::FixStringConstructor(Function *old_construct, Function *new_construct) { for (auto it = old_construct->use_begin(), end = old_construct->use_end(); it != end; ++it) { CallInst *CI = dyn_cast<CallInst>(*it); assert (CI); auto num_ops = CI->getNumArgOperands(); SmallVector<Value*, 4> ops; for (size_t i = 1; i < num_ops; ++i) ops.push_back(CI->getArgOperand(i)); IRBuilder<> builder(CI); auto new_call = builder.CreateCall(new_construct, ops); BitCastInst *this_ptr = cast<BitCastInst>(CI->getArgOperand(0)); auto alloc = cast<Instruction>(this_ptr->llvm::User::getOperand(0)); this_ptr->replaceAllUsesWith(new_call); CI->eraseFromParent(); this_ptr->eraseFromParent(); alloc->eraseFromParent(); } }
bool FuncAddrTaken::runOnModule(Module &M) { bool Changed = false; // add declaration of function __patch_at // declare void @__patch_at(void) FunctionType *FT = FunctionType::get(Type::getVoidTy(M.getContext()), false); Function* PatchAt = Function::Create(FT, Function::ExternalLinkage, "__patch_at", &M); if (PatchAt->getName() != "__patch_at") { PatchAt->eraseFromParent(); return false; } Changed = true; // Simple optimization so that no function address will be taken twice // in the same basic block. std::map<BasicBlock*, std::set<std::string> > UniqPatchAt; // before each store instruction that manipulates a function, create a call // to __patch_at for (auto F = M.getFunctionList().begin(); F != M.getFunctionList().end(); F++) { for (auto BB = F->begin(); BB != F->end(); BB++) { for (auto MI = BB->begin(); MI != BB->end(); MI++) { if (isa<StoreInst>(MI)) { // check if the store inst moves a function to a variable Value *V = InnerMost(cast<StoreInst>(MI)->getValueOperand()); addPatchAt(M, FT, V, MI, UniqPatchAt); if (isa<ConstantVector>(V)) { std::set<Value*> patched; for (unsigned i = 0; i < cast<ConstantVector>(V)->getNumOperands(); i++) { Value *VV = InnerMost(cast<ConstantVector>(V)->getOperand(i)); if (patched.find(VV) == patched.end()) { addPatchAt(M, FT, VV, MI, UniqPatchAt); patched.insert(VV); } } } else if (isa<ConstantStruct>(V)) { std::set<Value*> patched; for (unsigned i = 0; i < cast<ConstantStruct>(V)->getNumOperands(); i++) { Value *VV = InnerMost(cast<ConstantStruct>(V)->getOperand(i)); if (patched.find(VV) == patched.end()) { addPatchAt(M, FT, VV, MI, UniqPatchAt); patched.insert(VV); } } } else if (isa<ConstantArray>(V)) { std::set<Value*> patched; for (unsigned i = 0; i < cast<ConstantArray>(V)->getNumOperands(); i++) { Value *VV = InnerMost(cast<ConstantArray>(V)->getOperand(i)); if (patched.find(VV) == patched.end()) { addPatchAt(M, FT, VV, MI, UniqPatchAt); patched.insert(VV); } } } } else if (isa<SelectInst>(MI)) { Value *V = InnerMost(cast<SelectInst>(MI)->getTrueValue()); addPatchAt(M, FT, V, MI, UniqPatchAt); V = InnerMost(cast<SelectInst>(MI)->getFalseValue()); addPatchAt(M, FT, V, MI, UniqPatchAt); } else if (isa<CallInst>(MI)) { CallInst* CI = cast<CallInst>(MI); for (unsigned i = 0; i < CI->getNumArgOperands(); i++) { Value *V = InnerMost(CI->getArgOperand(i)); addPatchAt(M, FT, V, MI, UniqPatchAt); } } else if (isa<InvokeInst>(MI)) { InvokeInst* CI = cast<InvokeInst>(MI); for (unsigned i = 0; i < CI->getNumArgOperands(); i++) { Value *V = InnerMost(CI->getArgOperand(i)); addPatchAt(M, FT, V, MI, UniqPatchAt); } } else if (isa<ReturnInst>(MI)) { Value *V = cast<ReturnInst>(MI)->getReturnValue(); if (V) { V = InnerMost(V); addPatchAt(M, FT, V, MI, UniqPatchAt); } } else if (isa<PHINode>(MI)) { for (unsigned i = 0; i < cast<PHINode>(MI)->getNumIncomingValues(); i++) { Value *V = InnerMost(cast<PHINode>(MI)->getIncomingValue(i)); BasicBlock* BB = cast<PHINode>(MI)->getIncomingBlock(i); // right before the last (maybe terminator) instruction. addPatchAt(M, FT, V, &(BB->back()), UniqPatchAt); } } } } } // TODO: separate the following virtual table traversal code into another pass for (auto G = M.getGlobalList().begin(); G != M.getGlobalList().end(); G++) { if (isa<GlobalVariable>(G) && cast<GlobalVariable>(G)->hasInitializer()) { const GlobalVariable *GV = cast<GlobalVariable>(G); const Constant *C = GV->getInitializer(); if (GV->hasName() && isa<ConstantArray>(C) && GV->getName().startswith("_ZTV")) { std::string VTName = CXXDemangledName(GV->getName().data()); if (VTName.size() && VTName.find("vtable") == 0) { //llvm::errs() << VTName << "\n"; VTName = VTName.substr(11); // get pass "vtable for " llvm::NamedMDNode* MD = M.getOrInsertNamedMetadata("MCFIVtable"); std::string info = VTName; for (unsigned i = 0; i < cast<ConstantArray>(C)->getNumOperands(); i++) { Value *V = InnerMost(cast<ConstantArray>(C)->getOperand(i)); if (isa<Function>(V) && cast<Function>(V)->hasName()) { //llvm::errs() << cast<Function>(V)->getName() << "\n"; info += std::string("#") + cast<Function>(V)->getName().str(); } } MD->addOperand(llvm::MDNode::get(M.getContext(), llvm::MDString::get( M.getContext(), info.c_str()))); } } } } return Changed; }
void AMDGPUPromoteAlloca::handleAlloca(AllocaInst &I) { // Array allocations are probably not worth handling, since an allocation of // the array type is the canonical form. if (!I.isStaticAlloca() || I.isArrayAllocation()) return; IRBuilder<> Builder(&I); // First try to replace the alloca with a vector Type *AllocaTy = I.getAllocatedType(); DEBUG(dbgs() << "Trying to promote " << I << '\n'); if (tryPromoteAllocaToVector(&I)) return; DEBUG(dbgs() << " alloca is not a candidate for vectorization.\n"); const Function &ContainingFunction = *I.getParent()->getParent(); // FIXME: We should also try to get this value from the reqd_work_group_size // function attribute if it is available. unsigned WorkGroupSize = AMDGPU::getMaximumWorkGroupSize(ContainingFunction); int AllocaSize = WorkGroupSize * Mod->getDataLayout().getTypeAllocSize(AllocaTy); if (AllocaSize > LocalMemAvailable) { DEBUG(dbgs() << " Not enough local memory to promote alloca.\n"); return; } std::vector<Value*> WorkList; if (!collectUsesWithPtrTypes(&I, WorkList)) { DEBUG(dbgs() << " Do not know how to convert all uses\n"); return; } DEBUG(dbgs() << "Promoting alloca to local memory\n"); LocalMemAvailable -= AllocaSize; Function *F = I.getParent()->getParent(); Type *GVTy = ArrayType::get(I.getAllocatedType(), WorkGroupSize); GlobalVariable *GV = new GlobalVariable( *Mod, GVTy, false, GlobalValue::InternalLinkage, UndefValue::get(GVTy), Twine(F->getName()) + Twine('.') + I.getName(), nullptr, GlobalVariable::NotThreadLocal, AMDGPUAS::LOCAL_ADDRESS); GV->setUnnamedAddr(true); GV->setAlignment(I.getAlignment()); Value *TCntY, *TCntZ; std::tie(TCntY, TCntZ) = getLocalSizeYZ(Builder); Value *TIdX = getWorkitemID(Builder, 0); Value *TIdY = getWorkitemID(Builder, 1); Value *TIdZ = getWorkitemID(Builder, 2); Value *Tmp0 = Builder.CreateMul(TCntY, TCntZ, "", true, true); Tmp0 = Builder.CreateMul(Tmp0, TIdX); Value *Tmp1 = Builder.CreateMul(TIdY, TCntZ, "", true, true); Value *TID = Builder.CreateAdd(Tmp0, Tmp1); TID = Builder.CreateAdd(TID, TIdZ); Value *Indices[] = { Constant::getNullValue(Type::getInt32Ty(Mod->getContext())), TID }; Value *Offset = Builder.CreateInBoundsGEP(GVTy, GV, Indices); I.mutateType(Offset->getType()); I.replaceAllUsesWith(Offset); I.eraseFromParent(); for (Value *V : WorkList) { CallInst *Call = dyn_cast<CallInst>(V); if (!Call) { Type *EltTy = V->getType()->getPointerElementType(); PointerType *NewTy = PointerType::get(EltTy, AMDGPUAS::LOCAL_ADDRESS); // The operand's value should be corrected on its own. if (isa<AddrSpaceCastInst>(V)) continue; // FIXME: It doesn't really make sense to try to do this for all // instructions. V->mutateType(NewTy); continue; } IntrinsicInst *Intr = dyn_cast<IntrinsicInst>(Call); if (!Intr) { // FIXME: What is this for? It doesn't make sense to promote arbitrary // function calls. If the call is to a defined function that can also be // promoted, we should be able to do this once that function is also // rewritten. std::vector<Type*> ArgTypes; for (unsigned ArgIdx = 0, ArgEnd = Call->getNumArgOperands(); ArgIdx != ArgEnd; ++ArgIdx) { ArgTypes.push_back(Call->getArgOperand(ArgIdx)->getType()); } Function *F = Call->getCalledFunction(); FunctionType *NewType = FunctionType::get(Call->getType(), ArgTypes, F->isVarArg()); Constant *C = Mod->getOrInsertFunction((F->getName() + ".local").str(), NewType, F->getAttributes()); Function *NewF = cast<Function>(C); Call->setCalledFunction(NewF); continue; } Builder.SetInsertPoint(Intr); switch (Intr->getIntrinsicID()) { case Intrinsic::lifetime_start: case Intrinsic::lifetime_end: // These intrinsics are for address space 0 only Intr->eraseFromParent(); continue; case Intrinsic::memcpy: { MemCpyInst *MemCpy = cast<MemCpyInst>(Intr); Builder.CreateMemCpy(MemCpy->getRawDest(), MemCpy->getRawSource(), MemCpy->getLength(), MemCpy->getAlignment(), MemCpy->isVolatile()); Intr->eraseFromParent(); continue; } case Intrinsic::memmove: { MemMoveInst *MemMove = cast<MemMoveInst>(Intr); Builder.CreateMemMove(MemMove->getRawDest(), MemMove->getRawSource(), MemMove->getLength(), MemMove->getAlignment(), MemMove->isVolatile()); Intr->eraseFromParent(); continue; } case Intrinsic::memset: { MemSetInst *MemSet = cast<MemSetInst>(Intr); Builder.CreateMemSet(MemSet->getRawDest(), MemSet->getValue(), MemSet->getLength(), MemSet->getAlignment(), MemSet->isVolatile()); Intr->eraseFromParent(); continue; } case Intrinsic::invariant_start: case Intrinsic::invariant_end: case Intrinsic::invariant_group_barrier: Intr->eraseFromParent(); // FIXME: I think the invariant marker should still theoretically apply, // but the intrinsics need to be changed to accept pointers with any // address space. continue; case Intrinsic::objectsize: { Value *Src = Intr->getOperand(0); Type *SrcTy = Src->getType()->getPointerElementType(); Function *ObjectSize = Intrinsic::getDeclaration(Mod, Intrinsic::objectsize, { Intr->getType(), PointerType::get(SrcTy, AMDGPUAS::LOCAL_ADDRESS) } ); CallInst *NewCall = Builder.CreateCall(ObjectSize, { Src, Intr->getOperand(1) }); Intr->replaceAllUsesWith(NewCall); Intr->eraseFromParent(); continue; } default: Intr->dump(); llvm_unreachable("Don't know how to promote alloca intrinsic use."); } } }
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(); }
void AMDGPUPromoteAlloca::visitAlloca(AllocaInst &I) { IRBuilder<> Builder(&I); // First try to replace the alloca with a vector Type *AllocaTy = I.getAllocatedType(); DEBUG(dbgs() << "Trying to promote " << I << '\n'); if (tryPromoteAllocaToVector(&I)) return; DEBUG(dbgs() << " alloca is not a candidate for vectorization.\n"); // FIXME: This is the maximum work group size. We should try to get // value from the reqd_work_group_size function attribute if it is // available. unsigned WorkGroupSize = 256; int AllocaSize = WorkGroupSize * Mod->getDataLayout()->getTypeAllocSize(AllocaTy); if (AllocaSize > LocalMemAvailable) { DEBUG(dbgs() << " Not enough local memory to promote alloca.\n"); return; } std::vector<Value*> WorkList; if (!collectUsesWithPtrTypes(&I, WorkList)) { DEBUG(dbgs() << " Do not know how to convert all uses\n"); return; } DEBUG(dbgs() << "Promoting alloca to local memory\n"); LocalMemAvailable -= AllocaSize; GlobalVariable *GV = new GlobalVariable( *Mod, ArrayType::get(I.getAllocatedType(), 256), false, GlobalValue::ExternalLinkage, 0, I.getName(), 0, GlobalVariable::NotThreadLocal, AMDGPUAS::LOCAL_ADDRESS); FunctionType *FTy = FunctionType::get( Type::getInt32Ty(Mod->getContext()), false); AttributeSet AttrSet; AttrSet.addAttribute(Mod->getContext(), 0, Attribute::ReadNone); Value *ReadLocalSizeY = Mod->getOrInsertFunction( "llvm.r600.read.local.size.y", FTy, AttrSet); Value *ReadLocalSizeZ = Mod->getOrInsertFunction( "llvm.r600.read.local.size.z", FTy, AttrSet); Value *ReadTIDIGX = Mod->getOrInsertFunction( "llvm.r600.read.tidig.x", FTy, AttrSet); Value *ReadTIDIGY = Mod->getOrInsertFunction( "llvm.r600.read.tidig.y", FTy, AttrSet); Value *ReadTIDIGZ = Mod->getOrInsertFunction( "llvm.r600.read.tidig.z", FTy, AttrSet); Value *TCntY = Builder.CreateCall(ReadLocalSizeY); Value *TCntZ = Builder.CreateCall(ReadLocalSizeZ); Value *TIdX = Builder.CreateCall(ReadTIDIGX); Value *TIdY = Builder.CreateCall(ReadTIDIGY); Value *TIdZ = Builder.CreateCall(ReadTIDIGZ); Value *Tmp0 = Builder.CreateMul(TCntY, TCntZ); Tmp0 = Builder.CreateMul(Tmp0, TIdX); Value *Tmp1 = Builder.CreateMul(TIdY, TCntZ); Value *TID = Builder.CreateAdd(Tmp0, Tmp1); TID = Builder.CreateAdd(TID, TIdZ); std::vector<Value*> Indices; Indices.push_back(Constant::getNullValue(Type::getInt32Ty(Mod->getContext()))); Indices.push_back(TID); Value *Offset = Builder.CreateGEP(GV, Indices); I.mutateType(Offset->getType()); I.replaceAllUsesWith(Offset); I.eraseFromParent(); for (std::vector<Value*>::iterator i = WorkList.begin(), e = WorkList.end(); i != e; ++i) { Value *V = *i; CallInst *Call = dyn_cast<CallInst>(V); if (!Call) { Type *EltTy = V->getType()->getPointerElementType(); PointerType *NewTy = PointerType::get(EltTy, AMDGPUAS::LOCAL_ADDRESS); // The operand's value should be corrected on its own. if (isa<AddrSpaceCastInst>(V)) continue; // FIXME: It doesn't really make sense to try to do this for all // instructions. V->mutateType(NewTy); continue; } IntrinsicInst *Intr = dyn_cast<IntrinsicInst>(Call); if (!Intr) { std::vector<Type*> ArgTypes; for (unsigned ArgIdx = 0, ArgEnd = Call->getNumArgOperands(); ArgIdx != ArgEnd; ++ArgIdx) { ArgTypes.push_back(Call->getArgOperand(ArgIdx)->getType()); } Function *F = Call->getCalledFunction(); FunctionType *NewType = FunctionType::get(Call->getType(), ArgTypes, F->isVarArg()); Constant *C = Mod->getOrInsertFunction(StringRef(F->getName().str() + ".local"), NewType, F->getAttributes()); Function *NewF = cast<Function>(C); Call->setCalledFunction(NewF); continue; } Builder.SetInsertPoint(Intr); switch (Intr->getIntrinsicID()) { case Intrinsic::lifetime_start: case Intrinsic::lifetime_end: // These intrinsics are for address space 0 only Intr->eraseFromParent(); continue; case Intrinsic::memcpy: { MemCpyInst *MemCpy = cast<MemCpyInst>(Intr); Builder.CreateMemCpy(MemCpy->getRawDest(), MemCpy->getRawSource(), MemCpy->getLength(), MemCpy->getAlignment(), MemCpy->isVolatile()); Intr->eraseFromParent(); continue; } case Intrinsic::memset: { MemSetInst *MemSet = cast<MemSetInst>(Intr); Builder.CreateMemSet(MemSet->getRawDest(), MemSet->getValue(), MemSet->getLength(), MemSet->getAlignment(), MemSet->isVolatile()); Intr->eraseFromParent(); continue; } default: Intr->dump(); llvm_unreachable("Don't know how to promote alloca intrinsic use."); } } }
void insertCallToAccessFunction(Function *F, Function *cF) { CallInst *I; Instruction *bI; std::vector<Value *> Args; std::vector<Type *> ArgsTy; Module *M = F->getParent(); std::string name; Function *nF, *tF; FunctionType *FTy; std::stringstream out; Value::user_iterator i = F->user_begin(), e = F->user_end(); while (i != e) { Args.clear(); ArgsTy.clear(); /************* C codes ***********/ if (isa<CallInst>(*i)) { I = dyn_cast<CallInst>(*i); // call to the access function F Args.push_back(I->getArgOperand(0)); ArgsTy.push_back(I->getArgOperand(0)->getType()); // call to the execute function cF Args.push_back(cF); ArgsTy.push_back(PointerType::get(cF->getFunctionType(), 0)); unsigned int t; for (t = 1; t < I->getNumArgOperands(); t++) { Args.push_back(I->getArgOperand(t)); ArgsTy.push_back(I->getArgOperand(t)->getType()); // errs() << *(I->getArgOperand(t)) << " is or not " << // isa<GlobalVariable>(I->getArgOperand(t)) << "\n"; } tF = dyn_cast<Function>(I->getCalledFunction()); FTy = FunctionType::get(tF->getReturnType(), ArgsTy, 0); out.str(std::string()); out << "task_DAE_" << I->getNumArgOperands() - 1; nF = (Function *)M->getOrInsertFunction(out.str(), FTy); CallInst *ci = CallInst::Create(nF, Args, I->getName(), I); i++; I->replaceAllUsesWith(ci); I->eraseFromParent(); } /************* C++ codes ***********/ else { Value::user_iterator bit = (*i)->user_begin(), bite = (*i)->user_end(); Type *iTy = (*i)->getType(); i++; while (bit != bite) { Args.clear(); ArgsTy.clear(); I = dyn_cast<CallInst>(*bit); bit++; // call to the access function F Args.push_back(I->getArgOperand(0)); ArgsTy.push_back(I->getArgOperand(0)->getType()); // call to the execute function cF bI = new BitCastInst(cF, (iTy), "_TPR", I); Args.push_back(bI); ArgsTy.push_back(bI->getType()); unsigned int t; for (t = 1; t < I->getNumArgOperands(); t++) { Args.push_back(I->getArgOperand(t)); ArgsTy.push_back(I->getArgOperand(t)->getType()); } tF = dyn_cast<Function>(I->getCalledFunction()); FTy = FunctionType::get(tF->getReturnType(), ArgsTy, 0); out.str(std::string()); out << "task_DAE_" << I->getNumArgOperands() - 1; nF = (Function *)M->getOrInsertFunction(out.str(), FTy); CallInst *ci = CallInst::Create(nF, Args, I->getName(), I); I->replaceAllUsesWith(ci); I->eraseFromParent(); } } } }
void mapArgumentsToParams(Function *F, ValueToValueMapTy *VMap) { CallInst *I; Instruction *aux = 0; Value *vaux; Value::user_iterator i = F->user_begin(), e = F->user_end(); Function::arg_iterator a = F->arg_begin(); while (i != e) { a = F->arg_begin(); /************* C codes ***********/ if (isa<CallInst>(*i)) { I = dyn_cast<CallInst>(*i); unsigned int t; for (t = 1; t < I->getNumArgOperands(); t++) { aux = 0; vaux = I->getArgOperand(t); while (isa<Instruction>(vaux)) { aux = dyn_cast<Instruction>(vaux); vaux = aux->getOperand(0); } // errs() << "ARG "<< *(a) << " ----------------- " << *vaux << "\n"; Value *argument = &*a; VMap->insert(std::pair<Value *, Value *>(argument, &*vaux)); a++; } i++; } /************* C++ codes ***********/ else { Value::user_iterator bit = (*i)->user_begin(), bite = (*i)->user_end(); i++; while (bit != bite) { I = dyn_cast<CallInst>(*bit); a = F->arg_begin(); bit++; unsigned int t; for (t = 1; t < I->getNumArgOperands(); t++) { aux = 0; vaux = I->getArgOperand(t); errs() << "vaux=" << *vaux << " a=" << *a << "\n"; while ((isa<Instruction>(vaux)) && (!isa<PHINode>(vaux))) { aux = dyn_cast<Instruction>(vaux); if (!isa<PHINode>(aux)) vaux = aux->getOperand(0); // errs() << "vaux="<<*vaux << " a="<<*a <<"\n"; } errs() << "ARG " << *(a) << " ----------------- " << *vaux << "\n"; Value *argument = &*a; VMap->insert(std::pair<Value *, Value *>(argument, vaux)); a++; } } } } }
// // Method: runOnModule() // // Description: // Entry point for this LLVM pass. // Clone functions that take LoadInsts as arguments // // 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 LoadArgs::runOnModule(Module& M) { std::map<std::pair<Function*, const Type * > , Function* > fnCache; bool changed; do { changed = false; for (Module::iterator Func = M.begin(); Func != M.end(); ++Func) { for (Function::iterator B = Func->begin(), FE = Func->end(); B != FE; ++B) { for (BasicBlock::iterator I = B->begin(), BE = B->end(); I != BE;) { CallInst *CI = dyn_cast<CallInst>(I++); if(!CI) continue; if(CI->hasByValArgument()) continue; // if the CallInst calls a function, that is externally defined, // or might be changed, ignore this call site. Function *F = CI->getCalledFunction(); if (!F || (F->isDeclaration() || F->mayBeOverridden())) continue; if(F->hasStructRetAttr()) continue; if(F->isVarArg()) continue; // find the argument we must replace Function::arg_iterator ai = F->arg_begin(), ae = F->arg_end(); unsigned argNum = 0; for(; argNum < CI->getNumArgOperands();argNum++, ++ai) { // do not care about dead arguments if(ai->use_empty()) continue; if(F->getAttributes().getParamAttributes(argNum).hasAttrSomewhere(Attribute::SExt) || F->getAttributes().getParamAttributes(argNum).hasAttrSomewhere(Attribute::ZExt)) continue; if (isa<LoadInst>(CI->getArgOperand(argNum))) break; } // if no argument was a GEP operator to be changed if(ai == ae) continue; LoadInst *LI = dyn_cast<LoadInst>(CI->getArgOperand(argNum)); Instruction * InsertPt = &(Func->getEntryBlock().front()); AllocaInst *NewVal = new AllocaInst(LI->getType(), "",InsertPt); StoreInst *Copy = new StoreInst(LI, NewVal); Copy->insertAfter(LI); /*if(LI->getParent() != CI->getParent()) continue; // Also check that there is no store after the load. // TODO: Check if the load/store do not alias. BasicBlock::iterator bii = LI->getParent()->begin(); Instruction *BII = bii; while(BII != LI) { ++bii; BII = bii; } while(BII != CI) { if(isa<StoreInst>(BII)) break; ++bii; BII = bii; } if(isa<StoreInst>(bii)){ continue; }*/ // Construct the new Type // Appends the struct Type at the beginning std::vector<Type*>TP; for(unsigned c = 0; c < CI->getNumArgOperands();c++) { if(c == argNum) TP.push_back(LI->getPointerOperand()->getType()); TP.push_back(CI->getArgOperand(c)->getType()); } //return type is same as that of original instruction FunctionType *NewFTy = FunctionType::get(CI->getType(), TP, false); numSimplified++; //if(numSimplified > 1000) //return true; Function *NewF; std::map<std::pair<Function*, const Type* > , Function* >::iterator Test; Test = fnCache.find(std::make_pair(F, NewFTy)); if(Test != fnCache.end()) { NewF = Test->second; } else { NewF = Function::Create(NewFTy, GlobalValue::InternalLinkage, F->getName().str() + ".TEST", &M); fnCache[std::make_pair(F, NewFTy)] = NewF; Function::arg_iterator NI = NewF->arg_begin(); ValueToValueMapTy ValueMap; unsigned count = 0; for (Function::arg_iterator II = F->arg_begin(); NI != NewF->arg_end(); ++count, ++NI) { if(count == argNum) { NI->setName("LDarg"); continue; } ValueMap[II] = NI; NI->setName(II->getName()); NI->addAttr(F->getAttributes().getParamAttributes(II->getArgNo() + 1)); ++II; } // Perform the cloning. SmallVector<ReturnInst*,100> Returns; CloneFunctionInto(NewF, F, ValueMap, false, Returns); std::vector<Value*> fargs; for(Function::arg_iterator ai = NewF->arg_begin(), ae= NewF->arg_end(); ai != ae; ++ai) { fargs.push_back(ai); } NewF->setAttributes(NewF->getAttributes().addAttributes( F->getContext(), 0, F->getAttributes().getRetAttributes())); NewF->setAttributes(NewF->getAttributes().addAttributes( F->getContext(), ~0, F->getAttributes().getFnAttributes())); //Get the point to insert the GEP instr. Instruction *InsertPoint; for (BasicBlock::iterator insrt = NewF->front().begin(); isa<AllocaInst>(InsertPoint = insrt); ++insrt) {;} LoadInst *LI_new = new LoadInst(fargs.at(argNum), "", InsertPoint); fargs.at(argNum+1)->replaceAllUsesWith(LI_new); } //this does not seem to be a good idea AttributeSet NewCallPAL=AttributeSet(); // Get the initial attributes of the call AttributeSet CallPAL = CI->getAttributes(); AttributeSet RAttrs = CallPAL.getRetAttributes(); AttributeSet FnAttrs = CallPAL.getFnAttributes(); if (!RAttrs.isEmpty()) NewCallPAL=NewCallPAL.addAttributes(F->getContext(),0, RAttrs); SmallVector<Value*, 8> Args; for(unsigned j =0;j<CI->getNumArgOperands();j++) { if(j == argNum) { Args.push_back(NewVal); } Args.push_back(CI->getArgOperand(j)); // position in the NewCallPAL AttributeSet Attrs = CallPAL.getParamAttributes(j+1); if (!Attrs.isEmpty()) NewCallPAL=NewCallPAL.addAttributes(F->getContext(),Args.size(), Attrs); } // Create the new attributes vec. if (!FnAttrs.isEmpty()) NewCallPAL=NewCallPAL.addAttributes(F->getContext(),~0, FnAttrs); CallInst *CallI = CallInst::Create(NewF,Args,"", CI); CallI->setCallingConv(CI->getCallingConv()); CallI->setAttributes(NewCallPAL); CI->replaceAllUsesWith(CallI); CI->eraseFromParent(); changed = true; } } } } while(changed); return true; }
void AAAnalyzer::handle_inst(Instruction *inst, FunctionWrapper * parent_func) { //outs()<<*inst<<"\n"; outs().flush(); switch (inst->getOpcode()) { // common/bitwise binary operations // Terminator instructions case Instruction::Ret: { ReturnInst* retInst = ((ReturnInst*) inst); if (retInst->getNumOperands() > 0 && !retInst->getOperandUse(0)->getType()->isVoidTy()) { parent_func->addRet(retInst->getOperandUse(0)); } } break; case Instruction::Resume: { Value* resume = ((ResumeInst*) inst)->getOperand(0); parent_func->addResume(resume); } break; case Instruction::Switch: case Instruction::Br: case Instruction::IndirectBr: case Instruction::Unreachable: break; // vector operations case Instruction::ExtractElement: { } break; case Instruction::InsertElement: { } break; case Instruction::ShuffleVector: { } break; // aggregate operations case Instruction::ExtractValue: { Value * agg = ((ExtractValueInst*) inst)->getAggregateOperand(); DyckVertex* aggV = wrapValue(agg); Type* aggTy = agg->getType(); ArrayRef<unsigned> indices = ((ExtractValueInst*) inst)->getIndices(); DyckVertex* currentStruct = aggV; for (unsigned int i = 0; i < indices.size(); i++) { if (isa<CompositeType>(aggTy) && aggTy->isSized()) { if (!aggTy->isStructTy()) { aggTy = ((CompositeType*) aggTy)->getTypeAtIndex(indices[i]); #ifndef ARRAY_SIMPLIFIED current = addPtrOffset(current, (int) indices[i] * dl.getTypeAllocSize(aggTy), dgraph); #endif if (i == indices.size() - 1) { this->makeAlias(currentStruct, wrapValue(inst)); } } else { aggTy = ((CompositeType*) aggTy)->getTypeAtIndex(indices[i]); if (i != indices.size() - 1) { currentStruct = this->addField(currentStruct, -2 - (int) indices[i], NULL); } else { currentStruct = this->addField(currentStruct, -2 - (int) indices[i], wrapValue(inst)); } } } else { break; } } } break; case Instruction::InsertValue: { DyckVertex* resultV = wrapValue(inst); Value * agg = ((InsertValueInst*) inst)->getAggregateOperand(); if (!isa<UndefValue>(agg)) { makeAlias(resultV, wrapValue(agg)); } Value * val = ((InsertValueInst*) inst)->getInsertedValueOperand(); DyckVertex* insertedVal = wrapValue(val); Type *aggTy = inst->getType(); ArrayRef<unsigned> indices = ((InsertValueInst*) inst)->getIndices(); DyckVertex* currentStruct = resultV; for (unsigned int i = 0; i < indices.size(); i++) { if (isa<CompositeType>(aggTy) && aggTy->isSized()) { if (!aggTy->isStructTy()) { aggTy = ((CompositeType*) aggTy)->getTypeAtIndex(indices[i]); #ifndef ARRAY_SIMPLIFIED current = addPtrOffset(current, (int) indices[i] * dl.getTypeAllocSize(aggTy), dgraph); #endif if (i == indices.size() - 1) { this->makeAlias(currentStruct, insertedVal); } } else { aggTy = ((CompositeType*) aggTy)->getTypeAtIndex(indices[i]); if (i != indices.size() - 1) { currentStruct = this->addField(currentStruct, -2 - (int) indices[i], NULL); } else { currentStruct = this->addField(currentStruct, -2 - (int) indices[i], insertedVal); } } } else { break; } } } break; // memory accessing and addressing operations case Instruction::Alloca: { } break; case Instruction::Fence: { } break; case Instruction::AtomicCmpXchg: { Value * retXchg = inst; Value * ptrXchg = inst->getOperand(0); Value * newXchg = inst->getOperand(2); addPtrTo(wrapValue(ptrXchg), wrapValue(retXchg)); addPtrTo(wrapValue(ptrXchg), wrapValue(newXchg)); } break; case Instruction::AtomicRMW: { Value * retRmw = inst; Value * ptrRmw = ((AtomicRMWInst*) inst)->getPointerOperand(); addPtrTo(wrapValue(ptrRmw), wrapValue(retRmw)); switch (((AtomicRMWInst*) inst)->getOperation()) { case AtomicRMWInst::Max: case AtomicRMWInst::Min: case AtomicRMWInst::UMax: case AtomicRMWInst::UMin: case AtomicRMWInst::Xchg: { Value * newRmw = ((AtomicRMWInst*) inst)->getValOperand(); addPtrTo(wrapValue(ptrRmw), wrapValue(newRmw)); } break; default: //others are binary ops like add/sub/... ///@TODO break; } } break; case Instruction::Load: { Value *lval = inst; Value *ladd = inst->getOperand(0); addPtrTo(wrapValue(ladd), wrapValue(lval)); } break; case Instruction::Store: { Value * sval = inst->getOperand(0); Value * sadd = inst->getOperand(1); addPtrTo(wrapValue(sadd), wrapValue(sval)); } break; case Instruction::GetElementPtr: { makeAlias(wrapValue(inst), handle_gep((GEPOperator*) inst)); } break; // conversion operations case Instruction::Trunc: case Instruction::ZExt: case Instruction::SExt: case Instruction::FPTrunc: case Instruction::FPExt: case Instruction::FPToUI: case Instruction::FPToSI: case Instruction::UIToFP: case Instruction::SIToFP: case Instruction::BitCast: case Instruction::PtrToInt: case Instruction::IntToPtr: { Value * itpv = inst->getOperand(0); makeAlias(wrapValue(inst), wrapValue(itpv)); } break; // other operations case Instruction::Invoke: // invoke is a terminal operation { InvokeInst * invoke = (InvokeInst*) inst; LandingPadInst* lpd = invoke->getLandingPadInst(); parent_func->addLandingPad(invoke, lpd); Value * cv = invoke->getCalledValue(); vector<Value*> args; for (unsigned i = 0; i < invoke->getNumArgOperands(); i++) { args.push_back(invoke->getArgOperand(i)); } this->handle_invoke_call_inst(invoke, cv, &args, parent_func); } break; case Instruction::Call: { CallInst * callinst = (CallInst*) inst; if (callinst->isInlineAsm()) { break; } Value * cv = callinst->getCalledValue(); vector<Value*> args; for (unsigned i = 0; i < callinst->getNumArgOperands(); i++) { args.push_back(callinst->getArgOperand(i)); } this->handle_invoke_call_inst(callinst, cv, &args, parent_func); } break; case Instruction::PHI: { PHINode *phi = (PHINode *) inst; int nums = phi->getNumIncomingValues(); for (int i = 0; i < nums; i++) { Value * p = phi->getIncomingValue(i); makeAlias(wrapValue(inst), wrapValue(p)); } } break; case Instruction::Select: { Value *first = ((SelectInst*) inst)->getTrueValue(); Value *second = ((SelectInst*) inst)->getFalseValue(); makeAlias(wrapValue(inst), wrapValue(first)); makeAlias(wrapValue(inst), wrapValue(second)); } break; case Instruction::VAArg: { parent_func->addVAArg(inst); DyckVertex* vaarg = wrapValue(inst); Value * ptrVaarg = inst->getOperand(0); addPtrTo(wrapValue(ptrVaarg), vaarg); } break; case Instruction::LandingPad: // handled with invoke inst case Instruction::ICmp: case Instruction::FCmp: default: break; } }