|
|
|
@ -4,10 +4,14 @@
|
|
|
|
#include "llvm/Function.h"
|
|
|
|
#include "llvm/Function.h"
|
|
|
|
#include "llvm/Instructions.h"
|
|
|
|
#include "llvm/Instructions.h"
|
|
|
|
#include "llvm/Support/IRBuilder.h"
|
|
|
|
#include "llvm/Support/IRBuilder.h"
|
|
|
|
|
|
|
|
#include "llvm/Analysis/InlineCost.h"
|
|
|
|
|
|
|
|
#include "llvm/ADT/SmallPtrSet.h"
|
|
|
|
#include "llvm/Linker.h"
|
|
|
|
#include "llvm/Linker.h"
|
|
|
|
#include <vector>
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
#include "TypeInfoProvider.h"
|
|
|
|
|
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
using namespace GNUstep;
|
|
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
namespace {
|
|
|
|
struct GNUObjCTypeFeedbackDrivenInliner : public ModulePass {
|
|
|
|
struct GNUObjCTypeFeedbackDrivenInliner : public ModulePass {
|
|
|
|
@ -17,127 +21,65 @@ namespace {
|
|
|
|
static char ID;
|
|
|
|
static char ID;
|
|
|
|
uint32_t callsiteCount;
|
|
|
|
uint32_t callsiteCount;
|
|
|
|
const IntegerType *Int32Ty;
|
|
|
|
const IntegerType *Int32Ty;
|
|
|
|
GNUObjCTypeFeedbackDrivenInliner() : ModulePass(&ID), callsiteCount(0) {}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void profileFunction(Function &F, Constant *ModuleID) {
|
|
|
|
|
|
|
|
for (Function::iterator i=F.begin(), e=F.end() ;
|
|
|
|
|
|
|
|
i != e ; ++i) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
replacementVector replacements;
|
|
|
|
|
|
|
|
for (BasicBlock::iterator b=i->begin(), last=i->end() ;
|
|
|
|
|
|
|
|
b != last ; ++b) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Module *M = F.getParent();
|
|
|
|
|
|
|
|
if (CallInst *call = dyn_cast<CallInst>(b)) {
|
|
|
|
|
|
|
|
if (Function *callee = call->getCalledFunction()) {
|
|
|
|
|
|
|
|
if (callee->getName() == "objc_msg_lookup_sender") {
|
|
|
|
|
|
|
|
llvm::Value *args[] = { call->getOperand(1),
|
|
|
|
|
|
|
|
call->getOperand(2), call->getOperand(3),
|
|
|
|
|
|
|
|
ModuleID, ConstantInt::get(Int32Ty,
|
|
|
|
|
|
|
|
callsiteCount++) };
|
|
|
|
|
|
|
|
Function *profile = cast<Function>(
|
|
|
|
|
|
|
|
M->getOrInsertFunction("objc_msg_lookup_profile",
|
|
|
|
|
|
|
|
callee->getFunctionType()->getReturnType(),
|
|
|
|
|
|
|
|
args[0]->getType(), args[1]->getType(),
|
|
|
|
|
|
|
|
args[2]->getType(),
|
|
|
|
|
|
|
|
ModuleID->getType(), Int32Ty, NULL));
|
|
|
|
|
|
|
|
llvm::CallInst *profileCall =
|
|
|
|
|
|
|
|
CallInst::Create(profile, args, args+5, "", call);
|
|
|
|
|
|
|
|
replacements.push_back(callPair(call, profileCall));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
for (replacementVector::iterator r=replacements.begin(),
|
|
|
|
|
|
|
|
e=replacements.end() ; e!=r ; r++) {
|
|
|
|
|
|
|
|
r->first->replaceAllUsesWith(r->second);
|
|
|
|
|
|
|
|
r->second->getParent()->getInstList().erase(r->first);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
public:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
GNUObjCTypeFeedbackDrivenInliner() : ModulePass(&ID), callsiteCount(0) {}
|
|
|
|
|
|
|
|
|
|
|
|
virtual bool runOnModule(Module &M)
|
|
|
|
virtual bool runOnModule(Module &M)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
bool modified = false;
|
|
|
|
LLVMContext &VMContext = M.getContext();
|
|
|
|
LLVMContext &VMContext = M.getContext();
|
|
|
|
Int32Ty = IntegerType::get(VMContext, 32);
|
|
|
|
Int32Ty = IntegerType::get(VMContext, 32);
|
|
|
|
const PointerType *PtrTy = Type::getInt8PtrTy(VMContext);
|
|
|
|
TypeInfoProvider::CallSiteMap *SiteMap =
|
|
|
|
Constant *moduleName =
|
|
|
|
TypeInfoProvider::SharedTypeInfoProvider()->getCallSitesForModule(M);
|
|
|
|
ConstantArray::get(VMContext, M.getModuleIdentifier(), true);
|
|
|
|
SmallPtrSet<const Function *, 16> NeverInline;
|
|
|
|
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 =
|
|
|
|
//TypeInfoProvider::SharedTypeInfoProvider()->PrintStatistics();
|
|
|
|
llvm::ConstantArray::get(VMContext, F->getName());
|
|
|
|
GNUstep::IMPCacher cacher = GNUstep::IMPCacher(M.getContext(), this);
|
|
|
|
ConstStr = new GlobalVariable(M, ConstStr->getType(), true,
|
|
|
|
InlineCostAnalyzer CA;
|
|
|
|
GlobalValue::PrivateLinkage, ConstStr, "str");
|
|
|
|
SmallVector<CallSite, 16> messages;
|
|
|
|
functions.push_back(
|
|
|
|
|
|
|
|
ConstantExpr::getGetElementPtr(ConstStr, Zeros, 2));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
profileFunction(*F, moduleName);
|
|
|
|
for (Module::iterator F=M.begin(), fend=M.end() ;
|
|
|
|
}
|
|
|
|
F != fend ; ++F) {
|
|
|
|
functions.push_back(ConstantPointerNull::get(PtrTy));
|
|
|
|
|
|
|
|
Constant *symtab = ConstantArray::get(ArrayType::get(PtrTy,
|
|
|
|
|
|
|
|
functions.size()), functions);
|
|
|
|
if (F->isDeclaration()) { continue; }
|
|
|
|
Value *symbolTable = new GlobalVariable(M, symtab->getType(), true,
|
|
|
|
|
|
|
|
GlobalValue::InternalLinkage, symtab, "symtab");
|
|
|
|
for (Function::iterator i=F->begin(), end=F->end() ;
|
|
|
|
|
|
|
|
i != end ; ++i) {
|
|
|
|
Function *init =
|
|
|
|
for (BasicBlock::iterator b=i->begin(), last=i->end() ;
|
|
|
|
Function::Create(FunctionType::get(Type::getVoidTy(VMContext), false),
|
|
|
|
b != last ; ++b) {
|
|
|
|
GlobalValue::PrivateLinkage, "load_symbol_table", &M);
|
|
|
|
CallSite call = CallSite::get(b);
|
|
|
|
BasicBlock * EntryBB = BasicBlock::Create(VMContext, "entry", init);
|
|
|
|
if (call.getInstruction() && !call.getCalledFunction()) {
|
|
|
|
IRBuilder<> B = IRBuilder<>(EntryBB);
|
|
|
|
messages.push_back(call);
|
|
|
|
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));
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TypeInfoProvider::CallSiteMap::iterator Entry = SiteMap->begin();
|
|
|
|
|
|
|
|
|
|
|
|
// Type of one ctor
|
|
|
|
for (SmallVectorImpl<CallSite>::iterator i=messages.begin(),
|
|
|
|
const Type *ctorTy =
|
|
|
|
e=messages.end() ; e!=i ; ++i, ++Entry) {
|
|
|
|
cast<ArrayType>(GCL->getType()->getElementType())->getElementType();
|
|
|
|
|
|
|
|
// Add the
|
|
|
|
if (Entry->size() == 1) {
|
|
|
|
std::vector<Constant*> CSVals;
|
|
|
|
|
|
|
|
CSVals.push_back(ConstantInt::get(Type::getInt32Ty(VMContext),65535));
|
|
|
|
TypeInfoProvider::CallSiteEntry::iterator iterator = Entry->begin();
|
|
|
|
CSVals.push_back(init);
|
|
|
|
Function *method = M.getFunction(Entry->begin()->getKey());
|
|
|
|
ctors.push_back(ConstantStruct::get(GCL->getContext(), CSVals, false));
|
|
|
|
if (0 == method || method->isDeclaration()) { continue; }
|
|
|
|
// Create the array initializer.
|
|
|
|
|
|
|
|
CA = cast<ConstantArray>(ConstantArray::get(ArrayType::get(ctorTy,
|
|
|
|
InlineCost IC = CA.getInlineCost((*i), method, NeverInline);
|
|
|
|
ctors.size()), ctors));
|
|
|
|
// FIXME: 200 is a random number. Pick a better one!
|
|
|
|
// Create the new global and replace the old one
|
|
|
|
if (IC.isAlways() || (IC.isVariable() && IC.getValue() < 200)) {
|
|
|
|
GlobalVariable *NGV = new GlobalVariable(CA->getType(),
|
|
|
|
cacher.SpeculativelyInline((*i).getInstruction(), method);
|
|
|
|
GCL->isConstant(), GCL->getLinkage(), CA, "", GCL->isThreadLocal());
|
|
|
|
modified = true;
|
|
|
|
GCL->getParent()->getGlobalList().insert(GCL, NGV);
|
|
|
|
}
|
|
|
|
NGV->takeName(GCL);
|
|
|
|
}
|
|
|
|
GCL->replaceAllUsesWith(NGV);
|
|
|
|
// FIXME: Inline the most popular call if one is much more popular
|
|
|
|
GCL->eraseFromParent();
|
|
|
|
// than the others.
|
|
|
|
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
return modified;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|