@ -40,21 +40,39 @@ void GNUstep::IMPCacher::CacheLookup(Instruction *lookup, Value *slot, Value
removeTerminator ( beforeLookupBB ) ;
removeTerminator ( beforeLookupBB ) ;
IRBuilder< > B = IRBuilder < > ( beforeLookupBB ) ;
CGBuilder B = CGBuilder ( beforeLookupBB ) ;
// Load the slot and check that neither it nor the version is 0.
// Load the slot and check that neither it nor the version is 0.
Value * slotValue = B . CreateLoad ( slot ) ;
Value * versionValue = B . CreateLoad ( version ) ;
Value * versionValue = B . CreateLoad ( version ) ;
Value * receiverPtr = lookup - > getOperand ( 0 ) ;
Value * receiverPtr = lookup - > getOperand ( 0 ) ;
Value * receiver = receiverPtr ;
Value * receiver = receiverPtr ;
if ( ! isSuperMessage ) {
if ( ! isSuperMessage ) {
receiver = B . CreateLoad ( receiverPtr ) ;
receiver = B . CreateLoad ( receiverPtr ) ;
}
}
// For small objects, we skip the cache entirely.
// FIXME: Class messages are never to small objects...
bool is64Bit = llvm : : Module : : Pointer64 = =
B . GetInsertBlock ( ) - > getParent ( ) - > getParent ( ) - > getPointerSize ( ) ;
LLVMType * intPtrTy = is64Bit ? Type : : getInt64Ty ( Context ) :
Type : : getInt32Ty ( Context ) ;
// Receiver as an integer
Value * receiverSmallObject = B . CreatePtrToInt ( receiver , intPtrTy ) ;
// Receiver is a small object...
receiverSmallObject =
B . CreateAnd ( receiverSmallObject , is64Bit ? 7 : 1 ) ;
// Receiver is not a small object.
receiverSmallObject =
B . CreateICmpNE ( receiverSmallObject , Constant : : getNullValue ( intPtrTy ) ) ;
// Ideally, we'd call objc_msgSend() here, but for now just skip the cache
// lookup
Value * isCacheEmpty =
Value * isCacheEmpty =
B . CreateICmpEQ ( versionValue , Constant : : getNullValue ( IntTy ) ) ;
B . CreateICmpEQ ( versionValue , Constant : : getNullValue ( IntTy ) ) ;
Value * receiverNotNil =
Value * receiverNil =
B . CreateICmpNE ( receiver , Constant : : getNullValue ( receiver - > getType ( ) ) ) ;
B . CreateICmpEQ ( receiver , Constant : : getNullValue ( receiver - > getType ( ) ) ) ;
isCacheEmpty = B . CreateAnd ( isCacheEmpty , receiverNotNil ) ;
isCacheEmpty = B . CreateOr ( isCacheEmpty , receiverNil ) ;
isCacheEmpty = B . CreateOr ( isCacheEmpty , receiverSmallObject ) ;
BasicBlock * cacheLookupBB = BasicBlock : : Create ( Context , " cache_check " ,
BasicBlock * cacheLookupBB = BasicBlock : : Create ( Context , " cache_check " ,
lookupBB - > getParent ( ) ) ;
lookupBB - > getParent ( ) ) ;
@ -63,6 +81,7 @@ void GNUstep::IMPCacher::CacheLookup(Instruction *lookup, Value *slot, Value
// Check the cache node is current
// Check the cache node is current
B . SetInsertPoint ( cacheLookupBB ) ;
B . SetInsertPoint ( cacheLookupBB ) ;
Value * slotValue = B . CreateLoad ( slot , " slot_value " ) ;
Value * slotVersion = B . CreateStructGEP ( slotValue , 3 ) ;
Value * slotVersion = B . CreateStructGEP ( slotValue , 3 ) ;
// Note: Volatile load because the slot version might have changed in
// Note: Volatile load because the slot version might have changed in
// another thread.
// another thread.
@ -76,14 +95,15 @@ void GNUstep::IMPCacher::CacheLookup(Instruction *lookup, Value *slot, Value
// If this slot is still valid, skip the lookup.
// If this slot is still valid, skip the lookup.
B . CreateCondBr ( isSlotValid , afterLookupBB , lookupBB ) ;
B . CreateCondBr ( isSlotValid , afterLookupBB , lookupBB ) ;
// Perform the real lookup and cache the result
removeTerminator ( lookupBB ) ;
// Replace the looked up slot with the loaded one
// Replace the looked up slot with the loaded one
B . SetInsertPoint ( afterLookupBB , afterLookupBB - > begin ( ) ) ;
B . SetInsertPoint ( afterLookupBB , afterLookupBB - > begin ( ) ) ;
PHINode * newLookup = IRBuilderCreatePHI ( & B , lookup - > getType ( ) , 3 , " new_lookup " ) ;
// Not volatile, so a redundant load elimination pass can do some phi
// Not volatile, so a redundant load elimination pass can do some phi
// magic with this later.
// magic with this later.
lookup - > replaceAllUsesWith ( B. CreateLoad ( slot ) ) ;
lookup - > replaceAllUsesWith ( newLookup ) ;
// Perform the real lookup and cache the result
removeTerminator ( lookupBB ) ;
B . SetInsertPoint ( lookupBB ) ;
B . SetInsertPoint ( lookupBB ) ;
Value * newReceiver = receiver ;
Value * newReceiver = receiver ;
if ( ! isSuperMessage ) {
if ( ! isSuperMessage ) {
@ -93,18 +113,25 @@ void GNUstep::IMPCacher::CacheLookup(Instruction *lookup, Value *slot, Value
lookupBB - > getParent ( ) ) ;
lookupBB - > getParent ( ) ) ;
// Don't store the cached lookup if we are doing forwarding tricks.
// Don't store the cached lookup if we are doing forwarding tricks.
B . CreateCondBr ( B . CreateICmpEQ ( receiver , newReceiver ) , storeCacheBB ,
// Also skip caching small object messages for now
afterLookupBB ) ;
Value * skipCacheWrite =
B . CreateOr ( B . CreateICmpNE ( receiver , newReceiver ) , receiverSmallObject ) ;
skipCacheWrite = B . CreateOr ( skipCacheWrite , receiverNil ) ;
B . CreateCondBr ( skipCacheWrite , afterLookupBB , storeCacheBB ) ;
B . SetInsertPoint ( storeCacheBB ) ;
B . SetInsertPoint ( storeCacheBB ) ;
// Store it even if the version is 0, because we always check that the
// 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
// version is not 0 at the start and an occasional redundant store is
// probably better than a branch every time.
// probably better than a branch every time.
B . CreateStore ( lookup , slot ) ;
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 ) ) ;
cls = B . CreateLoad ( B . CreateBitCast ( receiver , IdTy ) ) ;
B . CreateStore ( cls , B . CreateStructGEP ( lookup , 1 ) ) ;
B . CreateStore ( cls , B . CreateStructGEP ( lookup , 1 ) ) ;
B . CreateBr ( afterLookupBB ) ;
B . CreateBr ( afterLookupBB ) ;
newLookup - > addIncoming ( lookup , lookupBB ) ;
newLookup - > addIncoming ( slotValue , cacheLookupBB ) ;
newLookup - > addIncoming ( lookup , storeCacheBB ) ;
}
}