Added unfinished inliner that uses type feedback info to inline instance methods.

Made class method inliner also inline message sends to super.

Various updates caused by clang now attaching more sensible metadata to the IR.
main
theraven 16 years ago
parent 160d1ce829
commit 6a58d3d49d

@ -1,9 +1,11 @@
#include "llvm/Pass.h" #include "llvm/Pass.h"
#include "llvm/Function.h" #include "llvm/Function.h"
#include "llvm/Module.h" #include "llvm/Module.h"
#include "llvm/LLVMContext.h"
#include "llvm/Instructions.h" #include "llvm/Instructions.h"
#include "llvm/Constants.h" #include "llvm/Constants.h"
#include "llvm/GlobalVariable.h" #include "llvm/GlobalVariable.h"
#include "llvm/Support/CallSite.h"
#include "llvm/Support/IRBuilder.h" #include "llvm/Support/IRBuilder.h"
#include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/LoopInfo.h"
#include "IMPCacher.h" #include "IMPCacher.h"
@ -28,53 +30,43 @@ namespace
IntTy = Type::getInt32Ty(M.getContext()); IntTy = Type::getInt32Ty(M.getContext());
bool modified = false; bool modified = false;
unsigned MessageSendMDKind = M.getContext().getMDKindID("GNUObjCMessageSend");
for (Module::iterator F=M.begin(), fend=M.end() ; for (Module::iterator F=M.begin(), fend=M.end() ;
F != fend ; ++F) { F != fend ; ++F) {
if (F->isDeclaration()) { continue; } if (F->isDeclaration()) { continue; }
SmallVector<CallInst*, 16> Lookups; SmallVector<std::pair<CallSite, bool>, 16> Lookups;
BasicBlock *entry = &F->getEntryBlock(); BasicBlock *entry = &F->getEntryBlock();
for (Function::iterator i=F->begin(), end=F->end() ; for (Function::iterator i=F->begin(), end=F->end() ;
i != end ; ++i) { i != end ; ++i) {
for (BasicBlock::iterator b=i->begin(), last=i->end() ; for (BasicBlock::iterator b=i->begin(), last=i->end() ;
b != last ; ++b) { b != last ; ++b) {
if (CallInst *call = dyn_cast<CallInst>(b)) { CallSite call = CallSite::get(b);
Value *callee = call->getCalledValue()->stripPointerCasts(); if (call.getInstruction()) {
Value *callee = call.getCalledValue()->stripPointerCasts();
if (Function *func = dyn_cast<Function>(callee)) { if (Function *func = dyn_cast<Function>(callee)) {
if (func->getName() == "objc_msg_lookup_sender") { if (func->getName() == "objc_msg_lookup_sender") {
// TODO: Move this to a helper MDNode *messageType =
Value *receiverPtr = call->getOperand(1); call.getInstruction()->getMetadata(MessageSendMDKind);
Value *receiver = 0; if (0 == messageType) { continue; }
// Find where the receiver comes from if (cast<ConstantInt>(messageType->getOperand(2))->isOne()) {
for (BasicBlock::iterator start=i->begin(),s=b ; s!=start ; s--) { Lookups.push_back(std::pair<CallSite, bool>(call, false));
if (StoreInst *store = dyn_cast<StoreInst>(s)) {
if (store->getOperand(1) == receiverPtr) {
receiver = store->getOperand(0);
break;
}
}
}
if (0 == receiver) { continue; }
if (CallInst *classLookup = dyn_cast<CallInst>(receiver)) {
Value *lookupVal = classLookup->getCalledValue()->stripPointerCasts();
if (Function *lookupFunc = dyn_cast<Function>(lookupVal)) {
if (lookupFunc->getName() == "objc_lookup_class") {
modified = true;
Lookups.push_back(call);
}
}
} }
} else if (func->getName() == "objc_slot_lookup_super") {
Lookups.push_back(std::pair<CallSite, bool>(call, true));
} }
} }
} }
} }
} }
IRBuilder<> B = IRBuilder<>(entry); IRBuilder<> B = IRBuilder<>(entry);
for (SmallVectorImpl<CallInst*>::iterator i=Lookups.begin(), for (SmallVectorImpl<std::pair<CallSite, bool> >::iterator
e=Lookups.end() ; e!=i ; i++) { i=Lookups.begin(), e=Lookups.end() ; e!=i ; i++) {
const Type *SlotPtrTy = (*i)->getType(); Instruction *call = i->first.getInstruction();
const Type *SlotPtrTy = call->getType();
Value *slot = new GlobalVariable(M, SlotPtrTy, false, Value *slot = new GlobalVariable(M, SlotPtrTy, false,
GlobalValue::PrivateLinkage, Constant::getNullValue(SlotPtrTy), GlobalValue::PrivateLinkage, Constant::getNullValue(SlotPtrTy),
@ -82,7 +74,7 @@ namespace
Value *version = new GlobalVariable(M, IntTy, false, Value *version = new GlobalVariable(M, IntTy, false,
GlobalValue::PrivateLinkage, Constant::getNullValue(IntTy), GlobalValue::PrivateLinkage, Constant::getNullValue(IntTy),
"version"); "version");
cacher.CacheLookup(*i, slot, version); cacher.CacheLookup(call, slot, version, i->second);
} }
} }
return modified; return modified;

@ -2,6 +2,7 @@
#include "llvm/Function.h" #include "llvm/Function.h"
#include "llvm/Module.h" #include "llvm/Module.h"
#include "llvm/Instructions.h" #include "llvm/Instructions.h"
#include "llvm/Support/CallSite.h"
#include "llvm/Constants.h" #include "llvm/Constants.h"
#include "llvm/LLVMContext.h" #include "llvm/LLVMContext.h"
#include "llvm/GlobalVariable.h" #include "llvm/GlobalVariable.h"
@ -47,41 +48,38 @@ namespace
for (Module::iterator F=M.begin(), fend=M.end() ; for (Module::iterator F=M.begin(), fend=M.end() ;
F != fend ; ++F) { F != fend ; ++F) {
SmallVector<CallInst*, 16> messages; SmallVector<CallSite, 16> messages;
if (F->isDeclaration()) { continue; } if (F->isDeclaration()) { continue; }
SmallVector<CallInst*, 16> Lookups;
for (Function::iterator i=F->begin(), end=F->end() ; for (Function::iterator i=F->begin(), end=F->end() ;
i != end ; ++i) { i != end ; ++i) {
for (BasicBlock::iterator b=i->begin(), last=i->end() ; for (BasicBlock::iterator b=i->begin(), last=i->end() ;
b != last ; ++b) { b != last ; ++b) {
// FIXME: InvokeInst CallSite call = CallSite::get(b);
if (CallInst *call = dyn_cast<CallInst>(b)) { if (call.getInstruction()) {
Instruction *callee = MDNode *messageType = call->getMetadata(MessageSendMDKind);
dyn_cast<Instruction>(call->getCalledValue()->stripPointerCasts());
if (0 == callee) { continue; }
MDNode *messageType = callee->getMetadata(MessageSendMDKind);
if (0 == messageType) { continue; } if (0 == messageType) { continue; }
messages.push_back(call); messages.push_back(call);
} }
} }
} }
for (SmallVectorImpl<CallInst*>::iterator i=messages.begin(), for (SmallVectorImpl<CallSite>::iterator i=messages.begin(),
e=messages.end() ; e!=i ; i++) { e=messages.end() ; e!=i ; i++) {
Instruction *callee = MDNode *messageType = (*i)->getMetadata(MessageSendMDKind);
dyn_cast<Instruction>((*i)->getCalledValue()->stripPointerCasts()); StringRef sel =
MDNode *messageType = callee->getMetadata(MessageSendMDKind); cast<MDString>(messageType->getOperand(0))->getString();
StringRef sel = cast<MDString>(messageType->getOperand(0))->getString(); StringRef cls =
StringRef cls = cast<MDString>(messageType->getOperand(1))->getString(); cast<MDString>(messageType->getOperand(1))->getString();
StringRef functionName = SymbolNameForMethod(cls, "", sel, true); bool isClassMethod =
cast<ConstantInt>(messageType->getOperand(2))->isOne();
StringRef functionName = SymbolNameForMethod(cls, "", sel, isClassMethod);
Function *method = M.getFunction(functionName); Function *method = M.getFunction(functionName);
if (0 == method || method->isDeclaration()) { continue; } if (0 == method || method->isDeclaration()) { continue; }
cacher.SpeculativelyInline(*i, method); cacher.SpeculativelyInline((*i).getInstruction(), method);
} }
} }
return modified; return modified;

@ -23,8 +23,8 @@ GNUstep::IMPCacher::IMPCacher(LLVMContext &C, Pass *owner) : Context(C),
IMPCacheFlagKind = Context.getMDKindID("IMPCache"); IMPCacheFlagKind = Context.getMDKindID("IMPCache");
} }
void GNUstep::IMPCacher::CacheLookup(CallInst *lookup, Value *slot, Value void GNUstep::IMPCacher::CacheLookup(Instruction *lookup, Value *slot, Value
*version) { *version, bool isSuperMessage) {
// If this IMP is already cached, don't cache it again. // If this IMP is already cached, don't cache it again.
if (lookup->getMetadata(IMPCacheFlagKind)) { return; } if (lookup->getMetadata(IMPCacheFlagKind)) { return; }
@ -44,7 +44,10 @@ void GNUstep::IMPCacher::CacheLookup(CallInst *lookup, Value *slot, Value
Value *slotValue = B.CreateLoad(slot); Value *slotValue = B.CreateLoad(slot);
Value *versionValue = B.CreateLoad(version); Value *versionValue = B.CreateLoad(version);
Value *receiverPtr = lookup->getOperand(1); Value *receiverPtr = lookup->getOperand(1);
Value *receiver = B.CreateLoad(receiverPtr); Value *receiver = receiverPtr;
if (!isSuperMessage) {
receiver = B.CreateLoad(receiverPtr);
}
Value *isCacheEmpty = Value *isCacheEmpty =
B.CreateOr(versionValue, B.CreatePtrToInt(slotValue, IntTy)); B.CreateOr(versionValue, B.CreatePtrToInt(slotValue, IntTy));
@ -83,7 +86,10 @@ void GNUstep::IMPCacher::CacheLookup(CallInst *lookup, Value *slot, Value
// Perform the real lookup and cache the result // Perform the real lookup and cache the result
removeTerminator(lookupBB); removeTerminator(lookupBB);
B.SetInsertPoint(lookupBB); B.SetInsertPoint(lookupBB);
Value * newReceiver = B.CreateLoad(receiverPtr); Value * newReceiver = receiver;
if (!isSuperMessage) {
newReceiver = B.CreateLoad(receiverPtr);
}
BasicBlock *storeCacheBB = BasicBlock::Create(Context, "cache_store", BasicBlock *storeCacheBB = BasicBlock::Create(Context, "cache_store",
lookupBB->getParent()); lookupBB->getParent());
@ -122,19 +128,40 @@ void GNUstep::IMPCacher::SpeculativelyInline(Instruction *call, Function
// function // function
IRBuilder<> B = IRBuilder<>(beforeCallBB); IRBuilder<> B = IRBuilder<>(beforeCallBB);
Value *callee = call->getOperand(0); Value *callee = call->getOperand(0);
if (callee->getType() != function->getType()) {
const FunctionType *FTy = function->getFunctionType();
const FunctionType *calleeTy = cast<FunctionType>(
cast<PointerType>(callee->getType())->getElementType());
if (calleeTy != FTy) {
callee = B.CreateBitCast(callee, function->getType()); callee = B.CreateBitCast(callee, function->getType());
} }
Value *isInlineValid = B.CreateICmpEQ(callee, function); Value *isInlineValid = B.CreateICmpEQ(callee, function);
B.CreateCondBr(isInlineValid, inlineBB, callBB); B.CreateCondBr(isInlineValid, inlineBB, callBB);
// In the inline BB, add a copy of the call, but this time calling the real // In the inline BB, add a copy of the call, but this time calling the real
// version. // version.
Instruction *inlineCall = call->clone(); Instruction *inlineCall = call->clone();
Value *inlineResult= inlineCall;
inlineBB->getInstList().push_back(inlineCall); inlineBB->getInstList().push_back(inlineCall);
inlineCall->setOperand(0, function); inlineCall->setOperand(0, function);
B.SetInsertPoint(inlineBB); B.SetInsertPoint(inlineBB);
if (calleeTy != FTy) {
for (unsigned i=0 ; i<FTy->getNumParams() ; i++) {
const Type *callType = calleeTy->getParamType(i);
const Type *argType = FTy->getParamType(i);
if (callType != argType) {
inlineCall->setOperand(i+1, new
BitCastInst(inlineCall->getOperand(i+1), argType, "", inlineCall));
}
}
if (FTy->getReturnType() != calleeTy->getReturnType()) {
inlineResult = new BitCastInst(inlineCall, calleeTy->getReturnType(), "", inlineBB);
}
}
B.CreateBr(afterCallBB); B.CreateBr(afterCallBB);
// Unify the return values // Unify the return values
@ -143,7 +170,7 @@ void GNUstep::IMPCacher::SpeculativelyInline(Instruction *call, Function
PHINode *phi = B.CreatePHI(call->getType()); PHINode *phi = B.CreatePHI(call->getType());
call->replaceAllUsesWith(phi); call->replaceAllUsesWith(phi);
phi->addIncoming(call, callBB); phi->addIncoming(call, callBB);
phi->addIncoming(inlineCall, inlineBB); phi->addIncoming(inlineResult, inlineBB);
} }
// Really do the real inlining // Really do the real inlining

@ -28,7 +28,8 @@ namespace GNUstep
const IntegerType *IntTy; const IntegerType *IntTy;
public: public:
IMPCacher(LLVMContext &C, Pass *owner); IMPCacher(LLVMContext &C, Pass *owner);
void CacheLookup(CallInst *lookup, Value *slot, Value *version); void CacheLookup(Instruction *lookup, Value *slot, Value *version, bool
isSuperMessage=false);
void SpeculativelyInline(Instruction *call, Function *function); void SpeculativelyInline(Instruction *call, Function *function);
}; };

@ -75,7 +75,6 @@ namespace {
Zeros[1] = Zeros[0]; Zeros[1] = Zeros[0];
moduleName = ConstantExpr::getGetElementPtr(moduleName, Zeros, 2); moduleName = ConstantExpr::getGetElementPtr(moduleName, Zeros, 2);
moduleName->dump();
functions.push_back(moduleName);; functions.push_back(moduleName);;
functions.push_back(moduleName);; functions.push_back(moduleName);;
@ -117,8 +116,7 @@ namespace {
ConstantArray *CA = cast<ConstantArray>(GCL->getInitializer()); ConstantArray *CA = cast<ConstantArray>(GCL->getInitializer());
for (User::op_iterator i = CA->op_begin(), e = CA->op_end(); i != e; ++i) { for (User::op_iterator i = CA->op_begin(), e = CA->op_end(); i != e; ++i) {
ConstantStruct *CS = cast<ConstantStruct>(*i); ctors.push_back(cast<ConstantStruct>(*i));
ctors.push_back(dyn_cast<Function>(CS->getOperand(1)));
} }
// Type of one ctor // Type of one ctor
@ -139,7 +137,6 @@ namespace {
NGV->takeName(GCL); NGV->takeName(GCL);
GCL->replaceAllUsesWith(NGV); GCL->replaceAllUsesWith(NGV);
GCL->eraseFromParent(); GCL->eraseFromParent();
M.dump();
return true; return true;
} }

@ -0,0 +1,150 @@
#include "llvm/Constants.h"
#include "llvm/Pass.h"
#include "llvm/Module.h"
#include "llvm/Function.h"
#include "llvm/Instructions.h"
#include "llvm/Support/IRBuilder.h"
#include "llvm/Linker.h"
#include <vector>
using namespace llvm;
namespace {
struct GNUObjCTypeFeedbackDrivenInliner : public ModulePass {
typedef std::pair<CallInst*,CallInst*> callPair;
typedef std::vector<callPair > replacementVector;
static char ID;
uint32_t callsiteCount;
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:
virtual bool runOnModule(Module &M)
{
LLVMContext &VMContext = M.getContext();
Int32Ty = IntegerType::get(VMContext, 32);
const PointerType *PtrTy = Type::getInt8PtrTy(VMContext);
Constant *moduleName =
ConstantArray::get(VMContext, M.getModuleIdentifier(), true);
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 =
llvm::ConstantArray::get(VMContext, F->getName());
ConstStr = new GlobalVariable(M, ConstStr->getType(), true,
GlobalValue::PrivateLinkage, ConstStr, "str");
functions.push_back(
ConstantExpr::getGetElementPtr(ConstStr, Zeros, 2));
profileFunction(*F, moduleName);
}
functions.push_back(ConstantPointerNull::get(PtrTy));
Constant *symtab = ConstantArray::get(ArrayType::get(PtrTy,
functions.size()), functions);
Value *symbolTable = new GlobalVariable(M, symtab->getType(), true,
GlobalValue::InternalLinkage, symtab, "symtab");
Function *init =
Function::Create(FunctionType::get(Type::getVoidTy(VMContext), false),
GlobalValue::PrivateLinkage, "load_symbol_table", &M);
BasicBlock * EntryBB = BasicBlock::Create(VMContext, "entry", init);
IRBuilder<> B = IRBuilder<>(EntryBB);
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));
}
// Type of one ctor
const Type *ctorTy =
cast<ArrayType>(GCL->getType()->getElementType())->getElementType();
// Add the
std::vector<Constant*> CSVals;
CSVals.push_back(ConstantInt::get(Type::getInt32Ty(VMContext),65535));
CSVals.push_back(init);
ctors.push_back(ConstantStruct::get(GCL->getContext(), CSVals, false));
// Create the array initializer.
CA = cast<ConstantArray>(ConstantArray::get(ArrayType::get(ctorTy,
ctors.size()), ctors));
// Create the new global and replace the old one
GlobalVariable *NGV = new GlobalVariable(CA->getType(),
GCL->isConstant(), GCL->getLinkage(), CA, "", GCL->isThreadLocal());
GCL->getParent()->getGlobalList().insert(GCL, NGV);
NGV->takeName(GCL);
GCL->replaceAllUsesWith(NGV);
GCL->eraseFromParent();
return true;
}
};
char GNUObjCTypeFeedbackDrivenInliner::ID = 0;
RegisterPass<GNUObjCTypeFeedbackDrivenInliner> X("gnu-objc-feedback-driven-inline",
"Objective-C type feedback-driven inliner for the GNU runtime.", false,
true);
}
Loading…
Cancel
Save