/// Remove redundant runtime calls for stack allocated buffers. /// If a buffer is allocated on the stack it's not needed to explicitly set /// the RC_DEALLOCATING_FLAG flag (except there is code which may depend on it). /// Also the a call to swift_deallocClassInstance (which stems from an inlined /// deallocator) is not needed. /// /// %0 = alloca /// ... /// call @swift_setDeallocating(%0) // not needed /// // code which does not depend on the RC_DEALLOCATING_FLAG flag. /// call @swift_deallocClassInstance(%0) // not needed /// call @llvm.lifetime.end(%0) /// static void removeRedundantRTCalls(CallInst *DeallocCall) { BasicBlock::iterator Iter(DeallocCall); BasicBlock::iterator Begin = DeallocCall->getParent()->begin(); Value *Buffer = DeallocCall->getArgOperand(0); CallInst *RedundantDealloc = nullptr; CallInst *RedundantSetFlag = nullptr; SmallVector<Instruction *, 2> ToDelete; while (Iter != Begin) { --Iter; Instruction *I = &*Iter; if (auto *CI = dyn_cast<CallInst>(I)) { // Check if we have a runtime function with the buffer as argument. if (CI->getNumArgOperands() < 1) break; if (CI->getArgOperand(0)->stripPointerCasts() != Buffer) break; auto *Callee = dyn_cast<Constant>(CI->getCalledValue()); if (!Callee) break; // The callee function my be a bitcast constant expression. if (auto *U = dyn_cast<ConstantExpr>(Callee)) { if (U->getOpcode() == Instruction::BitCast) Callee = U->getOperand(0); } auto *RTFunc = dyn_cast<Function>(Callee); if (!RTFunc) break; if (RTFunc->getName() == "swift_setDeallocating") { assert(RedundantDealloc && "dealloc call must follow setDeallocating"); assert(!RedundantSetFlag && "multiple setDeallocating calls"); RedundantSetFlag = CI; continue; } if (RTFunc->getName() == "swift_deallocClassInstance") { assert(!RedundantSetFlag && "dealloc call must follow setDeallocating"); assert(!RedundantDealloc && "multiple deallocClassInstance calls"); RedundantDealloc = CI; continue; } break; } // Bail if we have an instruction which may read the RC_DEALLOCATING_FLAG // flag. if (I->mayReadFromMemory()) break; } if (RedundantDealloc) RedundantDealloc->eraseFromParent(); if (RedundantSetFlag) RedundantSetFlag->eraseFromParent(); }
bool LowerExpectIntrinsic::runOnFunction(Function &F) { for (Function::iterator I = F.begin(), E = F.end(); I != E;) { BasicBlock *BB = I++; // Create "block_weights" metadata. if (BranchInst *BI = dyn_cast<BranchInst>(BB->getTerminator())) { if (HandleIfExpect(BI)) IfHandled++; } else if (SwitchInst *SI = dyn_cast<SwitchInst>(BB->getTerminator())) { if (HandleSwitchExpect(SI)) IfHandled++; } // remove llvm.expect intrinsics. for (BasicBlock::iterator BI = BB->begin(), BE = BB->end(); BI != BE; ) { CallInst *CI = dyn_cast<CallInst>(BI++); if (!CI) continue; Function *Fn = CI->getCalledFunction(); if (Fn && Fn->getIntrinsicID() == Intrinsic::expect) { Value *Exp = CI->getArgOperand(0); CI->replaceAllUsesWith(Exp); CI->eraseFromParent(); } } } return false; }
// visitCallInst - This converts all LLVM call instructions into invoke // instructions. The except part of the invoke goes to the "LongJmpBlkPre" // that grabs the exception and proceeds to determine if it's a longjmp // exception or not. void LowerSetJmp::visitCallInst(CallInst& CI) { if (CI.getCalledFunction()) if (!IsTransformableFunction(CI.getCalledFunction()->getName()) || CI.getCalledFunction()->isIntrinsic()) return; BasicBlock* OldBB = CI.getParent(); // If not reachable from a setjmp call, don't transform. if (!DFSBlocks.count(OldBB)) return; BasicBlock* NewBB = OldBB->splitBasicBlock(CI); assert(NewBB && "Couldn't split BB of \"call\" instruction!!"); DFSBlocks.insert(NewBB); NewBB->setName("Call2Invoke"); Function* Func = OldBB->getParent(); // Construct the new "invoke" instruction. TerminatorInst* Term = OldBB->getTerminator(); std::vector<Value*> Params(CI.op_begin() + 1, CI.op_end()); InvokeInst* II = InvokeInst::Create(CI.getCalledValue(), NewBB, PrelimBBMap[Func], Params.begin(), Params.end(), CI.getName(), Term); II->setCallingConv(CI.getCallingConv()); II->setAttributes(CI.getAttributes()); // Replace the old call inst with the invoke inst and remove the call. CI.replaceAllUsesWith(II); CI.eraseFromParent(); // The old terminator is useless now that we have the invoke inst. Term->eraseFromParent(); ++CallsTransformed; }
bool OptimizeFastMemoryChecks::runOnFunction(Function &F) { ABA = &getAnalysis<ArrayBoundsAnalysis>(); MSCI = &getAnalysis<MSCInfo>(); // Visit all call instructions in the function to find the checks. visit(F); for (size_t i = 0, N = FastCheckCalls.size(); i < N; ++i) { CallInst *CI = FastCheckCalls[i]; CheckInfoType *Info = MSCI->getCheckInfo(CI->getCalledFunction()); assert(Info && Info->isFastMemoryCheck() && "expecting fast memory checks"); Value *AccessPtr = CI->getArgOperand(Info->PtrArgNo); Value *AccessSize = CI->getArgOperand(Info->SizeArgNo); Value *ObjectPtr = CI->getArgOperand(Info->ObjArgNo); Value *ObjectSize = CI->getArgOperand(Info->ObjSizeArgNo); if (ABA->isAlwaysInBounds(AccessPtr, AccessSize, ObjectPtr, ObjectSize)) { CI->eraseFromParent(); ++FastMemoryChecksRemoved; } } bool ChangedAnything = !FastCheckCalls.empty(); FastCheckCalls.clear(); return ChangedAnything; }
// StripDebugInfo - Strip debug info in the module if it exists. // To do this, we remove llvm.dbg.func.start, llvm.dbg.stoppoint, and // llvm.dbg.region.end calls, and any globals they point to if now dead. static bool StripDebugInfo(Module &M) { bool Changed = false; // Remove all of the calls to the debugger intrinsics, and remove them from // the module. if (Function *Declare = M.getFunction("llvm.dbg.declare")) { while (!Declare->use_empty()) { CallInst *CI = cast<CallInst>(Declare->use_back()); CI->eraseFromParent(); } Declare->eraseFromParent(); Changed = true; } if (Function *DbgVal = M.getFunction("llvm.dbg.value")) { while (!DbgVal->use_empty()) { CallInst *CI = cast<CallInst>(DbgVal->use_back()); CI->eraseFromParent(); } DbgVal->eraseFromParent(); Changed = true; } for (Module::named_metadata_iterator NMI = M.named_metadata_begin(), NME = M.named_metadata_end(); NMI != NME;) { NamedMDNode *NMD = NMI; ++NMI; if (NMD->getName().startswith("llvm.dbg.")) { NMD->eraseFromParent(); Changed = true; } } for (Module::iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI) for (Function::iterator FI = MI->begin(), FE = MI->end(); FI != FE; ++FI) for (BasicBlock::iterator BI = FI->begin(), BE = FI->end(); BI != BE; ++BI) { if (!BI->getDebugLoc().isUnknown()) { Changed = true; BI->setDebugLoc(DebugLoc()); } } return Changed; }
/** * removeUndefCalls -- remove calls with undef function * * These are irrelevant to the code, so may be removed completely. */ void FunctionStaticSlicer::removeUndefCalls(ModulePass *MP, Function &F) { for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E;) { CallInst *CI = dyn_cast<CallInst>(&*I); ++I; if (CI && isa<UndefValue>(CI->getCalledValue())) { CI->replaceAllUsesWith(UndefValue::get(CI->getType())); CI->eraseFromParent(); } } }
static bool ExpandOpForIntSize(Module *M, unsigned Bits, bool Mul) { IntegerType *IntTy = IntegerType::get(M->getContext(), Bits); SmallVector<Type *, 1> Types; Types.push_back(IntTy); Intrinsic::ID ID = (Mul ? Intrinsic::umul_with_overflow : Intrinsic::uadd_with_overflow); std::string Name = Intrinsic::getName(ID, Types); Function *Intrinsic = M->getFunction(Name); if (!Intrinsic) return false; for (Value::use_iterator CallIter = Intrinsic->use_begin(), E = Intrinsic->use_end(); CallIter != E; ) { CallInst *Call = dyn_cast<CallInst>(*CallIter++); if (!Call) { report_fatal_error("ExpandArithWithOverflow: Taking the address of a " "*.with.overflow intrinsic is not allowed"); } Value *VariableArg; ConstantInt *ConstantArg; if (ConstantInt *C = dyn_cast<ConstantInt>(Call->getArgOperand(0))) { VariableArg = Call->getArgOperand(1); ConstantArg = C; } else if (ConstantInt *C = dyn_cast<ConstantInt>(Call->getArgOperand(1))) { VariableArg = Call->getArgOperand(0); ConstantArg = C; } else { errs() << "Use: " << *Call << "\n"; report_fatal_error("ExpandArithWithOverflow: At least one argument of " "*.with.overflow must be a constant"); } Value *ArithResult = BinaryOperator::Create( (Mul ? Instruction::Mul : Instruction::Add), VariableArg, ConstantArg, Call->getName() + ".arith", Call); uint64_t ArgMax; if (Mul) { ArgMax = UintTypeMax(Bits) / ConstantArg->getZExtValue(); } else { ArgMax = UintTypeMax(Bits) - ConstantArg->getZExtValue(); } Value *OverflowResult = new ICmpInst( Call, CmpInst::ICMP_UGT, VariableArg, ConstantInt::get(IntTy, ArgMax), Call->getName() + ".overflow"); // Construct the struct result. Value *NewStruct = UndefValue::get(Call->getType()); NewStruct = CreateInsertValue(NewStruct, 0, ArithResult, Call); NewStruct = CreateInsertValue(NewStruct, 1, OverflowResult, Call); Call->replaceAllUsesWith(NewStruct); Call->eraseFromParent(); } Intrinsic->eraseFromParent(); return true; }
bool llvm::StripDebugInfo(Module &M) { bool Changed = false; // Remove all of the calls to the debugger intrinsics, and remove them from // the module. if (Function *Declare = M.getFunction("llvm.dbg.declare")) { while (!Declare->use_empty()) { CallInst *CI = cast<CallInst>(Declare->user_back()); CI->eraseFromParent(); } Declare->eraseFromParent(); Changed = true; } if (Function *DbgVal = M.getFunction("llvm.dbg.value")) { while (!DbgVal->use_empty()) { CallInst *CI = cast<CallInst>(DbgVal->user_back()); CI->eraseFromParent(); } DbgVal->eraseFromParent(); Changed = true; } for (Module::named_metadata_iterator NMI = M.named_metadata_begin(), NME = M.named_metadata_end(); NMI != NME;) { NamedMDNode *NMD = NMI; ++NMI; if (NMD->getName().startswith("llvm.dbg.")) { NMD->eraseFromParent(); Changed = true; } } for (Function &F : M) Changed |= stripDebugInfo(F); if (GVMaterializer *Materializer = M.getMaterializer()) Materializer->setStripDebugInfo(); return Changed; }
void AsmDirectivesVisitor::visitCallInst(CallInst &CI) { if (!CI.isInlineAsm() || !cast<InlineAsm>(CI.getCalledValue())->isAsmMemory()) return; // In NaCl ``asm("":::"memory")`` always comes in pairs, straddling a // sequentially consistent fence. Other passes rewrite this fence to // an equivalent stable NaCl intrinsic, meaning that this assembly can // be removed. CI.eraseFromParent(); ModifiedFunction = true; }
CallInst* FunctionCalls::changeFunctionCall(Module &module, Change* change) { FunctionChange *funChange = (FunctionChange*)change; CallInst *oldCallInst = dyn_cast<CallInst>(funChange->getValue()); CallInst *newCallInst = NULL; string oldFunction = oldCallInst->getCalledFunction()->getName(); string newFunction = funChange->getSwitch(); // TODO: use the types vector to not assume signature Function *newCallee = module.getFunction(newFunction); if (newCallee) { errs() << "Changing function call from " << oldFunction << " to " << newFunction << "\n"; if (oldFunction != newFunction) { // retrieving original operand Value *oldOperand = oldCallInst->getOperand(0); // downcasting operand Type *fType = Type::getFloatTy(module.getContext()); FPTruncInst *newOperand = new FPTruncInst(oldOperand, fType, "", oldCallInst); // populating array of operands vector<Value*> operands; operands.push_back(newOperand); ArrayRef<Value*> *arrayRefOperands = new ArrayRef<Value*>(operands); // creating the new CallInst newCallInst = CallInst::Create(newCallee, *arrayRefOperands, "newCall", oldCallInst); // casting result to double Type *dType = Type::getDoubleTy(module.getContext()); FPExtInst *result = new FPExtInst(newCallInst, dType, "", oldCallInst); // replacing all uses of call instruction oldCallInst->replaceAllUsesWith(result); // deleting old callInst oldCallInst->eraseFromParent(); errs() << "\tChange was successful\n"; } else { errs() << "\tNo change required\n"; } } else { errs() << "\tDid not find function " << newFunction << "\n"; } return newCallInst; }
void RuntimeHelperFixupPass::FixArrayInit(Function *F) { Module *M = F->getParent(); LLVMContext &ctx = F->getContext(); for (auto it = F->use_begin(), end = F->use_end(); it != end; ++it) { CallInst *CI = dyn_cast<CallInst>(*it); assert (CI && "Unknown usage for array init helper"); Instruction *field_runtime_handle = dyn_cast<Instruction>(CI->getArgOperand(1)); assert (field_runtime_handle); MDNode *md = field_runtime_handle->getMetadata("silk_runtime_field_handle"); assert (md); ConstantInt *handle = dyn_cast<ConstantInt>(md->getOperand(0)); assert(handle); auto vm_field = reinterpret_cast<VMField*>(handle->getValue().getLimitedValue()); auto field_map = vm_field->field_mapping(); auto vm_named_class = dynamic_cast<VMNamedClass*>(vm_field->type()); auto size = vm_named_class->type_def()->class_size(); raw_istream is(field_map.start(), size); std::vector<uint8_t> buf; buf.resize(size); is.read((char*)buf.data(), size); Constant *predefined_value = ConstantDataArray::get(ctx, buf); auto GV = new GlobalVariable(*M, predefined_value->getType(), true, GlobalValue::InternalLinkage, predefined_value, ".initdata"); Value *array_ptr = CI->getArgOperand(0); IRBuilder<> builder(CI); auto intrinsic_array_base = intrinsic_->array_base_pointer(); auto array_ptr_casted = builder.CreateBitCast(array_ptr, builder.getInt8PtrTy()); auto array_base_ptr = builder.CreateCall(intrinsic_array_base, array_ptr_casted); builder.CreateMemCpy(array_base_ptr, GV, ConstantInt::get(Type::getInt64Ty(ctx), size), 0); CI->eraseFromParent(); } }
bool OptimizeGEPChecks::runOnFunction(Function &F) { ABC = &getAnalysis<ArrayBoundsCheckLocal>(); MSCI = &getAnalysis<MSCInfo>(); // Visit all call instructions in the function. visit(F); for (size_t i = 0, N = ToRemove.size(); i < N; ++i) { CallInst *CI = ToRemove[i]; CheckInfoType *Info = MSCI->getCheckInfo(CI->getCalledFunction()); CI->replaceAllUsesWith(CI->getArgOperand(Info->DestPtrArgNo)); CI->eraseFromParent(); ++SafeGEPs; } bool ChangedAnything = !ToRemove.empty(); ToRemove.clear(); return ChangedAnything; }
void ArgumentRecovery::fixCallSites(Function& base, Function& newTarget, const CallInformation& ci) { auto targetInfo = TargetInfo::getTargetInfo(*base.getParent()); // loop over callers and transform call sites. while (!base.use_empty()) { CallInst* call = cast<CallInst>(base.user_back()); Function* caller = call->getParent()->getParent(); auto registers = getRegisterPtr(*caller); auto newCall = createCallSite(*targetInfo, ci, newTarget, *registers, *call); // replace call newCall->takeName(call); call->eraseFromParent(); md::incrementFunctionVersion(*caller); } }
/// Replaces /// /// strong_retain_unowned %x /// ... // speculatively executable instructions, including loads from %x /// strong_release %x /// /// with /// /// ... // speculatively executable instructions, including loads from %x /// check_unowned %x /// static bool performLocalRetainUnownedOpt(CallInst *Retain, BasicBlock &BB, ARCEntryPointBuilder &B) { Value *RetainedObject = Retain->getArgOperand(0); Value *LoadBaseAddr = getBaseAddress(RetainedObject); auto BBI = Retain->getIterator(), BBE = BB.getTerminator()->getIterator(); // Scan until we get to the end of the block. for (++BBI; BBI != BBE; ++BBI) { Instruction &I = *BBI; if (classifyInstruction(I) == RT_Release) { CallInst *ThisRelease = cast<CallInst>(&I); // Is this the trailing release of the unowned-retained reference? if (ThisRelease->getArgOperand(0) != RetainedObject) return false; // Replace the trailing release with a check_unowned. B.setInsertPoint(ThisRelease); B.createCheckUnowned(RetainedObject, ThisRelease); Retain->eraseFromParent(); ThisRelease->eraseFromParent(); ++NumRetainReleasePairs; return true; } if (auto *LI = dyn_cast<LoadInst>(&I)) { // Accept loads from the unowned-referenced object. This may load garbage // values, but they are not used until the final check_unowned succeeds. if (getBaseAddress(LI->getPointerOperand()) == LoadBaseAddr) continue; } // Other than loads from the unowned-referenced object we only accept // speculatively executable instructions. if (!isSafeToSpeculativelyExecute(&I)) return false; } return false; }
bool StripDebugDeclare::runOnModule(Module &M) { if (skipModule(M)) return false; Function *Declare = M.getFunction("llvm.dbg.declare"); std::vector<Constant*> DeadConstants; if (Declare) { while (!Declare->use_empty()) { CallInst *CI = cast<CallInst>(Declare->user_back()); Value *Arg1 = CI->getArgOperand(0); Value *Arg2 = CI->getArgOperand(1); assert(CI->use_empty() && "llvm.dbg intrinsic should have void result"); CI->eraseFromParent(); if (Arg1->use_empty()) { if (Constant *C = dyn_cast<Constant>(Arg1)) DeadConstants.push_back(C); else RecursivelyDeleteTriviallyDeadInstructions(Arg1); } if (Arg2->use_empty()) if (Constant *C = dyn_cast<Constant>(Arg2)) DeadConstants.push_back(C); } Declare->eraseFromParent(); } while (!DeadConstants.empty()) { Constant *C = DeadConstants.back(); DeadConstants.pop_back(); if (GlobalVariable *GV = dyn_cast<GlobalVariable>(C)) { if (GV->hasLocalLinkage()) RemoveDeadConstant(GV); } else RemoveDeadConstant(C); } return true; }
/// This function strips all debug info intrinsics, except for llvm.dbg.declare. /// If an llvm.dbg.declare intrinsic is invalid, then this function simply /// strips that use. void llvm::CheckDebugInfoIntrinsics(Module *M) { if (Function *FuncStart = M->getFunction("llvm.dbg.func.start")) { while (!FuncStart->use_empty()) cast<CallInst>(FuncStart->use_back())->eraseFromParent(); FuncStart->eraseFromParent(); } if (Function *StopPoint = M->getFunction("llvm.dbg.stoppoint")) { while (!StopPoint->use_empty()) cast<CallInst>(StopPoint->use_back())->eraseFromParent(); StopPoint->eraseFromParent(); } if (Function *RegionStart = M->getFunction("llvm.dbg.region.start")) { while (!RegionStart->use_empty()) cast<CallInst>(RegionStart->use_back())->eraseFromParent(); RegionStart->eraseFromParent(); } if (Function *RegionEnd = M->getFunction("llvm.dbg.region.end")) { while (!RegionEnd->use_empty()) cast<CallInst>(RegionEnd->use_back())->eraseFromParent(); RegionEnd->eraseFromParent(); } if (Function *Declare = M->getFunction("llvm.dbg.declare")) { if (!Declare->use_empty()) { DbgDeclareInst *DDI = cast<DbgDeclareInst>(Declare->use_back()); if (!isa<MDNode>(DDI->getArgOperand(0)) || !isa<MDNode>(DDI->getArgOperand(1))) { while (!Declare->use_empty()) { CallInst *CI = cast<CallInst>(Declare->use_back()); CI->eraseFromParent(); } Declare->eraseFromParent(); } } } }
bool InlineSpecials::runOnFunction(Function &F) { std::set<CallInst*> worklist; for(inst_iterator i = inst_begin(F), e = inst_end(F); i != e; ++i) { Instruction *I = &*i; if(CallInst *C = dyn_cast<CallInst>(I)) { //get the target of the call, if known Function *invoked = C->getCalledFunction(); if(invoked != NULL) { worklist.insert(C); } } } for(std::set<CallInst*>::iterator itr = worklist.begin(); itr != worklist.end(); itr++) { CallInst *C = *itr; Function *invoked = C->getCalledFunction(); string invokedFuncName = invoked->getName(); map<string,ReplaceFunctionPt>::iterator it = specialMap.find(invokedFuncName); if(it != specialMap.end()) { ReplaceFunctionPt func = it->second; Value *newv = func(F.getParent(), C, this); C->replaceAllUsesWith(newv); C->eraseFromParent(); } } return false; }
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(); } }
void visitCallInst(CallInst &I) { string intrinsic = I.getCalledFunction()->getName().str(); if(intrinsic.find("modmul") != -1) { CallInst *enterMontpro1 = enterMontgomery(I.getOperand(0), I.getOperand(2), &I); CallInst *enterMontpro2 = enterMontgomery(I.getOperand(1), I.getOperand(2), &I); CallInst *mulMontpro = mulMontgomery(I.getName().str(), enterMontpro1, enterMontpro2, I.getOperand(2), &I); CallInst *exitMontpro = leaveMontgomery(mulMontpro, I.getOperand(2), &I); I.replaceAllUsesWith(exitMontpro); I.removeFromParent(); } else if(intrinsic.find("modexp") != -1) { CallInst *enterMontpro1 = enterMontgomery(I.getOperand(0), I.getOperand(2), &I); CallInst *expMontpro = expMontgomery(I.getName().str(), enterMontpro1, I.getOperand(1), I.getOperand(2), &I); CallInst *exitMontpro = leaveMontgomery(expMontpro, I.getOperand(2), &I); I.replaceAllUsesWith(exitMontpro); I.eraseFromParent(); } }
bool ObjCARCContract::tryToPeepholeInstruction( Function &F, Instruction *Inst, inst_iterator &Iter, SmallPtrSetImpl<Instruction *> &DependingInsts, SmallPtrSetImpl<const BasicBlock *> &Visited, bool &TailOkForStoreStrongs) { // Only these library routines return their argument. In particular, // objc_retainBlock does not necessarily return its argument. ARCInstKind Class = GetBasicARCInstKind(Inst); switch (Class) { case ARCInstKind::FusedRetainAutorelease: case ARCInstKind::FusedRetainAutoreleaseRV: return false; case ARCInstKind::Autorelease: case ARCInstKind::AutoreleaseRV: return contractAutorelease(F, Inst, Class, DependingInsts, Visited); case ARCInstKind::Retain: // Attempt to convert retains to retainrvs if they are next to function // calls. if (!optimizeRetainCall(F, Inst)) return false; // If we succeed in our optimization, fall through. // FALLTHROUGH case ARCInstKind::RetainRV: { // If we're compiling for a target which needs a special inline-asm // marker to do the retainAutoreleasedReturnValue optimization, // insert it now. if (!RetainRVMarker) return false; BasicBlock::iterator BBI = Inst; BasicBlock *InstParent = Inst->getParent(); // Step up to see if the call immediately precedes the RetainRV call. // If it's an invoke, we have to cross a block boundary. And we have // to carefully dodge no-op instructions. do { if (&*BBI == InstParent->begin()) { BasicBlock *Pred = InstParent->getSinglePredecessor(); if (!Pred) goto decline_rv_optimization; BBI = Pred->getTerminator(); break; } --BBI; } while (IsNoopInstruction(BBI)); if (&*BBI == GetArgRCIdentityRoot(Inst)) { DEBUG(dbgs() << "Adding inline asm marker for " "retainAutoreleasedReturnValue optimization.\n"); Changed = true; InlineAsm *IA = InlineAsm::get(FunctionType::get(Type::getVoidTy(Inst->getContext()), /*isVarArg=*/false), RetainRVMarker->getString(), /*Constraints=*/"", /*hasSideEffects=*/true); CallInst::Create(IA, "", Inst); } decline_rv_optimization: return false; } case ARCInstKind::InitWeak: { // objc_initWeak(p, null) => *p = null CallInst *CI = cast<CallInst>(Inst); if (IsNullOrUndef(CI->getArgOperand(1))) { Value *Null = ConstantPointerNull::get(cast<PointerType>(CI->getType())); Changed = true; new StoreInst(Null, CI->getArgOperand(0), CI); DEBUG(dbgs() << "OBJCARCContract: Old = " << *CI << "\n" << " New = " << *Null << "\n"); CI->replaceAllUsesWith(Null); CI->eraseFromParent(); } return true; } case ARCInstKind::Release: // Try to form an objc store strong from our release. If we fail, there is // nothing further to do below, so continue. tryToContractReleaseIntoStoreStrong(Inst, Iter); return true; case ARCInstKind::User: // Be conservative if the function has any alloca instructions. // Technically we only care about escaping alloca instructions, // but this is sufficient to handle some interesting cases. if (isa<AllocaInst>(Inst)) TailOkForStoreStrongs = false; return true; case ARCInstKind::IntrinsicUser: // Remove calls to @clang.arc.use(...). Inst->eraseFromParent(); return true; default: return true; } }
/// processMemCpy - perform simplication of memcpy's. If we have memcpy A which /// copies X to Y, and memcpy B which copies Y to Z, then we can rewrite B to be /// a memcpy from X to Z (or potentially a memmove, depending on circumstances). /// This allows later passes to remove the first memcpy altogether. bool MemCpyOpt::processMemCpy(MemCpyInst *M) { MemoryDependenceAnalysis &MD = getAnalysis<MemoryDependenceAnalysis>(); // The are two possible optimizations we can do for memcpy: // a) memcpy-memcpy xform which exposes redundance for DSE. // b) call-memcpy xform for return slot optimization. MemDepResult dep = MD.getDependency(M); if (!dep.isClobber()) return false; if (!isa<MemCpyInst>(dep.getInst())) { if (CallInst *C = dyn_cast<CallInst>(dep.getInst())) return performCallSlotOptzn(M, C); return false; } MemCpyInst *MDep = cast<MemCpyInst>(dep.getInst()); // We can only transforms memcpy's where the dest of one is the source of the // other if (M->getSource() != MDep->getDest()) return false; // Second, the length of the memcpy's must be the same, or the preceeding one // must be larger than the following one. ConstantInt *C1 = dyn_cast<ConstantInt>(MDep->getLength()); ConstantInt *C2 = dyn_cast<ConstantInt>(M->getLength()); if (!C1 || !C2) return false; uint64_t DepSize = C1->getValue().getZExtValue(); uint64_t CpySize = C2->getValue().getZExtValue(); if (DepSize < CpySize) return false; // Finally, we have to make sure that the dest of the second does not // alias the source of the first AliasAnalysis &AA = getAnalysis<AliasAnalysis>(); if (AA.alias(M->getRawDest(), CpySize, MDep->getRawSource(), DepSize) != AliasAnalysis::NoAlias) return false; else if (AA.alias(M->getRawDest(), CpySize, M->getRawSource(), CpySize) != AliasAnalysis::NoAlias) return false; else if (AA.alias(MDep->getRawDest(), DepSize, MDep->getRawSource(), DepSize) != AliasAnalysis::NoAlias) return false; // If all checks passed, then we can transform these memcpy's const Type *ArgTys[3] = { M->getRawDest()->getType(), MDep->getRawSource()->getType(), M->getLength()->getType() }; Function *MemCpyFun = Intrinsic::getDeclaration( M->getParent()->getParent()->getParent(), M->getIntrinsicID(), ArgTys, 3); Value *Args[5] = { M->getRawDest(), MDep->getRawSource(), M->getLength(), M->getAlignmentCst(), M->getVolatileCst() }; CallInst *C = CallInst::Create(MemCpyFun, Args, Args+5, "", M); // If C and M don't interfere, then this is a valid transformation. If they // did, this would mean that the two sources overlap, which would be bad. if (MD.getDependency(C) == dep) { MD.removeInstruction(M); M->eraseFromParent(); ++NumMemCpyInstr; return true; } // Otherwise, there was no point in doing this, so we remove the call we // inserted and act like nothing happened. MD.removeInstruction(C); C->eraseFromParent(); return false; }
bool ObjCARCContract::runOnFunction(Function &F) { if (!EnableARCOpts) return false; // If nothing in the Module uses ARC, don't do anything. if (!Run) return false; Changed = false; AA = &getAnalysis<AliasAnalysis>(); DT = &getAnalysis<DominatorTree>(); PA.setAA(&getAnalysis<AliasAnalysis>()); // Track whether it's ok to mark objc_storeStrong calls with the "tail" // keyword. Be conservative if the function has variadic arguments. // It seems that functions which "return twice" are also unsafe for the // "tail" argument, because they are setjmp, which could need to // return to an earlier stack state. bool TailOkForStoreStrongs = !F.isVarArg() && !F.callsFunctionThatReturnsTwice(); // For ObjC library calls which return their argument, replace uses of the // argument with uses of the call return value, if it dominates the use. This // reduces register pressure. SmallPtrSet<Instruction *, 4> DependingInstructions; SmallPtrSet<const BasicBlock *, 4> Visited; for (inst_iterator I = inst_begin(&F), E = inst_end(&F); I != E; ) { Instruction *Inst = &*I++; DEBUG(dbgs() << "ObjCARCContract: Visiting: " << *Inst << "\n"); // Only these library routines return their argument. In particular, // objc_retainBlock does not necessarily return its argument. InstructionClass Class = GetBasicInstructionClass(Inst); switch (Class) { case IC_Retain: case IC_FusedRetainAutorelease: case IC_FusedRetainAutoreleaseRV: break; case IC_Autorelease: case IC_AutoreleaseRV: if (ContractAutorelease(F, Inst, Class, DependingInstructions, Visited)) continue; break; case IC_RetainRV: { // If we're compiling for a target which needs a special inline-asm // marker to do the retainAutoreleasedReturnValue optimization, // insert it now. if (!RetainRVMarker) break; BasicBlock::iterator BBI = Inst; BasicBlock *InstParent = Inst->getParent(); // Step up to see if the call immediately precedes the RetainRV call. // If it's an invoke, we have to cross a block boundary. And we have // to carefully dodge no-op instructions. do { if (&*BBI == InstParent->begin()) { BasicBlock *Pred = InstParent->getSinglePredecessor(); if (!Pred) goto decline_rv_optimization; BBI = Pred->getTerminator(); break; } --BBI; } while (IsNoopInstruction(BBI)); if (&*BBI == GetObjCArg(Inst)) { DEBUG(dbgs() << "ObjCARCContract: Adding inline asm marker for " "retainAutoreleasedReturnValue optimization.\n"); Changed = true; InlineAsm *IA = InlineAsm::get(FunctionType::get(Type::getVoidTy(Inst->getContext()), /*isVarArg=*/false), RetainRVMarker->getString(), /*Constraints=*/"", /*hasSideEffects=*/true); CallInst::Create(IA, "", Inst); } decline_rv_optimization: break; } case IC_InitWeak: { // objc_initWeak(p, null) => *p = null CallInst *CI = cast<CallInst>(Inst); if (IsNullOrUndef(CI->getArgOperand(1))) { Value *Null = ConstantPointerNull::get(cast<PointerType>(CI->getType())); Changed = true; new StoreInst(Null, CI->getArgOperand(0), CI); DEBUG(dbgs() << "OBJCARCContract: Old = " << *CI << "\n" << " New = " << *Null << "\n"); CI->replaceAllUsesWith(Null); CI->eraseFromParent(); } continue; } case IC_Release: ContractRelease(Inst, I); continue; case IC_User: // Be conservative if the function has any alloca instructions. // Technically we only care about escaping alloca instructions, // but this is sufficient to handle some interesting cases. if (isa<AllocaInst>(Inst)) TailOkForStoreStrongs = false; continue; case IC_IntrinsicUser: // Remove calls to @clang.arc.use(...). Inst->eraseFromParent(); continue; default: continue; } DEBUG(dbgs() << "ObjCARCContract: Finished List.\n\n"); // Don't use GetObjCArg because we don't want to look through bitcasts // and such; to do the replacement, the argument must have type i8*. const Value *Arg = cast<CallInst>(Inst)->getArgOperand(0); for (;;) { // If we're compiling bugpointed code, don't get in trouble. if (!isa<Instruction>(Arg) && !isa<Argument>(Arg)) break; // Look through the uses of the pointer. for (Value::const_use_iterator UI = Arg->use_begin(), UE = Arg->use_end(); UI != UE; ) { Use &U = UI.getUse(); unsigned OperandNo = UI.getOperandNo(); ++UI; // Increment UI now, because we may unlink its element. // If the call's return value dominates a use of the call's argument // value, rewrite the use to use the return value. We check for // reachability here because an unreachable call is considered to // trivially dominate itself, which would lead us to rewriting its // argument in terms of its return value, which would lead to // infinite loops in GetObjCArg. if (DT->isReachableFromEntry(U) && DT->dominates(Inst, U)) { Changed = true; Instruction *Replacement = Inst; Type *UseTy = U.get()->getType(); if (PHINode *PHI = dyn_cast<PHINode>(U.getUser())) { // For PHI nodes, insert the bitcast in the predecessor block. unsigned ValNo = PHINode::getIncomingValueNumForOperand(OperandNo); BasicBlock *BB = PHI->getIncomingBlock(ValNo); if (Replacement->getType() != UseTy) Replacement = new BitCastInst(Replacement, UseTy, "", &BB->back()); // While we're here, rewrite all edges for this PHI, rather // than just one use at a time, to minimize the number of // bitcasts we emit. for (unsigned i = 0, e = PHI->getNumIncomingValues(); i != e; ++i) if (PHI->getIncomingBlock(i) == BB) { // Keep the UI iterator valid. if (&PHI->getOperandUse( PHINode::getOperandNumForIncomingValue(i)) == &UI.getUse()) ++UI; PHI->setIncomingValue(i, Replacement); } } else { if (Replacement->getType() != UseTy) Replacement = new BitCastInst(Replacement, UseTy, "", cast<Instruction>(U.getUser())); U.set(Replacement); } } } // If Arg is a no-op casted pointer, strip one level of casts and iterate. if (const BitCastInst *BI = dyn_cast<BitCastInst>(Arg)) Arg = BI->getOperand(0); else if (isa<GEPOperator>(Arg) && cast<GEPOperator>(Arg)->hasAllZeroIndices()) Arg = cast<GEPOperator>(Arg)->getPointerOperand(); else if (isa<GlobalAlias>(Arg) && !cast<GlobalAlias>(Arg)->mayBeOverridden()) Arg = cast<GlobalAlias>(Arg)->getAliasee(); else break; } } // If this function has no escaping allocas or suspicious vararg usage, // objc_storeStrong calls can be marked with the "tail" keyword. if (TailOkForStoreStrongs) for (SmallPtrSet<CallInst *, 8>::iterator I = StoreStrongCalls.begin(), E = StoreStrongCalls.end(); I != E; ++I) (*I)->setTailCall(); StoreStrongCalls.clear(); return Changed; }
int compile(list<string> args, list<string> kgen_args, string merge, list<string> merge_args, string input, string output, int arch, string host_compiler, string fileprefix) { // // The LLVM compiler to emit IR. // const char* llvm_compiler = "kernelgen-gfortran"; // // Interpret kernelgen compile options. // for (list<string>::iterator iarg = kgen_args.begin(), iearg = kgen_args.end(); iarg != iearg; iarg++) { const char* arg = (*iarg).c_str(); if (!strncmp(arg, "-Wk,--llvm-compiler=", 20)) llvm_compiler = arg + 20; } // // Generate temporary output file. // Check if output file is specified in the command line. // Replace or add output to the temporary file. // cfiledesc tmp_output = cfiledesc::mktemp(fileprefix); bool output_specified = false; for (list<string>::iterator iarg = args.begin(), iearg = args.end(); iarg != iearg; iarg++) { const char* arg = (*iarg).c_str(); if (!strcmp(arg, "-o")) { iarg++; *iarg = tmp_output.getFilename(); output_specified = true; break; } } if (!output_specified) { args.push_back("-o"); args.push_back(tmp_output.getFilename()); } // // 1) Compile source code using regular host compiler. // { if (verbose) { cout << host_compiler; for (list<string>::iterator iarg = args.begin(), iearg = args.end(); iarg != iearg; iarg++) cout << " " << *iarg; cout << endl; } int status = execute(host_compiler, args, "", NULL, NULL); if (status) return status; } // // 2) Emit LLVM IR. // string out = ""; { list<string> emit_ir_args; for (list<string>::iterator iarg = args.begin(), iearg = args.end(); iarg != iearg; iarg++) { const char* arg = (*iarg).c_str(); if (!strcmp(arg, "-c") || !strcmp(arg, "-o")) { iarg++; continue; } if (!strcmp(arg, "-g")) { continue; } emit_ir_args.push_back(*iarg); } emit_ir_args.push_back("-fplugin=/opt/kernelgen/lib/dragonegg.so"); emit_ir_args.push_back("-fplugin-arg-dragonegg-emit-ir"); emit_ir_args.push_back("-S"); emit_ir_args.push_back(input); emit_ir_args.push_back("-o"); emit_ir_args.push_back("-"); if (verbose) { cout << llvm_compiler; for (list<string>::iterator iarg = emit_ir_args.begin(), iearg = emit_ir_args.end(); iarg != iearg; iarg++) cout << " " << *iarg; cout << endl; } int status = execute(llvm_compiler, emit_ir_args, "", &out, NULL); if (status) return status; } // // 3) Record existing module functions. // LLVMContext &context = getGlobalContext(); SMDiagnostic diag; MemoryBuffer* buffer1 = MemoryBuffer::getMemBuffer(out); auto_ptr<Module> m1; m1.reset(ParseIR(buffer1, diag, context)); //m1.get()->dump(); // // 4) Inline calls and extract loops into new functions. // MemoryBuffer* buffer2 = MemoryBuffer::getMemBuffer(out); auto_ptr<Module> m2; m2.reset(ParseIR(buffer2, diag, context)); { PassManager manager; manager.add(createInstructionCombiningPass()); manager.run(*m2.get()); } std::vector<CallInst *> LoopFuctionCalls; { PassManager manager; manager.add(createBranchedLoopExtractorPass(LoopFuctionCalls)); manager.run(*m2.get()); } //m2.get()->dump(); // // 5) Replace call to loop functions with call to launcher. // Append "always inline" attribute to all other functions. // Type* int32Ty = Type::getInt32Ty(context); Function* launch = Function::Create( TypeBuilder<types::i<32>(types::i<8>*, types::i<64>, types::i<32>*), true>::get(context), GlobalValue::ExternalLinkage, "kernelgen_launch", m2.get()); for (Module::iterator f1 = m2.get()->begin(), fe1 = m2.get()->end(); f1 != fe1; f1++) { Function* func = f1; if (func->isDeclaration()) continue; // Search for the current function in original module // functions list. // If function is not in list of original module, then // it is generated by the loop extractor. // Append "always inline" attribute to all other functions. if (m1.get()->getFunction(func->getName())) { const AttrListPtr attr = func->getAttributes(); const AttrListPtr attr_new = attr.addAttr(~0U, Attribute::AlwaysInline); func->setAttributes(attr_new); continue; } // Each such function must be extracted to the // standalone module and packed into resulting // object file data section. if (verbose) cout << "Preparing loop function " << func->getName().data() << " ..." << endl; // Reset to default visibility. func->setVisibility(GlobalValue::DefaultVisibility); // Reset to default linkage. func->setLinkage(GlobalValue::ExternalLinkage); // Replace call to this function in module with call to launcher. bool found = false; for (Module::iterator f2 = m2->begin(), fe2 = m2->end(); (f2 != fe2) && !found; f2++) for (Function::iterator bb = f2->begin(); (bb != f2->end()) && !found; bb++) for (BasicBlock::iterator i = bb->begin(); i != bb->end(); i++) { // Check if instruction in focus is a call. CallInst* call = dyn_cast<CallInst>(cast<Value>(i)); if (!call) continue; // Check if function is called (needs -instcombine pass). Function* callee = call->getCalledFunction(); if (!callee) continue; if (callee->isDeclaration()) continue; if (callee->getName() != func->getName()) continue; // Create a constant array holding original called // function name. Constant* name = ConstantArray::get( context, callee->getName(), true); // Create and initialize the memory buffer for name. ArrayType* nameTy = cast<ArrayType>(name->getType()); AllocaInst* nameAlloc = new AllocaInst(nameTy, "", call); StoreInst* nameInit = new StoreInst(name, nameAlloc, "", call); Value* Idx[2]; Idx[0] = Constant::getNullValue(Type::getInt32Ty(context)); Idx[1] = ConstantInt::get(Type::getInt32Ty(context), 0); GetElementPtrInst* namePtr = GetElementPtrInst::Create(nameAlloc, Idx, "", call); // Add pointer to the original function string name. SmallVector<Value*, 16> call_args; call_args.push_back(namePtr); // Add size of the aggregated arguments structure. { BitCastInst* BC = new BitCastInst( call->getArgOperand(0), Type::getInt64PtrTy(context), "", call); LoadInst* LI = new LoadInst(BC, "", call); call_args.push_back(LI); } // Add original aggregated structure argument. call_args.push_back(call->getArgOperand(0)); // Create new function call with new call arguments // and copy old call properties. CallInst* newcall = CallInst::Create(launch, call_args, "", call); //newcall->takeName(call); newcall->setCallingConv(call->getCallingConv()); newcall->setAttributes(call->getAttributes()); newcall->setDebugLoc(call->getDebugLoc()); // Replace old call with new one. call->replaceAllUsesWith(newcall); call->eraseFromParent(); found = true; break; } } //m2.get()->dump(); // // 6) Apply optimization passes to the resulting common // module. // { PassManager manager; manager.add(createLowerSetJmpPass()); PassManagerBuilder builder; builder.Inliner = createFunctionInliningPass(); builder.OptLevel = 3; builder.DisableSimplifyLibCalls = true; builder.populateModulePassManager(manager); manager.run(*m2.get()); } //m2.get()->dump(); // // 7) Embed the resulting module into object file. // { string ir_string; raw_string_ostream ir(ir_string); ir << (*m2.get()); celf e(tmp_output.getFilename(), output); e.getSection(".data")->addSymbol( "__kernelgen_" + string(input), ir_string.c_str(), ir_string.size() + 1); } return 0; }
/// performLocalReleaseMotion - Scan backwards from the specified release, /// moving it earlier in the function if possible, over instructions that do not /// access the released object. If we get to a retain or allocation of the /// object, zap both. static bool performLocalReleaseMotion(CallInst &Release, BasicBlock &BB, SwiftRCIdentity *RC) { // FIXME: Call classifier should identify the object for us. Too bad C++ // doesn't have nice Swift-style enums. Value *ReleasedObject = RC->getSwiftRCIdentityRoot(Release.getArgOperand(0)); BasicBlock::iterator BBI = Release.getIterator(); // Scan until we get to the top of the block. while (BBI != BB.begin()) { --BBI; // Don't analyze PHI nodes. We can't move retains before them and they // aren't "interesting". if (isa<PHINode>(BBI) || // If we found the instruction that defines the value we're releasing, // don't push the release past it. &*BBI == Release.getArgOperand(0)) { ++BBI; goto OutOfLoop; } switch (classifyInstruction(*BBI)) { // These instructions should not reach here based on the pass ordering. // i.e. LLVMARCOpt -> LLVMContractOpt. case RT_UnknownRetainN: case RT_BridgeRetainN: case RT_RetainN: case RT_UnknownReleaseN: case RT_BridgeReleaseN: case RT_ReleaseN: llvm_unreachable("These are only created by LLVMARCContract !"); case RT_NoMemoryAccessed: // Skip over random instructions that don't touch memory. They don't need // protection by retain/release. continue; case RT_UnknownRelease: case RT_BridgeRelease: case RT_ObjCRelease: case RT_Release: { // If we get to a release, we can generally ignore it and scan past it. // However, if we get to a release of obviously the same object, we stop // scanning here because it should have already be moved as early as // possible, so there is no reason to move its friend to the same place. // // NOTE: If this occurs frequently, maybe we can have a release(Obj, N) // API to drop multiple retain counts at once. CallInst &ThisRelease = cast<CallInst>(*BBI); Value *ThisReleasedObject = ThisRelease.getArgOperand(0); ThisReleasedObject = RC->getSwiftRCIdentityRoot(ThisReleasedObject); if (ThisReleasedObject == ReleasedObject) { //Release.dump(); ThisRelease.dump(); BB.getParent()->dump(); ++BBI; goto OutOfLoop; } continue; } case RT_UnknownRetain: case RT_BridgeRetain: case RT_ObjCRetain: case RT_Retain: { // swift_retain(obj) CallInst &Retain = cast<CallInst>(*BBI); Value *RetainedObject = Retain.getArgOperand(0); RetainedObject = RC->getSwiftRCIdentityRoot(RetainedObject); // Since we canonicalized earlier, we know that if our retain has any // uses, they were replaced already. This assertion documents this // assumption. assert(Retain.use_empty() && "Retain should have been canonicalized to " "have no uses."); // If the retain and release are to obviously pointer-equal objects, then // we can delete both of them. We have proven that they do not protect // anything of value. if (RetainedObject == ReleasedObject) { Retain.eraseFromParent(); Release.eraseFromParent(); ++NumRetainReleasePairs; return true; } // Otherwise, this is a retain of an object that is not statically known // to be the same object. It may still be dynamically the same object // though. In this case, we can't move the release past it. // TODO: Strengthen analysis. //Release.dump(); ThisRelease.dump(); BB.getParent()->dump(); ++BBI; goto OutOfLoop; } case RT_AllocObject: { // %obj = swift_alloc(...) CallInst &Allocation = cast<CallInst>(*BBI); // If this is an allocation of an unrelated object, just ignore it. // TODO: This is not safe without proving the object being released is not // related to the allocated object. Consider something silly like this: // A = allocate() // B = bitcast A to object // release(B) if (ReleasedObject != &Allocation) { // Release.dump(); BB.getParent()->dump(); ++BBI; goto OutOfLoop; } // If this is a release right after an allocation of the object, then we // can zap both. Allocation.replaceAllUsesWith(UndefValue::get(Allocation.getType())); Allocation.eraseFromParent(); Release.eraseFromParent(); ++NumAllocateReleasePairs; return true; } case RT_FixLifetime: case RT_RetainUnowned: case RT_CheckUnowned: case RT_Unknown: // Otherwise, we have reached something that we do not understand. Do not // attempt to shorten the lifetime of this object beyond this point so we // are conservative. ++BBI; goto OutOfLoop; } } OutOfLoop: // If we got to the top of the block, (and if the instruction didn't start // there) move the release to the top of the block. // TODO: This is where we'd plug in some global algorithms someday. if (&*BBI != &Release) { Release.moveBefore(&*BBI); return true; } return false; }
bool GambasPass::runOnFunction(Function &F){ IRBuilder<> Builder(F.getContext()); bool changed = false; for(Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) { for(BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ){ ICmpInst* ICI = dyn_cast<ICmpInst>(I); CallInst* CI = dyn_cast<CallInst>(I++); if (ICI && ICI->hasMetadata() && ICI->getMetadata("unref_slt") && dyn_cast<LoadInst>(ICI->getOperand(0))){ ICI->replaceAllUsesWith(ConstantInt::get(ICI->getType(), false)); ICI->eraseFromParent(); changed = true; continue; } if (!CI) continue; Function* callee = CI->getCalledFunction(); if (callee == NULL || !callee->isDeclaration()) continue; StringRef name = callee->getName(); if (name == "JR_release_variant" || name == "JR_borrow_variant"){ ConstantInt* vtype_int = dyn_cast<ConstantInt>(CI->getArgOperand(0)); if (!vtype_int) continue; uint64_t vtype = vtype_int->getZExtValue(); if (TYPE_is_string(vtype) || TYPE_is_object(vtype)) continue; CI->eraseFromParent(); changed = true; } else if (name == FUNCTION_NAME(__finite)){ ConstantFP* op = dyn_cast<ConstantFP>(CI->getArgOperand(0)); if (!op) continue; int val = __finite(op->getValueAPF().convertToDouble()); Constant* res = ConstantInt::get(CI->getType(), val); CI->replaceAllUsesWith(res); CI->eraseFromParent(); changed = true; } else if (name == FUNCTION_NAME(__isnan)){ ConstantFP* op = dyn_cast<ConstantFP>(CI->getArgOperand(0)); if (!op) continue; int val = __isnan(op->getValueAPF().convertToDouble()); Constant* res = ConstantInt::get(CI->getType(), val); CI->replaceAllUsesWith(res); CI->eraseFromParent(); changed = true; } else if (name == FUNCTION_NAME(__isinf)){ ConstantFP* op = dyn_cast<ConstantFP>(CI->getArgOperand(0)); if (!op) continue; int val = __isinf(op->getValueAPF().convertToDouble()); Constant* res = ConstantInt::get(CI->getType(), val); CI->replaceAllUsesWith(res); CI->eraseFromParent(); changed = true; } } } return changed; }
/// performLocalRetainMotion - Scan forward from the specified retain, moving it /// later in the function if possible, over instructions that provably can't /// release the object. If we get to a release of the object, zap both. /// /// NOTE: this handles both objc_retain and swift_retain. /// static bool performLocalRetainMotion(CallInst &Retain, BasicBlock &BB, SwiftRCIdentity *RC) { // FIXME: Call classifier should identify the object for us. Too bad C++ // doesn't have nice Swift-style enums. Value *RetainedObject = RC->getSwiftRCIdentityRoot(Retain.getArgOperand(0)); BasicBlock::iterator BBI = Retain.getIterator(), BBE = BB.getTerminator()->getIterator(); bool isObjCRetain = Retain.getCalledFunction()->getName() == "objc_retain"; bool MadeProgress = false; // Scan until we get to the end of the block. for (++BBI; BBI != BBE; ++BBI) { Instruction &CurInst = *BBI; // Classify the instruction. This switch does a "break" when the instruction // can be skipped and is interesting, and a "continue" when it is a retain // of the same pointer. switch (classifyInstruction(CurInst)) { // These instructions should not reach here based on the pass ordering. // i.e. LLVMARCOpt -> LLVMContractOpt. case RT_RetainN: case RT_UnknownRetainN: case RT_BridgeRetainN: case RT_ReleaseN: case RT_UnknownReleaseN: case RT_BridgeReleaseN: llvm_unreachable("These are only created by LLVMARCContract !"); case RT_NoMemoryAccessed: case RT_AllocObject: case RT_CheckUnowned: // Skip over random instructions that don't touch memory. They don't need // protection by retain/release. break; case RT_FixLifetime: // This only stops release motion. Retains can move over it. break; case RT_Retain: case RT_UnknownRetain: case RT_BridgeRetain: case RT_RetainUnowned: case RT_ObjCRetain: { // swift_retain(obj) //CallInst &ThisRetain = cast<CallInst>(CurInst); //Value *ThisRetainedObject = ThisRetain.getArgOperand(0); // If we see a retain of the same object, we can skip over it, but we // can't count it as progress. Just pushing a retain(x) past a retain(y) // doesn't change the program. continue; } case RT_UnknownRelease: case RT_BridgeRelease: case RT_ObjCRelease: case RT_Release: { // If we get to a release that is provably to this object, then we can zap // it and the retain. CallInst &ThisRelease = cast<CallInst>(CurInst); Value *ThisReleasedObject = ThisRelease.getArgOperand(0); ThisReleasedObject = RC->getSwiftRCIdentityRoot(ThisReleasedObject); if (ThisReleasedObject == RetainedObject) { Retain.eraseFromParent(); ThisRelease.eraseFromParent(); if (isObjCRetain) { ++NumObjCRetainReleasePairs; } else { ++NumRetainReleasePairs; } return true; } // Otherwise, if this is some other pointer, we can only ignore it if we // can prove that the two objects don't alias. // Retain.dump(); ThisRelease.dump(); BB.getParent()->dump(); goto OutOfLoop; } case RT_Unknown: // Loads cannot affect the retain. if (isa<LoadInst>(CurInst)) continue; // Load, store, memcpy etc can't do a release. if (isa<LoadInst>(CurInst) || isa<StoreInst>(CurInst) || isa<MemIntrinsic>(CurInst)) break; // CurInst->dump(); BBI->dump(); // Otherwise, we get to something unknown/unhandled. Bail out for now. goto OutOfLoop; } // If the switch did a break, we made some progress moving this retain. MadeProgress = true; } OutOfLoop: // If we were able to move the retain down, move it now. // TODO: This is where we'd plug in some global algorithms someday. if (MadeProgress) { Retain.moveBefore(&*BBI); return true; } return false; }
// // Method: runOnModule() // // Description: // Entry point for this LLVM pass. // Clone functions that take GEPs 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 GEPExprArgs::runOnModule(Module& M) { 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;) { CallInst *CI = dyn_cast<CallInst>(I++); if(!CI) continue; if(CI->hasByValArgument()) continue; // if the GEP 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 = 1; for(; argNum < CI->getNumOperands();argNum++, ++ai) { if(ai->use_empty()) continue; if (isa<GEPOperator>(CI->getOperand(argNum))) break; } // if no argument was a GEP operator to be changed if(ai == ae) continue; GEPOperator *GEP = dyn_cast<GEPOperator>(CI->getOperand(argNum)); if(!GEP->hasAllConstantIndices()) continue; // Construct the new Type // Appends the struct Type at the beginning std::vector<Type*>TP; TP.push_back(GEP->getPointerOperand()->getType()); for(unsigned c = 1; c < CI->getNumOperands();c++) { TP.push_back(CI->getOperand(c)->getType()); } //return type is same as that of original instruction FunctionType *NewFTy = FunctionType::get(CI->getType(), TP, false); Function *NewF; numSimplified++; if(numSimplified > 800) return true; NewF = Function::Create(NewFTy, GlobalValue::InternalLinkage, F->getName().str() + ".TEST", &M); Function::arg_iterator NI = NewF->arg_begin(); NI->setName("GEParg"); ++NI; ValueToValueMapTy ValueMap; for (Function::arg_iterator II = F->arg_begin(); NI != NewF->arg_end(); ++II, ++NI) { ValueMap[II] = NI; NI->setName(II->getName()); NI->addAttr(F->getAttributes().getParamAttributes(II->getArgNo() + 1)); } NewF->setAttributes(NewF->getAttributes().addAttr( 0, F->getAttributes().getRetAttributes())); // 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().addAttr( ~0, F->getAttributes().getFnAttributes())); //Get the point to insert the GEP instr. SmallVector<Value*, 8> Ops(CI->op_begin()+1, CI->op_end()); Instruction *InsertPoint; for (BasicBlock::iterator insrt = NewF->front().begin(); isa<AllocaInst>(InsertPoint = insrt); ++insrt) {;} NI = NewF->arg_begin(); SmallVector<Value*, 8> Indices; Indices.append(GEP->op_begin()+1, GEP->op_end()); GetElementPtrInst *GEP_new = GetElementPtrInst::Create(cast<Value>(NI), Indices, "", InsertPoint); fargs.at(argNum)->replaceAllUsesWith(GEP_new); unsigned j = argNum + 1; for(; j < CI->getNumOperands();j++) { if(CI->getOperand(j) == GEP) fargs.at(j)->replaceAllUsesWith(GEP_new); } SmallVector<AttributeWithIndex, 8> AttributesVec; // Get the initial attributes of the call AttrListPtr CallPAL = CI->getAttributes(); Attributes RAttrs = CallPAL.getRetAttributes(); Attributes FnAttrs = CallPAL.getFnAttributes(); if (RAttrs) AttributesVec.push_back(AttributeWithIndex::get(0, RAttrs)); SmallVector<Value*, 8> Args; Args.push_back(GEP->getPointerOperand()); for(unsigned j =1;j<CI->getNumOperands();j++) { Args.push_back(CI->getOperand(j)); // position in the AttributesVec if (Attributes Attrs = CallPAL.getParamAttributes(j)) AttributesVec.push_back(AttributeWithIndex::get(Args.size(), Attrs)); } // Create the new attributes vec. if (FnAttrs != Attribute::None) AttributesVec.push_back(AttributeWithIndex::get(~0, FnAttrs)); AttrListPtr NewCallPAL = AttrListPtr::get(AttributesVec.begin(), AttributesVec.end()); 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; }
bool LowerExcHandlers::runOnFunction(Function &F) { if (!except_enter_func) return false; // No EH frames in this module /* Step 1: EH Depth Numbering */ std::map<llvm::CallInst *, int> EnterDepth; std::map<llvm::CallInst *, int> LeaveDepth; std::map<BasicBlock *, int> ExitDepth; int MaxDepth = 0; // Compute EH Depth at each basic block using a DFS traversal. for (df_iterator<BasicBlock *> I = df_begin(&F.getEntryBlock()), E = df_end(&F.getEntryBlock()); I != E; ++I) { auto *BB = *I; int Depth = 0; /* Here we use the assumption that all incoming edges have the same * EH depth. */ for (auto *Pred : predecessors(BB)) { auto it = ExitDepth.find(Pred); if (it != ExitDepth.end()) { Depth = it->second; break; } } /* Compute the depth within the basic block */ for (auto &I : *BB) { auto *CI = dyn_cast<CallInst>(&I); if (!CI) continue; Function *Callee = CI->getCalledFunction(); if (!Callee) continue; if (Callee == except_enter_func) EnterDepth[CI] = Depth++; else if (Callee == leave_func) { LeaveDepth[CI] = Depth; Depth -= cast<ConstantInt>(CI->getArgOperand(0))->getLimitedValue(); } assert(Depth >= 0); if (Depth > MaxDepth) MaxDepth = Depth; } /* Remember the depth at the BB boundary */ ExitDepth[BB] = Depth; } /* Step 2: EH Frame lowering */ // Allocate stack space for each handler. We allocate these as separate // allocas so the optimizer can later merge and reaarange them if it wants // to. Value *handler_sz = ConstantInt::get(Type::getInt32Ty(F.getContext()), sizeof(jl_handler_t)); Value *handler_sz64 = ConstantInt::get(Type::getInt64Ty(F.getContext()), sizeof(jl_handler_t)); Instruction *firstInst = &F.getEntryBlock().front(); std::vector<AllocaInst *> buffs; for (int i = 0; i < MaxDepth; ++i) { auto *buff = new AllocaInst(Type::getInt8Ty(F.getContext()), 0, handler_sz, "", firstInst); buff->setAlignment(16); buffs.push_back(buff); } // Lower enter funcs for (auto it : EnterDepth) { assert(it.second >= 0); AllocaInst *buff = buffs[it.second]; CallInst *enter = it.first; auto new_enter = CallInst::Create(jlenter_func, buff, "", enter); Value *lifetime_args[] = { handler_sz64, buff }; CallInst::Create(lifetime_start, lifetime_args, "", new_enter); #ifndef _OS_WINDOWS_ // For LLVM 3.3 compatibility Value *args[] = {buff, ConstantInt::get(Type::getInt32Ty(F.getContext()), 0)}; auto sj = CallInst::Create(setjmp_func, args, "", enter); #else auto sj = CallInst::Create(setjmp_func, buff, "", enter); #endif // We need to mark this on the call site as well. See issue #6757 sj->setCanReturnTwice(); if (auto dbg = enter->getMetadata(LLVMContext::MD_dbg)) { new_enter->setMetadata(LLVMContext::MD_dbg, dbg); sj->setMetadata(LLVMContext::MD_dbg, dbg); } enter->replaceAllUsesWith(sj); enter->eraseFromParent(); } // Insert lifetime end intrinsics after every leave. for (auto it : LeaveDepth) { int StartDepth = it.second - 1; int npops = cast<ConstantInt>(it.first->getArgOperand(0))->getLimitedValue(); for (int i = 0; i < npops; ++i) { assert(StartDepth-i >= 0); Value *lifetime_args[] = { handler_sz64, buffs[StartDepth-i] }; auto LifetimeEnd = CallInst::Create(lifetime_end, lifetime_args); LifetimeEnd->insertAfter(it.first); } } return true; }
int CGGraph::solve(std::vector<CallInst*> boundsChecks) { std::vector<CallInst*>::iterator callIt; std::string varOne; std::string varTwo; bool rCheck; vector<CallInst*> toRemove; for (callIt = boundsChecks.begin(); callIt != boundsChecks.end(); ++callIt) { if(std::find(owner->callInstsRemoved.begin(), owner->callInstsRemoved.end(), (*callIt)) != owner->callInstsRemoved.end()) { continue; } else { if ((*callIt)->getParent()->getParent()->getName() == this->funcName) { Value *v0 = (*callIt)->getArgOperand(0); Value *v1 = (*callIt)->getArgOperand(1); if (ConstantInt *c0 = dyn_cast<ConstantInt>(v0)) { if (ConstantInt *c1 = dyn_cast<ConstantInt>(v1)) { totalChecked++; if ((c0->getSExtValue() >= 0) && (c0->getSExtValue() < c1->getSExtValue())) { //trivial constant case totalRemoved++; toRemove.push_back(*callIt); } } } else { varOne = getNameFromValue((*callIt)->getArgOperand(1), (*callIt)); //length of array varTwo = getNameFromValue((*callIt)->getArgOperand(0), (*callIt)); //indexing variable if (hasNode(varOne) && hasNode(varTwo)) { rCheck = doTraverse(varOne, varTwo); totalChecked++; if (rCheck) { totalRemoved++; toRemove.push_back(*callIt); } } } } } } // Remove them outside the traversal loop so you don't screw the iterator. for(size_t i = 0; i < toRemove.size(); i++) { CallInst *deadCall = toRemove[i]; deadCall->eraseFromParent(); owner->callInstsRemoved.push_back(deadCall); } //errs() << "Total number of checks performed for function: " << totalChecked << "\n"; //errs() << "Total number of checks removed for function: " << totalRemoved << "\n"; return totalRemoved; }
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(); } } } }