Profile-driven inlining of Objective-C methods.

main
theraven 16 years ago
parent ede942cdd8
commit 23447feca5

@ -60,7 +60,7 @@ namespace
for (BasicBlock::iterator b=i->begin(), last=i->end() ; for (BasicBlock::iterator b=i->begin(), last=i->end() ;
b != last ; ++b) { b != last ; ++b) {
CallSite call = CallSite::get(b); CallSite call = CallSite::get(b);
if (call.getInstruction()) { if (call.getInstruction() && !call.getCalledFunction()) {
MDNode *messageType = call->getMetadata(MessageSendMDKind); MDNode *messageType = call->getMetadata(MessageSendMDKind);
if (0 == messageType) { continue; } if (0 == messageType) { continue; }
messages.push_back(call); messages.push_back(call);
@ -97,7 +97,7 @@ namespace
char ClassMethodInliner::ID = 0; char ClassMethodInliner::ID = 0;
RegisterPass<ClassMethodInliner> X("gnu-class-method-inline", RegisterPass<ClassMethodInliner> X("gnu-class-method-inline",
"Inline class methods"); "Inline class methods and message sends to super");
} }
ModulePass *createClassMethodInliner(void) ModulePass *createClassMethodInliner(void)

@ -158,7 +158,12 @@ void GNUstep::IMPCacher::SpeculativelyInline(Instruction *call, Function
} }
} }
if (FTy->getReturnType() != calleeTy->getReturnType()) { if (FTy->getReturnType() != calleeTy->getReturnType()) {
inlineResult = new BitCastInst(inlineCall, calleeTy->getReturnType(), "", inlineBB); if (FTy->getReturnType() == Type::getVoidTy(Context)) {
inlineResult = Constant::getNullValue(calleeTy->getReturnType());
} else {
inlineResult =
new BitCastInst(inlineCall, calleeTy->getReturnType(), "", inlineBB);
}
} }
} }

@ -3,6 +3,7 @@
#include "llvm/Module.h" #include "llvm/Module.h"
#include "llvm/Function.h" #include "llvm/Function.h"
#include "llvm/Instructions.h" #include "llvm/Instructions.h"
#include "llvm/Support/CallSite.h"
#include "llvm/Support/IRBuilder.h" #include "llvm/Support/IRBuilder.h"
#include "llvm/Linker.h" #include "llvm/Linker.h"
#include <vector> #include <vector>
@ -23,37 +24,23 @@ namespace {
for (Function::iterator i=F.begin(), e=F.end() ; for (Function::iterator i=F.begin(), e=F.end() ;
i != e ; ++i) { i != e ; ++i) {
Module *M = F.getParent();
replacementVector replacements; replacementVector replacements;
for (BasicBlock::iterator b=i->begin(), last=i->end() ; for (BasicBlock::iterator b=i->begin(), last=i->end() ;
b != last ; ++b) { b != last ; ++b) {
Module *M = F.getParent(); CallSite call = CallSite::get(b);
if (CallInst *call = dyn_cast<CallInst>(b)) { if (call.getInstruction() && !call.getCalledFunction()) {
if (Function *callee = call->getCalledFunction()) { llvm::Value *args[] = { call->getOperand(1), call->getOperand(0),
if (callee->getName() == "objc_msg_lookup_sender") { ModuleID, ConstantInt::get(Int32Ty, callsiteCount++) };
Constant *profile =
llvm::Value *args[] = { call->getOperand(1), M->getOrInsertFunction("objc_msg_profile",
call->getOperand(2), call->getOperand(3), Type::getVoidTy(M->getContext()),
ModuleID, ConstantInt::get(Int32Ty, args[0]->getType(), args[1]->getType(),
callsiteCount++) }; args[2]->getType(), args[3]->getType(), NULL);
Function *profile = cast<Function>( CallInst::Create(profile, args, args+4, "", call.getInstruction());
M->getOrInsertFunction("objc_msg_lookup_profile",
callee->getFunctionType()->getReturnType(),
args[0]->getType(), args[1]->getType(),
args[2]->getType(),
ModuleID->getType(), Int32Ty, NULL));
llvm::CallInst *profileCall =
CallInst::Create(profile, args, args+5, "", call);
replacements.push_back(callPair(call, profileCall));
}
}
} }
} }
for (replacementVector::iterator r=replacements.begin(),
e=replacements.end() ; e!=r ; r++) {
r->first->replaceAllUsesWith(r->second);
r->second->getParent()->getInstList().erase(r->first);
}
} }
} }

