leonardchan updated this revision to Diff 197196.
leonardchan marked an inline comment as done.
leonardchan retitled this revision from "[WIP] Support for relative vtables" to 
"Support for relative vtables".
leonardchan added a comment.

Ok. Formally requesting for code reviews now.

- Made the flag an `experimental` flag.
- Added changes to relevant AST Serialization code.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D58321/new/

https://reviews.llvm.org/D58321

Files:
  clang/include/clang/AST/DeclCXX.h
  clang/include/clang/AST/VTableBuilder.h
  clang/include/clang/Basic/LangOptions.def
  clang/include/clang/Driver/Options.td
  clang/include/clang/Sema/Sema.h
  clang/lib/AST/DeclCXX.cpp
  clang/lib/CodeGen/CGClass.cpp
  clang/lib/CodeGen/CGDebugInfo.cpp
  clang/lib/CodeGen/CGVTables.cpp
  clang/lib/CodeGen/CGVTables.h
  clang/lib/CodeGen/CodeGenFunction.h
  clang/lib/CodeGen/ItaniumCXXABI.cpp
  clang/lib/CodeGen/MicrosoftCXXABI.cpp
  clang/lib/Driver/ToolChains/Clang.cpp
  clang/lib/Frontend/CompilerInvocation.cpp
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/lib/Serialization/ASTReaderDecl.cpp
  clang/lib/Serialization/ASTWriter.cpp
  clang/test/CodeGenCXX/debug-info-virtual-fn-relative.cpp
  clang/test/CodeGenCXX/vtable-relative-abi.cpp
  llvm/lib/IR/Constants.cpp

Index: llvm/lib/IR/Constants.cpp
===================================================================
--- llvm/lib/IR/Constants.cpp
+++ llvm/lib/IR/Constants.cpp
@@ -495,6 +495,35 @@
   return false;
 }
 
+/// Returns true if this constant mathes the relative referencing for virtual
+/// functions introduced in the relative ABI. This is the difference between a
+/// function and its corresponding vtable entry.
+///
+/// i64 sub (
+///   i64 ptrtoint (i8* obj to i64),
+//    i64 ptrtoint (
+//      i32* getelementptr inbounds (%object_vtable, %object_vtable*
+//        @_ZTV12derived_virt, i32 0, i32 0, i32 2) to i64)
+static bool MatchesRelativeOffset(const Constant *C) {
+  const auto *CE = dyn_cast<ConstantExpr>(C);
+  if (!CE || CE->getOpcode() != Instruction::Sub)
+    return false;
+
+  const auto *LHS = dyn_cast<ConstantExpr>(CE->getOperand(0));
+  const auto *RHS = dyn_cast<ConstantExpr>(CE->getOperand(1));
+  if (!LHS || !RHS || LHS->getOpcode() != Instruction::PtrToInt ||
+      RHS->getOpcode() != Instruction::PtrToInt)
+    return false;
+
+  RHS = dyn_cast<ConstantExpr>(RHS->getOperand(0));
+  if (!RHS)
+    return false;
+
+  return (isa<GlobalValue>(LHS->getOperand(0)) &&
+          RHS->getOpcode() == Instruction::GetElementPtr &&
+          isa<GlobalValue>(RHS->getOperand(0)));
+}
+
 bool Constant::needsRelocation() const {
   if (isa<GlobalValue>(this))
     return true; // Global reference.
@@ -519,6 +548,10 @@
         return false;
     }
 
+  // This results in an R_PLT_PC reloc which can be computed at link time.
+  if (MatchesRelativeOffset(this))
+    return false;
+
   bool Result = false;
   for (unsigned i = 0, e = getNumOperands(); i != e; ++i)
     Result |= cast<Constant>(getOperand(i))->needsRelocation();
