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