[llvm-commits] [dragonegg] r95566 - /dragonegg/trunk/llvm-backend.cpp
Duncan Sands
baldrick at free.fr
Mon Feb 8 12:48:55 PST 2010
Author: baldrick
Date: Mon Feb 8 14:48:55 2010
New Revision: 95566
URL: http://llvm.org/viewvc/llvm-project?rev=95566&view=rev
Log:
Add support for covariant return thunks.
Modified:
dragonegg/trunk/llvm-backend.cpp
Modified: dragonegg/trunk/llvm-backend.cpp
URL: http://llvm.org/viewvc/llvm-project/dragonegg/trunk/llvm-backend.cpp?rev=95566&r1=95565&r2=95566&view=diff
==============================================================================
--- dragonegg/trunk/llvm-backend.cpp (original)
+++ dragonegg/trunk/llvm-backend.cpp Mon Feb 8 14:48:55 2010
@@ -1548,8 +1548,37 @@
pop_cfun ();
}
+/// ApplyVirtualOffset - Adjust 'this' by a virtual offset.
+static Value *ApplyVirtualOffset(Value *This, HOST_WIDE_INT virtual_value,
+ LLVMBuilder &Builder) {
+ LLVMContext &Context = getGlobalContext();
+ const Type *IntPtrTy = TheTarget->getTargetData()->getIntPtrType(Context);
+
+ // The vptr is always at offset zero in the object.
+ const Type *HandleTy = Type::getInt8PtrTy(Context)->getPointerTo();
+ Value *VPtr = Builder.CreateBitCast(This, HandleTy->getPointerTo());
+
+ // Form the vtable address.
+ Value *VTableAddr = Builder.CreateLoad(VPtr);
+
+ // Find the entry with the vcall offset.
+ VTableAddr = Builder.CreatePtrToInt(VTableAddr, IntPtrTy);
+ Value *VOffset = ConstantInt::get(IntPtrTy, virtual_value);
+ VTableAddr = Builder.CreateNSWAdd(VTableAddr, VOffset);
+ VTableAddr = Builder.CreateIntToPtr(VTableAddr, HandleTy);
+
+ // Get the offset itself.
+ Value *VCallOffset = Builder.CreateLoad(VTableAddr);
+ VCallOffset = Builder.CreatePtrToInt(VCallOffset, IntPtrTy);
+
+ // Adjust the 'this' pointer.
+ Value *Adjusted = Builder.CreatePtrToInt(This, IntPtrTy);
+ Adjusted = Builder.CreateNSWAdd(Adjusted, VCallOffset);
+ return Builder.CreateIntToPtr(Adjusted, This->getType());
+}
+
/// emit_thunk - Turn a thunk into LLVM IR.
-void emit_thunk(struct cgraph_node *node) {
+static void emit_thunk(struct cgraph_node *node) {
if (errorcount || sorrycount)
return; // Do not process broken code.
@@ -1559,13 +1588,22 @@
return;
}
- assert(node->thunk.this_adjusting && "covariant return thunks not done yet!");
+ // Mark the thunk as written so gcc doesn't waste time outputting it.
+ TREE_ASM_WRITTEN(node->decl) = 1;
+
+ // Whether the thunk adjusts 'this' before calling the thunk alias (otherwise
+ // it is the value returned by the alias that is adjusted).
+ bool ThisAdjusting = node->thunk.this_adjusting;
LLVMContext &Context = getGlobalContext();
+ const Type *IntPtrTy = TheTarget->getTargetData()->getIntPtrType(Context);
LLVMBuilder Builder(Context, *TheFolder);
Builder.SetInsertPoint(BasicBlock::Create(Context, "entry", Thunk));
- bool FoundThis = false; // Did we find 'this' yet?
+ // Whether we found 'this' yet. When not 'this adjusting', setting this to
+ // 'true' means all parameters (including 'this') are passed through as is.
+ bool FoundThis = !ThisAdjusting;
+
SmallVector<Value *, 16> Arguments;
for (Function::arg_iterator AI = Thunk->arg_begin(), AE = Thunk->arg_end();
AI != AE; ++AI) {
@@ -1582,34 +1620,16 @@
assert(isa<PointerType>(AI->getType()) && "Wrong type for 'this'!");
// Adjust 'this' according to the thunk offsets. First, the fixed offset.
- const Type *IntPtrTy = TheTarget->getTargetData()->getIntPtrType(Context);
Value *This = Builder.CreatePtrToInt(AI, IntPtrTy);
Value *Offset = ConstantInt::get(IntPtrTy, node->thunk.fixed_offset);
This = Builder.CreateNSWAdd(This, Offset);
+ This = Builder.CreateIntToPtr(This, AI->getType());
- if (node->thunk.virtual_offset_p) {
- // The vptr is always at offset zero in the object.
- const Type *HandleTy = Type::getInt8PtrTy(Context)->getPointerTo();
- Value *VPtr = Builder.CreateIntToPtr(This, HandleTy->getPointerTo());
-
- // Form the vtable address.
- Value *VTableAddr = Builder.CreateLoad(VPtr);
-
- // Find the entry with the vcall offset.
- VTableAddr = Builder.CreatePtrToInt(VTableAddr, IntPtrTy);
- Value *VOffset = ConstantInt::get(IntPtrTy, node->thunk.virtual_value);
- VTableAddr = Builder.CreateNSWAdd(VTableAddr, VOffset);
- VTableAddr = Builder.CreateIntToPtr(VTableAddr, HandleTy);
-
- // Get the offset itself.
- Value *VCallOffset = Builder.CreateLoad(VTableAddr);
- VCallOffset = Builder.CreatePtrToInt(VCallOffset, IntPtrTy);
+ // Then by the virtual offset, if any.
+ if (node->thunk.virtual_offset_p)
+ This = ApplyVirtualOffset(This, node->thunk.virtual_value, Builder);
- // Adjust the 'this' pointer.
- This = Builder.CreateNSWAdd(This, VCallOffset);
- }
-
- Arguments.push_back(Builder.CreateIntToPtr(This, AI->getType()));
+ Arguments.push_back(This);
}
CallInst *Call = Builder.CreateCall(DECL_LLVM(node->thunk.alias),
@@ -1619,13 +1639,44 @@
// All parameters except 'this' are passed on unchanged - this is a tail call.
Call->setTailCall();
- if (Thunk->getReturnType()->isVoidTy())
- Builder.CreateRetVoid();
- else
- Builder.CreateRet(Call);
+ if (ThisAdjusting) {
+ // Return the value unchanged.
+ if (Thunk->getReturnType()->isVoidTy())
+ Builder.CreateRetVoid();
+ else
+ Builder.CreateRet(Call);
+ return;
+ }
+
+ // Covariant return thunk - adjust the returned value by the thunk offsets.
+ assert(Call->getType()->isPointer() && "Only know how to adjust pointers!");
+ Value *RetVal = Call;
+
+ // First check if the returned value is NULL.
+ Value *Zero = Constant::getNullValue(RetVal->getType());
+ Value *isNull = Builder.CreateICmpEQ(RetVal, Zero);
+
+ BasicBlock *isNullBB = BasicBlock::Create(Context, "isNull", Thunk);
+ BasicBlock *isNotNullBB = BasicBlock::Create(Context, "isNotNull", Thunk);
+ Builder.CreateCondBr(isNull, isNullBB, isNotNullBB);
+
+ // If it is NULL, return it without any adjustment.
+ Builder.SetInsertPoint(isNullBB);
+ Builder.CreateRet(Zero);
+
+ // Otherwise, first adjust by the virtual offset, if any.
+ Builder.SetInsertPoint(isNotNullBB);
+ if (node->thunk.virtual_offset_p)
+ RetVal = ApplyVirtualOffset(RetVal, node->thunk.virtual_value, Builder);
+
+ // Then move 'this' by the fixed offset.
+ RetVal = Builder.CreatePtrToInt(RetVal, IntPtrTy);
+ Value *Offset = ConstantInt::get(IntPtrTy, node->thunk.fixed_offset);
+ RetVal = Builder.CreateNSWAdd(RetVal, Offset);
+ RetVal = Builder.CreateIntToPtr(RetVal, Thunk->getType());
- // Mark the thunk as written so gcc doesn't waste time outputting it.
- TREE_ASM_WRITTEN(node->decl) = 1;
+ // Return the adjusted value.
+ Builder.CreateRet(RetVal);
}
/// emit_alias - Given decl and target emit alias to target.
More information about the llvm-commits
mailing list