pcc updated this revision to Diff 50905.
pcc added a comment.

- Do not set virtual index in debug info for relative-ABI virtual functions


http://reviews.llvm.org/D18199

Files:
  docs/UsersManual.rst
  lib/CodeGen/CGDebugInfo.cpp
  lib/CodeGen/CGVTables.cpp
  lib/CodeGen/CGVTables.h
  lib/CodeGen/CodeGenFunction.h
  lib/CodeGen/ItaniumCXXABI.cpp
  lib/CodeGen/MicrosoftCXXABI.cpp
  test/CodeGenCXX/debug-info-virtual-fn-relative.cpp
  test/CodeGenCXX/vtable-relative-abi.cpp

Index: test/CodeGenCXX/vtable-relative-abi.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/vtable-relative-abi.cpp
@@ -0,0 +1,123 @@
+// RUN: %clang_cc1 %s -triple x86_64-unknown-linux-gnu -funstable-c++-abi-classes -emit-llvm -o - | FileCheck --check-prefix=CHECK --check-prefix=CHECK-ITANIUM %s
+// RUN: %clang_cc1 %s -triple x86_64-unknown-windows-msvc -funstable-c++-abi-classes -emit-llvm -o - | FileCheck --check-prefix=CHECK --check-prefix=CHECK-MS %s
+
+// CHECK-ITANIUM: @_ZTV1S = unnamed_addr constant { i8*, i8*, i32, i32 } { i8* null, i8* bitcast ({ i8*, i8* }* @_ZTI1S to i8*), i32 trunc (i64 sub (i64 ptrtoint (void (%struct.S*)* @_ZN1S2f1Ev to i64), i64 ptrtoint (i32* getelementptr inbounds ({ i8*, i8*, i32, i32 }, { i8*, i8*, i32, i32 }* @_ZTV1S, i32 0, i32 2) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (void (%struct.S*)* @_ZN1S2f2Ev to i64), i64 ptrtoint (i32* getelementptr inbounds ({ i8*, i8*, i32, i32 }, { i8*, i8*, i32, i32 }* @_ZTV1S, i32 0, i32 2) to i64)) to i32) }, align 8
+// CHECK-MS: @0 = private unnamed_addr constant { i8*, i32, i32 } { i8* bitcast (%rtti.CompleteObjectLocator* @"\01??_R4S@@6B@" to i8*), i32 trunc (i64 sub (i64 ptrtoint (void (%struct.S*)* @"\01?f1@S@@UEAAXXZ" to i64), i64 ptrtoint (i32* getelementptr inbounds ({ i8*, i32, i32 }, { i8*, i32, i32 }* @0, i32 0, i32 1) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (void (%struct.S*)* @"\01?f2@S@@UEAAXXZ" to i64), i64 ptrtoint (i32* getelementptr inbounds ({ i8*, i32, i32 }, { i8*, i32, i32 }* @0, i32 0, i32 1) to i64)) to i32) }, comdat($"\01??_7S@@6B@")
+struct S {
+  S();
+  virtual void f1();
+  virtual void f2();
+};
+
+// CHECK-ITANIUM: @_ZTV1T = unnamed_addr constant { i8*, i8*, i32 } { i8* null, i8* bitcast ({ i8*, i8* }* @_ZTI1T to i8*), i32 trunc (i64 sub (i64 ptrtoint (void (%struct.T*)* @_ZN1T1gEv to i64), i64 ptrtoint (i32* getelementptr inbounds ({ i8*, i8*, i32 }, { i8*, i8*, i32 }* @_ZTV1T, i32 0, i32 2) to i64)) to i32) }
+// CHECK-MS: @1 = private unnamed_addr constant { i8*, i32 } { i8* bitcast (%rtti.CompleteObjectLocator* @"\01??_R4T@@6B@" to i8*), i32 trunc (i64 sub (i64 ptrtoint (void (%struct.T*)* @"\01?g@T@@UEAAXXZ" to i64), i64 ptrtoint (i32* getelementptr inbounds ({ i8*, i32 }, { i8*, i32 }* @1, i32 0, i32 1) to i64)) to i32) }, comdat($"\01??_7T@@6B@")
+struct T {
+  T();
+  virtual void g();
+};
+
+// CHECK-ITANIUM: @_ZTV1U = unnamed_addr constant { i8*, i8*, i32, i32, i8*, i8*, i32 } { i8* null, i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64 }* @_ZTI1U to i8*), i32 trunc (i64 sub (i64 ptrtoint (void (%struct.U*)* @_ZN1U2f1Ev to i64), i64 ptrtoint (i32* getelementptr inbounds ({ i8*, i8*, i32, i32, i8*, i8*, i32 }, { i8*, i8*, i32, i32, i8*, i8*, i32 }* @_ZTV1U, i32 0, i32 2) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (void (%struct.S*)* @_ZN1S2f2Ev to i64), i64 ptrtoint (i32* getelementptr inbounds ({ i8*, i8*, i32, i32, i8*, i8*, i32 }, { i8*, i8*, i32, i32, i8*, i8*, i32 }* @_ZTV1U, i32 0, i32 2) to i64)) to i32), i8* inttoptr (i64 -8 to i8*), i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64 }* @_ZTI1U to i8*), i32 trunc (i64 sub (i64 ptrtoint (void (%struct.T*)* @_ZN1T1gEv to i64), i64 ptrtoint (i32* getelementptr inbounds ({ i8*, i8*, i32, i32, i8*, i8*, i32 }, { i8*, i8*, i32, i32, i8*, i8*, i32 }* @_ZTV1U, i32 0, i32 6) to i64)) to i32) }, align 8
+// CHECK-MS: @2 = private unnamed_addr constant { i8*, i32, i32 } { i8* bitcast (%rtti.CompleteObjectLocator* @"\01??_R4U@@6BS@@@" to i8*), i32 trunc (i64 sub (i64 ptrtoint (void (%struct.U*)* @"\01?f1@U@@UEAAXXZ" to i64), i64 ptrtoint (i32* getelementptr inbounds ({ i8*, i32, i32 }, { i8*, i32, i32 }* @2, i32 0, i32 1) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (void (%struct.S*)* @"\01?f2@S@@UEAAXXZ" to i64), i64 ptrtoint (i32* getelementptr inbounds ({ i8*, i32, i32 }, { i8*, i32, i32 }* @2, i32 0, i32 1) to i64)) to i32) }, comdat($"\01??_7U@@6BS@@@")
+// CHECK-MS: @3 = private unnamed_addr constant { i8*, i32 } { i8* bitcast (%rtti.CompleteObjectLocator* @"\01??_R4U@@6BT@@@" to i8*), i32 trunc (i64 sub (i64 ptrtoint (void (%struct.T*)* @"\01?g@T@@UEAAXXZ" to i64), i64 ptrtoint (i32* getelementptr inbounds ({ i8*, i32 }, { i8*, i32 }* @3, i32 0, i32 1) to i64)) to i32) }, comdat($"\01??_7U@@6BT@@@")
+struct U : S, T {
+  U();
+  virtual void f1();
+};
+
+S::S() {}
+void S::f1() {}
+
+T::T() {}
+void T::g() {}
+
+U::U() {}
+void U::f1() {}
+
+struct V {
+  virtual void f();
+};
+
+struct V1 : virtual V {
+};
+
+struct V2 : virtual V {
+};
+
+// CHECK-ITANIUM: @_ZTC2V30_2V1 = linkonce_odr unnamed_addr constant { i8*, i8*, i8*, i8*, i32 } { i8* null, i8* null, i8* null, i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64 }* @_ZTI2V1 to i8*), i32 trunc (i64 sub (i64 ptrtoint (void (%struct.V*)* @_ZN1V1fEv to i64), i64 ptrtoint (i32* getelementptr inbounds ({ i8*, i8*, i8*, i8*, i32 }, { i8*, i8*, i8*, i8*, i32 }* @_ZTC2V30_2V1, i32 0, i32 4) to i64)) to i32) }, comdat
+// CHECK-ITANIUM: @_ZTC2V38_2V2 = linkonce_odr unnamed_addr constant { i8*, i8*, i8*, i8*, i32, i8*, i8*, i8*, i32 } { i8* inttoptr (i64 -8 to i8*), i8* inttoptr (i64 -8 to i8*), i8* null, i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64 }* @_ZTI2V2 to i8*), i32 0, i8* null, i8* inttoptr (i64 8 to i8*), i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64 }* @_ZTI2V2 to i8*), i32 trunc (i64 sub (i64 ptrtoint (void (%struct.V*)* @_ZN1V1fEv to i64), i64 ptrtoint (i32* getelementptr inbounds ({ i8*, i8*, i8*, i8*, i32, i8*, i8*, i8*, i32 }, { i8*, i8*, i8*, i8*, i32, i8*, i8*, i8*, i32 }* @_ZTC2V38_2V2, i32 0, i32 8) to i64)) to i32) }, comdat
+struct V3 : V1, V2 {
+  V3();
+};
+
+V3::V3() {}
+
+// CHECK-ITANIUM: define void @_Z5call1P1S
+// CHECK-MS: define void @"\01?call1@@YAXPEAUS@@@Z"
+void call1(S *s) {
+  // CHECK: [[VOFFSETPTR:%.*]] = getelementptr inbounds i32, i32* [[VTABLE:%.*]], i64 0
+  // CHECK: [[VOFFSET:%.*]] = load i32, i32* [[VOFFSETPTR]], align 4
+  // CHECK: [[VTABLEI8:%.*]] = bitcast i32* [[VTABLE]] to i8*
+  // CHECK: [[VFN:%.*]] = getelementptr i8, i8* [[VTABLEI8]], i32 [[VOFFSET]]
+  // CHECK: [[VFNCASTED:%.*]] = bitcast i8* [[VFN]] to void (
+  // CHECK: call void [[VFNCASTED]](
+  s->f1();
+}
+
+// CHECK-ITANIUM: define void @_Z5call2P1S
+// CHECK-MS: define void @"\01?call2@@YAXPEAUS@@@Z"
+void call2(S *s) {
+  // CHECK: [[VOFFSETPTR:%.*]] = getelementptr inbounds i32, i32* [[VTABLE:%.*]], i64 1
+  // CHECK: [[VOFFSET:%.*]] = load i32, i32* [[VOFFSETPTR]], align 4
+  // CHECK: [[VTABLEI8:%.*]] = bitcast i32* [[VTABLE]] to i8*
+  // CHECK: [[VFN:%.*]] = getelementptr i8, i8* [[VTABLEI8]], i32 [[VOFFSET]]
+  // CHECK: [[VFNCASTED:%.*]] = bitcast i8* [[VFN]] to void (
+  // CHECK: call void [[VFNCASTED]](
+  s->f2();
+}
+
+typedef void (S::*mfp)();
+
+// CHECK-ITANIUM: define { i64, i64 } @_Z7getmfp1v()
+// CHECK-ITANIUM: ret { i64, i64 } { i64 1, i64 0 }
+// CHECK-MS: define i8* @"\01?getmfp1@@YAP8S@@EAAXXZXZ"()
+// CHECK-MS: ret i8* bitcast {{.*}} @"\01??_9S@@$BA@AA"
+// CHECK-MS: define linkonce_odr void @"\01??_9S@@$BA@AA"
+// CHECK-MS: [[VOFFSETPTR:%.*]] = getelementptr inbounds i32, i32* [[VTABLE:%.*]], i64 0
+// CHECK-MS: [[VOFFSET:%.*]] = load i32, i32* [[VOFFSETPTR]], align 4
+// CHECK-MS: [[VTABLEI8:%.*]] = bitcast i32* [[VTABLE]] to i8*
+// CHECK-MS: [[VFN:%.*]] = getelementptr i8, i8* [[VTABLEI8]], i32 [[VOFFSET]]
+// CHECK-MS: [[VFNCASTED:%.*]] = bitcast i8* [[VFN]] to void (
+// CHECK-MS: musttail call void {{.*}} [[VFNCASTED]](
+mfp getmfp1() {
+  return &S::f1;
+}
+
+// CHECK-ITANIUM: define { i64, i64 } @_Z7getmfp2v()
+// CHECK-ITANIUM: ret { i64, i64 } { i64 5, i64 0 }
+// CHECK-MS: define i8* @"\01?getmfp2@@YAP8S@@EAAXXZXZ"()
+// CHECK-MS: ret i8* bitcast {{.*}} @"\01??_9S@@$B7AA"
+// CHECK-MS: define linkonce_odr void @"\01??_9S@@$B7AA"
+// CHECK-MS: [[VOFFSETPTR:%.*]] = getelementptr inbounds i32, i32* [[VTABLE:%.*]], i64 1
+// CHECK-MS: [[VOFFSET:%.*]] = load i32, i32* [[VOFFSETPTR]], align 4
+// CHECK-MS: [[VTABLEI8:%.*]] = bitcast i32* [[VTABLE]] to i8*
+// CHECK-MS: [[VFN:%.*]] = getelementptr i8, i8* [[VTABLEI8]], i32 [[VOFFSET]]
+// CHECK-MS: [[VFNCASTED:%.*]] = bitcast i8* [[VFN]] to void (
+// CHECK-MS: musttail call void {{.*}} [[VFNCASTED]](
+mfp getmfp2() {
+  return &S::f2;
+}
+
+// In the MS ABI virtual member function calls use thunks (which we already
+// tested above), so there's nothing to test that's specific to the relative
+// ABI.
+
+// CHECK-ITANIUM: define void @_Z7callmfpP1SMS_FvvE
+void callmfp(S *s, mfp p) {
+  // CHECK-ITANIUM: [[VTOFFSET:%.*]] = sub i64 {{.*}}, 1
+  // CHECK-ITANIUM: [[VOFFSETPTR:%.*]] = getelementptr i8, i8* [[VTABLE:%.*]], i64 [[VTOFFSET]]
+  // CHECK-ITANIUM: [[VOFFSETI32PTR:%.*]] = bitcast i8* [[VOFFSETPTR]] to i32*
+  // CHECK-ITANIUM: [[VOFFSET:%.*]] = load i32, i32* [[VOFFSETI32PTR]], align 4
+  // CHECK-ITANIUM: [[VFN:%.*]] = getelementptr i8, i8* [[VTABLE]], i32 [[VOFFSET]]
+  // CHECK-ITANIUM: bitcast i8* [[VFN]] to void (
+  (s->*p)();
+}
Index: test/CodeGenCXX/debug-info-virtual-fn-relative.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/debug-info-virtual-fn-relative.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -emit-llvm -debug-info-kind=limited %s -o - | FileCheck --check-prefix=CHECK-STABLE %s
+// RUN: %clang_cc1 -funstable-c++-abi-classes -emit-llvm -debug-info-kind=limited %s -o - | FileCheck --check-prefix=CHECK-UNSTABLE %s
+
+struct S {
+  S();
+  virtual void f();
+};
+
+// CHECK-STABLE: virtualIndex
+// CHECK-UNSTABLE-NOT: virtualIndex
+S::S() {}
+void S::f() {}
Index: lib/CodeGen/MicrosoftCXXABI.cpp
===================================================================
--- lib/CodeGen/MicrosoftCXXABI.cpp
+++ lib/CodeGen/MicrosoftCXXABI.cpp
@@ -1572,12 +1572,10 @@
                [](const VTableComponent &VTC) { return VTC.isRTTIKind(); }))
       RTTI = getMSCompleteObjectLocator(RD, Info);
 
