From 84b41a8464e2ed379925ae9fdc066fdc3f4ae115 Mon Sep 17 00:00:00 2001 From: theraven Date: Wed, 28 Apr 2010 14:33:52 +0000 Subject: [PATCH] Added -gnu-class-lookup-cache and -gnu-class-imp-cache passes. These add caching for class messages and also skip the class lookup (using the class symbol directly) where possible. In combination, these make class messages marginally slower than function calls, rather than significantly slower than message sends. --- opts/ClassIMPCache.cpp | 105 ++++++++++++++++++++++++++++++++++++++ opts/ClassLookupCache.cpp | 83 ++++++++++++++++++++++++++++++ opts/IMPCacher.cpp | 20 +++++++- opts/IMPCacher.h | 15 +++--- 4 files changed, 214 insertions(+), 9 deletions(-) create mode 100644 opts/ClassIMPCache.cpp create mode 100644 opts/ClassLookupCache.cpp diff --git a/opts/ClassIMPCache.cpp b/opts/ClassIMPCache.cpp new file mode 100644 index 0000000..3fc5559 --- /dev/null +++ b/opts/ClassIMPCache.cpp @@ -0,0 +1,105 @@ +#include "llvm/Pass.h" +#include "llvm/Function.h" +#include "llvm/Module.h" +#include "llvm/Instructions.h" +#include "llvm/Constants.h" +#include "llvm/GlobalVariable.h" +#include "llvm/Support/IRBuilder.h" +#include "llvm/Analysis/LoopInfo.h" +#include "IMPCacher.h" +#include + +using namespace llvm; +using std::string; + +namespace +{ + class ClassIMPCachePass : public FunctionPass + { + GNUstep::IMPCacher *cacher; + Module *M; + const IntegerType *IntTy; + + public: + static char ID; + ClassIMPCachePass() : FunctionPass((intptr_t)&ID) {} + ~ClassIMPCachePass() { delete cacher; } + + virtual bool doInitialization(Module &Mod) { + M = &Mod; + cacher = new GNUstep::IMPCacher(Mod.getContext(), this); + // FIXME: ILP64 + IntTy = Type::getInt32Ty(Mod.getContext()); + return false; + } + + virtual bool runOnFunction(Function &F) { + bool modified = false; + SmallVector 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(); + 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") { + GlobalVariable *classNameVar = cast( + classLookup->getOperand(1)->stripPointerCasts()); + string className = cast( + classNameVar->getInitializer() )->getAsString(); + modified = true; + Lookups.push_back(call); + } + } + } + } + } + } + } + } + IRBuilder<> B = IRBuilder<>(entry); + for (SmallVectorImpl::iterator i=Lookups.begin(), + e=Lookups.end() ; e!=i ; i++) { + const Type *SlotPtrTy = (*i)->getType(); + + Value *slot = new GlobalVariable(*M, SlotPtrTy, false, + GlobalValue::PrivateLinkage, Constant::getNullValue(SlotPtrTy), + "slot"); + Value *version = new GlobalVariable(*M, IntTy, false, + GlobalValue::PrivateLinkage, Constant::getNullValue(IntTy), + "version"); + cacher->CacheLookup(*i, slot, version); + } + return modified; + } + }; + + char ClassIMPCachePass::ID = 0; + RegisterPass X("gnu-class-imp-cache", + "Cache IMPs for class messages"); +} + +FunctionPass *createClassIMPCachePass(void) +{ + return new ClassIMPCachePass(); +} diff --git a/opts/ClassLookupCache.cpp b/opts/ClassLookupCache.cpp new file mode 100644 index 0000000..940005e --- /dev/null +++ b/opts/ClassLookupCache.cpp @@ -0,0 +1,83 @@ +#include "llvm/Pass.h" +#include "llvm/Function.h" +#include "llvm/Module.h" +#include "llvm/Instructions.h" +#include "llvm/Constants.h" +#include "llvm/GlobalVariable.h" +#include "llvm/Support/IRBuilder.h" +#include "llvm/Analysis/LoopInfo.h" +#include + +using namespace llvm; +using std::string; +using std::pair; + +namespace +{ + class ClassLookupCachePass : public FunctionPass + { + Module *M; + typedef std::pair ClassLookup; + + public: + static char ID; + ClassLookupCachePass() : FunctionPass((intptr_t)&ID) {} + + virtual bool doInitialization(Module &Mod) { + M = &Mod; + return false; + } + + virtual bool runOnFunction(Function &F) { + bool modified = false; + SmallVector 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(); + if (Function *func = dyn_cast(callee)) { + if (func->getName() == "objc_lookup_class") { + ClassLookup lookup; + GlobalVariable *classNameVar = dyn_cast( + call->getOperand(1)->stripPointerCasts()); + if (0 == classNameVar) { continue; } + ConstantArray *init = dyn_cast( + classNameVar->getInitializer()); + if (0 == init || !init->isCString()) { continue; } + lookup.first = call; + lookup.second = init->getAsString(); + modified = true; + Lookups.push_back(lookup); + } + } + } + } + } + IRBuilder<> B = IRBuilder<>(entry); + for (SmallVectorImpl::iterator i=Lookups.begin(), + e=Lookups.end() ; e!=i ; i++) { + Value *global = M->getGlobalVariable(("_OBJC_CLASS_" + i->second).c_str(), true); + fprintf(stderr, "%s\n", ("_OBJC_CLASS_" + i->second).c_str()); + if (global) { + Value *cls = new BitCastInst(global, i->first->getType(), "class", i->first); + i->first->replaceAllUsesWith(cls); + i->first->removeFromParent(); + } + } + return modified; + } + }; + + char ClassLookupCachePass::ID = 0; + RegisterPass X("gnu-class-lookup-cache", + "Cache class lookups"); +} + +FunctionPass *createClassLookupCachePass(void) +{ + return new ClassLookupCachePass(); +} diff --git a/opts/IMPCacher.cpp b/opts/IMPCacher.cpp index 398634f..2400f07 100644 --- a/opts/IMPCacher.cpp +++ b/opts/IMPCacher.cpp @@ -1,14 +1,32 @@ +#include "IMPCacher.h" #include "llvm/Pass.h" #include "llvm/Function.h" #include "llvm/Instructions.h" #include "llvm/Constants.h" +#include "llvm/LLVMContext.h" +#include "llvm/Metadata.h" #include "llvm/Support/IRBuilder.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" -#include "IMPCacher.h" + +GNUstep::IMPCacher::IMPCacher(LLVMContext &C, Pass *owner) : Context(C), + Owner(owner) { + + PtrTy = Type::getInt8PtrTy(Context); + // FIXME: 64-bit. + IntTy = Type::getInt32Ty(Context); + IdTy = PointerType::getUnqual(PtrTy); + Value *AlreadyCachedFlagValue = MDString::get(C, "IMPCached"); + AlreadyCachedFlag = MDNode::get(C, &AlreadyCachedFlagValue, 1); + IMPCacheFlagKind = Context.getMDKindID("IMPCache"); +} void GNUstep::IMPCacher::CacheLookup(CallInst *lookup, Value *slot, Value *version) { + // If this IMP is already cached, don't cache it again. + if (lookup->getMetadata(IMPCacheFlagKind)) { return; } + + lookup->setMetadata(IMPCacheFlagKind, AlreadyCachedFlag); BasicBlock *beforeLookupBB = lookup->getParent(); BasicBlock *lookupBB = SplitBlock(beforeLookupBB, lookup, Owner); BasicBlock::iterator iter = lookup; diff --git a/opts/IMPCacher.h b/opts/IMPCacher.h index aa4a093..5403e70 100644 --- a/opts/IMPCacher.h +++ b/opts/IMPCacher.h @@ -1,10 +1,12 @@ namespace llvm { + class CallInst; + class IntegerType; class LLVMContext; + class MDNode; class Pass; class PointerType; - class IntegerType; - class CallInst; + class Value; } using namespace llvm; @@ -15,17 +17,14 @@ namespace GNUstep { private: LLVMContext &Context; + MDNode *AlreadyCachedFlag; + unsigned IMPCacheFlagKind; Pass *Owner; const PointerType *PtrTy; const PointerType *IdTy; const IntegerType *IntTy; public: - IMPCacher(LLVMContext &C, Pass *owner) : Context(C), Owner(owner) { - PtrTy = Type::getInt8PtrTy(Context); - // FIXME: 64-bit. - IntTy = Type::getInt32Ty(Context); - IdTy = PointerType::getUnqual(PtrTy); - } + IMPCacher(LLVMContext &C, Pass *owner); void CacheLookup(CallInst *lookup, Value *slot, Value *version); }; }