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
main
theraven 14 years ago
parent aece370989
commit 286892936d

@ -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<std::pair<CallSite, bool>, 16> Lookups;
SmallVector<CallSite, 16> 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<Function>(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<ConstantInt>(messageType->getOperand(2))->isOne()) {
if (func == lookupFn) {
Lookups.push_back(std::pair<CallSite, bool>(call, false));
} else {
Sends.push_back(call);
}
}
} else if (func->getName() == "objc_slot_lookup_super") {
Lookups.push_back(std::pair<CallSite, bool>(call, true));
@ -66,6 +79,10 @@ namespace
}
}
}
for (SmallVectorImpl<CallSite>::iterator i=Sends.begin(),
e=Sends.end() ; e!=i ; i++) {
Lookups.push_back(std::pair<CallSite, bool>(cacher.SplitSend(*i), false));
}
for (SmallVectorImpl<std::pair<CallSite, bool> >::iterator
i=Lookups.begin(), e=Lookups.end() ; e!=i ; i++) {
Instruction *call = i->first.getInstruction();

@ -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 *lookupFinishedBB = lookupBB;
BasicBlock *afterLookupBB;
if (InvokeInst *inv = dyn_cast<InvokeInst>(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++;
BasicBlock *afterLookupBB = SplitBlock(iter->getParent(), iter, Owner);
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<InvokeInst>(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<PHINode>(i)
; ++i) {
Value *v = phi->getIncomingValueForBlock(oldPredecessor);
phi->addIncoming(v, newPredecessor);
}
}

@ -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<LoopInfo>();
bool modified = false;
SmallVector<CallInst*, 16> Lookups;
SmallVector<CallSite, 16> Lookups;
SmallVector<CallSite, 16> 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<CallInst>(b)) {
Value *callee = call->getCalledValue()->stripPointerCasts();
if (Function *func = dyn_cast<Function>(callee)) {
if (func->getName() == "objc_msg_lookup_sender") {
CallSite call = CallSite(b);
if (CallSite() != call) {
Value *callee = call.getCalledValue()->stripPointerCasts();
Function *func = dyn_cast<Function>(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<CallSite>::iterator i=Sends.begin(),
e=Sends.end() ; e!=i ; i++) {
Lookups.push_back(cacher->SplitSend(*i));
}
IRBuilder<> B = IRBuilder<>(entry);
for (SmallVectorImpl<CallInst*>::iterator i=Lookups.begin(),
for (SmallVectorImpl<CallSite>::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;
}
};

Loading…
Cancel
Save