diff --git a/CMakeLists.txt b/CMakeLists.txt index eb29b99..9041e03 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -126,29 +126,6 @@ else () add_definitions(-DNO_LEGACY) endif () -#find_package(LLVM QUIET) -set(DEFAULT_ENABLE_LLVM ${LLVM_FOUND}) -if (DEFAULT_ENABLE_LLVM) - exec_program(llvm-config - ARGS --version - OUTPUT_VARIABLE LLVM_VER) - if (LLVM_VER MATCHES ".*svnn") - set(DEFAULT_ENABLE_LLVM FALSE) - message(STATUS "svn version of LLVM found.") - message(STATUS "Disabling LLVM options unless explicitly enabled.") - elseif (LLVM_VER VERSION_GREATER 3.3) - set(DEFAULT_ENABLE_LLVM FALSE) - message(STATUS "Untested version of LLVM (${LLVM_VER}) found.") - message(STATUS "Disabling LLVM options unless explicitly enabled.") - endif() -endif() -set(LLVM_OPTS ${DEFAULT_ENABLE_LLVM} CACHE BOOL - "Build LLVM Objective-C optimisations") -if (LLVM_OPTS) - add_subdirectory(opts) - message(STATUS "Found LLVM, enabling LLVM optimisations") -endif () - set(LIBOBJC_NAME "objc" CACHE STRING "Name of the Objective-C runtime library (e.g. objc2 for libobjc2)") diff --git a/opts/CMakeLists.txt b/opts/CMakeLists.txt deleted file mode 100644 index 5140443..0000000 --- a/opts/CMakeLists.txt +++ /dev/null @@ -1,47 +0,0 @@ -cmake_minimum_required(VERSION 2.8) - -find_package(LLVM) -include(AddLLVM OPTIONAL RESULT_VARIABLE INCLUDED_LLVM) - -if (${INCLUDED_LLVM} STREQUAL "NOTFOUND") - message(WARNING "Failed to include AddLLVM CMake module") -else() -message("Included: '${INCLUDED_LLVM}'") - -add_definitions(${LLVM_DEFINITIONS}) -include_directories(${LLVM_INCLUDE_DIRS}) -link_directories(${LLVM_LIBRARY_DIRS}) - - -add_llvm_loadable_module( libGNUObjCRuntime - ClassIMPCache.cpp - ClassMethodInliner.cpp - IvarPass.cpp - ObjectiveCOpts.cpp - TypeFeedbackDrivenInliner.cpp - ClassLookupCache.cpp - IMPCacher.cpp - LoopIMPCachePass.cpp - TypeFeedback.cpp -) - -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-variadic-macros") - -set(CMAKE_CXX "clang++") - -EXEC_PROGRAM(llvm-config - ARGS --src-root - OUTPUT_VARIABLE LLVM_SRC) -EXEC_PROGRAM(llvm-config - ARGS --obj-root - OUTPUT_VARIABLE LLVM_OBJ) -EXEC_PROGRAM(llvm-config - ARGS --version - OUTPUT_VARIABLE LLVM_VER) - -string(REGEX REPLACE "([0-9]*).([0-9]*).*" "-DLLVM_MAJOR=\\1 -DLLVM_MINOR=\\2" LLVM_VERSION "${LLVM_VER}") - -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LLVM_VERSION} -fno-rtti") -include_directories( ${LLVM_INCLUDE_DIRS} "${LLVM_SRC}/include/" "${LLVM_OBJ}/include/") - -endif() # AddLLVM include failed diff --git a/opts/COPYING b/opts/COPYING deleted file mode 100644 index 8647a56..0000000 --- a/opts/COPYING +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2009 David Chisnall - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - diff --git a/opts/ClassIMPCache.cpp b/opts/ClassIMPCache.cpp deleted file mode 100644 index 65968a2..0000000 --- a/opts/ClassIMPCache.cpp +++ /dev/null @@ -1,104 +0,0 @@ -#include "llvm/Pass.h" -#include "llvm/Support/CallSite.h" -#include "llvm/Analysis/LoopInfo.h" -#include "ObjectiveCOpts.h" -#include "IMPCacher.h" -#include -#include "LLVMCompat.h" - -using namespace GNUstep; -using namespace llvm; -using std::string; - -namespace -{ - class ClassIMPCachePass : public ModulePass - { - LLVMIntegerTy *IntTy; - - public: - static char ID; - ClassIMPCachePass() : ModulePass(ID) {} - - virtual bool runOnModule(Module &M) { - 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()) ; - 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, 16> Lookups; - SmallVector Sends; - - for (Function::iterator i=F->begin(), end=F->end() ; - i != end ; ++i) { - for (BasicBlock::iterator b=i->begin(), last=i->end() ; - b != last ; ++b) { - CallSite call(b); - if (call.getInstruction()) { - Value *callee = call.getCalledValue()->stripPointerCasts(); - if (Function *func = dyn_cast(callee)) { - 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()) { - 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)); - } - } - } - } - } - 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(); - LLVMType *SlotPtrTy = call->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(call, slot, version, i->second); - } - } - return modified; - } - }; - - char ClassIMPCachePass::ID = 0; - RegisterPass X("gnu-class-imp-cache", - "Cache IMPs for class messages"); -} - -ModulePass *createClassIMPCachePass(void) -{ - return new ClassIMPCachePass(); -} diff --git a/opts/ClassLookupCache.cpp b/opts/ClassLookupCache.cpp deleted file mode 100644 index e41aabe..0000000 --- a/opts/ClassLookupCache.cpp +++ /dev/null @@ -1,152 +0,0 @@ -#include "llvm/ADT/StringMap.h" -#include "llvm/Analysis/LoopInfo.h" -#include "llvm/Transforms/Utils/BasicBlockUtils.h" -#include "ObjectiveCOpts.h" -#include - -#include "IMPCacher.h" -#include "LLVMCompat.h" - -using namespace llvm; -using namespace GNUstep; -using std::string; -using std::pair; - -namespace -{ - class ClassLookupCachePass : public ModulePass { - /// Module that we're currently optimising - Module *M; - /// Static cache. If we're not using the non-fragile ABI, then we cache - /// all class lookups in static variables to avoid the overhead of the - /// lookup. With the non-fragile ABI, we don't need to do this. - llvm::StringMap statics; - - typedef std::pair ClassLookup; - - public: - static char ID; - ClassLookupCachePass() : ModulePass(ID) {} - - virtual bool doInitialization(Module &Mod) { - M = &Mod; - return false; - } - - bool runOnFunction(Function &F) { - bool modified = false; - 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) { - if (CallInst *call = dyn_cast(b)) { - if (Function *func = dyn_cast(call->getCalledValue()->stripPointerCasts())) { - if (func->getName() == "objc_lookup_class") { - ClassLookup lookup; - GlobalVariable *classNameVar = dyn_cast( - call->getOperand(0)->stripPointerCasts()); - if (0 == classNameVar) { continue; } -#if (LLVM_MAJOR > 3) || ((LLVM_MAJOR == 3) && (LLVM_MINOR > 0)) - ConstantDataArray *init = dyn_cast( - classNameVar->getInitializer()); -#else - ConstantArray *init = dyn_cast( - classNameVar->getInitializer()); -#endif - if (0 == init || !init->isCString()) { continue; } - lookup.first = call; - lookup.second = init->getAsString(); - modified = true; - Lookups.push_back(lookup); - } - } - } - } - } - for (SmallVectorImpl::iterator i=Lookups.begin(), - e=Lookups.end() ; e!=i ; i++) { - llvm::Instruction *lookup = i->first; - std::string &cls = i->second; - LLVMType *clsTy = lookup->getType(); - Value *global = M->getGlobalVariable(("_OBJC_CLASS_" + i->second).c_str(), true); - // If we can see the class reference for this, then reference it - // directly. If not, then do the lookup and cache it. - if (global) { - // Insert a bitcast of the class to the required type where the - // lookup is and then replace all references to the lookup with it. - Value *cls = new BitCastInst(global, clsTy, "class", lookup); - lookup->replaceAllUsesWith(cls); - lookup->removeFromParent(); - delete lookup; - } else { - GlobalVariable *cache = statics[cls]; - if (!cache) { - cache = new GlobalVariable(*M, clsTy, false, - GlobalVariable::PrivateLinkage, Constant::getNullValue(clsTy), - ".class_cache"); - statics[cls] = cache; - } - BasicBlock *beforeLookupBB = lookup->getParent(); - BasicBlock *lookupBB = SplitBlock(beforeLookupBB, lookup, this); - BasicBlock::iterator iter = lookup; - iter++; - BasicBlock *afterLookupBB = SplitBlock(iter->getParent(), iter, this); - // SplitBlock() adds an unconditional branch, which we don't want. - // Remove it. - removeTerminator(beforeLookupBB); - removeTerminator(lookupBB); - - PHINode *phi = CreatePHI(clsTy, 2, cls, afterLookupBB->begin()); - // We replace all of the existing uses with the PHI node now, because - // we're going to add some more uses later that we don't want - // replaced. - lookup->replaceAllUsesWith(phi); - - // In the original basic block, we test whether the cache is NULL, - // and skip the lookup if it isn't. - IRBuilder<> B(beforeLookupBB); - llvm::Value *cachedClass = - B.CreateBitCast(B.CreateLoad(cache), clsTy); - llvm::Value *needsLookup = B.CreateIsNull(cachedClass); - B.CreateCondBr(needsLookup, lookupBB, afterLookupBB); - // In the lookup basic block, we just do the lookup, store it in the - // cache, and then jump to the continue block - B.SetInsertPoint(lookupBB); - B.CreateStore(lookup, cache); - B.CreateBr(afterLookupBB); - // Now we just need to set the PHI node to use the cache or the - // lookup result - phi->addIncoming(cachedClass, beforeLookupBB); - phi->addIncoming(lookup, lookupBB); - } - } - return modified; - } - virtual bool runOnModule(Module &Mod) { - statics.empty(); - M = &Mod; - bool modified = false; - - for (Module::iterator F=Mod.begin(), fend=Mod.end() ; - F != fend ; ++F) { - - if (F->isDeclaration()) { continue; } - - modified |= runOnFunction(*F); - } - - return modified; - }; - }; - - char ClassLookupCachePass::ID = 0; - RegisterPass X("gnu-class-lookup-cache", - "Cache class lookups"); -} - -ModulePass *createClassLookupCachePass(void) -{ - return new ClassLookupCachePass(); -} diff --git a/opts/ClassMethodInliner.cpp b/opts/ClassMethodInliner.cpp deleted file mode 100644 index 7d061f3..0000000 --- a/opts/ClassMethodInliner.cpp +++ /dev/null @@ -1,105 +0,0 @@ -#include "llvm/Support/CallSite.h" -#include "llvm/Analysis/LoopInfo.h" -#include "llvm/Analysis/InlineCost.h" -#include "ObjectiveCOpts.h" -#include "IMPCacher.h" -#include - -using namespace llvm; -using namespace GNUstep; -using std::string; - -// Mangle a method name -// -// From clang: -static std::string SymbolNameForMethod(const std::string &ClassName, const - std::string &CategoryName, const std::string &MethodName, bool isClassMethod) -{ - std::string MethodNameColonStripped = MethodName; - std::replace(MethodNameColonStripped.begin(), MethodNameColonStripped.end(), - ':', '_'); - return std::string(isClassMethod ? "_c_" : "_i_") + ClassName + "_" + - CategoryName + "_" + MethodNameColonStripped; -} - -namespace -{ - class ClassMethodInliner : public ModulePass - { - const IntegerType *IntTy; - - public: - static char ID; - ClassMethodInliner() : ModulePass(ID) {} - - virtual bool runOnModule(Module &M) { - unsigned MessageSendMDKind = M.getContext().getMDKindID("GNUObjCMessageSend"); - InlineCostAnalyzer CA; - SmallPtrSet NeverInline; - - GNUstep::IMPCacher cacher = GNUstep::IMPCacher(M.getContext(), this); - IntTy = (sizeof(int) == 4 ) ? Type::getInt32Ty(M.getContext()) : - Type::getInt64Ty(M.getContext()) ; - bool modified = false; - - for (Module::iterator F=M.begin(), fend=M.end() ; - F != fend ; ++F) { - - SmallVector messages; - - if (F->isDeclaration()) { continue; } - - for (Function::iterator i=F->begin(), end=F->end() ; - i != end ; ++i) { - for (BasicBlock::iterator b=i->begin(), last=i->end() ; - b != last ; ++b) { - CallSite call(b); - if (call.getInstruction() && !call.getCalledFunction()) { - MDNode *messageType = call->getMetadata(MessageSendMDKind); - if (0 == messageType) { continue; } - messages.push_back(call); - } - } - } - for (SmallVectorImpl::iterator i=messages.begin(), - e=messages.end() ; e!=i ; i++) { - - 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(); - std::string functionName = SymbolNameForMethod(cls, "", sel, isClassMethod); - Function *method = M.getFunction(functionName); - - if (0 == method || method->isDeclaration()) { continue; } - -#if (LLVM_MAJOR > 3) || ((LLVM_MAJOR == 3) && (LLVM_MINOR > 0)) - InlineCost IC = CA.getInlineCost((*i), method, 200); -#else - InlineCost IC = CA.getInlineCost((*i), method, NeverInline); -#define getCost getValue -#endif - // FIXME: 200 is a random number. Pick a better one! - if (IC.isAlways() || (IC.isVariable() && IC.getCost() < 200)) { - cacher.SpeculativelyInline((*i).getInstruction(), method); - i->getInstruction()->setMetadata(MessageSendMDKind, 0); - modified = true; - } - } - } - return modified; - } - }; - - char ClassMethodInliner::ID = 0; - RegisterPass X("gnu-class-method-inline", - "Inline class methods and message sends to super"); -} - -ModulePass *createClassMethodInliner(void) -{ - return new ClassMethodInliner(); -} diff --git a/opts/IMPCacher.cpp b/opts/IMPCacher.cpp deleted file mode 100644 index 5b354c1..0000000 --- a/opts/IMPCacher.cpp +++ /dev/null @@ -1,295 +0,0 @@ -#include "llvm/Analysis/Verifier.h" -#include "IMPCacher.h" -#include "llvm/Support/CallSite.h" -#include "llvm/Transforms/Utils/BasicBlockUtils.h" -#include "llvm/Transforms/Utils/Cloning.h" - -#include "LLVMCompat.h" - -GNUstep::IMPCacher::IMPCacher(LLVMContext &C, Pass *owner) : Context(C), - Owner(owner) { - - PtrTy = Type::getInt8PtrTy(Context); - IntTy = (sizeof(int) == 4 ) ? Type::getInt32Ty(C) : Type::getInt64Ty(C); - IdTy = PointerType::getUnqual(PtrTy); - Value *AlreadyCachedFlagValue = MDString::get(C, "IMPCached"); - AlreadyCachedFlag = CreateMDNode(C, &AlreadyCachedFlagValue); - IMPCacheFlagKind = Context.getMDKindID("IMPCache"); -} - -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; } - - 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(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); - - CGBuilder B = CGBuilder(beforeLookupBB); - // Load the slot and check that neither it nor the version is 0. - Value *versionValue = B.CreateLoad(version); - Value *receiverPtr = lookup->getOperand(0); - Value *receiver = receiverPtr; - if (!isSuperMessage) { - receiver = B.CreateLoad(receiverPtr); - } - // For small objects, we skip the cache entirely. - // FIXME: Class messages are never to small objects... - bool is64Bit = llvm::Module::Pointer64 == - B.GetInsertBlock()->getParent()->getParent()->getPointerSize(); - LLVMType *intPtrTy = is64Bit ? Type::getInt64Ty(Context) : - Type::getInt32Ty(Context); - - // Receiver as an integer - Value *receiverSmallObject = B.CreatePtrToInt(receiver, intPtrTy); - // Receiver is a small object... - receiverSmallObject = - B.CreateAnd(receiverSmallObject, is64Bit ? 7 : 1); - // Receiver is not a small object. - receiverSmallObject = - B.CreateICmpNE(receiverSmallObject, Constant::getNullValue(intPtrTy)); - // Ideally, we'd call objc_msgSend() here, but for now just skip the cache - // lookup - - Value *isCacheEmpty = - B.CreateICmpEQ(versionValue, Constant::getNullValue(IntTy)); - Value *receiverNil = - B.CreateICmpEQ(receiver, Constant::getNullValue(receiver->getType())); - - isCacheEmpty = B.CreateOr(isCacheEmpty, receiverNil); - isCacheEmpty = B.CreateOr(isCacheEmpty, receiverSmallObject); - - BasicBlock *cacheLookupBB = BasicBlock::Create(Context, "cache_check", - lookupBB->getParent()); - - B.CreateCondBr(isCacheEmpty, lookupBB, cacheLookupBB); - - // Check the cache node is current - B.SetInsertPoint(cacheLookupBB); - Value *slotValue = B.CreateLoad(slot, "slot_value"); - Value *slotVersion = B.CreateStructGEP(slotValue, 3); - // Note: Volatile load because the slot version might have changed in - // another thread. - slotVersion = B.CreateLoad(slotVersion, true, "slot_version"); - Value *slotCachedFor = B.CreateStructGEP(slotValue, 1); - slotCachedFor = B.CreateLoad(slotCachedFor, true, "slot_owner"); - Value *cls = B.CreateLoad(B.CreateBitCast(receiver, IdTy)); - Value *isVersionCorrect = B.CreateICmpEQ(slotVersion, versionValue); - Value *isOwnerCorrect = B.CreateICmpEQ(slotCachedFor, cls); - Value *isSlotValid = B.CreateAnd(isVersionCorrect, isOwnerCorrect); - // If this slot is still valid, skip the lookup. - B.CreateCondBr(isSlotValid, afterLookupBB, lookupBB); - - // Perform the real lookup and cache the result - 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"); - // Not volatile, so a redundant load elimination pass can do some phi - // magic with this later. - lookup->replaceAllUsesWith(newLookup); - - B.SetInsertPoint(lookupFinishedBB); - Value * newReceiver = receiver; - if (!isSuperMessage) { - newReceiver = B.CreateLoad(receiverPtr); - } - BasicBlock *storeCacheBB = BasicBlock::Create(Context, "cache_store", - lookupBB->getParent()); - - // Don't store the cached lookup if we are doing forwarding tricks. - // Also skip caching small object messages for now - Value *skipCacheWrite = - B.CreateOr(B.CreateICmpNE(receiver, newReceiver), receiverSmallObject); - skipCacheWrite = B.CreateOr(skipCacheWrite, receiverNil); - B.CreateCondBr(skipCacheWrite, afterLookupBB, storeCacheBB); - B.SetInsertPoint(storeCacheBB); - - // Store it even if the version is 0, because we always check that the - // version is not 0 at the start and an occasional redundant store is - // probably better than a branch every time. - B.CreateStore(lookup, slot); - B.CreateStore(B.CreateLoad(B.CreateStructGEP(lookup, 3)), version); - cls = B.CreateLoad(B.CreateBitCast(receiver, IdTy)); - B.CreateStore(cls, B.CreateStructGEP(lookup, 1)); - B.CreateBr(afterLookupBB); - - newLookup->addIncoming(lookup, lookupFinishedBB); - newLookup->addIncoming(slotValue, cacheLookupBB); - newLookup->addIncoming(lookup, storeCacheBB); -} - - -void GNUstep::IMPCacher::SpeculativelyInline(Instruction *call, Function - *function) { - BasicBlock *beforeCallBB = call->getParent(); - BasicBlock *callBB = SplitBlock(beforeCallBB, call, Owner); - BasicBlock *inlineBB = BasicBlock::Create(Context, "inline", - callBB->getParent()); - - - BasicBlock::iterator iter = call; - iter++; - - BasicBlock *afterCallBB = SplitBlock(iter->getParent(), iter, Owner); - - removeTerminator(beforeCallBB); - - // Put a branch before the call, testing whether the callee really is the - // function - IRBuilder<> B = IRBuilder<>(beforeCallBB); - Value *callee = isa(call) ? cast(call)->getCalledValue() - : cast(call)->getCalledValue(); - - 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); - - B.SetInsertPoint(inlineBB); - - if (calleeTy != FTy) { - for (unsigned i=0 ; igetNumParams() ; i++) { - LLVMType *callType = calleeTy->getParamType(i); - LLVMType *argType = FTy->getParamType(i); - if (callType != argType) { - inlineCall->setOperand(i, new - BitCastInst(inlineCall->getOperand(i), argType, "", inlineCall)); - } - } - if (FTy->getReturnType() != calleeTy->getReturnType()) { - if (FTy->getReturnType() == Type::getVoidTy(Context)) { - inlineResult = Constant::getNullValue(calleeTy->getReturnType()); - } else { - inlineResult = - new BitCastInst(inlineCall, calleeTy->getReturnType(), "", inlineBB); - } - } - } - - B.CreateBr(afterCallBB); - - // Unify the return values - if (call->getType() != Type::getVoidTy(Context)) { - PHINode *phi = CreatePHI(call->getType(), 2, "", afterCallBB->begin()); - call->replaceAllUsesWith(phi); - phi->addIncoming(call, callBB); - phi->addIncoming(inlineResult, inlineBB); - } - - // Really do the real inlining - InlineFunctionInfo IFI(0, 0); - if (CallInst *c = dyn_cast(inlineCall)) { - c->setCalledFunction(function); - InlineFunction(c, IFI); - } else if (InvokeInst *c = dyn_cast(inlineCall)) { - c->setCalledFunction(function); - InlineFunction(c, IFI); - } -} - -CallSite GNUstep::IMPCacher::SplitSend(CallSite msgSend) -{ - BasicBlock *lookupBB = msgSend->getParent(); - Function *F = lookupBB->getParent(); - Module *M = F->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 { - abort(); - return CallSite(); - } - CGBuilder B(&F->getEntryBlock(), F->getEntryBlock().begin()); - Value *selfPtr = B.CreateAlloca(self->getType()); - B.SetInsertPoint(msgSend.getInstruction()); - 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(); - - // Remove the BB as a predecessor from all of successors - for (unsigned i = 0, e = BBTerm->getNumSuccessors(); i != e; ++i) { - BBTerm->getSuccessor(i)->removePredecessor(BB); - } - - BBTerm->replaceAllUsesWith(UndefValue::get(BBTerm->getType())); - // 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/IMPCacher.h b/opts/IMPCacher.h deleted file mode 100644 index 4991976..0000000 --- a/opts/IMPCacher.h +++ /dev/null @@ -1,49 +0,0 @@ -#include "LLVMCompat.h" -#include "llvm/Support/CallSite.h" -namespace llvm -{ - class BasicBlock; - class CallInst; - class Function; - class Instruction; - class IntegerType; - class LLVMContext; - class MDNode; - class Pass; - class PointerType; - class Value; -} - -using namespace llvm; - -namespace GNUstep -{ - class IMPCacher - { - private: - LLVMContext &Context; - MDNode *AlreadyCachedFlag; - unsigned IMPCacheFlagKind; - Pass *Owner; - LLVMPointerTy *PtrTy; - LLVMPointerTy *IdTy; - LLVMIntegerTy *IntTy; - public: - IMPCacher(LLVMContext &C, Pass *owner); - void CacheLookup(Instruction *lookup, Value *slot, Value *version, bool - isSuperMessage=false); - void SpeculativelyInline(Instruction *call, Function *function); - /** - * Turns a call to objc_msgSend*() into a call to - * objc_msg_lookup_sender() and a call to the resulting IMP. The call to - * the IMP is returned. The single call is faster, but prevents caching. - * The split call allows caching, which is faster in the best case and - * slower in the worst... - */ - CallSite SplitSend(CallSite msgSend); - }; - - void removeTerminator(BasicBlock *BB); - void addPredecssor(BasicBlock *block, BasicBlock *oldPredecessor, BasicBlock - *newPredecessor); -} diff --git a/opts/IvarPass.cpp b/opts/IvarPass.cpp deleted file mode 100644 index 5760963..0000000 --- a/opts/IvarPass.cpp +++ /dev/null @@ -1,165 +0,0 @@ -#include "LLVMCompat.h" -#include "llvm/Analysis/Verifier.h" -#include "llvm/ADT/DenseSet.h" -#include "ObjectiveCOpts.h" -#include - -using namespace llvm; -using std::string; - -typedef std::pair Replacement; - -namespace llvm { -template<> struct DenseMapInfo { - static inline Replacement getEmptyKey() { return Replacement(0,0); } - static inline Replacement getTombstoneKey() { return Replacement(0, (Value*)-1); } - static unsigned getHashValue(const Replacement& Val) { return ((uintptr_t)Val.first) * 37U; } - static bool isEqual(const Replacement& LHS, const Replacement& RHS) { - return LHS.first == RHS.first; - } -}; -} -namespace { - class GNUNonfragileIvarPass : public FunctionPass { - - public: - static char ID; - GNUNonfragileIvarPass() : FunctionPass(ID) {} - - Module *M; - size_t PointerSize; - virtual bool doInitialization(Module &Mod) { - M = &Mod; - PointerSize = 8; - if (M->getPointerSize() == Module::Pointer32) - PointerSize = 4; - return false; - } - - std::string getSuperName(Constant *ClsStruct) { - User *super = cast(ClsStruct->getOperand(1)); - if (isa(super)) return ""; - GlobalVariable *name = cast(super->getOperand(0)); -#if (LLVM_MAJOR > 3) || ((LLVM_MAJOR == 3) && (LLVM_MINOR > 0)) - return cast(name->getInitializer())->getAsString(); -#else - return cast(name->getInitializer())->getAsString(); -#endif - } - - size_t sizeOfClass(const std::string &className) { - // This is a root class - if ("" == className) { return 0; } - // These root classes are assumed to only have one ivar: isa - if (className.compare(0, 8, "NSObject") == 0 || - className.compare(0, 6, "Object") == 0) { - return PointerSize; - } - GlobalVariable *Cls = M->getGlobalVariable("_OBJC_CLASS_" + className); - if (!Cls) return 0; - Constant *ClsStruct = Cls->getInitializer(); - // Size is initialized to be negative for the non-fragile ABI. - ConstantInt *Size = cast(ClsStruct->getOperand(5)); - int s = Size->getSExtValue(); - // If we find a fragile class in the hierarchy, don't perform the - // simplification. This means that we're the mixed ABI, so we need the - // extra indirection. - if (s > 0) return 0; - return sizeOfClass(getSuperName(ClsStruct)) - Size->getSExtValue(); - } - - size_t hardCodedOffset(const StringRef &className, - const StringRef &ivarName) { - GlobalVariable *Cls = M->getGlobalVariable(("_OBJC_CLASS_" + className).str(), true); - if (!Cls) return 0; - Constant *ClsStruct = Cls->getInitializer(); - size_t superSize = sizeOfClass(getSuperName(ClsStruct)); - if (!superSize) return 0; - ConstantStruct *IvarStruct = cast( - cast(ClsStruct->getOperand(6))->getInitializer()); - int ivarCount = cast(IvarStruct->getOperand(0))->getSExtValue(); - Constant *ivars = IvarStruct->getOperand(1); - for (int i=0 ; i(ivars->getOperand(i)); - GlobalVariable *name = - cast( - cast(ivar->getOperand(0))->getOperand(0)); - std::string ivarNameStr = -#if (LLVM_MAJOR > 3) || ((LLVM_MAJOR == 3) && (LLVM_MINOR > 0)) - cast(name->getInitializer())->getAsString(); -#else - cast(name->getInitializer())->getAsString(); -#endif - // Remove the NULL terminator from the metadata string - ivarNameStr.resize(ivarNameStr.size() - 1); - if (ivarNameStr == ivarName.str()) - return superSize + - cast(ivar->getOperand(2))->getSExtValue(); - } - return 0; - } - - virtual bool runOnFunction(Function &F) { - bool modified = false; - llvm::DenseSet replacements; - //llvm::cerr << "IvarPass: " << F.getName() << "\n"; - 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 (LoadInst *indirectload = dyn_cast(b)) { - if (LoadInst *load = dyn_cast(indirectload->getOperand(0))) { - if (GlobalVariable *ivar = - dyn_cast(load->getOperand(0))) { - StringRef variableName = ivar->getName(); - - if (!variableName.startswith("__objc_ivar_offset_")) break; - - static size_t prefixLength = strlen("__objc_ivar_offset_"); - - StringRef suffix = variableName.substr(prefixLength, - variableName.size()-prefixLength); - - std::pair parts = suffix.split('.'); - StringRef className = parts.first; - StringRef ivarName = parts.second; - - // If the class, and all superclasses, are visible in this module - // then we can hard-code the ivar offset - if (size_t offset = hardCodedOffset(className, ivarName)) { - replacements.insert(Replacement(indirectload, - ConstantInt::get(indirectload->getType(), offset))); - replacements.insert(Replacement(load, 0)); - modified = true; - } else { - // If the class was compiled with the new ABI, then we have a - // direct offset variable that we can use - if (Value *offset = M->getGlobalVariable( - ("__objc_ivar_offset_value_" + suffix).str())) { - replacements.insert(Replacement(load, offset)); - modified = true; - } - } - } - } - } - } - } - for (DenseSet::iterator i=replacements.begin(), - end=replacements.end() ; i != end ; ++i) { - if (i->second) - i->first->replaceAllUsesWith(i->second); - } - verifyFunction(F); - return modified; - } - }; - - char GNUNonfragileIvarPass::ID = 0; - RegisterPass X("gnu-nonfragile-ivar", "Ivar fragility pass"); -} - -FunctionPass *createGNUNonfragileIvarPass(void) -{ - return new GNUNonfragileIvarPass(); -} diff --git a/opts/LLVMCompat.h b/opts/LLVMCompat.h deleted file mode 100644 index d59373e..0000000 --- a/opts/LLVMCompat.h +++ /dev/null @@ -1,172 +0,0 @@ -/** - * Compatibility header that wraps LLVM API breakage and lets us compile with - * old and new versions of LLVM. - * - * First LLVM version supported is 2.9. - */ - -#ifndef __LANGUAGEKIT_LLVM_HACKS__ -#define __LANGUAGEKIT_LLVM_HACKS__ -#if LLVM_MAJOR < 3 || (LLVM_MAJOR >=3 && LLVM_MINOR <= 2) -#if LLVM_MAJOR < 3 || (LLVM_MAJOR >=3 && LLVM_MINOR <= 1) -#include -#else -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#else -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#endif - -#if (LLVM_MAJOR > 3) || ((LLVM_MAJOR == 3) && (LLVM_MINOR >= 3)) -# define InlineCostAnalyzer InlineCostAnalysis -#endif - -// Only preserve names in a debug build. This simplifies the -// IR in a release build, but makes it much harder to debug. -#ifndef DEBUG - typedef llvm::IRBuilder CGBuilder; -#else - typedef llvm::IRBuilder<> CGBuilder; -#endif - -__attribute((unused)) static inline -llvm::PHINode* CreatePHI(llvm::Type *Ty, - unsigned NumReservedValues, - const llvm::Twine &NameStr="", - llvm::Instruction *InsertBefore=0) { -#if LLVM_MAJOR < 3 - llvm::PHINode *phi = llvm::PHINode::Create(Ty, NameStr, InsertBefore); - phi->reserveOperandSpace(NumReservedValues); - return phi; -#else - return llvm::PHINode::Create(Ty, NumReservedValues, NameStr, InsertBefore); -#endif -} - -__attribute((unused)) static inline -llvm::PHINode* IRBuilderCreatePHI(CGBuilder *Builder, - llvm::Type *Ty, - unsigned NumReservedValues, - const llvm::Twine &NameStr="") -{ -#if LLVM_MAJOR < 3 - llvm::PHINode *phi = Builder->CreatePHI(Ty, NameStr); - phi->reserveOperandSpace(NumReservedValues); - return phi; -#else - return Builder->CreatePHI(Ty, NumReservedValues, NameStr); -#endif -} - - - -__attribute((unused)) static inline -llvm::MDNode* CreateMDNode(llvm::LLVMContext &C, - llvm::Value **V, - unsigned length=1) { -#if LLVM_MAJOR < 3 - return llvm::MDNode::get(C, V, length); -#else - llvm::ArrayRef val(V, length); - return llvm::MDNode::get(C, val); -#endif -} - -template -static inline -llvm::InvokeInst* IRBuilderCreateInvoke(CGBuilder *Builder, - llvm::Value *callee, - llvm::BasicBlock *dest, - llvm::BasicBlock *dest2, - T values, - const llvm::Twine &NameStr="") -{ -#if LLVM_MAJOR < 3 - return Builder->CreateInvoke(callee, dest, dest2, values.begin(), values.end(), NameStr); -#else - return Builder->CreateInvoke(callee, dest, dest2, values, NameStr); -#endif -} - -template -static inline -llvm::CallInst* IRBuilderCreateCall(CGBuilder *Builder, - llvm::Value *callee, - T values, - const llvm::Twine &NameStr="") -{ -#if LLVM_MAJOR < 3 - return Builder->CreateCall(callee, values.begin(), values.end(), NameStr); -#else - return Builder->CreateCall(callee, values, NameStr); -#endif -} - -template -static inline -llvm::CallInst* CreateCall(llvm::Value *callee, - T values, - const llvm::Twine &NameStr, - llvm::Instruction *before) -{ -#if LLVM_MAJOR < 3 - return llvm::CallInst::Create(callee, values.begin(), values.end(), NameStr, before); -#else - return llvm::CallInst::Create(callee, values, NameStr, before); -#endif -} - - - -#if LLVM_MAJOR < 3 -#define GetStructType(context, ...) StructType::get(context, __VA_ARGS__) -#else -#define GetStructType(context, ...) StructType::get(__VA_ARGS__) -#endif - -__attribute((unused)) static inline -llvm::Constant* GetConstantStruct(llvm::LLVMContext &C, const std::vector - &V, bool Packed) { -#if LLVM_MAJOR < 3 - return llvm::ConstantStruct::get(C, V, Packed); -#else - return llvm::ConstantStruct::getAnon(C, V, Packed); -#endif -} - - -#if LLVM_MAJOR < 3 -typedef const llvm::Type LLVMType; -typedef const llvm::StructType LLVMStructTy; -typedef const llvm::ArrayType LLVMArrayTy; -typedef const llvm::PointerType LLVMPointerTy; -typedef const llvm::IntegerType LLVMIntegerTy; -#else -typedef llvm::Type LLVMType; -typedef llvm::StructType LLVMStructTy; -typedef llvm::ArrayType LLVMArrayTy; -typedef llvm::PointerType LLVMPointerTy; -typedef llvm::IntegerType LLVMIntegerTy; -#endif - -#endif diff --git a/opts/LoopIMPCachePass.cpp b/opts/LoopIMPCachePass.cpp deleted file mode 100644 index f57e761..0000000 --- a/opts/LoopIMPCachePass.cpp +++ /dev/null @@ -1,117 +0,0 @@ -#include "LLVMCompat.h" -#include "llvm/Analysis/LoopInfo.h" -#include "llvm/Analysis/Verifier.h" -#include "ObjectiveCOpts.h" -#include "IMPCacher.h" -#include - -using namespace GNUstep; -using namespace llvm; -using std::string; - -namespace -{ - class GNULoopIMPCachePass : public FunctionPass - { - GNUstep::IMPCacher *cacher; - LLVMIntegerTy *IntTy; - Module *M; - bool skip; - Function *sendFn; - Function *lookupFn; - Function *send_stretFn; - Function *send_fpretFn; - - public: - static char ID; - GNULoopIMPCachePass() : FunctionPass(ID) {} - ~GNULoopIMPCachePass() { delete cacher; } - - virtual bool doInitialization(Module &Mod) { - cacher = new GNUstep::IMPCacher(Mod.getContext(), this); - 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; - } - - virtual void getAnalysisUsage(AnalysisUsage &Info) const { - Info.addRequired(); - } - - - virtual bool runOnFunction(Function &F) { - if (skip) { return false; } - LoopInfo &LI = getAnalysis(); - bool modified = false; - SmallVector Lookups; - SmallVector Sends; - BasicBlock *entry = &F.getEntryBlock(); - - for (Function::iterator i=F.begin(), end=F.end() ; - i != end ; ++i) { - // Ignore basic blocks that are not parts of loops. - if (LI.getLoopDepth(i) == 0) { continue; } - for (BasicBlock::iterator b=i->begin(), last=i->end() ; - b != last ; ++b) { - CallSite call = CallSite(b); - if (CallSite() != call) { - Value *callee = call.getCalledValue()->stripPointerCasts(); - Function *func = dyn_cast(callee); - if (func) { - if (func == lookupFn) { - 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(), - e=Lookups.end() ; e!=i ; i++) { - LLVMType *SlotPtrTy = (*i)->getType(); - B.SetInsertPoint(entry, entry->begin()); - Value *slot = B.CreateAlloca(SlotPtrTy, 0, "slot"); - Value *version = B.CreateAlloca(IntTy, 0, "slot_version"); - - B.CreateStore(Constant::getNullValue(SlotPtrTy), slot); - B.CreateStore(Constant::getNullValue(IntTy), version); - cacher->CacheLookup(i->getInstruction(), slot, version); - } -#ifdef DEBUG - if (modified){ - verifyFunction(F); - } -#endif - return modified; - } - }; - - char GNULoopIMPCachePass::ID = 0; - RegisterPass X("gnu-loop-imp-cache", - "Cache IMPs in loops pass"); -} - -FunctionPass *createGNULoopIMPCachePass(void) -{ - return new GNULoopIMPCachePass(); -} diff --git a/opts/ObjectiveCOpts.cpp b/opts/ObjectiveCOpts.cpp deleted file mode 100644 index fa585f7..0000000 --- a/opts/ObjectiveCOpts.cpp +++ /dev/null @@ -1,91 +0,0 @@ -#include "LLVMCompat.h" -#if LLVM_MAJOR >= 3 -#include -#include -#endif - -#include "ObjectiveCOpts.h" - -using namespace llvm; - -namespace -{ - class ObjectiveCOpts : public ModulePass { - ModulePass *ClassIMPCachePass; - ModulePass *ClassLookupCachePass; - ModulePass *ClassMethodInliner; - FunctionPass *GNUNonfragileIvarPass; - FunctionPass *GNULoopIMPCachePass; - - public: - static char ID; - ObjectiveCOpts() : ModulePass(ID) { - ClassIMPCachePass = createClassIMPCachePass(); - ClassLookupCachePass = createClassLookupCachePass(); - ClassMethodInliner = createClassMethodInliner(); - GNUNonfragileIvarPass = createGNUNonfragileIvarPass(); - GNULoopIMPCachePass = createGNULoopIMPCachePass(); - } - virtual ~ObjectiveCOpts() { - delete ClassIMPCachePass; - delete ClassMethodInliner; - delete ClassLookupCachePass; - delete GNULoopIMPCachePass; - delete GNUNonfragileIvarPass; - } - - virtual bool runOnModule(Module &Mod) { - bool modified; - modified = ClassIMPCachePass->runOnModule(Mod); - modified |= ClassLookupCachePass->runOnModule(Mod); - modified |= ClassMethodInliner->runOnModule(Mod); - - for (Module::iterator F=Mod.begin(), fend=Mod.end() ; - F != fend ; ++F) { - - if (F->isDeclaration()) { continue; } - modified |= GNUNonfragileIvarPass->runOnFunction(*F); - modified |= GNULoopIMPCachePass->runOnFunction(*F); - } - - return modified; - }; - }; - - char ObjectiveCOpts::ID = 0; - RegisterPass X("gnu-objc", - "Run all of the GNUstep Objective-C runtimm optimisations"); - - -#if LLVM_MAJOR >= 3 - - void addObjCPasses(const PassManagerBuilder &Builder, PassManagerBase &PM) { - // Always add the ivar simplification pass - PM.add(createGNUNonfragileIvarPass()); - // Only cache IMPs in loops if we're not optimising for size. - if (Builder.SizeLevel == 0) { - PM.add(createGNULoopIMPCachePass()); - } - // Do the rest of the caching if we're not aggressively optimising for size - if (Builder.SizeLevel < 2) { - PM.add(createClassIMPCachePass()); - PM.add(createClassLookupCachePass()); - } - // Definitely don't do extra inlining if we're optimising for size! - if (Builder.SizeLevel == 0) { - PM.add(createClassMethodInliner()); - } - } - /* - static struct PluginRegister { - PluginRegister() { - PassManagerBuilder::addGlobalExtension(PassManagerBuilder::EP_LoopOptimizerEnd, - addObjCPasses); - } - } Register; - */ - RegisterStandardPasses S(PassManagerBuilder::EP_LoopOptimizerEnd, - addObjCPasses); -#endif - -} diff --git a/opts/ObjectiveCOpts.h b/opts/ObjectiveCOpts.h deleted file mode 100644 index c90452d..0000000 --- a/opts/ObjectiveCOpts.h +++ /dev/null @@ -1,7 +0,0 @@ -llvm::ModulePass *createClassIMPCachePass(void); -llvm::ModulePass *createClassLookupCachePass(void); -llvm::ModulePass *createClassMethodInliner(void); -llvm::FunctionPass *createGNUNonfragileIvarPass(void); -llvm::FunctionPass *createGNULoopIMPCachePass(void); -llvm::ModulePass *createTypeFeedbackPass(void); -llvm::ModulePass *createTypeFeedbackDrivenInlinerPass(void); diff --git a/opts/README b/opts/README deleted file mode 100644 index 9a646ad..0000000 --- a/opts/README +++ /dev/null @@ -1,30 +0,0 @@ -GNUstep Runtime Optimisations -============================= - -This directory contains LLVM optimisations specific to libobjc2. To build -them, you must copy this directory to llvm/lib/Transforms/GNURuntime (where -llvm is the root of your llvm checkout). - -Running GNU make will then create GNUObjCRuntime.so. This library can be -passed to opt to run optimisations on bitcode generated with clang or -LanguageKit. - -Non-Fragile Ivar Pass ---------------------- - -Running `opt -gnu-nonfragile-ivar` will invoke the non-fragile instance -variable lowering pass. This will turn non-fragile instance variable accesses, -which go via one or two indirection layers, into more fragile ones. If a class -and all of its superclasses are present in the module then this pass will turn -indirect instance variable accesses into hard-coded ones. - -For this pass to be most useful, it should be run as a link-time optimisation. - -Type Feedback -------------- - -Running `opt -gnu-objc-type-feedback` enables type feedback. Objective-C -message lookups will be replaced by calls to the profiling version in the -runtime library. The generated data can then be used for future optimisations -(speculative inlining, polymorphic inline caching, and so on), which have not -yet been written. diff --git a/opts/TypeFeedback.cpp b/opts/TypeFeedback.cpp deleted file mode 100644 index bf9edaf..0000000 --- a/opts/TypeFeedback.cpp +++ /dev/null @@ -1,151 +0,0 @@ -#include -#include -#include - -using namespace llvm; -#include "LLVMCompat.h" - -namespace { - struct GNUObjCTypeFeedback : public ModulePass { - - typedef std::pair callPair; - typedef std::vector replacementVector; - static char ID; - uint32_t callsiteCount; - LLVMIntegerTy *Int32Ty; - GNUObjCTypeFeedback() : ModulePass(ID), callsiteCount(0) {} - - void profileFunction(Function &F, Constant *ModuleID) { - for (Function::iterator i=F.begin(), e=F.end() ; - i != e ; ++i) { - - Module *M = F.getParent(); - replacementVector replacements; - for (BasicBlock::iterator b=i->begin(), last=i->end() ; - b != last ; ++b) { - - CallSite call(b); - if (call.getInstruction() && !call.getCalledFunction()) { - llvm::SmallVector args; - args.push_back(call->getOperand(1)); - args.push_back(call->getOperand(0)), - args.push_back(ModuleID); - args.push_back(ConstantInt::get(Int32Ty, callsiteCount++)); - Constant *profile = - M->getOrInsertFunction("objc_msg_profile", - Type::getVoidTy(M->getContext()), - args[0]->getType(), args[1]->getType(), - args[2]->getType(), args[3]->getType(), NULL); - CreateCall(profile, args, "", call.getInstruction()); - } - } - } - } - - public: - virtual bool runOnModule(Module &M) - { - LLVMContext &VMContext = M.getContext(); - Int32Ty = IntegerType::get(VMContext, 32); - LLVMPointerTy *PtrTy = Type::getInt8PtrTy(VMContext); - Constant *moduleName = -#if (LLVM_MAJOR > 3) || ((LLVM_MAJOR == 3) && (LLVM_MINOR > 0)) - ConstantDataArray::getString(VMContext, M.getModuleIdentifier(), true); -#else - ConstantArray::get(VMContext, M.getModuleIdentifier(), true); -#endif - 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 = -#if (LLVM_MAJOR > 3) || ((LLVM_MAJOR == 3) && (LLVM_MINOR > 0)) - llvm::ConstantDataArray::getString(VMContext, F->getName(), true); -#else - llvm::ConstantArray::get(VMContext, F->getName()); -#endif - 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 - LLVMType *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(GetConstantStruct(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, "", -#if LLVM_MAJOR < 3 || (LLVM_MAJOR == 3 && LLVM_MINOR < 2) - GCL->isThreadLocal()); -#else - GCL-> getThreadLocalMode()); -#endif - GCL->getParent()->getGlobalList().insert(GCL, NGV); - NGV->takeName(GCL); - GCL->replaceAllUsesWith(NGV); - GCL->eraseFromParent(); - - return true; - } - - }; - - char GNUObjCTypeFeedback::ID = 0; - RegisterPass X("gnu-objc-type-feedback", - "Objective-C type feedback for the GNU runtime.", false, true); -} - -ModulePass *createTypeFeedbackPass(void) { - return new GNUObjCTypeFeedback(); -} diff --git a/opts/TypeFeedbackDrivenInliner.cpp b/opts/TypeFeedbackDrivenInliner.cpp deleted file mode 100644 index 050c8be..0000000 --- a/opts/TypeFeedbackDrivenInliner.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#include "LLVMCompat.h" -#include "llvm/Analysis/InlineCost.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/Linker.h" -#include -#include "TypeInfoProvider.h" - -using namespace llvm; -using namespace GNUstep; - -namespace { - struct GNUObjCTypeFeedbackDrivenInliner : public ModulePass { - - typedef std::pair callPair; - typedef std::vector replacementVector; - static char ID; - uint32_t callsiteCount; - const IntegerType *Int32Ty; - - - public: - - GNUObjCTypeFeedbackDrivenInliner() : ModulePass(ID), callsiteCount(0) {} - - virtual bool runOnModule(Module &M) - { - bool modified = false; - LLVMContext &VMContext = M.getContext(); - Int32Ty = IntegerType::get(VMContext, 32); - TypeInfoProvider::CallSiteMap *SiteMap = - TypeInfoProvider::SharedTypeInfoProvider()->getCallSitesForModule(M); - SmallPtrSet NeverInline; - - //TypeInfoProvider::SharedTypeInfoProvider()->PrintStatistics(); - GNUstep::IMPCacher cacher = GNUstep::IMPCacher(M.getContext(), this); - InlineCostAnalyzer CA; - SmallVector messages; - - for (Module::iterator F=M.begin(), fend=M.end() ; - F != fend ; ++F) { - - - if (F->isDeclaration()) { continue; } - - for (Function::iterator i=F->begin(), end=F->end() ; - i != end ; ++i) { - for (BasicBlock::iterator b=i->begin(), last=i->end() ; - b != last ; ++b) { - CallSite call(b); - if (call.getInstruction() && !call.getCalledFunction()) { - messages.push_back(call); - } - } - } - } - TypeInfoProvider::CallSiteMap::iterator Entry = SiteMap->begin(); - - for (SmallVectorImpl::iterator i=messages.begin(), - e=messages.end() ; e!=i ; ++i, ++Entry) { - - if (Entry->size() == 1) { - - Function *method = M.getFunction(Entry->begin()->getKey()); - if (0 == method || method->isDeclaration()) { continue; } - -#if (LLVM_MAJOR > 3) || ((LLVM_MAJOR == 3) && (LLVM_MINOR > 0)) - InlineCost IC = CA.getInlineCost((*i), method, 200); -#else - InlineCost IC = CA.getInlineCost((*i), method, NeverInline); -#define getCost getValue -#endif - // FIXME: 200 is a random number. Pick a better one! - if (IC.isAlways() || (IC.isVariable() && IC.getCost() < 200)) { - cacher.SpeculativelyInline((*i).getInstruction(), method); - modified = true; - } - } - // FIXME: Inline the most popular call if one is much more popular - // than the others. - } - return modified; - } - - }; - - char GNUObjCTypeFeedbackDrivenInliner::ID = 0; - RegisterPass X("gnu-objc-feedback-driven-inline", - "Objective-C type feedback-driven inliner for the GNU runtime.", false, - true); -} - -ModulePass *createTypeFeedbackDrivenInlinerPass(void) { - return new GNUObjCTypeFeedbackDrivenInliner(); -} diff --git a/opts/TypeInfoProvider.h b/opts/TypeInfoProvider.h deleted file mode 100644 index be50c36..0000000 --- a/opts/TypeInfoProvider.h +++ /dev/null @@ -1,38 +0,0 @@ -#include "LLVMCompat.h" -#include "IMPCacher.h" -#include "llvm/Support/CallSite.h" -#include "llvm/Transforms/Utils/BasicBlockUtils.h" -#include "llvm/Transforms/Utils/Cloning.h" -#include "llvm/ADT/StringMap.h" - -using namespace llvm; -namespace GNUstep -{ - class TypeInfoProvider - { - public: - typedef StringMap CallSiteEntry; - //typedef std::vector CallSiteMap; - typedef SmallVector CallSiteMap; - private: - struct callsite_info - { - uintptr_t moduleID; - int32_t callsiteID; - uintptr_t methodID; - }; - const char *symbol_table; - size_t symbol_size; - StringMap CallSiteRecords; - - void loadCallsiteRecords(callsite_info *callsite_records, size_t size); - TypeInfoProvider(void); - - public: - CallSiteMap* getCallSitesForModule(Module &M); - void PrintStatistics(); - static TypeInfoProvider* SharedTypeInfoProvider(); - ~TypeInfoProvider(); - }; - -}