Factored out code that performs IMP caching into a separate class. This can now be used by other passes that cache IMPs outside of loops (for example, always caching class messages because they always have the same receiver).
parent
1918888ce1
commit
dfc4a0286b
@ -0,0 +1,76 @@
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Function.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Instructions.h"
|
||||
#include "llvm/GlobalAlias.h"
|
||||
#include "llvm/GlobalVariable.h"
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/Support/IRBuilder.h"
|
||||
#include "llvm/Analysis/LoopInfo.h"
|
||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
||||
#include "IMPCacher.h"
|
||||
|
||||
void GNUstep::IMPCacher::CacheLookup(CallInst *lookup, Value *slot, Value
|
||||
*version) {
|
||||
|
||||
BasicBlock *beforeLookupBB = lookup->getParent();
|
||||
BasicBlock *lookupBB = SplitBlock(beforeLookupBB, lookup, Owner);
|
||||
BasicBlock::iterator iter = lookup;
|
||||
iter++;
|
||||
BasicBlock *afterLookupBB = SplitBlock(iter->getParent(), iter, Owner);
|
||||
|
||||
beforeLookupBB->getTerminator()->removeFromParent();
|
||||
|
||||
IRBuilder<> B = IRBuilder<>(beforeLookupBB);
|
||||
// Load the slot and check that neither it nor the version is 0.
|
||||
Value *slotValue = B.CreateLoad(slot);
|
||||
Value *versionValue = B.CreateLoad(version);
|
||||
Value *receiver = lookup->getOperand(1);
|
||||
|
||||
Value *isCacheEmpty =
|
||||
B.CreateOr(versionValue, B.CreatePtrToInt(slotValue, IntTy));
|
||||
isCacheEmpty =
|
||||
B.CreateICmpEQ(isCacheEmpty, Constant::getNullValue(IntTy));
|
||||
Value *receiverNotNil =
|
||||
B.CreateICmpNE(receiver, Constant::getNullValue(receiver->getType()));
|
||||
isCacheEmpty = B.CreateAnd(isCacheEmpty, receiverNotNil);
|
||||
|
||||
BasicBlock *cacheLookupBB = BasicBlock::Create(Context, "cache_check",
|
||||
lookupBB->getParent());
|
||||
|
||||
B.CreateCondBr(isCacheEmpty, lookupBB, cacheLookupBB);
|
||||
|
||||
// Check the cache node is current
|
||||
B.SetInsertPoint(cacheLookupBB);
|
||||
Value *slotVersion = B.CreateStructGEP(slotValue, 3);
|
||||
// Note: Volatile load because the slot version might have changed in
|
||||
// another thread.
|
||||
slotVersion = B.CreateLoad(slotVersion, true, "slot_version");
|
||||
Value *slotCachedFor = B.CreateStructGEP(slotValue, 1);
|
||||
slotCachedFor = B.CreateLoad(slotCachedFor, true, "slot_owner");
|
||||
Value *cls = B.CreateLoad(B.CreateBitCast(receiver, IdTy));
|
||||
Value *isVersionCorrect = B.CreateICmpEQ(slotVersion, versionValue);
|
||||
Value *isOwnerCorrect = B.CreateICmpEQ(slotCachedFor, cls);
|
||||
Value *isSlotValid = B.CreateAnd(isVersionCorrect, isOwnerCorrect);
|
||||
// If this slot is still valid, skip the lookup.
|
||||
B.CreateCondBr(isSlotValid, afterLookupBB, lookupBB);
|
||||
|
||||
// Replace the looked up slot with the loaded one
|
||||
B.SetInsertPoint(afterLookupBB, afterLookupBB->begin());
|
||||
// Not volatile, so a redundant load elimination pass can do some phi
|
||||
// magic with this later.
|
||||
lookup->replaceAllUsesWith(B.CreateLoad(slot));
|
||||
|
||||
// Perform the real lookup and cache the result
|
||||
lookupBB->getTerminator()->removeFromParent();
|
||||
B.SetInsertPoint(lookupBB);
|
||||
// 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);
|
||||
cls = B.CreateLoad(B.CreateBitCast(receiver, IdTy));
|
||||
B.CreateStore(cls, B.CreateStructGEP(lookup, 1));
|
||||
B.CreateBr(afterLookupBB);
|
||||
}
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
namespace llvm
|
||||
{
|
||||
class LLVMContext;
|
||||
class Pass;
|
||||
class PointerType;
|
||||
class IntegerType;
|
||||
class CallInst;
|
||||
}
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace GNUstep
|
||||
{
|
||||
class IMPCacher
|
||||
{
|
||||
private:
|
||||
LLVMContext &Context;
|
||||
Pass *Owner;
|
||||
const PointerType *PtrTy;
|
||||
const PointerType *IdTy;
|
||||
const IntegerType *IntTy;
|
||||
public:
|
||||
IMPCacher(LLVMContext &C, Pass *owner) : Context(C), Owner(owner) {
|
||||
PtrTy = Type::getInt8PtrTy(Context);
|
||||
// FIXME: 64-bit.
|
||||
IntTy = Type::getInt32Ty(Context);
|
||||
IdTy = PointerType::getUnqual(PtrTy);
|
||||
}
|
||||
void CacheLookup(CallInst *lookup, Value *slot, Value *version);
|
||||
};
|
||||
}
|
||||
Loading…
Reference in New Issue