Index: clang/test/CodeGenCXX/vtable-relative-abi.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGenCXX/vtable-relative-abi.cpp
@@ -0,0 +1,117 @@
+// RUN: %clang_cc1 %s -triple x86_64-unknown-linux-gnu -fexperimental-relative-c++-abi-vtables -emit-llvm -o - | FileCheck --check-prefix=CHECK --check-prefix=CHECK-ITANIUM %s
+// RUN: %clang_cc1 %s -triple x86_64-unknown-windows-msvc -fexperimental-relative-c++-abi-vtables -emit-llvm -o - | FileCheck --check-prefix=CHECK --check-prefix=CHECK-MS %s
+
+// CHECK-ITANIUM: @_ZTV1S = unnamed_addr constant { { i8*, i8*, i32, i32 } } { { 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 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 0, i32 2) to i64)) to i32) } }, align 8
+// CHECK-MS: @0 = private unnamed_addr constant { { i8*, i32, i32 } } { { i8*, i32, i32 } { i8* bitcast (%rtti.CompleteObjectLocator* @"??_R4S@@6B@" to i8*), i32 trunc (i64 sub (i64 ptrtoint (void (%struct.S*)* @"?f1@S@@UEAAXXZ" to i64), i64 ptrtoint (i32* getelementptr inbounds ({ { i8*, i32, i32 } }, { { i8*, i32, i32 } }* @0, i32 0, i32 0, i32 1) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (void (%struct.S*)* @"?f2@S@@UEAAXXZ" to i64), i64 ptrtoint (i32* getelementptr inbounds ({ { i8*, i32, i32 } }, { { i8*, i32, i32 } }* @0, i32 0, i32 0, i32 1) to i64)) to i32) } }, comdat($"??_7S@@6B@")
+
+struct S {
+  S();
+  virtual void f1();
+  virtual void f2();
+};
+
+// CHECK-ITANIUM: @_ZTV1T = unnamed_addr constant { { i8*, i8*, i32 } } { { 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 0, i32 2) to i64)) to i32) } }, align 8
+// CHECK-MS: @1 = private unnamed_addr constant { { i8*, i32 } } { { i8*, i32 } { i8* bitcast (%rtti.CompleteObjectLocator* @"??_R4T@@6B@" to i8*), i32 trunc (i64 sub (i64 ptrtoint (void (%struct.T*)* @"?g@T@@UEAAXXZ" to i64), i64 ptrtoint (i32* getelementptr inbounds ({ { i8*, i32 } }, { { i8*, i32 } }* @1, i32 0, i32 0, i32 1) to i64)) to i32) } }, comdat($"??_7T@@6B@")
+struct T {
+  T();
+  virtual void g();
+};
+
+// CHECK-ITANIUM: @_ZTV1U = unnamed_addr constant { { i8*, i8*, i32, i32 }, { i8*, i8*, i32 } } { { i8*, i8*, i32, 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 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 0, i32 2) to i64)) to i32) }, { i8*, i8*, 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 1, i32 2) to i64)) to i32) } }, align 8
+// CHECK-MS: @2 = private unnamed_addr constant { { i8*, i32, i32 } } { { i8*, i32, i32 } { i8* bitcast (%rtti.CompleteObjectLocator* @"??_R4U@@6BS@@@" to i8*), i32 trunc (i64 sub (i64 ptrtoint (void (%struct.U*)* @"?f1@U@@UEAAXXZ" to i64), i64 ptrtoint (i32* getelementptr inbounds ({ { i8*, i32, i32 } }, { { i8*, i32, i32 } }* @2, i32 0, i32 0, i32 1) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (void (%struct.S*)* @"?f2@S@@UEAAXXZ" to i64), i64 ptrtoint (i32* getelementptr inbounds ({ { i8*, i32, i32 } }, { { i8*, i32, i32 } }* @2, i32 0, i32 0, i32 1) to i64)) to i32) } }, comdat($"??_7U@@6BS@@@")
+// CHECK-MS: @3 = private unnamed_addr constant { { i8*, i32 } } { { i8*, i32 } { i8* bitcast (%rtti.CompleteObjectLocator* @"??_R4U@@6BT@@@" to i8*), i32 trunc (i64 sub (i64 ptrtoint (void (%struct.T*)* @"?g@T@@UEAAXXZ" to i64), i64 ptrtoint (i32* getelementptr inbounds ({ { i8*, i32 } }, { { i8*, i32 } }* @3, i32 0, i32 0, i32 1) to i64)) to i32) } }, comdat($"??_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*, 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 0, i32 4) to i64)) to i32) } }, comdat, align 8
+// CHECK-ITANIUM: @_ZTC2V38_2V2 = linkonce_odr unnamed_addr constant { { i8*, i8*, i8*, i8*, i32 }, { i8*, i8*, i8*, i32 } } { { i8*, 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*, i8*, i8*, i32 } { 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 1, i32 3) to i64)) to i32) } }, comdat, align 8
+struct V3 : V1, V2 {
+  V3();
+};
+
+V3::V3() {}
+
+// CHECK-ITANIUM: define void @_Z5call1P1S
+// CHECK-MS: define {{.*}} void @"?call1@@YAXPEAUS@@@Z"
+void call1(S *s) {
+  // CHECK: [[VTABLE:%.*]] = load void
+  // CHECK: [[VTABLEI8:%.*]] = bitcast {{.*}} [[VTABLE]] to i8*
+  // CHECK: [[VFN:%.*]] = call i8* @llvm.load.relative.i32(i8* [[VTABLEI8]], i32 0)
+  // CHECK: [[VFNCASTED:%.*]] = bitcast i8* [[VFN]] to void (
+  // CHECK: call void [[VFNCASTED]](
+  s->f1();
+}
+
+// CHECK-ITANIUM: define void @_Z5call2P1S
+// CHECK-MS: define {{.*}} void @"?call2@@YAXPEAUS@@@Z"
+void call2(S *s) {
+  // CHECK: [[VTABLE:%.*]] = load void
+  // CHECK: [[VTABLEI8:%.*]] = bitcast {{.*}} [[VTABLE]] to i8*
+  // CHECK: [[VFN:%.*]] = call i8* @llvm.load.relative.i32(i8* [[VTABLEI8]], i32 4)
+  // 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* @"?getmfp1@@YAP8S@@EAAXXZXZ"()
+// CHECK-MS: ret i8* bitcast {{.*}} @"??_9S@@$BA@AA"
+// CHECK-MS: define linkonce_odr void @"??_9S@@$BA@AA"
+// CHECK-MS: [[VTABLE:%.*]] = load void
+// CHECK-MS: [[VTABLEI8:%.*]] = bitcast {{.*}} [[VTABLE]] to i8*
+// CHECK-MS: [[VFN:%.*]] = call i8* @llvm.load.relative.i32(i8* [[VTABLEI8]], i32 0)
+// CHECK-MS: [[VFNCASTED:%.*]] = bitcast i8* [[VFN]] to void (
+// CHECK-MS: musttail call {{.*}} [[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* @"?getmfp2@@YAP8S@@EAAXXZXZ"()
+// CHECK-MS: ret i8* bitcast {{.*}} @"??_9S@@$B7AA"
+// CHECK-MS: define linkonce_odr void @"??_9S@@$B7AA"
+// CHECK-MS: [[VTABLE:%.*]] = load void
+// CHECK-MS: [[VTABLEI8:%.*]] = bitcast {{.*}} [[VTABLE]] to i8*
+// CHECK-MS: [[VFN:%.*]] = call i8* @llvm.load.relative.i32(i8* [[VTABLEI8]], i32 4)
+// CHECK-MS: [[VFNCASTED:%.*]] = bitcast i8* [[VFN]] to void (
+// CHECK-MS: musttail call {{.*}} [[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: [[VFN:%.*]] = call i8* @llvm.load.relative.i64(i8* {{.*}}, i64 [[VTOFFSET]])
+  // CHECK-ITANIUM: bitcast i8* [[VFN]] to void (
+  (s->*p)();
+}
Index: clang/test/CodeGenCXX/debug-info-virtual-fn-relative.cpp
===================================================================
--- /dev/null
+++ clang/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 -fexperimental-relative-c++-abi-vtables -emit-llvm -debug-info-kind=limited %s -o - | FileCheck --check-prefix=CHECK-UNSTABLE %s
+
+struct S {
+  S();
+  virtual void f();
+};
+
+// CHECK-STABLE: virtualIndex: 0,
+// CHECK-UNSTABLE: virtualIndex: 4294967295,
+S::S() {}
+void S::f() {}
Index: clang/lib/Serialization/ASTWriter.cpp
===================================================================
--- clang/lib/Serialization/ASTWriter.cpp
+++ clang/lib/Serialization/ASTWriter.cpp
@@ -6105,6 +6105,7 @@
   Record->push_back(Data.ImplicitCopyAssignmentHasConstParam);
   Record->push_back(Data.HasDeclaredCopyConstructorWithConstParam);
   Record->push_back(Data.HasDeclaredCopyAssignmentWithConstParam);
