mirror of
https://github.com/darlinghq/darling-libobjc2.git
synced 2025-02-26 03:26:16 +00:00
Fixed LLVM passes to compile with recent LLVM.
Made class caching pass cache classes in a static variable if the original class is not available.
This commit is contained in:
parent
52381f163b
commit
9d5452b147
@ -22,7 +22,7 @@ namespace
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
ClassIMPCachePass() : ModulePass((intptr_t)&ID) {}
|
||||
ClassIMPCachePass() : ModulePass(ID) {}
|
||||
|
||||
virtual bool runOnModule(Module &M) {
|
||||
GNUstep::IMPCacher cacher = GNUstep::IMPCacher(M.getContext(), this);
|
||||
@ -44,7 +44,7 @@ namespace
|
||||
i != end ; ++i) {
|
||||
for (BasicBlock::iterator b=i->begin(), last=i->end() ;
|
||||
b != last ; ++b) {
|
||||
CallSite call = CallSite::get(b);
|
||||
CallSite call(b);
|
||||
if (call.getInstruction()) {
|
||||
Value *callee = call.getCalledValue()->stripPointerCasts();
|
||||
if (Function *func = dyn_cast<Function>(callee)) {
|
||||
|
@ -5,45 +5,53 @@
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/GlobalVariable.h"
|
||||
#include "llvm/Support/IRBuilder.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/Analysis/LoopInfo.h"
|
||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
||||
#include <string>
|
||||
|
||||
#include "IMPCacher.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace GNUstep;
|
||||
using std::string;
|
||||
using std::pair;
|
||||
|
||||
namespace
|
||||
{
|
||||
class ClassLookupCachePass : public FunctionPass
|
||||
{
|
||||
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() : FunctionPass((intptr_t)&ID) {}
|
||||
ClassLookupCachePass() : ModulePass(ID) {}
|
||||
|
||||
virtual bool doInitialization(Module &Mod) {
|
||||
M = &Mod;
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool runOnFunction(Function &F) {
|
||||
bool runOnFunction(Function &F) {
|
||||
bool modified = false;
|
||||
SmallVector<ClassLookup, 16> Lookups;
|
||||
BasicBlock *entry = &F.getEntryBlock();
|
||||
|
||||
for (Function::iterator i=F.begin(), end=F.end() ;
|
||||
i != end ; ++i) {
|
||||
for (BasicBlock::iterator b=i->begin(), last=i->end() ;
|
||||
b != last ; ++b) {
|
||||
if (CallInst *call = dyn_cast<CallInst>(b)) {
|
||||
Value *callee = call->getCalledValue()->stripPointerCasts();
|
||||
if (Function *func = dyn_cast<Function>(callee)) {
|
||||
if (Function *func = call->getCalledFunction()) {
|
||||
if (func->getName() == "objc_lookup_class") {
|
||||
ClassLookup lookup;
|
||||
GlobalVariable *classNameVar = dyn_cast<GlobalVariable>(
|
||||
call->getOperand(1)->stripPointerCasts());
|
||||
call->getOperand(0)->stripPointerCasts());
|
||||
if (0 == classNameVar) { continue; }
|
||||
ConstantArray *init = dyn_cast<ConstantArray>(
|
||||
classNameVar->getInitializer());
|
||||
@ -57,18 +65,81 @@ namespace
|
||||
}
|
||||
}
|
||||
}
|
||||
IRBuilder<> B = IRBuilder<>(entry);
|
||||
for (SmallVectorImpl<ClassLookup>::iterator i=Lookups.begin(),
|
||||
e=Lookups.end() ; e!=i ; i++) {
|
||||
llvm::Instruction *lookup = i->first;
|
||||
std::string &cls = i->second;
|
||||
const llvm::Type *clsTy = lookup->getType();
|
||||
Value *global = M->getGlobalVariable(("_OBJC_CLASS_" + i->second).c_str(), true);
|
||||
global = 0;
|
||||
// If we can see the class reference for this, then reference it
|
||||
// directly. If not, then do the lookup and cache it.
|
||||
if (global) {
|
||||
Value *cls = new BitCastInst(global, i->first->getType(), "class", i->first);
|
||||
i->first->replaceAllUsesWith(cls);
|
||||
i->first->removeFromParent();
|
||||
// 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();
|
||||
} 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 =
|
||||
PHINode::Create(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;
|
||||
|
||||
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;
|
||||
@ -76,7 +147,7 @@ namespace
|
||||
"Cache class lookups");
|
||||
}
|
||||
|
||||
FunctionPass *createClassLookupCachePass(void)
|
||||
ModulePass *createClassLookupCachePass(void)
|
||||
{
|
||||
return new ClassLookupCachePass();
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ namespace
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
ClassMethodInliner() : ModulePass((intptr_t)&ID) {}
|
||||
ClassMethodInliner() : ModulePass(ID) {}
|
||||
|
||||
virtual bool runOnModule(Module &M) {
|
||||
unsigned MessageSendMDKind = M.getContext().getMDKindID("GNUObjCMessageSend");
|
||||
@ -59,7 +59,7 @@ namespace
|
||||
i != end ; ++i) {
|
||||
for (BasicBlock::iterator b=i->begin(), last=i->end() ;
|
||||
b != last ; ++b) {
|
||||
CallSite call = CallSite::get(b);
|
||||
CallSite call(b);
|
||||
if (call.getInstruction() && !call.getCalledFunction()) {
|
||||
MDNode *messageType = call->getMetadata(MessageSendMDKind);
|
||||
if (0 == messageType) { continue; }
|
||||
|
@ -172,7 +172,7 @@ void GNUstep::IMPCacher::SpeculativelyInline(Instruction *call, Function
|
||||
// Unify the return values
|
||||
if (call->getType() != Type::getVoidTy(Context)) {
|
||||
B.SetInsertPoint(afterCallBB, afterCallBB->begin());
|
||||
PHINode *phi = B.CreatePHI(call->getType());
|
||||
PHINode *phi = B.CreatePHI(call->getType(), 2);
|
||||
call->replaceAllUsesWith(phi);
|
||||
phi->addIncoming(call, callBB);
|
||||
phi->addIncoming(inlineResult, inlineBB);
|
||||
|
@ -17,7 +17,7 @@ namespace
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
GNUNonfragileIvarPass() : FunctionPass((intptr_t)&ID) {}
|
||||
GNUNonfragileIvarPass() : FunctionPass(ID) {}
|
||||
|
||||
Module *M;
|
||||
size_t PointerSize;
|
||||
@ -31,7 +31,8 @@ namespace
|
||||
|
||||
std::string getSuperName(Constant *ClsStruct) {
|
||||
GlobalVariable *name =
|
||||
cast<GlobalVariable>(ClsStruct->getOperand(1)->getOperand(0));
|
||||
cast<GlobalVariable>(
|
||||
cast<Instruction>(ClsStruct->getOperand(1))->getOperand(0));
|
||||
return cast<ConstantArray>(name->getInitializer())->getAsString();
|
||||
}
|
||||
|
||||
@ -62,7 +63,8 @@ namespace
|
||||
for (int i=0 ; i<ivarCount ; i++) {
|
||||
Constant *ivar = cast<Constant>(ivars->getOperand(i));
|
||||
GlobalVariable *name =
|
||||
cast<GlobalVariable>(ivar->getOperand(0)->getOperand(0));
|
||||
cast<GlobalVariable>(
|
||||
cast<Instruction>(ivar->getOperand(0))->getOperand(0));
|
||||
std::string ivarNameStr =
|
||||
cast<ConstantArray>(name->getInitializer())->getAsString();
|
||||
if (ivarNameStr.compare(0, ivarName.size(), ivarName.str()) == 0)
|
||||
|
@ -20,7 +20,7 @@ namespace
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
GNULoopIMPCachePass() : FunctionPass((intptr_t)&ID) {}
|
||||
GNULoopIMPCachePass() : FunctionPass(ID) {}
|
||||
~GNULoopIMPCachePass() { delete cacher; }
|
||||
|
||||
virtual bool doInitialization(Module &Mod) {
|
||||
|
@ -18,7 +18,7 @@ namespace {
|
||||
static char ID;
|
||||
uint32_t callsiteCount;
|
||||
const IntegerType *Int32Ty;
|
||||
GNUObjCTypeFeedback() : ModulePass(&ID), callsiteCount(0) {}
|
||||
GNUObjCTypeFeedback() : ModulePass(ID), callsiteCount(0) {}
|
||||
|
||||
void profileFunction(Function &F, Constant *ModuleID) {
|
||||
for (Function::iterator i=F.begin(), e=F.end() ;
|
||||
@ -29,7 +29,7 @@ namespace {
|
||||
for (BasicBlock::iterator b=i->begin(), last=i->end() ;
|
||||
b != last ; ++b) {
|
||||
|
||||
CallSite call = CallSite::get(b);
|
||||
CallSite call(b);
|
||||
if (call.getInstruction() && !call.getCalledFunction()) {
|
||||
llvm::Value *args[] = { call->getOperand(1), call->getOperand(0),
|
||||
ModuleID, ConstantInt::get(Int32Ty, callsiteCount++) };
|
||||
|
@ -25,7 +25,7 @@ namespace {
|
||||
|
||||
public:
|
||||
|
||||
GNUObjCTypeFeedbackDrivenInliner() : ModulePass(&ID), callsiteCount(0) {}
|
||||
GNUObjCTypeFeedbackDrivenInliner() : ModulePass(ID), callsiteCount(0) {}
|
||||
|
||||
virtual bool runOnModule(Module &M)
|
||||
{
|
||||
@ -51,7 +51,7 @@ namespace {
|
||||
i != end ; ++i) {
|
||||
for (BasicBlock::iterator b=i->begin(), last=i->end() ;
|
||||
b != last ; ++b) {
|
||||
CallSite call = CallSite::get(b);
|
||||
CallSite call(b);
|
||||
if (call.getInstruction() && !call.getCalledFunction()) {
|
||||
messages.push_back(call);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user