Added -gnu-class-lookup-cache and -gnu-class-imp-cache passes. These add caching for class messages and also skip the class lookup (using the class symbol directly) where possible.
In combination, these make class messages marginally slower than function calls, rather than significantly slower than message sends.main
parent
352dfe2d93
commit
84b41a8464
@ -0,0 +1,105 @@
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Function.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Instructions.h"
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/GlobalVariable.h"
|
||||
#include "llvm/Support/IRBuilder.h"
|
||||
#include "llvm/Analysis/LoopInfo.h"
|
||||
#include "IMPCacher.h"
|
||||
#include <string>
|
||||
|
||||
using namespace llvm;
|
||||
using std::string;
|
||||
|
||||
namespace
|
||||
{
|
||||
class ClassIMPCachePass : public FunctionPass
|
||||
{
|
||||
GNUstep::IMPCacher *cacher;
|
||||
Module *M;
|
||||
const IntegerType *IntTy;
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
ClassIMPCachePass() : FunctionPass((intptr_t)&ID) {}
|
||||
~ClassIMPCachePass() { delete cacher; }
|
||||
|
||||
virtual bool doInitialization(Module &Mod) {
|
||||
M = &Mod;
|
||||
cacher = new GNUstep::IMPCacher(Mod.getContext(), this);
|
||||
// FIXME: ILP64
|
||||
IntTy = Type::getInt32Ty(Mod.getContext());
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool runOnFunction(Function &F) {
|
||||
bool modified = false;
|
||||
SmallVector<CallInst*, 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 (func->getName() == "objc_msg_lookup_sender") {
|
||||
// TODO: Move this to a helper
|
||||
Value *receiverPtr = call->getOperand(1);
|
||||
Value *receiver = 0;
|
||||
// Find where the receiver comes from
|
||||
for (BasicBlock::iterator start=i->begin(),s=b ; s!=start ; s--) {
|
||||
if (StoreInst *store = dyn_cast<StoreInst>(s)) {
|
||||
if (store->getOperand(1) == receiverPtr) {
|
||||
receiver = store->getOperand(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (0 == receiver) { continue; }
|
||||
if (CallInst *classLookup = dyn_cast<CallInst>(receiver)) {
|
||||
Value *lookupVal = classLookup->getCalledValue()->stripPointerCasts();
|
||||
if (Function *lookupFunc = dyn_cast<Function>(lookupVal)) {
|
||||
if (lookupFunc->getName() == "objc_lookup_class") {
|
||||
GlobalVariable *classNameVar = cast<GlobalVariable>(
|
||||
classLookup->getOperand(1)->stripPointerCasts());
|
||||
string className = cast<ConstantArray>(
|
||||
classNameVar->getInitializer() )->getAsString();
|
||||
modified = true;
|
||||
Lookups.push_back(call);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
IRBuilder<> B = IRBuilder<>(entry);
|
||||
for (SmallVectorImpl<CallInst*>::iterator i=Lookups.begin(),
|
||||
e=Lookups.end() ; e!=i ; i++) {
|
||||
const Type *SlotPtrTy = (*i)->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(*i, slot, version);
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
};
|
||||
|
||||
char ClassIMPCachePass::ID = 0;
|
||||
RegisterPass<ClassIMPCachePass> X("gnu-class-imp-cache",
|
||||
"Cache IMPs for class messages");
|
||||
}
|
||||
|
||||
FunctionPass *createClassIMPCachePass(void)
|
||||
{
|
||||
return new ClassIMPCachePass();
|
||||
}
|
||||
@ -0,0 +1,83 @@
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Function.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Instructions.h"
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/GlobalVariable.h"
|
||||
#include "llvm/Support/IRBuilder.h"
|
||||
#include "llvm/Analysis/LoopInfo.h"
|
||||
#include <string>
|
||||
|
||||
using namespace llvm;
|
||||
using std::string;
|
||||
using std::pair;
|
||||
|
||||
namespace
|
||||
{
|
||||
class ClassLookupCachePass : public FunctionPass
|
||||
{
|
||||
Module *M;
|
||||
typedef std::pair<CallInst*,std::string> ClassLookup;
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
ClassLookupCachePass() : FunctionPass((intptr_t)&ID) {}
|
||||
|
||||
virtual bool doInitialization(Module &Mod) {
|
||||
M = &Mod;
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual 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 (func->getName() == "objc_lookup_class") {
|
||||
ClassLookup lookup;
|
||||
GlobalVariable *classNameVar = dyn_cast<GlobalVariable>(
|
||||
call->getOperand(1)->stripPointerCasts());
|
||||
if (0 == classNameVar) { continue; }
|
||||
ConstantArray *init = dyn_cast<ConstantArray>(
|
||||
classNameVar->getInitializer());
|
||||
if (0 == init || !init->isCString()) { continue; }
|
||||
lookup.first = call;
|
||||
lookup.second = init->getAsString();
|
||||
modified = true;
|
||||
Lookups.push_back(lookup);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
IRBuilder<> B = IRBuilder<>(entry);
|
||||
for (SmallVectorImpl<ClassLookup>::iterator i=Lookups.begin(),
|
||||
e=Lookups.end() ; e!=i ; i++) {
|
||||
Value *global = M->getGlobalVariable(("_OBJC_CLASS_" + i->second).c_str(), true);
|
||||
fprintf(stderr, "%s\n", ("_OBJC_CLASS_" + i->second).c_str());
|
||||
if (global) {
|
||||
Value *cls = new BitCastInst(global, i->first->getType(), "class", i->first);
|
||||
i->first->replaceAllUsesWith(cls);
|
||||
i->first->removeFromParent();
|
||||
}
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
};
|
||||
|
||||
char ClassLookupCachePass::ID = 0;
|
||||
RegisterPass<ClassLookupCachePass> X("gnu-class-lookup-cache",
|
||||
"Cache class lookups");
|
||||
}
|
||||
|
||||
FunctionPass *createClassLookupCachePass(void)
|
||||
{
|
||||
return new ClassLookupCachePass();
|
||||
}
|
||||
Loading…
Reference in New Issue