Added unfinished inliner that uses type feedback info to inline instance methods.

Made class method inliner also inline message sends to super.

Various updates caused by clang now attaching more sensible metadata to the IR.
main
theraven 16 years ago
parent 160d1ce829
commit 6a58d3d49d

@ -1,9 +1,11 @@
#include "llvm/Pass.h"
#include "llvm/Function.h"
#include "llvm/Module.h"
#include "llvm/LLVMContext.h"
#include "llvm/Instructions.h"
#include "llvm/Constants.h"
#include "llvm/GlobalVariable.h"
#include "llvm/Support/CallSite.h"
#include "llvm/Support/IRBuilder.h"
#include "llvm/Analysis/LoopInfo.h"
#include "IMPCacher.h"
@ -28,53 +30,43 @@ namespace
IntTy = Type::getInt32Ty(M.getContext());
bool modified = false;
unsigned MessageSendMDKind = M.getContext().getMDKindID("GNUObjCMessageSend");
for (Module::iterator F=M.begin(), fend=M.end() ;
F != fend ; ++F) {
if (F->isDeclaration()) { continue; }
SmallVector<CallInst*, 16> Lookups;
SmallVector<std::pair<CallSite, bool>, 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();
CallSite call = CallSite::get(b);
if (call.getInstruction()) {
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") {
modified = true;
Lookups.push_back(call);
}
}
MDNode *messageType =
call.getInstruction()->getMetadata(MessageSendMDKind);
if (0 == messageType) { continue; }
if (cast<ConstantInt>(messageType->getOperand(2))->isOne()) {
Lookups.push_back(std::pair<CallSite, bool>(call, false));
}
} else if (func->getName() == "objc_slot_lookup_super") {
Lookups.push_back(std::pair<CallSite, bool>(call, true));
}
}
}
}
}
IRBuilder<> B = IRBuilder<>(entry);
for (SmallVectorImpl<CallInst*>::iterator i=Lookups.begin(),
e=Lookups.end() ; e!=i ; i++) {
const Type *SlotPtrTy = (*i)->getType();
for (SmallVectorImpl<std::pair<CallSite, bool> >::iterator
i=Lookups.begin(), e=Lookups.end() ; e!=i ; i++) {
Instruction *call = i->first.getInstruction();
const Type *SlotPtrTy = call->getType();
Value *slot = new GlobalVariable(M, SlotPtrTy, false,
GlobalValue::PrivateLinkage, Constant::getNullValue(SlotPtrTy),
@ -82,7 +74,7 @@ namespace
Value *version = new GlobalVariable(M, IntTy, false,
GlobalValue::PrivateLinkage, Constant::getNullValue(IntTy),
"version");
cacher.CacheLookup(*i, slot, version);
cacher.CacheLookup(call, slot, version, i->second);
}
}
return modified;

@ -2,6 +2,7 @@
#include "llvm/Function.h"
#include "llvm/Module.h"
#include "llvm/Instructions.h"
#include "llvm/Support/CallSite.h"
#include "llvm/Constants.h"
#include "llvm/LLVMContext.h"
#include "llvm/GlobalVariable.h"
@ -47,41 +48,38 @@ namespace
for (Module::iterator F=M.begin(), fend=M.end() ;
F != fend ; ++F) {
SmallVector<CallInst*, 16> messages;
SmallVector<CallSite, 16> messages;
if (F->isDeclaration()) { continue; }
SmallVector<CallInst*, 16> Lookups;
for (Function::iterator i=F->begin(), end=F->end() ;
i != end ; ++i) {
for (BasicBlock::iterator b=i->begin(), last=i->end() ;
b != last ; ++b) {
// FIXME: InvokeInst
if (CallInst *call = dyn_cast<CallInst>(b)) {
Instruction *callee =
dyn_cast<Instruction>(call->getCalledValue()->stripPointerCasts());
if (0 == callee) { continue; }
MDNode *messageType = callee->getMetadata(MessageSendMDKind);
CallSite call = CallSite::get(b);
if (call.getInstruction()) {
MDNode *messageType = call->getMetadata(MessageSendMDKind);
if (0 == messageType) { continue; }
messages.push_back(call);
}
}
}
for (SmallVectorImpl<CallInst*>::iterator i=messages.begin(),
for (SmallVectorImpl<CallSite>::iterator i=messages.begin(),
e=messages.end() ; e!=i ; i++) {
Instruction *callee =
dyn_cast<Instruction>((*i)->getCalledValue()->stripPointerCasts());
MDNode *messageType = callee->getMetadata(MessageSendMDKind);
StringRef sel = cast<MDString>(messageType->getOperand(0))->getString();
StringRef cls = cast<MDString>(messageType->getOperand(1))->getString();
StringRef functionName = SymbolNameForMethod(cls, "", sel, true);
MDNode *messageType = (*i)->getMetadata(MessageSendMDKind);
StringRef sel =
cast<MDString>(messageType->getOperand(0))->getString();
StringRef cls =
cast<MDString>(messageType->getOperand(1))->getString();
bool isClassMethod =
cast<ConstantInt>(messageType->getOperand(2))->isOne();
StringRef functionName = SymbolNameForMethod(cls, "", sel, isClassMethod);
Function *method = M.getFunction(functionName);
if (0 == method || method->isDeclaration()) { continue; }
cacher.SpeculativelyInline(*i, method);
cacher.SpeculativelyInline((*i).getInstruction(), method);
}
}
return modified;

@ -23,8 +23,8 @@ GNUstep::IMPCacher::IMPCacher(LLVMContext &C, Pass *owner) : Context(C),
IMPCacheFlagKind = Context.getMDKindID("IMPCache");
}
void GNUstep::IMPCacher::CacheLookup(CallInst *lookup, Value *slot, Value
*version) {
void GNUstep::IMPCacher::CacheLookup(Instruction *lookup, Value *slot, Value
*version, bool isSuperMessage) {
// If this IMP is already cached, don't cache it again.
if (lookup->getMetadata(IMPCacheFlagKind)) { return; }
@ -44,7 +44,10 @@ void GNUstep::IMPCacher::CacheLookup(CallInst *lookup, Value *slot, Value
Value *slotValue = B.CreateLoad(slot);
Value *versionValue = B.CreateLoad(version);
Value *receiverPtr = lookup->getOperand(1);
Value *receiver = B.CreateLoad(receiverPtr);
Value *receiver = receiverPtr;
if (!isSuperMessage) {
receiver = B.CreateLoad(receiverPtr);
}
Value *isCacheEmpty =
B.CreateOr(versionValue, B.CreatePtrToInt(slotValue, IntTy));
@ -83,7 +86,10 @@ void GNUstep::IMPCacher::CacheLookup(CallInst *lookup, Value *slot, Value
// Perform the real lookup and cache the result
removeTerminator(lookupBB);
B.SetInsertPoint(lookupBB);
Value * newReceiver = B.CreateLoad(receiverPtr);
Value * newReceiver = receiver;
if (!isSuperMessage) {
newReceiver = B.CreateLoad(receiverPtr);
}
BasicBlock *storeCacheBB = BasicBlock::Create(Context, "cache_store",
lookupBB->getParent());
@ -122,19 +128,40 @@ void GNUstep::IMPCacher::SpeculativelyInline(Instruction *call, Function
// function
IRBuilder<> B = IRBuilder<>(beforeCallBB);
Value *callee = call->getOperand(0);
if (callee->getType() != function->getType()) {
const FunctionType *FTy = function->getFunctionType();
const FunctionType *calleeTy = cast<FunctionType>(
cast<PointerType>(callee->getType())->getElementType());
if (calleeTy != FTy) {
callee = B.CreateBitCast(callee, function->getType());
}
Value *isInlineValid = B.CreateICmpEQ(callee, function);
B.CreateCondBr(isInlineValid, inlineBB, callBB);
// In the inline BB, add a copy of the call, but this time calling the real
// version.
Instruction *inlineCall = call->clone();
Value *inlineResult= inlineCall;
inlineBB->getInstList().push_back(inlineCall);
inlineCall->setOperand(0, function);
B.SetInsertPoint(inlineBB);
if (calleeTy != FTy) {
for (unsigned i=0 ; i<FTy->getNumParams() ; i++) {
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));
}
}
if (FTy->getReturnType() != calleeTy->getReturnType()) {
inlineResult = new BitCastInst(inlineCall, calleeTy->getReturnType(), "", inlineBB);
}
}
B.CreateBr(afterCallBB);
// Unify the return values
@ -143,7 +170,7 @@ void GNUstep::IMPCacher::SpeculativelyInline(Instruction *call, Function
PHINode *phi = B.CreatePHI(call->getType());
call->replaceAllUsesWith(phi);
phi->addIncoming(call, callBB);
phi->addIncoming(inlineCall, inlineBB);
phi->addIncoming(inlineResult, inlineBB);
}
// Really do the real inlining

@ -28,7 +28,8 @@ namespace GNUstep
const IntegerType *IntTy;
public:
IMPCacher(LLVMContext &C, Pass *owner);
void CacheLookup(CallInst *lookup, Value *slot, Value *version);
void CacheLookup(Instruction *lookup, Value *slot, Value *version, bool
isSuperMessage=false);
void SpeculativelyInline(Instruction *call, Function *function);
};

@ -75,7 +75,6 @@ namespace {
Zeros[1] = Zeros[0];
moduleName = ConstantExpr::getGetElementPtr(moduleName, Zeros, 2);
moduleName->dump();
functions.push_back(moduleName);;
functions.push_back(moduleName);;
@ -117,8 +116,7 @@ namespace {
ConstantArray *CA = cast<ConstantArray>(GCL->getInitializer());
for (User::op_iterator i = CA->op_begin(), e = CA->op_end(); i != e; ++i) {
ConstantStruct *CS = cast<ConstantStruct>(*i);
ctors.push_back(dyn_cast<Function>(CS->getOperand(1)));
ctors.push_back(cast<ConstantStruct>(*i));
}
// Type of one ctor
@ -139,7 +137,6 @@ namespace {
NGV->takeName(GCL);
GCL->replaceAllUsesWith(NGV);
GCL->eraseFromParent();
M.dump();
return true;
}

@ -0,0 +1,150 @@
#include "llvm/Constants.h"
#include "llvm/Pass.h"
#include "llvm/Module.h"
#include "llvm/Function.h"
#include "llvm/Instructions.h"
#include "llvm/Support/IRBuilder.h"
#include "llvm/Linker.h"
#include <vector>
using namespace llvm;
namespace {
struct GNUObjCTypeFeedbackDrivenInliner : public ModulePass {
typedef std::pair<CallInst*,CallInst*> callPair;
typedef std::vector<callPair > replacementVector;
static char ID;
uint32_t callsiteCount;
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:
virtual bool runOnModule(Module &M)
{
LLVMContext &VMContext = M.getContext();
Int32Ty = IntegerType::get(VMContext, 32);
const PointerType *PtrTy = Type::getInt8PtrTy(VMContext);
Constant *moduleName =
ConstantArray::get(VMContext, M.getModuleIdentifier(), true);
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 =
llvm::ConstantArray::get(VMContext, F->getName());
ConstStr = new GlobalVariable(M, ConstStr->getType(), true,
GlobalValue::PrivateLinkage, ConstStr, "str");
functions.push_back(
ConstantExpr::getGetElementPtr(ConstStr, Zeros, 2));
profileFunction(*F, moduleName);
}
functions.push_back(ConstantPointerNull::get(PtrTy));
Constant *symtab = ConstantArray::get(ArrayType::get(PtrTy,
functions.size()), functions);
Value *symbolTable = new GlobalVariable(M, symtab->getType(), true,
GlobalValue::InternalLinkage, symtab, "symtab");
Function *init =
Function::Create(FunctionType::get(Type::getVoidTy(VMContext), false),
GlobalValue::PrivateLinkage, "load_symbol_table", &M);
BasicBlock * EntryBB = BasicBlock::Create(VMContext, "entry", init);
IRBuilder<> B = IRBuilder<>(EntryBB);
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));
}
// Type of one ctor
const Type *ctorTy =
cast<ArrayType>(GCL->getType()->getElementType())->getElementType();
// Add the
std::vector<Constant*> CSVals;
CSVals.push_back(ConstantInt::get(Type::getInt32Ty(VMContext),65535));
CSVals.push_back(init);
ctors.push_back(ConstantStruct::get(GCL->getContext(), CSVals, false));
// Create the array initializer.
CA = cast<ConstantArray>(ConstantArray::get(ArrayType::get(ctorTy,
ctors.size()), ctors));
// Create the new global and replace the old one
GlobalVariable *NGV = new GlobalVariable(CA->getType(),
GCL->isConstant(), GCL->getLinkage(), CA, "", GCL->isThreadLocal());
GCL->getParent()->getGlobalList().insert(GCL, NGV);
NGV->takeName(GCL);
GCL->replaceAllUsesWith(NGV);
GCL->eraseFromParent();
return true;
}
};
char GNUObjCTypeFeedbackDrivenInliner::ID = 0;
RegisterPass<GNUObjCTypeFeedbackDrivenInliner> X("gnu-objc-feedback-driven-inline",
"Objective-C type feedback-driven inliner for the GNU runtime.", false,
true);
}
Loading…
Cancel
Save