-    llvm::Constant *Init = CGVT.CreateVTableInitializer(
-        RD, VTLayout.vtable_component_begin(),
-        VTLayout.getNumVTableComponents(), VTLayout.vtable_thunk_begin(),
-        VTLayout.getNumVTableThunks(), RTTI);
-
-    VTable->setInitializer(Init);
+    CGVT.SetVTableInitializer(VTable, RD, VTLayout.vtable_component_begin(),
+                              VTLayout.getNumVTableComponents(),
+                              VTLayout.vtable_thunk_begin(),
+                              VTLayout.getNumVTableThunks(), RTTI);
 
     emitVTableBitSetEntries(Info, RD, VTable);
   }
@@ -1696,16 +1694,14 @@
     return VTable;
   }
 
-  uint64_t NumVTableSlots =
-      VTContext.getVFTableLayout(RD, VFPtr->FullOffsetInMDC)
-          .getNumVTableComponents();
+  const VTableLayout &VTLayout =
+      VTContext.getVFTableLayout(RD, VFPtr->FullOffsetInMDC);
   llvm::GlobalValue::LinkageTypes VTableLinkage =
       VTableAliasIsRequred ? llvm::GlobalValue::PrivateLinkage : VFTableLinkage;
 
   StringRef VTableName = VTableAliasIsRequred ? StringRef() : VFTableName.str();
 
