From 286892936dbe248f0db0db4c96169ca7afeaa901 Mon Sep 17 00:00:00 2001 From: theraven Date: Fri, 18 Nov 2011 20:28:02 +0000 Subject: [PATCH] Teach the optimisations to work in the presence of exception handling and if the front end emits objc_msgSend() instead of indirect lookups. The GNUstep-base test suite now passes when compiled with: -fno-objc-legacy-dispatch -Xclang -load -Xclang /path/to/libGNUObjCRuntime.so -O3 --- opts/ClassIMPCache.cpp | 23 +++++++++-- opts/IMPCacher.cpp | 85 ++++++++++++++++++++++++++++++++++++--- opts/LoopIMPCachePass.cpp | 44 ++++++++++++++++---- 3 files changed, 136 insertions(+), 16 deletions(-) diff --git a/opts/ClassIMPCache.cpp b/opts/ClassIMPCache.cpp index 43a5a33..e427eec 100644 --- a/opts/ClassIMPCache.cpp +++ b/opts/ClassIMPCache.cpp @@ -29,7 +29,14 @@ namespace ClassIMPCachePass() : ModulePass(ID) {} virtual bool runOnModule(Module &M) { - return false; + Function *sendFn = M.getFunction("objc_msgSend"); + Function *send_stretFn = M.getFunction("objc_msgSend_stret"); + Function *send_fpretFn = M.getFunction("objc_msgSend_fpret"); + Function *lookupFn =M.getFunction("objc_msg_lookup_sender"); + // If this module doesn't contain any message sends, then skip it + if ((sendFn == 0) && (send_stretFn == 0) && (send_fpretFn == 0) && + (lookupFn ==0)) { return false; } + GNUstep::IMPCacher cacher = GNUstep::IMPCacher(M.getContext(), this); IntTy = (sizeof(int) == 4 ) ? Type::getInt32Ty(M.getContext()) : Type::getInt64Ty(M.getContext()) ; @@ -43,6 +50,7 @@ namespace if (F->isDeclaration()) { continue; } SmallVector, 16> Lookups; + SmallVector Sends; for (Function::iterator i=F->begin(), end=F->end() ; i != end ; ++i) { @@ -52,12 +60,17 @@ namespace if (call.getInstruction()) { Value *callee = call.getCalledValue()->stripPointerCasts(); if (Function *func = dyn_cast(callee)) { - if (func->getName() == "objc_msg_lookup_sender") { + if ((func == lookupFn) || (func == sendFn) || + (func == send_fpretFn) || (func == send_stretFn)) { MDNode *messageType = call.getInstruction()->getMetadata(MessageSendMDKind); if (0 == messageType) { continue; } if (cast(messageType->getOperand(2))->isOne()) { - Lookups.push_back(std::pair(call, false)); + if (func == lookupFn) { + Lookups.push_back(std::pair(call, false)); + } else { + Sends.push_back(call); + } } } else if (func->getName() == "objc_slot_lookup_super") { Lookups.push_back(std::pair(call, true)); @@ -66,6 +79,10 @@ namespace } } } + for (SmallVectorImpl::iterator i=Sends.begin(), + e=Sends.end() ; e!=i ; i++) { + Lookups.push_back(std::pair(cacher.SplitSend(*i), false)); + } for (SmallVectorImpl >::iterator i=Lookups.begin(), e=Lookups.end() ; e!=i ; i++) { Instruction *call = i->first.getInstruction(); diff --git a/opts/IMPCacher.cpp b/opts/IMPCacher.cpp index c1d22a5..b10998c 100644 --- a/opts/IMPCacher.cpp +++ b/opts/IMPCacher.cpp @@ -1,3 +1,4 @@ +#include "llvm/Analysis/Verifier.h" #include "IMPCacher.h" #include "llvm/Pass.h" #include "llvm/Function.h" @@ -31,12 +32,26 @@ void GNUstep::IMPCacher::CacheLookup(Instruction *lookup, Value *slot, Value if (lookup->getMetadata(IMPCacheFlagKind)) { return; } lookup->setMetadata(IMPCacheFlagKind, AlreadyCachedFlag); + bool isInvoke = false; BasicBlock *beforeLookupBB = lookup->getParent(); BasicBlock *lookupBB = SplitBlock(beforeLookupBB, lookup, Owner); - BasicBlock::iterator iter = lookup; - iter++; - BasicBlock *afterLookupBB = SplitBlock(iter->getParent(), iter, Owner); + BasicBlock *lookupFinishedBB = lookupBB; + BasicBlock *afterLookupBB; + + if (InvokeInst *inv = dyn_cast(lookup)) { + afterLookupBB = inv->getNormalDest(); + lookupFinishedBB = + BasicBlock::Create(Context, "done_lookup", lookupBB->getParent()); + CGBuilder B(lookupFinishedBB); + B.CreateBr(afterLookupBB); + inv->setNormalDest(lookupFinishedBB); + isInvoke = true; + } else { + BasicBlock::iterator iter = lookup; + iter++; + afterLookupBB = SplitBlock(iter->getParent(), iter, Owner); + } removeTerminator(beforeLookupBB); @@ -96,7 +111,7 @@ void GNUstep::IMPCacher::CacheLookup(Instruction *lookup, Value *slot, Value B.CreateCondBr(isSlotValid, afterLookupBB, lookupBB); // Perform the real lookup and cache the result - removeTerminator(lookupBB); + removeTerminator(lookupFinishedBB); // Replace the looked up slot with the loaded one B.SetInsertPoint(afterLookupBB, afterLookupBB->begin()); PHINode *newLookup = IRBuilderCreatePHI(&B, lookup->getType(), 3, "new_lookup"); @@ -104,7 +119,7 @@ void GNUstep::IMPCacher::CacheLookup(Instruction *lookup, Value *slot, Value // magic with this later. lookup->replaceAllUsesWith(newLookup); - B.SetInsertPoint(lookupBB); + B.SetInsertPoint(lookupFinishedBB); Value * newReceiver = receiver; if (!isSuperMessage) { newReceiver = B.CreateLoad(receiverPtr); @@ -129,7 +144,7 @@ void GNUstep::IMPCacher::CacheLookup(Instruction *lookup, Value *slot, Value B.CreateStore(cls, B.CreateStructGEP(lookup, 1)); B.CreateBr(afterLookupBB); - newLookup->addIncoming(lookup, lookupBB); + newLookup->addIncoming(lookup, lookupFinishedBB); newLookup->addIncoming(slotValue, cacheLookupBB); newLookup->addIncoming(lookup, storeCacheBB); } @@ -214,6 +229,56 @@ void GNUstep::IMPCacher::SpeculativelyInline(Instruction *call, Function } } +CallSite GNUstep::IMPCacher::SplitSend(CallSite msgSend) +{ + BasicBlock *lookupBB = msgSend->getParent(); + Module *M = lookupBB->getParent()->getParent(); + Function *send = M->getFunction("objc_msgSend"); + Function *send_stret = M->getFunction("objc_msgSend_stret"); + Function *send_fpret = M->getFunction("objc_msgSend_fpret"); + Value *self; + Value *cmd; + int selfIndex = 0; + if ((msgSend.getCalledFunction() == send) || + (msgSend.getCalledFunction() == send_fpret)) { + self = msgSend.getArgument(0); + cmd = msgSend.getArgument(1); + } else if (msgSend.getCalledFunction() == send_stret) { + selfIndex = 1; + self = msgSend.getArgument(1); + cmd = msgSend.getArgument(2); + } else { + msgSend.getCalledFunction()->dump(); + abort(); + return CallSite(); + } + CGBuilder B(msgSend.getInstruction()); + Value *selfPtr = B.CreateAlloca(self->getType()); + B.CreateStore(self, selfPtr, true); + LLVMType *impTy = msgSend.getCalledValue()->getType(); + LLVMType *slotTy = PointerType::getUnqual(StructType::get(PtrTy, PtrTy, PtrTy, + IntTy, impTy, PtrTy, NULL)); + Value *slot; + Constant *lookupFn = M->getOrInsertFunction("objc_msg_lookup_sender", + slotTy, selfPtr->getType(), cmd->getType(), PtrTy, NULL); + if (msgSend.isCall()) { + slot = B.CreateCall3(lookupFn, selfPtr, cmd, Constant::getNullValue(PtrTy)); + } else { + InvokeInst *inv = cast(msgSend.getInstruction()); + BasicBlock *callBB = SplitBlock(lookupBB, msgSend.getInstruction(), Owner); + removeTerminator(lookupBB); + B.SetInsertPoint(lookupBB); + slot = B.CreateInvoke3(lookupFn, callBB, inv->getUnwindDest(), selfPtr, cmd, + Constant::getNullValue(PtrTy)); + addPredecssor(inv->getUnwindDest(), msgSend->getParent(), lookupBB); + B.SetInsertPoint(msgSend.getInstruction()); + } + Value *imp = B.CreateLoad(B.CreateStructGEP(slot, 4)); + msgSend.setArgument(selfIndex, B.CreateLoad(selfPtr, true)); + msgSend.setCalledFunction(imp); + return CallSite(slot); +} + // Cleanly removes a terminator instruction. void GNUstep::removeTerminator(BasicBlock *BB) { TerminatorInst *BBTerm = BB->getTerminator(); @@ -227,3 +292,11 @@ void GNUstep::removeTerminator(BasicBlock *BB) { // Remove the terminator instruction itself. BBTerm->eraseFromParent(); } +void GNUstep::addPredecssor(BasicBlock *block, BasicBlock *oldPredecessor, + BasicBlock *newPredecessor) { + for (BasicBlock::iterator i=block->begin() ; PHINode *phi=dyn_cast(i) + ; ++i) { + Value *v = phi->getIncomingValueForBlock(oldPredecessor); + phi->addIncoming(v, newPredecessor); + } +} diff --git a/opts/LoopIMPCachePass.cpp b/opts/LoopIMPCachePass.cpp index 21cfb45..6581a68 100644 --- a/opts/LoopIMPCachePass.cpp +++ b/opts/LoopIMPCachePass.cpp @@ -23,6 +23,11 @@ namespace GNUstep::IMPCacher *cacher; LLVMIntegerType *IntTy; Module *M; + bool skip; + Function *sendFn; + Function *lookupFn; + Function *send_stretFn; + Function *send_fpretFn; public: static char ID; @@ -34,6 +39,16 @@ namespace IntTy = (sizeof(int) == 4 ) ? Type::getInt32Ty(Mod.getContext()) : Type::getInt64Ty(Mod.getContext()) ; M = &Mod; + skip = false; + sendFn = M->getFunction("objc_msgSend"); + send_stretFn = M->getFunction("objc_msgSend_stret"); + send_fpretFn = M->getFunction("objc_msgSend_fpret"); + lookupFn =M->getFunction("objc_msg_lookup_sender"); + // If this module doesn't contain any message sends, then skip it + if ((sendFn == 0) && (send_stretFn == 0) && (send_fpretFn == 0) && + (lookupFn ==0)) { + skip = true; + } return false; } @@ -43,9 +58,11 @@ namespace virtual bool runOnFunction(Function &F) { + if (skip) { return false; } LoopInfo &LI = getAnalysis(); bool modified = false; - SmallVector Lookups; + SmallVector Lookups; + SmallVector Sends; BasicBlock *entry = &F.getEntryBlock(); for (Function::iterator i=F.begin(), end=F.end() ; @@ -54,19 +71,30 @@ namespace if (LI.getLoopDepth(i) == 0) { continue; } 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") { + CallSite call = CallSite(b); + if (CallSite() != call) { + Value *callee = call.getCalledValue()->stripPointerCasts(); + Function *func = dyn_cast(callee); + if (func) { + if (func == lookupFn) { + func->dump(); modified = true; Lookups.push_back(call); + } else if ((func == sendFn) || (func == send_fpretFn) || + (func == send_stretFn)) { + modified = true; + Sends.push_back(call); } } } } } + for (SmallVectorImpl::iterator i=Sends.begin(), + e=Sends.end() ; e!=i ; i++) { + Lookups.push_back(cacher->SplitSend(*i)); + } IRBuilder<> B = IRBuilder<>(entry); - for (SmallVectorImpl::iterator i=Lookups.begin(), + for (SmallVectorImpl::iterator i=Lookups.begin(), e=Lookups.end() ; e!=i ; i++) { LLVMType *SlotPtrTy = (*i)->getType(); B.SetInsertPoint(entry, entry->begin()); @@ -75,11 +103,13 @@ namespace B.CreateStore(Constant::getNullValue(SlotPtrTy), slot); B.CreateStore(Constant::getNullValue(IntTy), version); - cacher->CacheLookup(*i, slot, version); + cacher->CacheLookup(i->getInstruction(), slot, version); } +#ifdef DEBUG if (modified){ verifyFunction(F); } +#endif return modified; } };