From 6a58d3d49de95600e9e1f1be0feda1a59f8894d8 Mon Sep 17 00:00:00 2001 From: theraven Date: Sat, 1 May 2010 13:56:59 +0000 Subject: [PATCH] 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. --- opts/ClassIMPCache.cpp | 48 ++++----- opts/ClassMethodInliner.cpp | 32 +++--- opts/IMPCacher.cpp | 39 ++++++-- opts/IMPCacher.h | 3 +- opts/TypeFeedback.cpp | 5 +- opts/TypeFeedbackDrivenInliner.cpp | 150 +++++++++++++++++++++++++++++ 6 files changed, 221 insertions(+), 56 deletions(-) create mode 100644 opts/TypeFeedbackDrivenInliner.cpp diff --git a/opts/ClassIMPCache.cpp b/opts/ClassIMPCache.cpp index 354a526..bb9807c 100644 --- a/opts/ClassIMPCache.cpp +++ b/opts/ClassIMPCache.cpp @@ -1,9 +1,11 @@ #include "llvm/Pass.h" #include "llvm/Function.h" #include "llvm/Module.h" +#include "llvm/LLVMContext.h" #include "llvm/Instructions.h" #include "llvm/Constants.h" #include "llvm/GlobalVariable.h" +#include "llvm/Support/CallSite.h" #include "llvm/Support/IRBuilder.h" #include "llvm/Analysis/LoopInfo.h" #include "IMPCacher.h" @@ -28,53 +30,43 @@ namespace IntTy = Type::getInt32Ty(M.getContext()); bool modified = false; + unsigned MessageSendMDKind = M.getContext().getMDKindID("GNUObjCMessageSend"); + for (Module::iterator F=M.begin(), fend=M.end() ; F != fend ; ++F) { if (F->isDeclaration()) { continue; } - SmallVector Lookups; + SmallVector, 16> Lookups; BasicBlock *entry = &F->getEntryBlock(); for (Function::iterator i=F->begin(), end=F->end() ; i != end ; ++i) { for (BasicBlock::iterator b=i->begin(), last=i->end() ; b != last ; ++b) { - if (CallInst *call = dyn_cast(b)) { - Value *callee = call->getCalledValue()->stripPointerCasts(); + CallSite call = CallSite::get(b); + if (call.getInstruction()) { + Value *callee = call.getCalledValue()->stripPointerCasts(); if (Function *func = dyn_cast(callee)) { if (func->getName() == "objc_msg_lookup_sender") { - // TODO: Move this to a helper - Value *receiverPtr = call->getOperand(1); - Value *receiver = 0; - // Find where the receiver comes from - for (BasicBlock::iterator start=i->begin(),s=b ; s!=start ; s--) { - if (StoreInst *store = dyn_cast(s)) { - if (store->getOperand(1) == receiverPtr) { - receiver = store->getOperand(0); - break; - } - } - } - if (0 == receiver) { continue; } - if (CallInst *classLookup = dyn_cast(receiver)) { - Value *lookupVal = classLookup->getCalledValue()->stripPointerCasts(); - if (Function *lookupFunc = dyn_cast(lookupVal)) { - if (lookupFunc->getName() == "objc_lookup_class") { - modified = true; - Lookups.push_back(call); - } - } + MDNode *messageType = + call.getInstruction()->getMetadata(MessageSendMDKind); + if (0 == messageType) { continue; } + if (cast(messageType->getOperand(2))->isOne()) { + Lookups.push_back(std::pair(call, false)); } + } else if (func->getName() == "objc_slot_lookup_super") { + Lookups.push_back(std::pair(call, true)); } } } } } IRBuilder<> B = IRBuilder<>(entry); - for (SmallVectorImpl::iterator i=Lookups.begin(), - e=Lookups.end() ; e!=i ; i++) { - const Type *SlotPtrTy = (*i)->getType(); + for (SmallVectorImpl >::iterator + i=Lookups.begin(), e=Lookups.end() ; e!=i ; i++) { + Instruction *call = i->first.getInstruction(); + const Type *SlotPtrTy = call->getType(); Value *slot = new GlobalVariable(M, SlotPtrTy, false, GlobalValue::PrivateLinkage, Constant::getNullValue(SlotPtrTy), @@ -82,7 +74,7 @@ namespace Value *version = new GlobalVariable(M, IntTy, false, GlobalValue::PrivateLinkage, Constant::getNullValue(IntTy), "version"); - cacher.CacheLookup(*i, slot, version); + cacher.CacheLookup(call, slot, version, i->second); } } return modified; diff --git a/opts/ClassMethodInliner.cpp b/opts/ClassMethodInliner.cpp index f3a6786..0a68bae 100644 --- a/opts/ClassMethodInliner.cpp +++ b/opts/ClassMethodInliner.cpp @@ -2,6 +2,7 @@ #include "llvm/Function.h" #include "llvm/Module.h" #include "llvm/Instructions.h" +#include "llvm/Support/CallSite.h" #include "llvm/Constants.h" #include "llvm/LLVMContext.h" #include "llvm/GlobalVariable.h" @@ -47,41 +48,38 @@ namespace for (Module::iterator F=M.begin(), fend=M.end() ; F != fend ; ++F) { - SmallVector messages; + SmallVector messages; if (F->isDeclaration()) { continue; } - SmallVector Lookups; - for (Function::iterator i=F->begin(), end=F->end() ; i != end ; ++i) { for (BasicBlock::iterator b=i->begin(), last=i->end() ; b != last ; ++b) { - // FIXME: InvokeInst - if (CallInst *call = dyn_cast(b)) { - Instruction *callee = - dyn_cast(call->getCalledValue()->stripPointerCasts()); - if (0 == callee) { continue; } - MDNode *messageType = callee->getMetadata(MessageSendMDKind); + CallSite call = CallSite::get(b); + if (call.getInstruction()) { + MDNode *messageType = call->getMetadata(MessageSendMDKind); if (0 == messageType) { continue; } messages.push_back(call); } } } - for (SmallVectorImpl::iterator i=messages.begin(), + for (SmallVectorImpl::iterator i=messages.begin(), e=messages.end() ; e!=i ; i++) { - Instruction *callee = - dyn_cast((*i)->getCalledValue()->stripPointerCasts()); - MDNode *messageType = callee->getMetadata(MessageSendMDKind); - StringRef sel = cast(messageType->getOperand(0))->getString(); - StringRef cls = cast(messageType->getOperand(1))->getString(); - StringRef functionName = SymbolNameForMethod(cls, "", sel, true); + MDNode *messageType = (*i)->getMetadata(MessageSendMDKind); + StringRef sel = + cast(messageType->getOperand(0))->getString(); + StringRef cls = + cast(messageType->getOperand(1))->getString(); + bool isClassMethod = + cast(messageType->getOperand(2))->isOne(); + StringRef functionName = SymbolNameForMethod(cls, "", sel, isClassMethod); Function *method = M.getFunction(functionName); if (0 == method || method->isDeclaration()) { continue; } - cacher.SpeculativelyInline(*i, method); + cacher.SpeculativelyInline((*i).getInstruction(), method); } } return modified; diff --git a/opts/IMPCacher.cpp b/opts/IMPCacher.cpp index 724e857..9d3dec0 100644 --- a/opts/IMPCacher.cpp +++ b/opts/IMPCacher.cpp @@ -23,8 +23,8 @@ GNUstep::IMPCacher::IMPCacher(LLVMContext &C, Pass *owner) : Context(C), IMPCacheFlagKind = Context.getMDKindID("IMPCache"); } -void GNUstep::IMPCacher::CacheLookup(CallInst *lookup, Value *slot, Value - *version) { +void GNUstep::IMPCacher::CacheLookup(Instruction *lookup, Value *slot, Value + *version, bool isSuperMessage) { // If this IMP is already cached, don't cache it again. if (lookup->getMetadata(IMPCacheFlagKind)) { return; } @@ -44,7 +44,10 @@ void GNUstep::IMPCacher::CacheLookup(CallInst *lookup, Value *slot, Value Value *slotValue = B.CreateLoad(slot); Value *versionValue = B.CreateLoad(version); Value *receiverPtr = lookup->getOperand(1); - Value *receiver = B.CreateLoad(receiverPtr); + Value *receiver = receiverPtr; + if (!isSuperMessage) { + receiver = B.CreateLoad(receiverPtr); + } Value *isCacheEmpty = 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 removeTerminator(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", lookupBB->getParent()); @@ -122,19 +128,40 @@ void GNUstep::IMPCacher::SpeculativelyInline(Instruction *call, Function // function IRBuilder<> B = IRBuilder<>(beforeCallBB); Value *callee = call->getOperand(0); - if (callee->getType() != function->getType()) { + + const FunctionType *FTy = function->getFunctionType(); + const FunctionType *calleeTy = cast( + cast(callee->getType())->getElementType()); + if (calleeTy != FTy) { callee = B.CreateBitCast(callee, function->getType()); } + Value *isInlineValid = B.CreateICmpEQ(callee, function); B.CreateCondBr(isInlineValid, inlineBB, callBB); // In the inline BB, add a copy of the call, but this time calling the real // version. Instruction *inlineCall = call->clone(); + Value *inlineResult= inlineCall; inlineBB->getInstList().push_back(inlineCall); inlineCall->setOperand(0, function); B.SetInsertPoint(inlineBB); + + if (calleeTy != FTy) { + for (unsigned i=0 ; igetNumParams() ; 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); // Unify the return values @@ -143,7 +170,7 @@ void GNUstep::IMPCacher::SpeculativelyInline(Instruction *call, Function PHINode *phi = B.CreatePHI(call->getType()); call->replaceAllUsesWith(phi); phi->addIncoming(call, callBB); - phi->addIncoming(inlineCall, inlineBB); + phi->addIncoming(inlineResult, inlineBB); } // Really do the real inlining diff --git a/opts/IMPCacher.h b/opts/IMPCacher.h index 028a116..702bd05 100644 --- a/opts/IMPCacher.h +++ b/opts/IMPCacher.h @@ -28,7 +28,8 @@ namespace GNUstep const IntegerType *IntTy; public: 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); }; diff --git a/opts/TypeFeedback.cpp b/opts/TypeFeedback.cpp index efea27f..bc958e4 100644 --- a/opts/TypeFeedback.cpp +++ b/opts/TypeFeedback.cpp @@ -75,7 +75,6 @@ namespace { Zeros[1] = Zeros[0]; moduleName = ConstantExpr::getGetElementPtr(moduleName, Zeros, 2); - moduleName->dump(); functions.push_back(moduleName);; functions.push_back(moduleName);; @@ -117,8 +116,7 @@ namespace { ConstantArray *CA = cast(GCL->getInitializer()); for (User::op_iterator i = CA->op_begin(), e = CA->op_end(); i != e; ++i) { - ConstantStruct *CS = cast(*i); - ctors.push_back(dyn_cast(CS->getOperand(1))); + ctors.push_back(cast(*i)); } // Type of one ctor @@ -139,7 +137,6 @@ namespace { NGV->takeName(GCL); GCL->replaceAllUsesWith(NGV); GCL->eraseFromParent(); - M.dump(); return true; } diff --git a/opts/TypeFeedbackDrivenInliner.cpp b/opts/TypeFeedbackDrivenInliner.cpp new file mode 100644 index 0000000..5ed8ac6 --- /dev/null +++ b/opts/TypeFeedbackDrivenInliner.cpp @@ -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 + +using namespace llvm; + +namespace { + struct GNUObjCTypeFeedbackDrivenInliner : public ModulePass { + + typedef std::pair callPair; + typedef std::vector 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(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( + 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 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 ctors; + + ConstantArray *CA = cast(GCL->getInitializer()); + + for (User::op_iterator i = CA->op_begin(), e = CA->op_end(); i != e; ++i) { + ctors.push_back(cast(*i)); + } + + // Type of one ctor + const Type *ctorTy = + cast(GCL->getType()->getElementType())->getElementType(); + // Add the + std::vector 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::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 X("gnu-objc-feedback-driven-inline", + "Objective-C type feedback-driven inliner for the GNU runtime.", false, + true); +} +