-  llvm::ArrayType *VTableType =
-      llvm::ArrayType::get(CGM.Int8PtrTy, NumVTableSlots);
+  llvm::Type *VTableType = CGM.getVTables().GetVTableType(RD, VTLayout);
 
   // Create a backing variable for the contents of VTable.  The VTable may
   // or may not include space for a pointer to RTTI data.
@@ -1726,8 +1722,8 @@
   // importing it.  We never reference the RTTI data directly so there is no
   // need to make room for it.
   if (VTableAliasIsRequred) {
-    llvm::Value *GEPIndices[] = {llvm::ConstantInt::get(CGM.IntTy, 0),
-                                 llvm::ConstantInt::get(CGM.IntTy, 1)};
+    llvm::Value *GEPIndices[] = {llvm::ConstantInt::get(CGM.Int32Ty, 0),
+                                 llvm::ConstantInt::get(CGM.Int32Ty, 1)};
     // Create a GEP which points just after the first entry in the VFTable,
     // this should be the location of the first virtual method.
     llvm::Constant *VTableGEP = llvm::ConstantExpr::getInBoundsGetElementPtr(
@@ -1737,6 +1733,7 @@
       if (C)
         C->setSelectionKind(llvm::Comdat::Largest);
     }
+    VTableGEP = llvm::ConstantExpr::getBitCast(VTableGEP, CGM.Int8PtrPtrTy);
     VFTable = llvm::GlobalAlias::create(CGM.Int8PtrTy,
                                         /*AddressSpace=*/0, VFTableLinkage,
                                         VFTableName.str(), VTableGEP,
@@ -1808,24 +1805,22 @@
                                                         llvm::Type *Ty,
                                                         SourceLocation Loc) {
   GD = GD.getCanonicalDecl();
-  CGBuilderTy &Builder = CGF.Builder;
 
-  Ty = Ty->getPointerTo()->getPointerTo();
   Address VPtr =
       adjustThisArgumentForVirtualFunctionCall(CGF, GD, This, true);
 
   auto *MethodDecl = cast<CXXMethodDecl>(GD.getDecl());
-  llvm::Value *VTable = CGF.GetVTablePtr(VPtr, Ty, MethodDecl->getParent());
+  llvm::Value *VTable = CGF.GetVTablePtr(
+      VPtr, Ty->getPointerTo()->getPointerTo(), MethodDecl->getParent());
 
   MicrosoftVTableContext::MethodVFTableLocation ML =
       CGM.getMicrosoftVTableContext().getMethodVFTableLocation(GD);
   if (CGM.NeedVTableBitSets())
     CGF.EmitBitSetCodeForVCall(getClassAtVTableLocation(getContext(), GD, ML),
                                VTable, Loc);
 
-  llvm::Value *VFuncPtr =
-      Builder.CreateConstInBoundsGEP1_64(VTable, ML.Index, "vfn");
-  return Builder.CreateAlignedLoad(VFuncPtr, CGF.getPointerAlign());
+  return CGF.GetVirtualFunctionFromVTable(MethodDecl->getParent(), VTable,
+                                          ML.Index, Ty);
 }
 
 llvm::Value *MicrosoftCXXABI::EmitVirtualDestructorCall(
@@ -1941,12 +1936,11 @@
   // Load the vfptr and then callee from the vftable.  The callee should have
   // adjusted 'this' so that the vfptr is at offset zero.
   llvm::Value *VTable = CGF.GetVTablePtr(
-      getThisAddress(CGF), ThunkTy->getPointerTo()->getPointerTo(), MD->getParent());
+      getThisAddress(CGF), ThunkTy->getPointerTo()->getPointerTo(),
+      MD->getParent());
 
-  llvm::Value *VFuncPtr =
-      CGF.Builder.CreateConstInBoundsGEP1_64(VTable, ML.Index, "vfn");
-  llvm::Value *Callee =
-    CGF.Builder.CreateAlignedLoad(VFuncPtr, CGF.getPointerAlign());
+  llvm::Value *Callee = CGF.GetVirtualFunctionFromVTable(
+      MD->getParent(), VTable, ML.Index, ThunkTy);
 
   CGF.EmitMustTailThunk(MD, getThisValue(CGF), Callee);
 
Index: lib/CodeGen/ItaniumCXXABI.cpp
===================================================================
--- lib/CodeGen/ItaniumCXXABI.cpp
+++ lib/CodeGen/ItaniumCXXABI.cpp
@@ -589,13 +589,24 @@
   llvm::Value *VTableOffset = FnAsInt;
   if (!UseARMMethodPtrABI)
     VTableOffset = Builder.CreateSub(VTableOffset, ptrdiff_1);
-  VTable = Builder.CreateGEP(VTable, VTableOffset);
+  llvm::Value *VTableSlotPtr = Builder.CreateGEP(VTable, VTableOffset);
 
   // Load the virtual function to call.
-  VTable = Builder.CreateBitCast(VTable, FTy->getPointerTo()->getPointerTo());
-  llvm::Value *VirtualFn =
-    Builder.CreateAlignedLoad(VTable, CGF.getPointerAlign(),
-                              "memptr.virtualfn");
+  llvm::Value *VirtualFn;
+  if (CGM.getVTables().shouldUseRelativeABI(RD)) {
+    VTableSlotPtr =
+        Builder.CreateBitCast(VTableSlotPtr, CGF.Int32Ty->getPointerTo());
+    llvm::Value *VirtualFnOffset =
+        Builder.CreateAlignedLoad(VTableSlotPtr, 4, "memptr.vfnoffset");
+    llvm::Value *VTableInt8Ptr = Builder.CreateBitCast(VTable, CGF.Int8PtrTy);
+    VirtualFn = Builder.CreateGEP(VTableInt8Ptr, VirtualFnOffset);
+    VirtualFn = Builder.CreateBitCast(VirtualFn, FTy->getPointerTo());
+  } else {
+    VTableSlotPtr = Builder.CreateBitCast(VTableSlotPtr,
+                                          FTy->getPointerTo()->getPointerTo());
+    VirtualFn = Builder.CreateAlignedLoad(VTableSlotPtr, CGF.getPointerAlign(),
+                                          "memptr.virtualfn");
+  }
   CGF.EmitBranch(FnEnd);
 
   // In the non-virtual path, the function pointer is actually a
@@ -803,7 +814,11 @@
     const ASTContext &Context = getContext();
     CharUnits PointerWidth =
       Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
-    uint64_t VTableOffset = (Index * PointerWidth.getQuantity());
+    uint64_t VTableOffset = Index;
+    if (CGM.getVTables().shouldUseRelativeABI(MD->getParent()))
+      VTableOffset *= 4;
+    else
+      VTableOffset *= PointerWidth.getQuantity();
 
     if (UseARMMethodPtrABI) {
       // ARM C++ ABI 3.2.1:
@@ -1465,10 +1480,10 @@
       CGM.GetAddrOfRTTIDescriptor(CGM.getContext().getTagDeclType(RD));
 
   // Create and set the initializer.
-  llvm::Constant *Init = CGVT.CreateVTableInitializer(
-      RD, VTLayout.vtable_component_begin(), VTLayout.getNumVTableComponents(),
-      VTLayout.vtable_thunk_begin(), VTLayout.getNumVTableThunks(), RTTI);
-  VTable->setInitializer(Init);
+  CGVT.SetVTableInitializer(VTable, RD, VTLayout.vtable_component_begin(),
+                            VTLayout.getNumVTableComponents(),
+                            VTLayout.vtable_thunk_begin(),
+                            VTLayout.getNumVTableThunks(), RTTI);
 
   // Set the correct linkage.
   VTable->setLinkage(Linkage);
@@ -1576,12 +1591,12 @@
   llvm::raw_svector_ostream Out(Name);
   getMangleContext().mangleCXXVTable(RD, Out);
 
-  ItaniumVTableContext &VTContext = CGM.getItaniumVTableContext();
-  llvm::ArrayType *ArrayType = llvm::ArrayType::get(
-      CGM.Int8PtrTy, VTContext.getVTableLayout(RD).getNumVTableComponents());
+  const VTableLayout &VTLayout =
+      CGM.getItaniumVTableContext().getVTableLayout(RD);
+  llvm::Type *VTableType = CGM.getVTables().GetVTableType(RD, VTLayout);
 
   VTable = CGM.CreateOrReplaceCXXRuntimeVariable(
-      Name, ArrayType, llvm::GlobalValue::ExternalLinkage);
+      Name, VTableType, llvm::GlobalValue::ExternalLinkage);
   VTable->setUnnamedAddr(true);
 
   if (RD->hasAttr<DLLImportAttr>())
@@ -1598,16 +1613,35 @@
                                                       llvm::Type *Ty,
                                                       SourceLocation Loc) {
   GD = GD.getCanonicalDecl();
-  Ty = Ty->getPointerTo()->getPointerTo();
   auto *MethodDecl = cast<CXXMethodDecl>(GD.getDecl());
-  llvm::Value *VTable = CGF.GetVTablePtr(This, Ty, MethodDecl->getParent());
+  llvm::Value *VTable = CGF.GetVTablePtr(
+      This, Ty->getPointerTo()->getPointerTo(), MethodDecl->getParent());
 
   CGF.EmitBitSetCodeForVCall(MethodDecl->getParent(), VTable, Loc);
 
   uint64_t VTableIndex = CGM.getItaniumVTableContext().getMethodVTableIndex(GD);
-  llvm::Value *VFuncPtr =
-      CGF.Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfn");
-  return CGF.Builder.CreateAlignedLoad(VFuncPtr, CGF.getPointerAlign());
+  return CGF.GetVirtualFunctionFromVTable(MethodDecl->getParent(), VTable,
+                                          VTableIndex, Ty);
+}
+
+llvm::Value *CodeGenFunction::GetVirtualFunctionFromVTable(const CXXRecordDecl *RD,
+                                                           llvm::Value *VTable,
+                                                           uint64_t VTableIndex,
+                                                           llvm::Type *Ty) {
+  if (!CGM.getVTables().shouldUseRelativeABI(RD)) {
+    VTable = Builder.CreateBitCast(VTable, Ty->getPointerTo()->getPointerTo());
+    llvm::Value *VTableSlotPtr =
+        Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfn");
+    return Builder.CreateAlignedLoad(VTableSlotPtr, getPointerAlign());
+  }
+
+  VTable = Builder.CreateBitCast(VTable, Int32Ty->getPointerTo());
+  llvm::Value *VTableSlotPtr =
+      Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfn");
+  llvm::Value *VTableSlot = Builder.CreateAlignedLoad(VTableSlotPtr, 4);
+  llvm::Value *VTableInt8Ptr = Builder.CreateBitCast(VTable, Int8PtrTy);
+  llvm::Value *FnPtr = Builder.CreateGEP(VTableInt8Ptr, VTableSlot);
+  return Builder.CreateBitCast(FnPtr, Ty->getPointerTo());
 }
 
 llvm::Value *ItaniumCXXABI::EmitVirtualDestructorCall(
Index: lib/CodeGen/CodeGenFunction.h
===================================================================
--- lib/CodeGen/CodeGenFunction.h
+++ lib/CodeGen/CodeGenFunction.h
@@ -1383,6 +1383,11 @@
   llvm::Value *GetVTablePtr(Address This, llvm::Type *VTableTy,
                             const CXXRecordDecl *VTableClass);
 
+  llvm::Value *GetVirtualFunctionFromVTable(const CXXRecordDecl *RD,
+                                            llvm::Value *VTable,
+                                            uint64_t VTableIndex,
+                                            llvm::Type *Ty);
+
   enum CFITypeCheckKind {
     CFITCK_VCall,
     CFITCK_NVCall,
Index: lib/CodeGen/CGVTables.h
===================================================================
--- lib/CodeGen/CGVTables.h
+++ lib/CodeGen/CGVTables.h
@@ -57,14 +57,16 @@
   void maybeEmitThunkForVTable(GlobalDecl GD, const ThunkInfo &Thunk);
 
 public:
-  /// CreateVTableInitializer - Create a vtable initializer for the given record
-  /// decl.
+  /// SetVTableInitializer - Set VTable's initializer to the vtable initializer
+  /// for the given record decl.
   /// \param Components - The vtable components; this is really an array of
   /// VTableComponents.
-  llvm::Constant *CreateVTableInitializer(
-      const CXXRecordDecl *RD, const VTableComponent *Components,
-      unsigned NumComponents, const VTableLayout::VTableThunkTy *VTableThunks,
-      unsigned NumVTableThunks, llvm::Constant *RTTI);
+  void SetVTableInitializer(llvm::GlobalVariable *VTable,
+                            const CXXRecordDecl *RD,
+                            const VTableComponent *Components,
+                            unsigned NumComponents,
+                            const VTableLayout::VTableThunkTy *VTableThunks,
+                            unsigned NumVTableThunks, llvm::Constant *RTTI);
 
   CodeGenVTables(CodeGenModule &CGM);
 
@@ -112,6 +114,14 @@
   void GenerateClassData(const CXXRecordDecl *RD);
 
   bool isVTableExternal(const CXXRecordDecl *RD);
+
+  /// Whether to use the relative vtable ABI for this record.
+  bool shouldUseRelativeABI(const CXXRecordDecl *RD);
+
+  /// Returns the type of a vtable with the given layout. Normally an array of
+  /// pointers, but may be a struct under the relative vtable ABI.
+  llvm::Type *GetVTableType(const CXXRecordDecl *RD,
+                            const VTableLayout &VTLayout);
 };
 
 } // end namespace CodeGen
