Remove the LLVM optimisation passes. They don’t work with a recent LLVM, can be recovered from git if required, and are better off being upstreamed into LLVM if they make sense.

main
David Chisnall 10 years ago
parent c7c193e4c7
commit 2ea11117a3

@ -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)")

@ -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

@ -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.

@ -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 <string>
#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<std::pair<CallSite, bool>, 16> Lookups;
SmallVector<CallSite, 16> 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<Function>(callee)) {
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));
}
}
}
}
}
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();
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<ClassIMPCachePass> X("gnu-class-imp-cache",
"Cache IMPs for class messages");
}
ModulePass *createClassIMPCachePass(void)
{
return new ClassIMPCachePass();
}

@ -1,152 +0,0 @@
#include "llvm/ADT/StringMap.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "ObjectiveCOpts.h"
#include <string>
#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<GlobalVariable*> statics;
typedef std::pair<CallInst*,std::string> 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<ClassLookup, 16> 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<CallInst>(b)) {
if (Function *func = dyn_cast<Function>(call->getCalledValue()->stripPointerCasts())) {
if (func->getName() == "objc_lookup_class") {
ClassLookup lookup;
GlobalVariable *classNameVar = dyn_cast<GlobalVariable>(
call->getOperand(0)->stripPointerCasts());
if (0 == classNameVar) { continue; }
#if (LLVM_MAJOR > 3) || ((LLVM_MAJOR == 3) && (LLVM_MINOR > 0))
ConstantDataArray *init = dyn_cast<ConstantDataArray>(
classNameVar->getInitializer());
#else
ConstantArray *init = dyn_cast<ConstantArray>(
classNameVar->getInitializer());
#endif
if (0 == init || !init->isCString()) { continue; }
lookup.first = call;
lookup.second = init->getAsString();
modified = true;
Lookups.push_back(lookup);
}
}
}
}
}
for (SmallVectorImpl<ClassLookup>::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<ClassLookupCachePass> X("gnu-class-lookup-cache",
"Cache class lookups");
}
ModulePass *createClassLookupCachePass(void)
{
return new ClassLookupCachePass();
}

