From: Mike Stump Date: Tue, 3 Nov 2009 16:59:27 +0000 (+0000) Subject: Refine return value adjustments for thunks. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c902d22129322731607988dafb8cd7f708eb75b1;p=clang Refine return value adjustments for thunks. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@85905 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index d8db9ab7c4..06a17ff6e7 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -705,6 +705,38 @@ llvm::Constant *CodeGenFunction::GenerateThunk(llvm::Function *Fn, return GenerateCovariantThunk(Fn, MD, Extern, nv, v, 0, 0); } +llvm::Value *CodeGenFunction::DynamicTypeAdjust(llvm::Value *V, int64_t nv, + int64_t v) { + llvm::Type *Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), + 0); + const llvm::Type *OrigTy = V->getType(); + if (nv) { + // Do the non-virtual adjustment + V = Builder.CreateBitCast(V, Ptr8Ty); + V = Builder.CreateConstInBoundsGEP1_64(V, nv); + V = Builder.CreateBitCast(V, OrigTy); + } + if (v) { + // Do the virtual this adjustment + const llvm::Type *PtrDiffTy = + ConvertType(getContext().getPointerDiffType()); + llvm::Type *PtrPtr8Ty, *PtrPtrDiffTy; + PtrPtr8Ty = llvm::PointerType::get(Ptr8Ty, 0); + PtrPtrDiffTy = llvm::PointerType::get(PtrDiffTy, 0); + llvm::Value *ThisVal = Builder.CreateBitCast(V, Ptr8Ty); + V = Builder.CreateBitCast(V, PtrPtrDiffTy->getPointerTo()); + V = Builder.CreateLoad(V, "vtable"); + llvm::Value *VTablePtr = V; + assert(v % (LLVMPointerWidth/8) == 0 && "vtable entry unaligned"); + v /= LLVMPointerWidth/8; + V = Builder.CreateConstInBoundsGEP1_64(VTablePtr, v); + V = Builder.CreateLoad(V); + V = Builder.CreateGEP(ThisVal, V); + V = Builder.CreateBitCast(V, OrigTy); + } + return V; +} + llvm::Constant *CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, const CXXMethodDecl *MD, bool Extern, @@ -746,33 +778,9 @@ llvm::Constant *CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, QualType ArgType = MD->getThisType(getContext()); llvm::Value *Arg = Builder.CreateLoad(LocalDeclMap[ThisDecl], "this"); - llvm::Type *Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), - 0); - const llvm::Type *OrigTy = Arg->getType(); - if (nv_t) { - // Do the non-virtual this adjustment - Arg = Builder.CreateBitCast(Arg, Ptr8Ty); - Arg = Builder.CreateConstInBoundsGEP1_64(Arg, nv_t); - Arg = Builder.CreateBitCast(Arg, OrigTy); - } - if (v_t) { - // Do the virtual this adjustment - const llvm::Type *PtrDiffTy = - ConvertType(getContext().getPointerDiffType()); - llvm::Type *PtrPtr8Ty, *PtrPtrDiffTy; - PtrPtr8Ty = llvm::PointerType::get(Ptr8Ty, 0); - PtrPtrDiffTy = llvm::PointerType::get(PtrDiffTy, 0); - llvm::Value *ThisVal = Builder.CreateBitCast(Arg, Ptr8Ty); - Arg = Builder.CreateBitCast(Arg, PtrPtrDiffTy->getPointerTo()); - Arg = Builder.CreateLoad(Arg, "vtable"); - llvm::Value *VTablePtr = Arg; - assert(v_t % (LLVMPointerWidth/8) == 0 && "vtable entry unaligned"); - v_t /= LLVMPointerWidth/8; - Arg = Builder.CreateConstInBoundsGEP1_64(VTablePtr, v_t); - Arg = Builder.CreateLoad(Arg); - Arg = Builder.CreateGEP(ThisVal, Arg); - Arg = Builder.CreateBitCast(Arg, OrigTy); - } + if (nv_t || v_t) + // Do the this adjustment. + Arg = DynamicTypeAdjust(Arg, nv_t, v_t); CallArgs.push_back(std::make_pair(RValue::get(Arg), ArgType)); for (FunctionDecl::param_const_iterator i = MD->param_begin(), @@ -790,7 +798,8 @@ llvm::Constant *CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, RValue RV = EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), Callee, CallArgs, MD); if (nv_r || v_r) { - // FIXME: Add return value adjustments. + // Do the return result adjustment. + RV = RValue::get(DynamicTypeAdjust(RV.getScalarVal(), nv_r, v_r)); } if (!ResultType->isVoidType()) diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index c4b8945ce3..893f1ed880 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -387,6 +387,11 @@ public: /// GenerateVtable - Generate the vtable for the given type. llvm::Value *GenerateVtable(const CXXRecordDecl *RD); + /// DynamicTypeAdjust - Do the non-virtual and virtual adjustments on an + /// object pointer to alter the dynamic type of the pointer. Used by + /// GenerateCovariantThunk for building thunks. + llvm::Value *DynamicTypeAdjust(llvm::Value *V, int64_t nv, int64_t v); + /// GenerateThunk - Generate a thunk for the given method llvm::Constant *GenerateThunk(llvm::Function *Fn, const CXXMethodDecl *MD, bool Extern, int64_t nv, int64_t v); diff --git a/test/CodeGenCXX/virt.cpp b/test/CodeGenCXX/virt.cpp index e3b4526bb4..e0067d6c12 100644 --- a/test/CodeGenCXX/virt.cpp +++ b/test/CodeGenCXX/virt.cpp @@ -91,6 +91,36 @@ int main() { // CHECK-LP64: movl $1, 12(%rax) // CHECK-LP64: movl $2, 8(%rax) +// FIXME: This is the wrong thunk, but until these issues are fixed, better +// than nothing. +// CHECK-LP64: __ZTcvn16_n72_v16_n32_N8test16_D4foo1Ev27: +// CHECK-LP64-NEXT:Leh_func_begin33: +// CHECK-LP64-NEXT: subq $24, %rsp +// CHECK-LP64-NEXT:Llabel33: +// CHECK-LP64-NEXT: movq %rdi, %rax +// CHECK-LP64-NEXT: movq %rax, 8(%rsp) +// CHECK-LP64-NEXT: movq 8(%rsp), %rax +// CHECK-LP64-NEXT: movq %rax, %rcx +// CHECK-LP64-NEXT: movabsq $-16, %rdx +// CHECK-LP64-NEXT: addq %rdx, %rcx +// CHECK-LP64-NEXT: movq -16(%rax), %rax +// CHECK-LP64-NEXT: movq -72(%rax), %rax +// CHECK-LP64-NEXT: addq %rax, %rcx +// CHECK-LP64-NEXT: movq %rcx, %rax +// CHECK-LP64-NEXT: movq %rax, %rdi +// CHECK-LP64-NEXT: call __ZN8test16_D4foo1Ev +// CHECK-LP64-NEXT: movq %rax, %rcx +// CHECK-LP64-NEXT: movabsq $16, %rdx +// CHECK-LP64-NEXT: addq %rdx, %rcx +// CHECK-LP64-NEXT: movq 16(%rax), %rax +// CHECK-LP64-NEXT: movq -32(%rax), %rax +// CHECK-LP64-NEXT: addq %rax, %rcx +// CHECK-LP64-NEXT: movq %rcx, %rax +// CHECK-LP64-NEXT: movq %rax, 16(%rsp) +// CHECK-LP64-NEXT: movq 16(%rsp), %rax +// CHECK-LP64-NEXT: addq $24, %rsp +// CHECK-LP64-NEXT: ret + struct test12_A { virtual void foo0() { } virtual void foo();