Index: lib/CodeGen/CGVTables.cpp
===================================================================
--- lib/CodeGen/CGVTables.cpp
+++ lib/CodeGen/CGVTables.cpp
@@ -523,24 +523,73 @@
     emitThunk(GD, Thunk, /*ForVTable=*/false);
 }
 
-llvm::Constant *CodeGenVTables::CreateVTableInitializer(
-    const CXXRecordDecl *RD, const VTableComponent *Components,
-    unsigned NumComponents, const VTableLayout::VTableThunkTy *VTableThunks,
-    unsigned NumVTableThunks, llvm::Constant *RTTI) {
+bool CodeGenVTables::shouldUseRelativeABI(const CXXRecordDecl *RD) {
+  return RD->isUnstableCXXABI();
+}
+
+llvm::Type *CodeGenVTables::GetVTableType(const CXXRecordDecl *RD,
+                                          const VTableLayout &VTLayout) {
+  if (!shouldUseRelativeABI(RD))
+    return llvm::ArrayType::get(CGM.Int8PtrTy,
+                                VTLayout.getNumVTableComponents());
+
+  std::vector<llvm::Type *> Types;
+  for (auto &Comp : VTLayout.vtable_components()) {
+    if (Comp.isFunctionPointerKind())
+      Types.push_back(CGM.Int32Ty);
+    else
+      Types.push_back(CGM.Int8PtrTy);
+  }
+  return llvm::StructType::get(CGM.getLLVMContext(), Types);
+}
+
+void CodeGenVTables::SetVTableInitializer(
+    llvm::GlobalVariable *VTable, const CXXRecordDecl *RD,
+    const VTableComponent *Components, unsigned NumComponents,
+    const VTableLayout::VTableThunkTy *VTableThunks, unsigned NumVTableThunks,
+    llvm::Constant *RTTI) {
   SmallVector<llvm::Constant *, 64> Inits;
 
   llvm::Type *Int8PtrTy = CGM.Int8PtrTy;
+  llvm::Type *Int32Ty = CGM.Int32Ty;
   
   llvm::Type *PtrDiffTy = 
     CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType());
 
   unsigned NextVTableThunkIndex = 0;
 
   llvm::Constant *PureVirtualFn = nullptr, *DeletedVirtualFn = nullptr;
 
+  bool RelativeABI = shouldUseRelativeABI(RD);
+  llvm::Type *VTableTy = VTable->getValueType();
+  llvm::Type *FunctionPtrTy = RelativeABI ? Int32Ty : Int8PtrTy;
+  llvm::Constant *AddrPointInt;
+
+  auto maybeMakeRelative = [&](llvm::Constant *C) {
+    if (!RelativeABI)
+      return C;
+    return llvm::ConstantExpr::getIntegerCast(
+        llvm::ConstantExpr::getSub(
+            llvm::ConstantExpr::getPtrToInt(C, PtrDiffTy), AddrPointInt),
+        Int32Ty, /*isSigned=*/true);
+  };
+
   for (unsigned I = 0; I != NumComponents; ++I) {
     VTableComponent Component = Components[I];
 
+    if (RelativeABI && Component.isFunctionPointerKind() &&
+        (I == 0 || !Components[I - 1].isFunctionPointerKind())) {
+      // FIXME: Need a better way of identifying address points that works with
+      // the Itanium and MS ABIs.
+      AddrPointInt = llvm::ConstantExpr::getPtrToInt(
+          llvm::ConstantExpr::getGetElementPtr(
+              VTableTy, VTable,
+              llvm::ArrayRef<llvm::Constant *>{
+                  llvm::ConstantInt::get(Int32Ty, 0),
+                  llvm::ConstantInt::get(Int32Ty, I)}),
+          PtrDiffTy);
+    }
+
     llvm::Constant *Init = nullptr;
 
     switch (Component.getKind()) {
@@ -594,7 +643,7 @@
                                  : (MD->hasAttr<CUDAHostAttr>() ||
                                     !MD->hasAttr<CUDADeviceAttr>());
         if (!CanEmitMethod) {
-          Init = llvm::ConstantExpr::getNullValue(Int8PtrTy);
+          Init = llvm::ConstantExpr::getNullValue(FunctionPtrTy);
           break;
         }
         // Method is acceptable, continue processing as usual.
@@ -612,7 +661,7 @@
           PureVirtualFn = llvm::ConstantExpr::getBitCast(PureVirtualFn,
                                                          CGM.Int8PtrTy);
         }
-        Init = PureVirtualFn;
+        Init = maybeMakeRelative(PureVirtualFn);
       } else if (cast<CXXMethodDecl>(GD.getDecl())->isDeleted()) {
         if (!DeletedVirtualFn) {
           llvm::FunctionType *Ty =
@@ -625,7 +674,7 @@
           DeletedVirtualFn = llvm::ConstantExpr::getBitCast(DeletedVirtualFn,
                                                          CGM.Int8PtrTy);
         }
-        Init = DeletedVirtualFn;
+        Init = maybeMakeRelative(DeletedVirtualFn);
       } else {
         // Check if we should use a thunk.
         if (NextVTableThunkIndex < NumVTableThunks &&
@@ -643,20 +692,26 @@
         }
 
         Init = llvm::ConstantExpr::getBitCast(Init, Int8PtrTy);
+        Init = maybeMakeRelative(Init);
       }
       break;
     }
 
     case VTableComponent::CK_UnusedFunctionPointer:
