Fixed some bugs with the optimisation passes and introduced support for automatically running them (requires LLVM 3 + a patch that is not yet in trunk, but should be soon).

main
theraven 15 years ago
parent dd81cda462
commit 5705845e98

@ -25,9 +25,10 @@ namespace
ClassIMPCachePass() : ModulePass(ID) {}
virtual bool runOnModule(Module &M) {
return false;
GNUstep::IMPCacher cacher = GNUstep::IMPCacher(M.getContext(), this);
// FIXME: ILP64
IntTy = Type::getInt32Ty(M.getContext());
IntTy = (sizeof(int) == 4 ) ? Type::getInt32Ty(M.getContext()) :
Type::getInt64Ty(M.getContext()) ;
bool modified = false;
unsigned MessageSendMDKind = M.getContext().getMDKindID("GNUObjCMessageSend");

@ -8,6 +8,8 @@
#include "llvm/ADT/StringMap.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/DefaultPasses.h"
#include "ObjectiveCOpts.h"
#include <string>
#include "IMPCacher.h"
@ -41,6 +43,7 @@ namespace
bool runOnFunction(Function &F) {
bool modified = false;
return false;
SmallVector<ClassLookup, 16> Lookups;
for (Function::iterator i=F.begin(), end=F.end() ;
@ -145,6 +148,14 @@ namespace
char ClassLookupCachePass::ID = 0;
RegisterPass<ClassLookupCachePass> X("gnu-class-lookup-cache",
"Cache class lookups");
#if LLVM_MAJOR > 2
StandardPass::RegisterStandardPass<ClassLookupCachePass> D(
StandardPass::Module, &LoopIMPCacheID,
StandardPass::OptimzationFlags(1), &ClassLookupCacheID);
StandardPass::RegisterStandardPass<ClassLookupCachePass> L(StandardPass::LTO,
&LoopIMPCacheID, StandardPass::OptimzationFlags(0),
&ClassLookupCacheID);
#endif
}
ModulePass *createClassLookupCachePass(void)

@ -9,10 +9,13 @@
#include "llvm/Support/IRBuilder.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/InlineCost.h"
#include "llvm/DefaultPasses.h"
#include "ObjectiveCOpts.h"
#include "IMPCacher.h"
#include <string>
using namespace llvm;
using namespace GNUstep;
using std::string;
// Mangle a method name
@ -39,13 +42,14 @@ namespace
ClassMethodInliner() : ModulePass(ID) {}
virtual bool runOnModule(Module &M) {
return false;
unsigned MessageSendMDKind = M.getContext().getMDKindID("GNUObjCMessageSend");
InlineCostAnalyzer CA;
SmallPtrSet<const Function *, 16> NeverInline;
GNUstep::IMPCacher cacher = GNUstep::IMPCacher(M.getContext(), this);
// FIXME: ILP64
IntTy = Type::getInt32Ty(M.getContext());
IntTy = (sizeof(int) == 4 ) ? Type::getInt32Ty(M.getContext()) :
Type::getInt64Ty(M.getContext()) ;
bool modified = false;
for (Module::iterator F=M.begin(), fend=M.end() ;
@ -98,6 +102,14 @@ namespace
char ClassMethodInliner::ID = 0;
RegisterPass<ClassMethodInliner> X("gnu-class-method-inline",
"Inline class methods and message sends to super");
#if LLVM_MAJOR > 2
StandardPass::RegisterStandardPass<ClassMethodInliner> D(
StandardPass::Module, &ClassLookupCacheID,
StandardPass::OptimzationFlags(1), &ClassMethodInlinerID);
StandardPass::RegisterStandardPass<ClassMethodInliner> L(StandardPass::LTO,
&ClassLookupCacheID, StandardPass::OptimzationFlags(0),
&ClassMethodInlinerID);
#endif
}
ModulePass *createClassMethodInliner(void)

@ -17,8 +17,7 @@ GNUstep::IMPCacher::IMPCacher(LLVMContext &C, Pass *owner) : Context(C),
Owner(owner) {
PtrTy = Type::getInt8PtrTy(Context);
// FIXME: 64-bit.
IntTy = Type::getInt32Ty(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);
@ -45,16 +44,14 @@ void GNUstep::IMPCacher::CacheLookup(Instruction *lookup, Value *slot, Value
// Load the slot and check that neither it nor the version is 0.
Value *slotValue = B.CreateLoad(slot);
Value *versionValue = B.CreateLoad(version);
Value *receiverPtr = lookup->getOperand(1);
Value *receiverPtr = lookup->getOperand(0);
Value *receiver = receiverPtr;
if (!isSuperMessage) {
receiver = B.CreateLoad(receiverPtr);
}
Value *isCacheEmpty =
B.CreateOr(versionValue, B.CreatePtrToInt(slotValue, IntTy));
isCacheEmpty =
B.CreateICmpEQ(isCacheEmpty, Constant::getNullValue(IntTy));
B.CreateICmpEQ(versionValue, Constant::getNullValue(IntTy));
Value *receiverNotNil =
B.CreateICmpNE(receiver, Constant::getNullValue(receiver->getType()));
isCacheEmpty = B.CreateAnd(isCacheEmpty, receiverNotNil);
@ -96,15 +93,18 @@ void GNUstep::IMPCacher::CacheLookup(Instruction *lookup, Value *slot, Value
lookupBB->getParent());
// Don't store the cached lookup if we are doing forwarding tricks.
B.CreateBr(storeCacheBB);
/*
B.CreateCondBr(B.CreateICmpEQ(receiver, newReceiver), storeCacheBB,
afterLookupBB);
*/
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);
//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);
@ -129,7 +129,8 @@ void GNUstep::IMPCacher::SpeculativelyInline(Instruction *call, Function
// Put a branch before the call, testing whether the callee really is the
// function
IRBuilder<> B = IRBuilder<>(beforeCallBB);
Value *callee = call->getOperand(0);
Value *callee = isa<CallInst>(call) ? cast<CallInst>(call)->getCalledValue()
: cast<InvokeInst>(call)->getCalledValue();
const FunctionType *FTy = function->getFunctionType();
const FunctionType *calleeTy = cast<FunctionType>(
@ -146,7 +147,6 @@ void GNUstep::IMPCacher::SpeculativelyInline(Instruction *call, Function
Instruction *inlineCall = call->clone();
Value *inlineResult= inlineCall;
inlineBB->getInstList().push_back(inlineCall);
inlineCall->setOperand(0, function);
B.SetInsertPoint(inlineBB);
@ -155,8 +155,8 @@ void GNUstep::IMPCacher::SpeculativelyInline(Instruction *call, Function
const Type *callType = calleeTy->getParamType(i);
const Type *argType = FTy->getParamType(i);
if (callType != argType) {
inlineCall->setOperand(i+1, new
BitCastInst(inlineCall->getOperand(i+1), argType, "", inlineCall));
inlineCall->setOperand(i, new
BitCastInst(inlineCall->getOperand(i), argType, "", inlineCall));
}
}
if (FTy->getReturnType() != calleeTy->getReturnType()) {
@ -173,7 +173,7 @@ void GNUstep::IMPCacher::SpeculativelyInline(Instruction *call, Function
// Unify the return values
if (call->getType() != Type::getVoidTy(Context)) {
PHINode *phi = CreatePHI(call->getType(), 2, 0, afterCallBB->begin());
PHINode *phi = CreatePHI(call->getType(), 2, "", afterCallBB->begin());
call->replaceAllUsesWith(phi);
phi->addIncoming(call, callBB);
phi->addIncoming(inlineResult, inlineBB);
@ -182,8 +182,10 @@ void GNUstep::IMPCacher::SpeculativelyInline(Instruction *call, Function
// 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);
}
}

@ -5,15 +5,18 @@
#include "llvm/GlobalAlias.h"
#include "llvm/GlobalVariable.h"
#include "llvm/Constants.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/DefaultPasses.h"
#include "ObjectiveCOpts.h"
#include <string>
using namespace GNUstep;
using namespace llvm;
using std::string;
namespace
{
class GNUNonfragileIvarPass : public FunctionPass
{
namespace {
class GNUNonfragileIvarPass : public FunctionPass {
public:
static char ID;
@ -30,13 +33,16 @@ namespace
}
std::string getSuperName(Constant *ClsStruct) {
GlobalVariable *name =
cast<GlobalVariable>(
cast<Instruction>(ClsStruct->getOperand(1))->getOperand(0));
User *super = cast<User>(ClsStruct->getOperand(1));
if (isa<ConstantPointerNull>(super)) return "";
GlobalVariable *name = cast<GlobalVariable>(super->getOperand(0));
return cast<ConstantArray>(name->getInitializer())->getAsString();
}
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;
@ -64,7 +70,7 @@ namespace
Constant *ivar = cast<Constant>(ivars->getOperand(i));
GlobalVariable *name =
cast<GlobalVariable>(
cast<Instruction>(ivar->getOperand(0))->getOperand(0));
cast<User>(ivar->getOperand(0))->getOperand(0));
std::string ivarNameStr =
cast<ConstantArray>(name->getInitializer())->getAsString();
if (ivarNameStr.compare(0, ivarName.size(), ivarName.str()) == 0)
@ -76,6 +82,8 @@ namespace
virtual bool runOnFunction(Function &F) {
bool modified = false;
typedef std::pair<Instruction*, Value*> Replacement;
llvm::SmallVector<Replacement, 16> replacements;
//llvm::cerr << "IvarPass: " << F.getName() << "\n";
for (Function::iterator i=F.begin(), end=F.end() ;
i != end ; ++i) {
@ -86,9 +94,10 @@ namespace
if (GlobalVariable *ivar =
dyn_cast<GlobalVariable>(load->getOperand(0))) {
StringRef variableName = ivar->getName();
if (!variableName.startswith("__objc_ivar_offset_"))
break;
size_t prefixLength = strlen("__objc_ivar_offset_");
if (!variableName.startswith("__objc_ivar_offset_")) break;
static size_t prefixLength = strlen("__objc_ivar_offset_");
StringRef suffix = variableName.substr(prefixLength,
variableName.size()-prefixLength);
@ -100,13 +109,16 @@ namespace
// 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)) {
indirectload->replaceAllUsesWith(ConstantInt::get(indirectload->getType(), offset));
replacements.push_back(Replacement(load, 0));
replacements.push_back(Replacement(indirectload,
ConstantInt::get(indirectload->getType(), offset)));
modified = true;
} else {
// If the class was compiled with the new
if (Value *offset =
M->getGlobalVariable(("__objc_ivar_offset_value_" + suffix).str())) {
load->replaceAllUsesWith(offset);
// 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.push_back(Replacement(load, offset));
modified = true;
}
}
@ -115,12 +127,27 @@ namespace
}
}
}
for (SmallVector<Replacement, 16>::iterator i=replacements.begin(),
end=replacements.end() ; i != end ; ++i) {
if (i->second)
i->first->replaceAllUsesWith(i->second);
i->first->removeFromParent();
}
verifyFunction(F);
return modified;
}
};
char GNUNonfragileIvarPass::ID = 0;
RegisterPass<GNUNonfragileIvarPass> X("gnu-nonfragile-ivar", "Ivar fragility pass");
#if LLVM_MAJOR > 2
StandardPass::RegisterStandardPass<GNUNonfragileIvarPass> D(
StandardPass::Module, &DefaultStandardPasses::LoopUnrollID,
StandardPass::OptimzationFlags(1), &NonfragileIvarID);
StandardPass::RegisterStandardPass<GNUNonfragileIvarPass> L(StandardPass::LTO,
&DefaultStandardPasses::JumpThreadingID,
StandardPass::OptimzationFlags(0), &NonfragileIvarID);
#endif
}
FunctionPass *createGNUNonfragileIvarPass(void)

@ -1,3 +1,4 @@
#include "llvm/LLVMContext.h"
#include "llvm/Pass.h"
#include "llvm/Function.h"
#include "llvm/Module.h"
@ -5,9 +6,13 @@
#include "llvm/Constants.h"
#include "llvm/Support/IRBuilder.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/DefaultPasses.h"
#include "ObjectiveCOpts.h"
#include "IMPCacher.h"
#include <string>
using namespace GNUstep;
using namespace llvm;
using std::string;
@ -17,6 +22,7 @@ namespace
{
GNUstep::IMPCacher *cacher;
const IntegerType *IntTy;
Module *M;
public:
static char ID;
@ -25,8 +31,9 @@ namespace
virtual bool doInitialization(Module &Mod) {
cacher = new GNUstep::IMPCacher(Mod.getContext(), this);
// FIXME: ILP64
IntTy = Type::getInt32Ty(Mod.getContext());
IntTy = (sizeof(int) == 4 ) ? Type::getInt32Ty(Mod.getContext()) :
Type::getInt64Ty(Mod.getContext()) ;
M = &Mod;
return false;
}
@ -66,11 +73,13 @@ namespace
Value *slot = B.CreateAlloca(SlotPtrTy, 0, "slot");
Value *version = B.CreateAlloca(IntTy, 0, "slot_version");
B.SetInsertPoint(entry, entry->getTerminator());
B.CreateStore(Constant::getNullValue(SlotPtrTy), slot);
B.CreateStore(Constant::getNullValue(IntTy), version);
cacher->CacheLookup(*i, slot, version);
}
if (modified){
verifyFunction(F);
}
return modified;
}
};
@ -78,6 +87,14 @@ namespace
char GNULoopIMPCachePass::ID = 0;
RegisterPass<GNULoopIMPCachePass> X("gnu-loop-imp-cache",
"Cache IMPs in loops pass");
#if LLVM_MAJOR > 2
StandardPass::RegisterStandardPass<GNULoopIMPCachePass> D(
StandardPass::Module, &NonfragileIvarID,
StandardPass::OptimzationFlags(1), &LoopIMPCacheID);
StandardPass::RegisterStandardPass<GNULoopIMPCachePass> L(StandardPass::LTO,
&NonfragileIvarID, StandardPass::OptimzationFlags(0),
&LoopIMPCacheID);
#endif
}
FunctionPass *createGNULoopIMPCachePass(void)

@ -7,7 +7,7 @@ using namespace llvm;
namespace
{
class ObjectiveCOpts : public ModulePass {
ModulePass *IMPCachePass;
ModulePass *ClassIMPCachePass;
ModulePass *ClassLookupCachePass;
ModulePass *ClassMethodInliner;
FunctionPass *GNUNonfragileIvarPass;
@ -16,14 +16,14 @@ namespace
public:
static char ID;
ObjectiveCOpts() : ModulePass(ID) {
IMPCachePass = createClassIMPCachePass();
ClassIMPCachePass = createClassIMPCachePass();
ClassLookupCachePass = createClassLookupCachePass();
ClassMethodInliner = createClassMethodInliner();
GNUNonfragileIvarPass = createGNUNonfragileIvarPass();
GNULoopIMPCachePass = createGNULoopIMPCachePass();
}
virtual ~ObjectiveCOpts() {
delete IMPCachePass;
delete ClassIMPCachePass;
delete ClassMethodInliner;
delete ClassLookupCachePass;
delete GNULoopIMPCachePass;
@ -32,7 +32,7 @@ namespace
virtual bool runOnModule(Module &Mod) {
bool modified;
modified = IMPCachePass->runOnModule(Mod);
modified = ClassIMPCachePass->runOnModule(Mod);
modified |= ClassLookupCachePass->runOnModule(Mod);
modified |= ClassMethodInliner->runOnModule(Mod);
@ -51,4 +51,11 @@ namespace
char ObjectiveCOpts::ID = 0;
RegisterPass<ObjectiveCOpts> X("gnu-objc",
"Run all of the GNUstep Objective-C runtimm optimisations");
}
unsigned char GNUstep::ClassIMPCacheID;
unsigned char GNUstep::ClassMethodInlinerID;
unsigned char GNUstep::ClassLookupCacheID;
unsigned char GNUstep::LoopIMPCacheID;
unsigned char GNUstep::NonfragileIvarID;

@ -5,3 +5,11 @@ llvm::FunctionPass *createGNUNonfragileIvarPass(void);
llvm::FunctionPass *createGNULoopIMPCachePass(void);
llvm::ModulePass *createTypeFeedbackPass(void);
llvm::ModulePass *createTypeFeedbackDrivenInlinerPass(void);
namespace GNUstep {
extern unsigned char ClassIMPCacheID;
extern unsigned char ClassMethodInlinerID;
extern unsigned char ClassLookupCacheID;
extern unsigned char LoopIMPCacheID;
extern unsigned char NonfragileIvarID;
}

Loading…
Cancel
Save