CallSite GNUstep::IMPCacher::SplitSend(CallSite msgSend) { BasicBlock *lookupBB = msgSend->getParent(); Function *F = lookupBB->getParent(); Module *M = F->getParent(); Function *send = M->getFunction("objc_msgSend"); Function *send_stret = M->getFunction("objc_msgSend_stret"); Function *send_fpret = M->getFunction("objc_msgSend_fpret"); Value *self; Value *cmd; int selfIndex = 0; if ((msgSend.getCalledFunction() == send) || (msgSend.getCalledFunction() == send_fpret)) { self = msgSend.getArgument(0); cmd = msgSend.getArgument(1); } else if (msgSend.getCalledFunction() == send_stret) { selfIndex = 1; self = msgSend.getArgument(1); cmd = msgSend.getArgument(2); } else { abort(); return CallSite(); } CGBuilder B(&F->getEntryBlock(), F->getEntryBlock().begin()); Value *selfPtr = B.CreateAlloca(self->getType()); B.SetInsertPoint(msgSend.getInstruction()); B.CreateStore(self, selfPtr, true); LLVMType *impTy = msgSend.getCalledValue()->getType(); LLVMType *slotTy = PointerType::getUnqual(StructType::get(PtrTy, PtrTy, PtrTy, IntTy, impTy, PtrTy, NULL)); Value *slot; Constant *lookupFn = M->getOrInsertFunction("objc_msg_lookup_sender", slotTy, selfPtr->getType(), cmd->getType(), PtrTy, NULL); if (msgSend.isCall()) { slot = B.CreateCall3(lookupFn, selfPtr, cmd, Constant::getNullValue(PtrTy)); } else { InvokeInst *inv = cast<InvokeInst>(msgSend.getInstruction()); BasicBlock *callBB = SplitBlock(lookupBB, msgSend.getInstruction(), Owner); removeTerminator(lookupBB); B.SetInsertPoint(lookupBB); slot = B.CreateInvoke3(lookupFn, callBB, inv->getUnwindDest(), selfPtr, cmd, Constant::getNullValue(PtrTy)); addPredecssor(inv->getUnwindDest(), msgSend->getParent(), lookupBB); B.SetInsertPoint(msgSend.getInstruction()); } Value *imp = B.CreateLoad(B.CreateStructGEP(slot, 4)); msgSend.setArgument(selfIndex, B.CreateLoad(selfPtr, true)); msgSend.setCalledFunction(imp); return CallSite(slot); }
// FIXME: This might have been relevant for the old JIT but the MCJIT // has a completly different implementation so this comment below is // likely irrelevant and misleading. // // For performance purposes we construct the stub in such a way that the // arguments pointer is passed through the static global variable gTheArgsP in // this file. This is done so that the stub function prototype trivially matches // the special cases that the JIT knows how to directly call. If this is not // done, then the jit will end up generating a nullary stub just to call our // stub, for every single function call. Function *ExternalDispatcherImpl::createDispatcher(Function *target, Instruction *inst, Module *module) { if (!resolveSymbol(target->getName())) return 0; CallSite cs; if (inst->getOpcode() == Instruction::Call) { cs = CallSite(cast<CallInst>(inst)); } else { cs = CallSite(cast<InvokeInst>(inst)); } Value **args = new Value *[cs.arg_size()]; std::vector<Type *> nullary; // MCJIT functions need unique names, or wrong function can be called. // The module identifier is included because for the MCJIT we need // unique function names across all `llvm::Modules`s. std::string fnName = "dispatcher_" + target->getName().str() + module->getModuleIdentifier(); Function *dispatcher = Function::Create(FunctionType::get(Type::getVoidTy(ctx), nullary, false), GlobalVariable::ExternalLinkage, fnName, module); BasicBlock *dBB = BasicBlock::Create(ctx, "entry", dispatcher); // Get a Value* for &gTheArgsP, as an i64**. Instruction *argI64sp = new IntToPtrInst( ConstantInt::get(Type::getInt64Ty(ctx), (uintptr_t)(void *)&gTheArgsP), PointerType::getUnqual(PointerType::getUnqual(Type::getInt64Ty(ctx))), "argsp", dBB); Instruction *argI64s = new LoadInst(argI64sp, "args", dBB); // Get the target function type. FunctionType *FTy = cast<FunctionType>( cast<PointerType>(target->getType())->getElementType()); // Each argument will be passed by writing it into gTheArgsP[i]. unsigned i = 0, idx = 2; for (CallSite::arg_iterator ai = cs.arg_begin(), ae = cs.arg_end(); ai != ae; ++ai, ++i) { // Determine the type the argument will be passed as. This accomodates for // the corresponding code in Executor.cpp for handling calls to bitcasted // functions. Type *argTy = (i < FTy->getNumParams() ? FTy->getParamType(i) : (*ai)->getType()); Instruction *argI64p = GetElementPtrInst::Create( KLEE_LLVM_GEP_TYPE(nullptr) argI64s, ConstantInt::get(Type::getInt32Ty(ctx), idx), "", dBB); Instruction *argp = new BitCastInst(argI64p, PointerType::getUnqual(argTy), "", dBB); args[i] = new LoadInst(argp, "", dBB); unsigned argSize = argTy->getPrimitiveSizeInBits(); idx += ((!!argSize ? argSize : 64) + 63) / 64; } Constant *dispatchTarget = module->getOrInsertFunction( target->getName(), FTy, target->getAttributes()); Instruction *result = CallInst::Create( dispatchTarget, llvm::ArrayRef<Value *>(args, args + i), "", dBB); if (result->getType() != Type::getVoidTy(ctx)) { Instruction *resp = new BitCastInst( argI64s, PointerType::getUnqual(result->getType()), "", dBB); new StoreInst(result, resp, dBB); } ReturnInst::Create(ctx, dBB); delete[] args; return dispatcher; }
/* * Rewrite the given module according to the ComponentInterfaceTransformer. */ bool TransformComponentWithoutUse(Module& M, ComponentInterfaceTransform& T) { assert(T.interface != NULL); bool modified = false; for (Module::iterator f = M.begin(), e = M.end(); f != e; ++f) { for (Function::iterator bb = f->begin(), bbe = f->end(); bb != bbe; ++bb) { for (BasicBlock::iterator I = bb->begin(), E = bb->end(); I != E; ++I) { // TODO: Handle the operands CallSite call; if (CallInst* ci = dyn_cast<CallInst>(&*I)) { if (ci->isInlineAsm()) continue; call = CallSite(ci); } else if (InvokeInst* ci = dyn_cast<InvokeInst>(&*I)) { call = CallSite(ci); } else { // TODO: We need to find all references, including ones stored in variables // we'll be conservative and say that if it is stored in a variable then // we can't optimize it at all continue; } Function* target = call.getCalledFunction(); if (target == NULL || !target->isDeclaration()) { continue; } //iam const CallRewrite* const rw = T.lookupRewrite(target->getNameStr(), call.arg_begin(), call.arg_end()); const CallRewrite* const rw = T.lookupRewrite(target->getName().str(), call.arg_begin(), call.arg_end()); if (rw == NULL) { // There is no rewrite for this function continue; } // Get/Create the function Function* newTarget = M.getFunction(rw->function); if (newTarget == NULL) { // There isn't a function, we need to construct it FunctionType* newType = target->getFunctionType(); std::vector<Type*> argTypes; for (std::vector<unsigned>::const_iterator i = rw->args.begin(), e = rw->args.end(); i != e; ++i) argTypes.push_back(newType->getParamType(*i)); ArrayRef<Type*> params(argTypes); newType = FunctionType::get(target->getReturnType(), params, target->isVarArg()); newTarget = dyn_cast<Function> (M.getOrInsertFunction(rw->function, newType)); } assert(newTarget != NULL); Instruction* newInst = specializeCallSite(I, newTarget, rw->args); llvm::ReplaceInstWithInst(bb->getInstList(), I, newInst); modified = true; } } } return modified; }