-      Init = llvm::ConstantExpr::getNullValue(Int8PtrTy);
+      Init = llvm::ConstantExpr::getNullValue(FunctionPtrTy);
       break;
     };
     
     Inits.push_back(Init);
   }
-  
-  llvm::ArrayType *ArrayType = llvm::ArrayType::get(Int8PtrTy, NumComponents);
-  return llvm::ConstantArray::get(ArrayType, Inits);
+
+  if (RelativeABI) {
+    VTable->setInitializer(
+        llvm::ConstantStruct::get(cast<llvm::StructType>(VTableTy), Inits));
+  } else {
+    VTable->setInitializer(
+        llvm::ConstantArray::get(cast<llvm::ArrayType>(VTableTy), Inits));
+  }
 }
 
 llvm::GlobalVariable *
@@ -683,8 +738,7 @@
                            Base.getBase(), Out);
   StringRef Name = OutName.str();
 
-  llvm::ArrayType *ArrayType = 
-    llvm::ArrayType::get(CGM.Int8PtrTy, VTLayout->getNumVTableComponents());
+  llvm::Type *VTType = GetVTableType(RD, *VTLayout);
 
   // Construction vtable symbols are not part of the Itanium ABI, so we cannot
   // guarantee that they actually will be available externally. Instead, when