+  Record->push_back(Data.IsRelativeCXXABI);
 
   // getODRHash will compute the ODRHash if it has not been previously computed.
   Record->push_back(D->getODRHash());
Index: clang/lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- clang/lib/Serialization/ASTReaderDecl.cpp
+++ clang/lib/Serialization/ASTReaderDecl.cpp
@@ -1689,6 +1689,7 @@
   Data.ImplicitCopyAssignmentHasConstParam = Record.readInt();
   Data.HasDeclaredCopyConstructorWithConstParam = Record.readInt();
   Data.HasDeclaredCopyAssignmentWithConstParam = Record.readInt();
+  Data.IsRelativeCXXABI = Record.readInt();
   Data.ODRHash = Record.readInt();
   Data.HasODRHash = true;
 
@@ -1830,6 +1831,7 @@
   MATCH_FIELD(ImplicitCopyAssignmentHasConstParam)
   OR_FIELD(HasDeclaredCopyConstructorWithConstParam)
   OR_FIELD(HasDeclaredCopyAssignmentWithConstParam)
+  MATCH_FIELD(IsRelativeCXXABI)
   MATCH_FIELD(IsLambda)
 #undef OR_FIELD
 #undef MATCH_FIELD
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -5893,6 +5893,13 @@
   }
 }
 
+void Sema::checkClassABI(CXXRecordDecl *Record) {
+  if (!getLangOpts().RelativeCXXABIVTables)
+    return;
+
+  Record->setIsRelativeCXXABI();
+}
+
 /// Determine whether a type is permitted to be passed or returned in
 /// registers, per C++ [class.temporary]p3.
 static bool canPassInRegisters(Sema &S, CXXRecordDecl *D,
@@ -6172,6 +6179,7 @@
 
   checkClassLevelDLLAttribute(Record);
   checkClassLevelCodeSegAttribute(Record);
+  checkClassABI(Record);
 
   bool ClangABICompat4 =
       Context.getLangOpts().getClangABICompat() <= LangOptions::ClangABI::Ver4;
Index: clang/lib/Frontend/CompilerInvocation.cpp
===================================================================
--- clang/lib/Frontend/CompilerInvocation.cpp
+++ clang/lib/Frontend/CompilerInvocation.cpp
@@ -3045,6 +3045,9 @@
 
   Opts.CompleteMemberPointers = Args.hasArg(OPT_fcomplete_member_pointers);
   Opts.BuildingPCHWithObjectFile = Args.hasArg(OPT_building_pch_with_obj);
+
+  Opts.RelativeCXXABIVTables =
+      Args.hasArg(OPT_fexperimental_relative_cxx_abi_vtables);
 }
 
 static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) {
Index: clang/lib/Driver/ToolChains/Clang.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Clang.cpp
+++ clang/lib/Driver/ToolChains/Clang.cpp
@@ -5309,6 +5309,10 @@
     CmdArgs.push_back("-fwhole-program-vtables");
   }
 
+  // Add unstable C++ ABI flags.
+  if (Args.hasArg(options::OPT_fexperimental_relative_cxx_abi_vtables))
+    CmdArgs.push_back("-fexperimental-relative-c++-abi-vtables");
+
   bool RequiresSplitLTOUnit = WholeProgramVTables || Sanitize.needsLTO();
   bool SplitLTOUnit =
       Args.hasFlag(options::OPT_fsplit_lto_unit,
Index: clang/lib/CodeGen/MicrosoftCXXABI.cpp
===================================================================
--- clang/lib/CodeGen/MicrosoftCXXABI.cpp
+++ clang/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -1645,10 +1645,7 @@
                [](const VTableComponent &VTC) { return VTC.isRTTIKind(); }))
       RTTI = getMSCompleteObjectLocator(RD, *Info);
 