@ -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 <string>
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<const Function *, 16> 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<CallSite, 16> 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<CallSite>::iterator i=messages.begin(),
e=messages.end() ; e!=i ; i++) {
MDNode *messageType = (*i)->getMetadata(MessageSendMDKind);
StringRef sel =
cast<MDString>(messageType->getOperand(0))->getString();
StringRef cls =
cast<MDString>(messageType->getOperand(1))->getString();
bool isClassMethod =
cast<ConstantInt>(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<ClassMethodInliner> X("gnu-class-method-inline",
"Inline class methods and message sends to super");
}
ModulePass *createClassMethodInliner(void)
{
return new ClassMethodInliner();
}

@ -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<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++;
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<CallInst>(call) ? cast<CallInst>(call)->getCalledValue()
: cast<InvokeInst>(call)->getCalledValue();
const FunctionType *FTy = function->getFunctionType();
const FunctionType *calleeTy = cast<FunctionType>(
cast<PointerType>(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 ; i<FTy->getNumParams() ; 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<CallInst>(inlineCall)) {
c->setCalledFunction(function);
InlineFunction(c, IFI);
} else if (InvokeInst *c = dyn_cast<InvokeInst>(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<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();
// 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<PHINode>(i)
; ++i) {
Value *v = phi->getIncomingValueForBlock(oldPredecessor);
phi->addIncoming(v, newPredecessor);
}
}

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

@ -1,165 +0,0 @@
#include "LLVMCompat.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/ADT/DenseSet.h"
#include "ObjectiveCOpts.h"
#include <string>
using namespace llvm;
using std::string;
typedef std::pair<Instruction*, Value*> Replacement;
namespace llvm {
template<> struct DenseMapInfo<Replacement> {
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<User>(ClsStruct->getOperand(1));
if (isa<ConstantPointerNull>(super)) return "";
GlobalVariable *name = cast<GlobalVariable>(super->getOperand(0));
#if (LLVM_MAJOR > 3) || ((LLVM_MAJOR == 3) && (LLVM_MINOR > 0))
return cast<ConstantDataArray>(name->getInitializer())->getAsString();
#else
return cast<ConstantArray>(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<ConstantInt>(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<ConstantStruct>(
cast<GlobalVariable>(ClsStruct->getOperand(6))->getInitializer());
int ivarCount = cast<ConstantInt>(IvarStruct->getOperand(0))->getSExtValue();
Constant *ivars = IvarStruct->getOperand(1);
for (int i=0 ; i<ivarCount ; i++) {
Constant *ivar = cast<Constant>(ivars->getOperand(i));
GlobalVariable *name =
cast<GlobalVariable>(
cast<User>(ivar->getOperand(0))->getOperand(0));
std::string ivarNameStr =
#if (LLVM_MAJOR > 3) || ((LLVM_MAJOR == 3) && (LLVM_MINOR > 0))
cast<ConstantDataArray>(name->getInitializer())->getAsString();
#else
cast<ConstantArray>(name->getInitializer())->getAsString();
#endif
// Remove the NULL terminator from the metadata string
ivarNameStr.resize(ivarNameStr.size() - 1);
if (ivarNameStr == ivarName.str())
return superSize +
cast<ConstantInt>(ivar->getOperand(2))->getSExtValue();
}
return 0;
}
virtual bool runOnFunction(Function &F) {
bool modified = false;
llvm::DenseSet<Replacement> 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<LoadInst>(b)) {
if (LoadInst *load = dyn_cast<LoadInst>(indirectload->getOperand(0))) {
if (GlobalVariable *ivar =
dyn_cast<GlobalVariable>(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<StringRef,StringRef> 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<Replacement>::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<GNUNonfragileIvarPass> X("gnu-nonfragile-ivar", "Ivar fragility pass");
}
FunctionPass *createGNUNonfragileIvarPass(void)
{
return new GNUNonfragileIvarPass();
}

@ -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 <llvm/Support/IRBuilder.h>
#else
#include <llvm/IRBuilder.h>
#endif
#include <llvm/Function.h>
#include <llvm/Module.h>
#include <llvm/LLVMContext.h>
#include <llvm/Instructions.h>
#include <llvm/Metadata.h>
#include <llvm/Intrinsics.h>
#include <llvm/Constants.h>
#include <llvm/GlobalAlias.h>
#include <llvm/GlobalVariable.h>
#include <llvm/DefaultPasses.h>
#else
#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Instructions.h>
#include <llvm/IR/Metadata.h>
#include <llvm/IR/Intrinsics.h>
#include <llvm/IR/Constants.h>
#include <llvm/IR/GlobalVariable.h>
#include <llvm/IR/GlobalAlias.h>
#include <llvm/PassSupport.h>
#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<false> 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<llvm::Value*> val(V, length);
return llvm::MDNode::get(C, val);
#endif
}
template<typename T>
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<typename T>
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<typename T>
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<llvm::Constant*>
&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

@ -1,117 +0,0 @@
#include "LLVMCompat.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/Verifier.h"
#include "ObjectiveCOpts.h"
#include "IMPCacher.h"
#include <string>
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<LoopInfo>();
}
virtual bool runOnFunction(Function &F) {
if (skip) { return false; }
LoopInfo &LI = getAnalysis<LoopInfo>();
bool modified = false;
SmallVector<CallSite, 16> Lookups;
SmallVector<CallSite, 16> 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<Function>(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<CallSite>::iterator i=Sends.begin(),
e=Sends.end() ; e!=i ; i++) {
Lookups.push_back(cacher->SplitSend(*i));
}
IRBuilder<> B = IRBuilder<>(entry);
for (SmallVectorImpl<CallSite>::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<GNULoopIMPCachePass> X("gnu-loop-imp-cache",
"Cache IMPs in loops pass");
}
FunctionPass *createGNULoopIMPCachePass(void)
{
return new GNULoopIMPCachePass();
}

@ -1,91 +0,0 @@
#include "LLVMCompat.h"
#if LLVM_MAJOR >= 3
#include <llvm/Transforms/IPO/PassManagerBuilder.h>
#include <llvm/PassManager.h>
#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<ObjectiveCOpts> 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
}

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

@ -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.

@ -1,151 +0,0 @@
#include <llvm/Support/CallSite.h>
#include <llvm/Linker.h>
#include <vector>
using namespace llvm;
#include "LLVMCompat.h"
namespace {
struct GNUObjCTypeFeedback : public ModulePass {
typedef std::pair<CallInst*,CallInst*> callPair;
typedef std::vector<callPair > 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<llvm::Value*, 4> 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<Constant*> 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<Constant*> ctors;
ConstantArray *CA = cast<ConstantArray>(GCL->getInitializer());
for (User::op_iterator i = CA->op_begin(), e = CA->op_end(); i != e; ++i) {
ctors.push_back(cast<ConstantStruct>(*i));
}
// Type of one ctor
LLVMType *ctorTy =
cast<ArrayType>(GCL->getType()->getElementType())->getElementType();
// Add the
std::vector<Constant*> 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>(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<GNUObjCTypeFeedback> X("gnu-objc-type-feedback",
"Objective-C type feedback for the GNU runtime.", false, true);
}
ModulePass *createTypeFeedbackPass(void) {
return new GNUObjCTypeFeedback();
}

@ -1,94 +0,0 @@
#include "LLVMCompat.h"
#include "llvm/Analysis/InlineCost.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Linker.h"
#include <vector>
#include "TypeInfoProvider.h"
using namespace llvm;
using namespace GNUstep;
namespace {
struct GNUObjCTypeFeedbackDrivenInliner : public ModulePass {
typedef std::pair<CallInst*,CallInst*> callPair;
typedef std::vector<callPair > 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<const Function *, 16> NeverInline;
//TypeInfoProvider::SharedTypeInfoProvider()->PrintStatistics();
GNUstep::IMPCacher cacher = GNUstep::IMPCacher(M.getContext(), this);
InlineCostAnalyzer CA;
SmallVector<CallSite, 16> 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<CallSite>::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<GNUObjCTypeFeedbackDrivenInliner> X("gnu-objc-feedback-driven-inline",
"Objective-C type feedback-driven inliner for the GNU runtime.", false,
true);
}
ModulePass *createTypeFeedbackDrivenInlinerPass(void) {
return new GNUObjCTypeFeedbackDrivenInliner();
}

@ -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<uintptr_t> CallSiteEntry;
//typedef std::vector<CallSiteEntry> CallSiteMap;
typedef SmallVector<CallSiteEntry, 16> CallSiteMap;
private:
struct callsite_info
{
uintptr_t moduleID;
int32_t callsiteID;
uintptr_t methodID;
};
const char *symbol_table;
size_t symbol_size;
StringMap<CallSiteMap> CallSiteRecords;
void loadCallsiteRecords(callsite_info *callsite_records, size_t size);
TypeInfoProvider(void);
public:
CallSiteMap* getCallSitesForModule(Module &M);
void PrintStatistics();
static TypeInfoProvider* SharedTypeInfoProvider();
~TypeInfoProvider();
};
}
Loading…
Cancel
Save