@@ -696,7 +750,7 @@
 
   // Create the variable that will hold the construction vtable.
   llvm::GlobalVariable *VTable = 
-    CGM.CreateOrReplaceCXXRuntimeVariable(Name, ArrayType, Linkage);
+    CGM.CreateOrReplaceCXXRuntimeVariable(Name, VTType, Linkage);
   CGM.setGlobalVisibility(VTable, RD);
 
   // V-tables are always unnamed_addr.
@@ -706,12 +760,11 @@
       CGM.getContext().getTagDeclType(Base.getBase()));
 
   // Create and set the initializer.
-  llvm::Constant *Init = CreateVTableInitializer(
-      Base.getBase(), VTLayout->vtable_component_begin(),
+  SetVTableInitializer(
+      VTable, Base.getBase(), VTLayout->vtable_component_begin(),
       VTLayout->getNumVTableComponents(), VTLayout->vtable_thunk_begin(),
       VTLayout->getNumVTableThunks(), RTTI);
-  VTable->setInitializer(Init);
-  
+
   CGM.EmitVTableBitSetEntries(VTable, *VTLayout.get());
 
   return VTable;
Index: lib/CodeGen/CGDebugInfo.cpp
===================================================================
--- lib/CodeGen/CGDebugInfo.cpp
+++ lib/CodeGen/CGDebugInfo.cpp
@@ -1150,7 +1150,7 @@
   // Collect virtual method info.
   llvm::DIType *ContainingType = nullptr;
   unsigned Virtuality = 0;
-  unsigned VIndex = 0;
+  unsigned VIndex = -1u;
 
   if (Method->isVirtual()) {
     if (Method->isPure())
@@ -1163,8 +1163,12 @@
     // FIXME: Add proper support for debug info for virtual calls in
     // the Microsoft ABI, where we may use multiple vptrs to make a vftable
     // lookup if we have multiple or virtual inheritance.
+    // FIXME: Add support for debug info for virtual calls in the relative
+    // ABI, where the virtual function address needs to be calculated from
+    // the virtual table address.
     if (!isa<CXXDestructorDecl>(Method) &&
-        !CGM.getTarget().getCXXABI().isMicrosoft())
+        !CGM.getTarget().getCXXABI().isMicrosoft() &&
+        !CGM.getVTables().shouldUseRelativeABI(Method->getParent()))
       VIndex = CGM.getItaniumVTableContext().getMethodVTableIndex(Method);
     ContainingType = RecordTy;
   }