@ -4,10 +4,14 @@
#include "llvm/Function.h" #include "llvm/Function.h"
#include "llvm/Instructions.h" #include "llvm/Instructions.h"
#include "llvm/Support/IRBuilder.h" #include "llvm/Support/IRBuilder.h"
#include "llvm/Analysis/InlineCost.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Linker.h" #include "llvm/Linker.h"
#include <vector> #include <vector>
#include "TypeInfoProvider.h"
using namespace llvm; using namespace llvm;
using namespace GNUstep;
namespace { namespace {
struct GNUObjCTypeFeedbackDrivenInliner : public ModulePass { struct GNUObjCTypeFeedbackDrivenInliner : public ModulePass {
@ -17,127 +21,65 @@ namespace {
static char ID; static char ID;
uint32_t callsiteCount; uint32_t callsiteCount;
const IntegerType *Int32Ty; const IntegerType *Int32Ty;
GNUObjCTypeFeedbackDrivenInliner() : ModulePass(&ID), callsiteCount(0) {}
void profileFunction(Function &F, Constant *ModuleID) {
for (Function::iterator i=F.begin(), e=F.end() ;
i != e ; ++i) {
replacementVector replacements;
for (BasicBlock::iterator b=i->begin(), last=i->end() ;
b != last ; ++b) {
Module *M = F.getParent();
if (CallInst *call = dyn_cast<CallInst>(b)) {
if (Function *callee = call->getCalledFunction()) {
if (callee->getName() == "objc_msg_lookup_sender") {
llvm::Value *args[] = { call->getOperand(1),
call->getOperand(2), call->getOperand(3),
ModuleID, ConstantInt::get(Int32Ty,
callsiteCount++) };
Function *profile = cast<Function>(
M->getOrInsertFunction("objc_msg_lookup_profile",
callee->getFunctionType()->getReturnType(),
args[0]->getType(), args[1]->getType(),
args[2]->getType(),
ModuleID->getType(), Int32Ty, NULL));
llvm::CallInst *profileCall =
CallInst::Create(profile, args, args+5, "", call);
replacements.push_back(callPair(call, profileCall));
}
}
}
}
for (replacementVector::iterator r=replacements.begin(),
e=replacements.end() ; e!=r ; r++) {
r->first->replaceAllUsesWith(r->second);
r->second->getParent()->getInstList().erase(r->first);
}
}
}
public: public:
GNUObjCTypeFeedbackDrivenInliner() : ModulePass(&ID), callsiteCount(0) {}
virtual bool runOnModule(Module &M) virtual bool runOnModule(Module &M)
{ {
bool modified = false;
LLVMContext &VMContext = M.getContext(); LLVMContext &VMContext = M.getContext();
Int32Ty = IntegerType::get(VMContext, 32); Int32Ty = IntegerType::get(VMContext, 32);
const PointerType *PtrTy = Type::getInt8PtrTy(VMContext); TypeInfoProvider::CallSiteMap *SiteMap =
Constant *moduleName = TypeInfoProvider::SharedTypeInfoProvider()->getCallSitesForModule(M);
ConstantArray::get(VMContext, M.getModuleIdentifier(), true); SmallPtrSet<const Function *, 16> NeverInline;
moduleName = new GlobalVariable(M, moduleName->getType(), true,
GlobalValue::InternalLinkage, moduleName,
".objc_profile_module_name");
std::vector<Constant*> functions;
llvm::Constant *Zeros[2];
Zeros[0] = ConstantInt::get(Type::getInt32Ty(VMContext), 0);
Zeros[1] = Zeros[0];
moduleName = ConstantExpr::getGetElementPtr(moduleName, Zeros, 2);
functions.push_back(moduleName);;
functions.push_back(moduleName);;
for (Module::iterator F=M.begin(), e=M.end() ;
F != e ; ++F) {
if (F->isDeclaration()) { continue; }
functions.push_back(ConstantExpr::getBitCast(F, PtrTy));
Constant * ConstStr = //TypeInfoProvider::SharedTypeInfoProvider()->PrintStatistics();
llvm::ConstantArray::get(VMContext, F->getName()); GNUstep::IMPCacher cacher = GNUstep::IMPCacher(M.getContext(), this);
ConstStr = new GlobalVariable(M, ConstStr->getType(), true, InlineCostAnalyzer CA;
GlobalValue::PrivateLinkage, ConstStr, "str"); SmallVector<CallSite, 16> messages;
functions.push_back(
ConstantExpr::getGetElementPtr(ConstStr, Zeros, 2));
profileFunction(*F, moduleName); for (Module::iterator F=M.begin(), fend=M.end() ;
} F != fend ; ++F) {
functions.push_back(ConstantPointerNull::get(PtrTy));
Constant *symtab = ConstantArray::get(ArrayType::get(PtrTy,
functions.size()), functions); if (F->isDeclaration()) { continue; }
Value *symbolTable = new GlobalVariable(M, symtab->getType(), true,
GlobalValue::InternalLinkage, symtab, "symtab"); for (Function::iterator i=F->begin(), end=F->end() ;
i != end ; ++i) {
Function *init = for (BasicBlock::iterator b=i->begin(), last=i->end() ;
Function::Create(FunctionType::get(Type::getVoidTy(VMContext), false), b != last ; ++b) {
GlobalValue::PrivateLinkage, "load_symbol_table", &M); CallSite call = CallSite::get(b);
BasicBlock * EntryBB = BasicBlock::Create(VMContext, "entry", init); if (call.getInstruction() && !call.getCalledFunction()) {
IRBuilder<> B = IRBuilder<>(EntryBB); messages.push_back(call);
Value *syms = B.CreateStructGEP(symbolTable, 0); }
B.CreateCall(M.getOrInsertFunction("objc_profile_write_symbols", }
Type::getVoidTy(VMContext), syms->getType(), NULL), }
syms);
B.CreateRetVoid();
GlobalVariable *GCL = M.getGlobalVariable("llvm.global_ctors");
std::vector<Constant*> ctors;
ConstantArray *CA = cast<ConstantArray>(GCL->getInitializer());
for (User::op_iterator i = CA->op_begin(), e = CA->op_end(); i != e; ++i) {
ctors.push_back(cast<ConstantStruct>(*i));
} }
TypeInfoProvider::CallSiteMap::iterator Entry = SiteMap->begin();
// Type of one ctor for (SmallVectorImpl<CallSite>::iterator i=messages.begin(),
const Type *ctorTy = e=messages.end() ; e!=i ; ++i, ++Entry) {
cast<ArrayType>(GCL->getType()->getElementType())->getElementType();
// Add the if (Entry->size() == 1) {
std::vector<Constant*> CSVals;
CSVals.push_back(ConstantInt::get(Type::getInt32Ty(VMContext),65535)); TypeInfoProvider::CallSiteEntry::iterator iterator = Entry->begin();
CSVals.push_back(init); Function *method = M.getFunction(Entry->begin()->getKey());
ctors.push_back(ConstantStruct::get(GCL->getContext(), CSVals, false)); if (0 == method || method->isDeclaration()) { continue; }
// Create the array initializer.
CA = cast<ConstantArray>(ConstantArray::get(ArrayType::get(ctorTy, InlineCost IC = CA.getInlineCost((*i), method, NeverInline);
ctors.size()), ctors)); // FIXME: 200 is a random number. Pick a better one!
// Create the new global and replace the old one if (IC.isAlways() || (IC.isVariable() && IC.getValue() < 200)) {
GlobalVariable *NGV = new GlobalVariable(CA->getType(), cacher.SpeculativelyInline((*i).getInstruction(), method);
GCL->isConstant(), GCL->getLinkage(), CA, "", GCL->isThreadLocal()); modified = true;
GCL->getParent()->getGlobalList().insert(GCL, NGV); }
NGV->takeName(GCL); }
GCL->replaceAllUsesWith(NGV); // FIXME: Inline the most popular call if one is much more popular
GCL->eraseFromParent(); // than the others.
}
return true; return modified;
} }
}; };

Loading…
Cancel
Save