bool handleCls(LoadInst *li, GlobalVariable *gv) { bool changed = true; if (VERBOSITY("opt") >= 1) { errs() << "\nFound load of class-typed global variable:\n" << *li << '\n'; } BoxedClass *cls = getClassFromGV(gv); if (!cls->is_constant) { assert(0 && "what globally-resolved classes are not constant??"); if (VERBOSITY("opt") >= 1) { errs() << gv->getName() << " is not constant; moving on\n"; } return false; } std::vector<Instruction*> to_remove; for (Value::use_iterator use_it = li->use_begin(), use_end = li->use_end(); use_it != use_end; ++use_it) { if (CallInst *call = dyn_cast<CallInst>(*use_it)) { if (call->getCalledFunction()->getName() == "_maybeDecrefCls") { errs() << "Found decrefcls call: " << *call << '\n'; if (!isUserDefined(cls)) { // Don't delete right away; I think that invalidates the iterator // we're currently iterating over to_remove.push_back(call); } } continue; } GetElementPtrInst *gep = dyn_cast<GetElementPtrInst>(*use_it); if (!gep) { //errs() << "Not a gep: " << **use_it << '\n'; continue; } APInt ap_offset(64, 0, true); bool success = gep->accumulateConstantOffset(*g.tm->getDataLayout(), ap_offset); assert(success); int64_t offset = ap_offset.getSExtValue(); errs() << "Found a gep at offset " << offset << ": " << *gep << '\n'; for (Value::use_iterator gep_use_it = gep->use_begin(), gep_use_end = gep->use_end(); gep_use_it != gep_use_end; ++gep_use_it) { LoadInst *gep_load = dyn_cast<LoadInst>(*gep_use_it); if (!gep_load) { //errs() << "Not a load: " << **gep_use_it << '\n'; continue; } errs() << "Found a load: " << *gep_load << '\n'; if (offset == CLS_DTOR_OFFSET) { errs() << "Dtor; replacing with " << cls->dtor << "\n"; replaceUsesWithConstant(gep_load, (uintptr_t)cls->dtor); changed = true; } else if (offset == CLS_HASATTRS_OFFSET) { errs() << "Hasattrs; replacing with " << cls->hasattrs << "\n"; replaceUsesWithConstant(gep_load, cls->hasattrs); changed = true; } } } for (int i = 0; i < to_remove.size(); i++) { to_remove[i]->eraseFromParent(); changed = true; } if (VERBOSITY()) { llvm::errs() << "Constant-folding this load: " << *li << '\n'; } li->replaceAllUsesWith(embedConstantPtr(cls, g.llvm_class_type_ptr)); changed = true; return changed; }
/// updateCallSites - Update all sites that call F to use NF. CallGraphNode *SRETPromotion::updateCallSites(Function *F, Function *NF) { CallGraph &CG = getAnalysis<CallGraph>(); SmallVector<Value*, 16> Args; // Attributes - Keep track of the parameter attributes for the arguments. SmallVector<AttributeWithIndex, 8> ArgAttrsVec; // Get a new callgraph node for NF. CallGraphNode *NF_CGN = CG.getOrInsertFunction(NF); while (!F->use_empty()) { CallSite CS(*F->use_begin()); Instruction *Call = CS.getInstruction(); const AttrListPtr &PAL = F->getAttributes(); // Add any return attributes. if (Attributes attrs = PAL.getRetAttributes()) ArgAttrsVec.push_back(AttributeWithIndex::get(0, attrs)); // Copy arguments, however skip first one. CallSite::arg_iterator AI = CS.arg_begin(), AE = CS.arg_end(); Value *FirstCArg = *AI; ++AI; // 0th parameter attribute is reserved for return type. // 1th parameter attribute is for first 1st sret argument. unsigned ParamIndex = 2; while (AI != AE) { Args.push_back(*AI); if (Attributes Attrs = PAL.getParamAttributes(ParamIndex)) ArgAttrsVec.push_back(AttributeWithIndex::get(ParamIndex - 1, Attrs)); ++ParamIndex; ++AI; } // Add any function attributes. if (Attributes attrs = PAL.getFnAttributes()) ArgAttrsVec.push_back(AttributeWithIndex::get(~0, attrs)); AttrListPtr NewPAL = AttrListPtr::get(ArgAttrsVec.begin(), ArgAttrsVec.end()); // Build new call instruction. 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(NewPAL); } else { New = CallInst::Create(NF, Args.begin(), Args.end(), "", Call); cast<CallInst>(New)->setCallingConv(CS.getCallingConv()); cast<CallInst>(New)->setAttributes(NewPAL); if (cast<CallInst>(Call)->isTailCall()) cast<CallInst>(New)->setTailCall(); } Args.clear(); ArgAttrsVec.clear(); New->takeName(Call); // Update the callgraph to know that the callsite has been transformed. CallGraphNode *CalleeNode = CG[Call->getParent()->getParent()]; CalleeNode->removeCallEdgeFor(Call); CalleeNode->addCalledFunction(New, NF_CGN); // Update all users of sret parameter to extract value using extractvalue. for (Value::use_iterator UI = FirstCArg->use_begin(), UE = FirstCArg->use_end(); UI != UE; ) { User *U2 = *UI++; CallInst *C2 = dyn_cast<CallInst>(U2); if (C2 && (C2 == Call)) continue; GetElementPtrInst *UGEP = cast<GetElementPtrInst>(U2); ConstantInt *Idx = cast<ConstantInt>(UGEP->getOperand(2)); Value *GR = ExtractValueInst::Create(New, Idx->getZExtValue(), "evi", UGEP); while(!UGEP->use_empty()) { // isSafeToUpdateAllCallers has checked that all GEP uses are // LoadInsts LoadInst *L = cast<LoadInst>(*UGEP->use_begin()); L->replaceAllUsesWith(GR); L->eraseFromParent(); } UGEP->eraseFromParent(); continue; } Call->eraseFromParent(); } return NF_CGN; }
bool Aa::LowerGepPass::runOnFunction(Function &F) { const llvm::Type *ptr_int_type = TD->getIntPtrType(F.getContext()); for (Function::iterator bi = F.begin(), be = F.end(); bi != be; ++bi) { BasicBlock *bb = bi; BasicBlock::iterator ii = bb->begin(); while (ii != bb->end()) { GetElementPtrInst *gep = dyn_cast<GetElementPtrInst>(ii); BasicBlock::iterator gi = ii++; if (!gep) { continue; } for (llvm::Value::use_iterator ui = gep->use_begin(), ue = gep->use_end(); ui != ue; ++ui) { Use &u = ui.getUse(); IOCode ioc = get_io_code(u); if (ioc == NOT_IO) continue; u.set(CastInst::CreatePointerCast(gep->getPointerOperand() , gep->getType() , "", gep)); } assert(gep->hasIndices() && "GEP without indices??"); llvm::Value *ptr = gep->getPointerOperand(); const Type *ctype = ptr->getType(); // deal with the base pointer first llvm::Value *base = gep->getPointerOperand(); std::string base_name = gep->getNameStr() + ".base"; llvm::Value *address = new PtrToIntInst(base, ptr_int_type, base_name + ".cast", gi); unsigned i = 0; for (User::op_iterator oi = gep->idx_begin(), oe = gep->idx_end(); oi != oe; ++oi, ++i) { llvm::Value *index = *oi; llvm::Value *offset = NULL; std::stringstream index_name; index_name << gep->getNameStr() << ".idx." << i; if (const SequentialType *qtype = dyn_cast<SequentialType>(ctype)) { // multiply index by size of element unsigned element_size = getTypePaddedSize(TD, qtype->getElementType()); const llvm::IntegerType *index_type = cast<IntegerType>(index->getType()); ConstantInt *cint = ConstantInt::get(index_type, element_size); assert(cint && "uh oh!"); offset = BinaryOperator::Create(Instruction::Mul , cint , index , index_name.str() , gi); ctype = qtype->getElementType(); } else if (const StructType *stype = dyn_cast<StructType>(ctype)) { // calculate offset into the struct const StructLayout *layout = TD->getStructLayout(stype); unsigned idx = cast<ConstantInt>(index)->getValue().getZExtValue(); unsigned struct_offset = layout->getElementOffset(idx); offset = ConstantInt::get(ptr_int_type, struct_offset); ctype = stype->getElementType(idx); } else assert(false && "unhandled offset into composite type"); // add offset to the address assert(address && "uh oh!"); std::stringstream add_name; add_name << gep->getNameStr() << ".lvl." << i; if (offset->getType() != address->getType()) { offset = CastInst::CreateIntegerCast(offset, address->getType() , false, offset->getName() + ".resized" , gi); } address = BinaryOperator::Create(Instruction::Add , address, offset , add_name.str(), gi); } if (address->getType() != ptr_int_type) address = CastInst::CreateIntegerCast(address, ptr_int_type , false, address->getName() + ".final", gi); Instruction *new_ptr = new IntToPtrInst(address, gep->getType() , gep->getName() + ".cast"); ReplaceInstWithInst(bb->getInstList(), gi, new_ptr); } } return true; }