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); }; }