diff --git a/opts/ClassIMPCache.cpp b/opts/ClassIMPCache.cpp index 493e969..d99e371 100644 --- a/opts/ClassIMPCache.cpp +++ b/opts/ClassIMPCache.cpp @@ -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"); diff --git a/opts/ClassLookupCache.cpp b/opts/ClassLookupCache.cpp index 6068357..fe9348e 100644 --- a/opts/ClassLookupCache.cpp +++ b/opts/ClassLookupCache.cpp @@ -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 #include "IMPCacher.h" @@ -41,6 +43,7 @@ namespace bool runOnFunction(Function &F) { bool modified = false; + return false; SmallVector Lookups; for (Function::iterator i=F.begin(), end=F.end() ; @@ -145,6 +148,14 @@ namespace char ClassLookupCachePass::ID = 0; RegisterPass X("gnu-class-lookup-cache", "Cache class lookups"); +#if LLVM_MAJOR > 2 + StandardPass::RegisterStandardPass D( + StandardPass::Module, &LoopIMPCacheID, + StandardPass::OptimzationFlags(1), &ClassLookupCacheID); + StandardPass::RegisterStandardPass L(StandardPass::LTO, + &LoopIMPCacheID, StandardPass::OptimzationFlags(0), + &ClassLookupCacheID); +#endif } ModulePass *createClassLookupCachePass(void) diff --git a/opts/ClassMethodInliner.cpp b/opts/ClassMethodInliner.cpp index f5e33ef..5a45278 100644 --- a/opts/ClassMethodInliner.cpp +++ b/opts/ClassMethodInliner.cpp @@ -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 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 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 X("gnu-class-method-inline", "Inline class methods and message sends to super"); +#if LLVM_MAJOR > 2 + StandardPass::RegisterStandardPass D( + StandardPass::Module, &ClassLookupCacheID, + StandardPass::OptimzationFlags(1), &ClassMethodInlinerID); + StandardPass::RegisterStandardPass L(StandardPass::LTO, + &ClassLookupCacheID, StandardPass::OptimzationFlags(0), + &ClassMethodInlinerID); +#endif } ModulePass *createClassMethodInliner(void) diff --git a/opts/IMPCacher.cpp b/opts/IMPCacher.cpp index 0638eb3..527e44f 100644 --- a/opts/IMPCacher.cpp +++ b/opts/IMPCacher.cpp @@ -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(call) ? cast(call)->getCalledValue() + : cast(call)->getCalledValue(); const FunctionType *FTy = function->getFunctionType(); const FunctionType *calleeTy = cast( @@ -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(inlineCall)) { + c->setCalledFunction(function); InlineFunction(c, IFI); } else if (InvokeInst *c = dyn_cast(inlineCall)) { + c->setCalledFunction(function); InlineFunction(c, IFI); } } diff --git a/opts/IvarPass.cpp b/opts/IvarPass.cpp index 8d0c694..c61772b 100644 --- a/opts/IvarPass.cpp +++ b/opts/IvarPass.cpp @@ -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 +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( - cast(ClsStruct->getOperand(1))->getOperand(0)); + User *super = cast(ClsStruct->getOperand(1)); + if (isa(super)) return ""; + GlobalVariable *name = cast(super->getOperand(0)); return cast(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(ivars->getOperand(i)); GlobalVariable *name = cast( - cast(ivar->getOperand(0))->getOperand(0)); + cast(ivar->getOperand(0))->getOperand(0)); std::string ivarNameStr = cast(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 Replacement; + llvm::SmallVector 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(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::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 X("gnu-nonfragile-ivar", "Ivar fragility pass"); +#if LLVM_MAJOR > 2 + StandardPass::RegisterStandardPass D( + StandardPass::Module, &DefaultStandardPasses::LoopUnrollID, + StandardPass::OptimzationFlags(1), &NonfragileIvarID); + StandardPass::RegisterStandardPass L(StandardPass::LTO, + &DefaultStandardPasses::JumpThreadingID, + StandardPass::OptimzationFlags(0), &NonfragileIvarID); +#endif } FunctionPass *createGNUNonfragileIvarPass(void) diff --git a/opts/LoopIMPCachePass.cpp b/opts/LoopIMPCachePass.cpp index 3d4cfa0..43b101f 100644 --- a/opts/LoopIMPCachePass.cpp +++ b/opts/LoopIMPCachePass.cpp @@ -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 +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 X("gnu-loop-imp-cache", "Cache IMPs in loops pass"); +#if LLVM_MAJOR > 2 + StandardPass::RegisterStandardPass D( + StandardPass::Module, &NonfragileIvarID, + StandardPass::OptimzationFlags(1), &LoopIMPCacheID); + StandardPass::RegisterStandardPass L(StandardPass::LTO, + &NonfragileIvarID, StandardPass::OptimzationFlags(0), + &LoopIMPCacheID); +#endif } FunctionPass *createGNULoopIMPCachePass(void) diff --git a/opts/ObjectiveCOpts.cpp b/opts/ObjectiveCOpts.cpp index 0adbb02..bd82276 100644 --- a/opts/ObjectiveCOpts.cpp +++ b/opts/ObjectiveCOpts.cpp @@ -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 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; diff --git a/opts/ObjectiveCOpts.h b/opts/ObjectiveCOpts.h index c90452d..332e914 100644 --- a/opts/ObjectiveCOpts.h +++ b/opts/ObjectiveCOpts.h @@ -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; +}