-    ConstantInitBuilder Builder(CGM);
-    auto Components = Builder.beginStruct();
-    CGVT.createVTableInitializer(Components, VTLayout, RTTI);
-    Components.finishAndSetAsInitializer(VTable);
+    CGVT.SetVTableInitializer(VTable, VTLayout, RTTI, RD->isRelativeCXXABI());
 
     emitVTableTypeMetadata(*Info, RD, VTable);
   }
@@ -1774,7 +1771,7 @@
 
   StringRef VTableName = VTableAliasIsRequred ? StringRef() : VFTableName.str();
 
-  llvm::Type *VTableType = CGM.getVTables().getVTableType(VTLayout);
+  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.
@@ -1807,6 +1804,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,
@@ -1834,14 +1832,12 @@
                                                     Address This,
                                                     llvm::Type *Ty,
                                                     SourceLocation Loc) {
-  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 &VFTContext = CGM.getMicrosoftVTableContext();
   MethodVFTableLocation ML = VFTContext.getMethodVFTableLocation(GD);
@@ -1867,9 +1863,8 @@
     if (CGM.getCodeGenOpts().PrepareForLTO)
       CGF.EmitTypeMetadataCodeForVCall(getObjectWithVPtr(), VTable, Loc);
 
-    llvm::Value *VFuncPtr =
-        Builder.CreateConstInBoundsGEP1_64(VTable, ML.Index, "vfn");
-    VFunc = Builder.CreateAlignedLoad(VFuncPtr, CGF.getPointerAlign());
+    VFunc = CGF.GetVirtualFunctionFromVTable(MethodDecl->getParent(), VTable,
+                                             ML.Index, Ty);
   }
 
   CGCallee Callee(GD, VFunc);
@@ -1990,10 +1985,8 @@
   llvm::Value *VTable = CGF.GetVTablePtr(
       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), {ThunkTy, Callee});
 
Index: clang/lib/CodeGen/ItaniumCXXABI.cpp
===================================================================
--- clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -666,9 +666,20 @@
   }
 
   // Load the virtual function to call.
-  VFPAddr = Builder.CreateBitCast(VFPAddr, FTy->getPointerTo()->getPointerTo());
-  llvm::Value *VirtualFn = Builder.CreateAlignedLoad(
-      VFPAddr, CGF.getPointerAlign(), "memptr.virtualfn");
+  llvm::Value *VirtualFn;
+  if (RD->hasDefinition() && RD->isRelativeCXXABI()) {
+    VirtualFn =
+        Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::load_relative,
+                                            {VTableOffset->getType()}),
+                           {VTable, VTableOffset});
+    VirtualFn = Builder.CreateBitCast(VirtualFn, FTy->getPointerTo());
+  } else {
+    // Apply the offset.
+    llvm::Value *VTableSlotPtr =
+        Builder.CreateBitCast(VFPAddr, 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
@@ -914,7 +925,11 @@
     const ASTContext &Context = getContext();
     CharUnits PointerWidth =
       Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
-    uint64_t VTableOffset = (Index * PointerWidth.getQuantity());
+    uint64_t VTableOffset = Index;
+    if (MD->getParent()->isRelativeCXXABI())
+      VTableOffset *= 4;
+    else
+      VTableOffset *= PointerWidth.getQuantity();
 
     if (UseARMMethodPtrABI) {
       // ARM C++ ABI 3.2.1:
@@ -1584,10 +1599,7 @@
       CGM.GetAddrOfRTTIDescriptor(CGM.getContext().getTagDeclType(RD));
 
   // Create and set the initializer.
-  ConstantInitBuilder Builder(CGM);
-  auto Components = Builder.beginStruct();
-  CGVT.createVTableInitializer(Components, VTLayout, RTTI);
-  Components.finishAndSetAsInitializer(VTable);
+  CGVT.SetVTableInitializer(VTable, VTLayout, RTTI, RD->isRelativeCXXABI());
 
   // Set the correct linkage.
   VTable->setLinkage(Linkage);
@@ -1695,7 +1707,7 @@
 
   const VTableLayout &VTLayout =
       CGM.getItaniumVTableContext().getVTableLayout(RD);
-  llvm::Type *VTableType = CGM.getVTables().getVTableType(VTLayout);
+  llvm::Type *VTableType = CGM.getVTables().getVTableType(RD, VTLayout);
 
   // Use pointer alignment for the vtable. Otherwise we would align them based
   // on the size of the initializer which doesn't make sense as only single
@@ -1717,9 +1729,9 @@
                                                   Address This,
                                                   llvm::Type *Ty,
                                                   SourceLocation Loc) {
-  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());
 
   uint64_t VTableIndex = CGM.getItaniumVTableContext().getMethodVTableIndex(GD);
   llvm::Value *VFunc;
@@ -1730,10 +1742,8 @@
   } else {
     CGF.EmitTypeMetadataCodeForVCall(MethodDecl->getParent(), VTable, Loc);
 
-    llvm::Value *VFuncPtr =
-        CGF.Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfn");
-    auto *VFuncLoad =
-        CGF.Builder.CreateAlignedLoad(VFuncPtr, CGF.getPointerAlign());
+    auto *VFuncLoad = CGF.GetVirtualFunctionFromVTable(MethodDecl->getParent(),
+                                                       VTable, VTableIndex, Ty);
 
     // Add !invariant.load md to virtual function load to indicate that
     // function didn't change inside vtable.
@@ -1742,11 +1752,14 @@
     // the same virtual function loads from the same vtable load, which won't
     // happen without enabled devirtualization with -fstrict-vtable-pointers.
     if (CGM.getCodeGenOpts().OptimizationLevel > 0 &&
-        CGM.getCodeGenOpts().StrictVTablePointers)
-      VFuncLoad->setMetadata(
-          llvm::LLVMContext::MD_invariant_load,
-          llvm::MDNode::get(CGM.getLLVMContext(),
-                            llvm::ArrayRef<llvm::Metadata *>()));
+        CGM.getCodeGenOpts().StrictVTablePointers) {
+      if (auto *VFuncLoadInstr = dyn_cast<llvm::Instruction>(VFuncLoad)) {
+        VFuncLoadInstr->setMetadata(
+            llvm::LLVMContext::MD_invariant_load,
+            llvm::MDNode::get(CGM.getLLVMContext(),
+                              llvm::ArrayRef<llvm::Metadata *>()));
+      }
+    }
     VFunc = VFuncLoad;
   }
 