Index: docs/UsersManual.rst
===================================================================
--- docs/UsersManual.rst
+++ docs/UsersManual.rst
@@ -1165,6 +1165,52 @@
         // value of -fmax-type-align.
       }
 
+**-funstable-c++-abi-classes**
+
+**-funstable-c++-abi-classes=PATH**
+
+   These flags control whether the compiler uses a more space-efficient
+   virtual table ABI, known as the relative ABI. The first flag enables the
+   ABI for all classes in the program, while the second flag enables the
+   ABI for classes in namespaces named in the file at ``PATH``.
+
+   This ABI is not guaranteed to be stable between versions of Clang. This
+   means that it is an ODR violation to define a class with the relative
+   ABI in two translation units compiled with different versions of
+   Clang. Specifically, mixing different head revisions or major releases
+   is not allowed, but mixing different point releases is fine.
+
+   The format of the namespace list file is a series of lines ending in
+   either ``*`` or ``**``. Preceding that is a namespace specifier delimited
+   by double-colons followed by ``::``, or the empty string to denote the
+   global namespace. ``#`` serves as a comment character. Each entry in the
+   list indicates that classes in that namespace, including nested classes,
+   classes defined in enclosed anonymous namespaces, and classes defined
+   within member functions of those classes, may use the relative ABI.
+
+   If the line ends in ``*`` this applies to the given namespace only,
+   while if the line ends in ``**`` it applies to the given namespace and
+   any enclosed namespaces.
+
+   It is not guaranteed that all such classes will use the relative ABI. For
+   example, if a base class uses the platform ABI and declares virtual functions,
+   that will force any derived classes to use the platform ABI. The compiler
+   will diagnose any cases where a class derives from multiple incompatible
+   base classes.
+
+   Example:
+
+   .. code-block:: console
+
+      # Enables the unstable ABI for classes in the global namespace.
+      *
+
+      # Enables the unstable ABI for classes in the base namespace, and
+      # any enclosed namespaces.
+      base::**
+
+   Note that it is recommended to use the ``[[clang::unstable_abi]]``
+   attribute instead of these flags wherever possible.
 
 Profile Guided Optimization
 ---------------------------
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to