mirror of
https://github.com/darlinghq/darling-libobjc2.git
synced 2024-11-27 06:00:30 +00:00
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.
This commit is contained in:
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;
|
||||
}
|
||||
|
150
opts/TypeFeedbackDrivenInliner.cpp
Normal file
150
opts/TypeFeedbackDrivenInliner.cpp
Normal file
@ -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…
Reference in New Issue
Block a user