Index: clang/lib/CodeGen/CodeGenFunction.h
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.h
+++ clang/lib/CodeGen/CodeGenFunction.h
@@ -1904,6 +1904,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: clang/lib/CodeGen/CGVTables.h
===================================================================
--- clang/lib/CodeGen/CGVTables.h
+++ clang/lib/CodeGen/CGVTables.h
@@ -61,17 +61,33 @@
                                  const ThunkInfo &ThunkAdjustments,
                                  bool ForVTable);
 
-  void addVTableComponent(ConstantArrayBuilder &builder,
-                          const VTableLayout &layout, unsigned idx,
-                          llvm::Constant *rtti,
-                          unsigned &nextVTableThunkIndex);
+  /// Get the constant to be added to a VTable.
+  llvm::Constant *getVTableComponent(const VTableLayout &layout,
+                                     unsigned componentIdx, unsigned vtableIdx,
+                                     llvm::Constant *rtti,
+                                     unsigned &nextVTableThunkIndex,
+                                     bool RelativeABI);
 
 public:
   /// Add vtable components for the given vtable layout to the given
   /// global initializer.
-  void createVTableInitializer(ConstantStructBuilder &builder,
-                               const VTableLayout &layout,
-                               llvm::Constant *rtti);
+  void SetVTableInitializer(llvm::GlobalVariable *VTable,
+                            const VTableLayout &VTLayout, llvm::Constant *RTTI,
+                            bool RelativeABI);
+
+  /// Make a function pointer into a relative integer when using the relative
+  /// vtables ABI.
+  llvm::Constant *makeRelative(llvm::Constant *C, llvm::GlobalVariable *VTable,
+                               unsigned vtableIdx,
+                               unsigned lastAddrPoint) const;
+
+  /// Populate the fields of a single vtable element. This accepts either a
+  /// StructBuilder or ArrayBuilder.
+  template <class BuilderTy>
+  void buildVTableElement(BuilderTy &builder, llvm::GlobalVariable *VTable,
+                          const VTableLayout &VTLayout, llvm::Constant *RTTI,
+                          unsigned &nextVTableThunkIndex, unsigned vtableIdx,
+                          bool RelativeABI);
 
   CodeGenVTables(CodeGenModule &CGM);
 
@@ -123,7 +139,8 @@
   /// Returns the type of a vtable with the given layout. Normally a struct of
   /// arrays of pointers, with one struct element for each vtable in the vtable
   /// group.
-  llvm::Type *getVTableType(const VTableLayout &layout);
+  llvm::Type *getVTableType(const CXXRecordDecl *RD,
+                            const VTableLayout &layout);
 };
 
 } // end namespace CodeGen
Index: clang/lib/CodeGen/CGVTables.cpp
===================================================================
--- clang/lib/CodeGen/CGVTables.cpp
+++ clang/lib/CodeGen/CGVTables.cpp
@@ -586,15 +586,43 @@
     maybeEmitThunk(GD, Thunk, /*ForVTable=*/false);
 }
 
