[PATCH] MS ABI: Remove nv adjustment from direct vdtor calls and prologues

Reid Kleckner rnk at google.com
Tue Feb 18 11:13:37 PST 2014


Hi timurrrr,

Generally the vector deleting dtor, which we model as a vtable thunk,
takes care of non-virtual adjustment and delegates to the other
destructor variants.  The other non-complete destructor variants assume
that 'this' on entry points to the virtual base subobject that first
declared the virtual destructor.

We need to change the adjustment in both the prologue and the vdtor call
setup.

http://llvm-reviews.chandlerc.com/D2821

Files:
  lib/CodeGen/MicrosoftCXXABI.cpp
  test/CodeGenCXX/microsoft-abi-structors.cpp

Index: lib/CodeGen/MicrosoftCXXABI.cpp
===================================================================
--- lib/CodeGen/MicrosoftCXXABI.cpp
+++ lib/CodeGen/MicrosoftCXXABI.cpp
@@ -601,6 +601,13 @@
   unsigned AS = cast<llvm::PointerType>(This->getType())->getAddressSpace();
   llvm::Type *charPtrTy = CGF.Int8Ty->getPointerTo(AS);
   CharUnits StaticOffset = ML.VFPtrOffset;
+
+  // Base destructors expect 'this' to point to the beginning of the base
+  // subobject, not the first vfptr that happens to contain the virtual dtor.
+  // However, we still need to apply the virtual base adjustment.
+  if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base)
+    StaticOffset = CharUnits::Zero();
+
   if (ML.VBase) {
     bool AvoidVirtualOffset = false;
     if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base) {
@@ -729,6 +736,14 @@
   MicrosoftVTableContext::MethodVFTableLocation ML =
       CGM.getMicrosoftVTableContext().getMethodVFTableLocation(LookupGD);
   CharUnits Adjustment = ML.VFPtrOffset;
+
+  // Normal virtual instance methods need to adjust from the vfptr that first
+  // defined the virtual method to the virtual base subobject, but destructors
+  // do not.  The vector deleting destructor thunk applies this adjustment for
+  // us if necessary.
+  if (isa<CXXDestructorDecl>(MD))
+    Adjustment = CharUnits::Zero();
+
   if (ML.VBase) {
     const ASTRecordLayout &DerivedLayout =
         CGF.getContext().getASTRecordLayout(MD->getParent());
Index: test/CodeGenCXX/microsoft-abi-structors.cpp
===================================================================
--- test/CodeGenCXX/microsoft-abi-structors.cpp
+++ test/CodeGenCXX/microsoft-abi-structors.cpp
@@ -3,6 +3,8 @@
 // vftables are emitted very late, so do another pass to try to keep the checks
 // in source order.
 // RUN: FileCheck --check-prefix DTORS %s < %t
+// RUN: FileCheck --check-prefix DTORS2 %s < %t
+// RUN: FileCheck --check-prefix DTORS3 %s < %t
 //
 // RUN: %clang_cc1 -emit-llvm %s -o - -mconstructor-aliases -triple=x86_64-pc-win32 -fno-rtti | FileCheck --check-prefix DTORS-X64 %s
 
@@ -121,6 +123,79 @@
 
 } // end namespace basic
 
+namespace dtor_in_second_nvbase {
+
+struct A {
+  virtual void f();  // A needs vftable to be primary.
+};
+struct B {
+  virtual ~B();
+};
+struct C : A, B {
+  virtual ~C();
+};
+
+C::~C() {
+// CHECK-LABEL: define x86_thiscallcc void @"\01??1C at dtor_in_second_nvbase@@UAE at XZ"
+// CHECK:       (%"struct.dtor_in_second_nvbase::C"* %this)
+//      No this adjustment!
+// CHECK-NOT: getelementptr
+// CHECK:   load %"struct.dtor_in_second_nvbase::C"** %{{.*}}
+//      Now we this-adjust before calling ~B.
+// CHECK:   bitcast %"struct.dtor_in_second_nvbase::C"* %{{.*}} to i8*
+// CHECK:   getelementptr inbounds i8* %{{.*}}, i64 4
+// CHECK:   bitcast i8* %{{.*}} to %"struct.dtor_in_second_nvbase::B"*
+// CHECK:   call x86_thiscallcc void @"\01??1B at dtor_in_second_nvbase@@UAE at XZ"
+// CHECK:       (%"struct.dtor_in_second_nvbase::B"* %{{.*}})
+// CHECK:   ret void
+}
+
+void foo() {
+  C c;
+}
+// DTORS2-LABEL: define weak x86_thiscallcc void @"\01??_EC at dtor_in_second_nvbase@@W3AEPAXI at Z"
+// DTORS2:       (%"struct.dtor_in_second_nvbase::C"* %this, i32 %should_call_delete)
+//      Do an adjustment from B* to C*.
+// DTORS2:   getelementptr i8* %{{.*}}, i32 -4
+// DTORS2:   bitcast i8* %{{.*}} to %"struct.dtor_in_second_nvbase::C"*
+// DTORS2:   call x86_thiscallcc void @"\01??_GC at dtor_in_second_nvbase@@UAEPAXI at Z"
+// DTORS2:   ret void
+
+}
+
+namespace test2 {
+// Just like dtor_in_second_nvbase, except put that in a vbase of a diamond.
+
+// C's dtor is in the non-primary base.
+struct A { virtual void f(); };
+struct B { virtual ~B(); };
+struct C : A, B { virtual ~C(); int c; };
+
+// Diamond hierarchy, with C as the shared vbase.
+struct D : virtual C { int d; };
+struct E : virtual C { int e; };
+struct F : D, E { ~F(); int f; };
+
+F::~F() {
+// CHECK-LABEL: define x86_thiscallcc void @"\01??1F at test2@@UAE at XZ"(%"struct.test2::F"*)
+//      Do an adjustment from C vbase subobject to F as though F was the
+//      complete type.
+// CHECK:   getelementptr inbounds i8* %{{.*}}, i32 -20
+// CHECK:   bitcast i8* %{{.*}} to %"struct.test2::F"*
+// CHECK:   store %"struct.test2::F"*
+}
+
+void foo() {
+  F f;
+}
+// DTORS3-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_DF at test2@@UAE at XZ"
+//      Do an adjustment from C* to F*.
+// DTORS3:   getelementptr i8* %{{.*}}, i32 20
+// DTORS3:   bitcast i8* %{{.*}} to %"struct.test2::F"*
+// DTORS3:   call x86_thiscallcc void @"\01??1F at test2@@UAE at XZ"
+// DTORS3:   ret void
+
+}
 
 namespace constructors {
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D2821.1.patch
Type: text/x-patch
Size: 4664 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20140218/41393e54/attachment.bin>


More information about the cfe-commits mailing list