-void CodeGenVTables::addVTableComponent(
-    ConstantArrayBuilder &builder, const VTableLayout &layout,
-    unsigned idx, llvm::Constant *rtti, unsigned &nextVTableThunkIndex) {
-  auto &component = layout.vtable_components()[idx];
+llvm::Constant *CodeGenVTables::makeRelative(llvm::Constant *C,
+                                             llvm::GlobalVariable *VTable,
+                                             unsigned vtableIdx,
+                                             unsigned lastAddrPoint) const {
+  llvm::Type *Int32Ty = CGM.Int32Ty;
+  llvm::Type *PtrDiffTy =
+      CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType());
+  llvm::Type *VTableTy = VTable->getValueType();
+  llvm::Constant *gep = llvm::ConstantExpr::getGetElementPtr(
+      VTableTy, VTable,
+      llvm::ArrayRef<llvm::Constant *>{
+          llvm::ConstantInt::get(Int32Ty, 0),
+          llvm::ConstantInt::get(Int32Ty, vtableIdx),
+          llvm::ConstantInt::get(Int32Ty, lastAddrPoint)});
+
+  llvm::Constant *AddrPointInt =
+      llvm::ConstantExpr::getPtrToInt(gep, PtrDiffTy);
+  llvm::Constant *ptrToInt = llvm::ConstantExpr::getPtrToInt(C, PtrDiffTy);
+
+  return llvm::ConstantExpr::getIntegerCast(
+      llvm::ConstantExpr::getSub(ptrToInt, AddrPointInt), Int32Ty,
+      /*isSigned=*/true);
+}
+
+llvm::Constant *CodeGenVTables::getVTableComponent(
+    const VTableLayout &layout, unsigned componentIdx, unsigned vtableIdx,
+    llvm::Constant *rtti, unsigned &nextVTableThunkIndex, bool RelativeABI) {
+  auto &component = layout.getVTableComponent(componentIdx);
+
+  llvm::Type *Int8PtrTy = CGM.Int8PtrTy;
+  llvm::Type *Int32Ty = CGM.Int32Ty;
+  llvm::Type *FunctionPtrTy = RelativeABI ? Int32Ty : Int8PtrTy;
 
   auto addOffsetConstant = [&](CharUnits offset) {
-    builder.add(llvm::ConstantExpr::getIntToPtr(
+    return llvm::ConstantExpr::getIntToPtr(
         llvm::ConstantInt::get(CGM.PtrDiffTy, offset.getQuantity()),
-        CGM.Int8PtrTy));
+        CGM.Int8PtrTy);
   };
 
   switch (component.getKind()) {
@@ -608,7 +636,7 @@
     return addOffsetConstant(component.getOffsetToTop());
 
   case VTableComponent::CK_RTTI:
-    return builder.add(llvm::ConstantExpr::getBitCast(rtti, CGM.Int8PtrTy));
+    return llvm::ConstantExpr::getBitCast(rtti, CGM.Int8PtrTy);
 
   case VTableComponent::CK_FunctionPointer:
   case VTableComponent::CK_CompleteDtorPointer:
@@ -642,7 +670,7 @@
               ? MD->hasAttr<CUDADeviceAttr>()
               : (MD->hasAttr<CUDAHostAttr>() || !MD->hasAttr<CUDADeviceAttr>());
       if (!CanEmitMethod)
-        return builder.addNullPointer(CGM.Int8PtrTy);
+        return llvm::ConstantExpr::getNullValue(FunctionPtrTy);
       // Method is acceptable, continue processing as usual.
     }
 
@@ -674,7 +702,8 @@
 
     // Thunks.
     } else if (nextVTableThunkIndex < layout.vtable_thunks().size() &&
-               layout.vtable_thunks()[nextVTableThunkIndex].first == idx) {
+               layout.vtable_thunks()[nextVTableThunkIndex].first ==
+                   componentIdx) {
       auto &thunkInfo = layout.vtable_thunks()[nextVTableThunkIndex].second;
 
       nextVTableThunkIndex++;
@@ -686,40 +715,104 @@
       fnPtr = CGM.GetAddrOfFunction(GD, fnTy, /*ForVTable=*/true);
     }
 
-    fnPtr = llvm::ConstantExpr::getBitCast(fnPtr, CGM.Int8PtrTy);
-    builder.add(fnPtr);
-    return;
+    return llvm::ConstantExpr::getBitCast(fnPtr, CGM.Int8PtrTy);
   }
 
   case VTableComponent::CK_UnusedFunctionPointer:
-    return builder.addNullPointer(CGM.Int8PtrTy);
+    return llvm::ConstantExpr::getNullValue(FunctionPtrTy);
   }
 
   llvm_unreachable("Unexpected vtable component kind");
 }
 
-llvm::Type *CodeGenVTables::getVTableType(const VTableLayout &layout) {
-  SmallVector<llvm::Type *, 4> tys;
+llvm::Type *CodeGenVTables::getVTableType(const CXXRecordDecl *RD,
+                                          const VTableLayout &layout) {
+  SmallVector<llvm::Type *, 4> types;
   for (unsigned i = 0, e = layout.getNumVTables(); i != e; ++i) {
-    tys.push_back(llvm::ArrayType::get(CGM.Int8PtrTy, layout.getVTableSize(i)));
+    if (!RD->isRelativeCXXABI()) {
+      types.push_back(
+          llvm::ArrayType::get(CGM.Int8PtrTy, layout.getVTableSize(i)));
+    } else {
+      SmallVector<llvm::Type *, 4> innerTypes;
+      size_t thisIndex = layout.getVTableOffset(i);
+      size_t nextIndex = thisIndex + layout.getVTableSize(i);
+      for (unsigned componentIdx = thisIndex; componentIdx != nextIndex;
+           ++componentIdx) {
+        auto &component = layout.getVTableComponent(componentIdx);
+        if (component.isFunctionPointerKind())
+          innerTypes.push_back(CGM.Int32Ty);
+        else
+          innerTypes.push_back(CGM.Int8PtrTy);
+      }
+      types.push_back(llvm::StructType::get(CGM.getLLVMContext(), innerTypes));
+    }
   }
 
-  return llvm::StructType::get(CGM.getLLVMContext(), tys);
+  return llvm::StructType::get(CGM.getLLVMContext(), types);
 }
 
-void CodeGenVTables::createVTableInitializer(ConstantStructBuilder &builder,
-                                             const VTableLayout &layout,
-                                             llvm::Constant *rtti) {
+template <class BuilderTy>
+void CodeGenVTables::buildVTableElement(BuilderTy &builder,
+                                        llvm::GlobalVariable *VTable,
+                                        const VTableLayout &VTLayout,
+                                        llvm::Constant *RTTI,
+                                        unsigned &nextVTableThunkIndex,
+                                        unsigned vtableIdx, bool RelativeABI) {
+  // We want to point to the first function in the vtable. This would
+  // normally be the 3rd component under Itanium ABI (2nd for Microsoft),
+  // but not in the case of virtual inheritance. For both of these ABIs, the
+  // first virtual function comes after the RTTI component, so we can just
+  // check if the previous component was RTTI.
+  //
+  // FIXME: Need a better way of identifying address points that works with
+  // the Itanium and MS ABIs.
+  unsigned lastAddrPoint = 0;
+
+  size_t thisIndex = VTLayout.getVTableOffset(vtableIdx);
+  size_t nextIndex = thisIndex + VTLayout.getVTableSize(vtableIdx);
+  for (unsigned componentIdx = thisIndex; componentIdx != nextIndex;
+       ++componentIdx) {
+    if (componentIdx > 0 &&
+        VTLayout.getVTableComponent(componentIdx - 1).isRTTIKind())
+      lastAddrPoint = componentIdx;
+
+    llvm::Constant *component =
+        getVTableComponent(VTLayout, componentIdx, vtableIdx, RTTI,
+                           nextVTableThunkIndex, RelativeABI);
+
+    auto &layoutComponent = VTLayout.getVTableComponent(componentIdx);
+    if (RelativeABI && layoutComponent.isUsedFunctionPointerKind())
+      component =
+          makeRelative(component, VTable, vtableIdx, lastAddrPoint - thisIndex);
+
+    builder.add(component);
+  }
+}
+
+void CodeGenVTables::SetVTableInitializer(llvm::GlobalVariable *VTable,
+                                          const VTableLayout &VTLayout,
+                                          llvm::Constant *RTTI,
+                                          bool RelativeABI) {
+  ConstantInitBuilder builder(CGM);
+  auto components = builder.beginStruct();
+
   unsigned nextVTableThunkIndex = 0;
-  for (unsigned i = 0, e = layout.getNumVTables(); i != e; ++i) {
-    auto vtableElem = builder.beginArray(CGM.Int8PtrTy);
-    size_t thisIndex = layout.getVTableOffset(i);
-    size_t nextIndex = thisIndex + layout.getVTableSize(i);
-    for (unsigned i = thisIndex; i != nextIndex; ++i) {
-      addVTableComponent(vtableElem, layout, i, rtti, nextVTableThunkIndex);
+  for (unsigned vtableIdx = 0; vtableIdx != VTLayout.getNumVTables();
+       ++vtableIdx) {
+    if (!RelativeABI) {
+      auto vtableElem = components.beginArray(CGM.Int8PtrTy);
+      buildVTableElement(vtableElem, VTable, VTLayout, RTTI,
+                         nextVTableThunkIndex, vtableIdx, RelativeABI);
+      vtableElem.finishAndAddTo(components);
+    } else {
+      auto vtableElem = components.beginStruct();
+      buildVTableElement(vtableElem, VTable, VTLayout, RTTI,
+                         nextVTableThunkIndex, vtableIdx, RelativeABI);
+      vtableElem.finishAndAddTo(components);
     }
-    vtableElem.finishAndAddTo(builder);
   }
+
+  components.finishAndSetAsInitializer(VTable);
 }
 
 llvm::GlobalVariable *
@@ -746,7 +839,7 @@
                            Base.getBase(), Out);
   StringRef Name = OutName.str();
 
-  llvm::Type *VTType = getVTableType(*VTLayout);
+  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
@@ -769,10 +862,7 @@
       CGM.getContext().getTagDeclType(Base.getBase()));
 
   // Create and set the initializer.
-  ConstantInitBuilder builder(CGM);
-  auto components = builder.beginStruct();
-  createVTableInitializer(components, *VTLayout, RTTI);
-  components.finishAndSetAsInitializer(VTable);
+  SetVTableInitializer(VTable, *VTLayout, RTTI, RD->isRelativeCXXABI());
 
   // Set properties only after the initializer has been set to ensure that the
   // GV is treated as definition and not declaration.
@@ -1053,8 +1143,10 @@
 
   ArrayRef<VTableComponent> Comps = VTLayout.vtable_components();
   for (auto AP : AddressPoints) {
+    CharUnits ByteOffset = PointerWidth * AP.second;
+
     // Create type metadata for the address point.
-    AddVTableTypeMetadata(VTable, PointerWidth * AP.second, AP.first);
+    AddVTableTypeMetadata(VTable, ByteOffset, AP.first);
 
     // The class associated with each address point could also potentially be
     // used for indirect calls via a member function pointer, so we need to
Index: clang/lib/CodeGen/CGDebugInfo.cpp
===================================================================
--- clang/lib/CodeGen/CGDebugInfo.cpp
+++ clang/lib/CodeGen/CGDebugInfo.cpp
@@ -1542,8 +1542,11 @@
     if (CGM.getTarget().getCXXABI().isItaniumFamily()) {
       // It doesn't make sense to give a virtual destructor a vtable index,
       // since a single destructor has two entries in the vtable.
-      if (!isa<CXXDestructorDecl>(Method))
+      if (!isa<CXXDestructorDecl>(Method) &&
+          !Method->getParent()->isRelativeCXXABI())
         VIndex = CGM.getItaniumVTableContext().getMethodVTableIndex(Method);
+      else
+        VIndex = -1u;
     } else {
       // Emit MS ABI vftable information.  There is only one entry for the
       // deleting dtor.
Index: clang/lib/CodeGen/CGClass.cpp
===================================================================
--- clang/lib/CodeGen/CGClass.cpp
+++ clang/lib/CodeGen/CGClass.cpp
@@ -2587,6 +2587,23 @@
   return VTable;
 }
 
+llvm::Value *CodeGenFunction::GetVirtualFunctionFromVTable(
+    const CXXRecordDecl *RD, llvm::Value *VTable, uint64_t VTableIndex,
+    llvm::Type *Ty) {
+  if (!RD->isRelativeCXXABI()) {
+    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, Int8PtrTy);
+  llvm::Value *Load = Builder.CreateCall(
+      CGM.getIntrinsic(llvm::Intrinsic::load_relative, {Int32Ty}),
+      {VTable, llvm::ConstantInt::get(Int32Ty, 4 * VTableIndex)});
+  return Builder.CreateBitCast(Load, Ty->getPointerTo());
+}
+
 // If a class has a single non-virtual base and does not introduce or override
 // virtual member functions or fields, it will have the same layout as its base.
 // This function returns the least derived such class.
Index: clang/lib/AST/DeclCXX.cpp
===================================================================
--- clang/lib/AST/DeclCXX.cpp
+++ clang/lib/AST/DeclCXX.cpp
@@ -35,6 +35,7 @@
 #include "clang/Basic/PartialDiagnostic.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/Specifiers.h"
+#include "clang/Basic/TargetInfo.h"
 #include "llvm/ADT/None.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallVector.h"
@@ -102,7 +103,8 @@
       ImplicitCopyAssignmentHasConstParam(true),
       HasDeclaredCopyConstructorWithConstParam(false),
       HasDeclaredCopyAssignmentWithConstParam(false), IsLambda(false),
-      IsParsingBaseSpecifiers(false), HasODRHash(false), Definition(D) {}
+      IsParsingBaseSpecifiers(false), IsRelativeCXXABI(false),
+      HasODRHash(false), Definition(D) {}
 
 CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getBasesSlowCase() const {
   return Bases.get(Definition->getASTContext().getExternalSource());
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -10972,6 +10972,9 @@
   // (including field initializers) is fully parsed.
   SmallVector<CXXRecordDecl*, 4> DelayedDllExportClasses;
 
+  /// Determine if this class can use the relative vtable ABI.
+  void checkClassABI(CXXRecordDecl *RD);
+
 private:
   class SavePendingParsedClassStateRAII {
   public:
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -1245,6 +1245,10 @@
   "fno-fine-grained-bitfield-accesses">, Group<f_clang_Group>, Flags<[CC1Option]>,
   HelpText<"Use large-integer access for consecutive bitfield runs.">;
 
+def fexperimental_relative_cxx_abi_vtables : Flag<["-"], "fexperimental-relative-c++-abi-vtables">,
+  Group<f_Group>, Flags<[CC1Option]>,
+  HelpText<"Use the experimental C++ class ABI for classes with virtual tables">;
+
 def flat__namespace : Flag<["-"], "flat_namespace">;
 def flax_vector_conversions : Flag<["-"], "flax-vector-conversions">, Group<f_Group>;
 def flimited_precision_EQ : Joined<["-"], "flimited-precision=">, Group<f_Group>;
Index: clang/include/clang/Basic/LangOptions.def
===================================================================
--- clang/include/clang/Basic/LangOptions.def
+++ clang/include/clang/Basic/LangOptions.def
@@ -324,6 +324,10 @@
 
 LANGOPT(RegisterStaticDestructors, 1, 1, "Register C++ static destructors")
 
+LANGOPT(RelativeCXXABIVTables, 1, 0,
+        "Whether to use clang's relative C++ ABI "
+        "for classes with vtables")
+
 #undef LANGOPT
 #undef COMPATIBLE_LANGOPT
 #undef BENIGN_LANGOPT
Index: clang/include/clang/AST/VTableBuilder.h
===================================================================
--- clang/include/clang/AST/VTableBuilder.h
+++ clang/include/clang/AST/VTableBuilder.h
@@ -264,6 +264,10 @@
     return VTableComponents;
   }
 
+  VTableComponent &getVTableComponent(size_t i) const {
+    return VTableComponents[i];
+  }
+
   ArrayRef<VTableThunkTy> vtable_thunks() const {
     return VTableThunks;
   }
Index: clang/include/clang/AST/DeclCXX.h
===================================================================
--- clang/include/clang/AST/DeclCXX.h
+++ clang/include/clang/AST/DeclCXX.h
@@ -527,6 +527,9 @@
     /// Whether we are currently parsing base specifiers.
     unsigned IsParsingBaseSpecifiers : 1;
 
+    /// \brief Whether the class uses the relative C++ vtable ABI.
+    unsigned IsRelativeCXXABI : 1;
+
     unsigned HasODRHash : 1;
 
     /// A hash of parts of the class to help in ODR checking.
@@ -807,6 +810,10 @@
     return data().IsParsingBaseSpecifiers;
   }
 
+  void setIsRelativeCXXABI() { data().IsRelativeCXXABI = true; }
+
+  bool isRelativeCXXABI() const { return data().IsRelativeCXXABI; }
+
   unsigned getODRHash() const;
 
   /// Sets the base classes of this struct or class.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to