[clang] f45f1c3 - Reland "[clang] Add experimental option to omit the RTTI component from the vtable when -fno-rtti is used"

Leonard Chan via cfe-commits cfe-commits at lists.llvm.org
Thu Sep 14 11:29:05 PDT 2023


Author: Leonard Chan
Date: 2023-09-14T18:28:37Z
New Revision: f45f1c3585e6b50dd134b3b23ac14d1ca322dc6f

URL: https://github.com/llvm/llvm-project/commit/f45f1c3585e6b50dd134b3b23ac14d1ca322dc6f
DIFF: https://github.com/llvm/llvm-project/commit/f45f1c3585e6b50dd134b3b23ac14d1ca322dc6f.diff

LOG: Reland "[clang] Add experimental option to omit the RTTI component from the vtable when -fno-rtti is used"

This reverts commit 070493ddbd9473499d6f00ca62bc6aa92808ed79 (and
relands the original change). This removes a test run that makes an
assumption of RTTI being on by default for a given target.

Added: 
    clang/test/CodeGenCXX/OmitRTTIComponentABI/simple-vtable-definition.cpp
    clang/test/CodeGenCXX/OmitRTTIComponentABI/vbase-offset.cpp
    clang/test/CodeGenCXX/OmitRTTIComponentABI/vtable-layout.cpp
    clang/test/Driver/omit-rtti-component-flag.cpp
    clang/test/Driver/omit-rtti-component-without-no-rtti.cpp

Modified: 
    clang/include/clang/Basic/DiagnosticDriverKinds.td
    clang/include/clang/Basic/LangOptions.def
    clang/include/clang/Driver/Options.td
    clang/lib/AST/VTableBuilder.cpp
    clang/lib/Driver/ToolChains/Clang.cpp
    clang/lib/Frontend/CompilerInvocation.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index 86567267cfb437a..9349ff85ca8a1d3 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -674,6 +674,9 @@ def err_cc1_round_trip_mismatch : Error<
 def err_cc1_unbounded_vscale_min : Error<
   "minimum vscale must be an unsigned integer greater than 0">;
 
+def err_drv_using_omit_rtti_component_without_no_rtti : Error<
+  "-fexperimental-omit-vtable-rtti call only be used with -fno-rtti">;
+
 def err_drv_ssp_missing_offset_argument : Error<
   "'%0' is used without '-mstack-protector-guard-offset', and there is no default">;
 

diff  --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 102209ce899d70c..e18b5b80a34e718 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -450,6 +450,9 @@ LANGOPT(SpeculativeLoadHardening, 1, 0, "Speculative load hardening enabled")
 LANGOPT(RelativeCXXABIVTables, 1, 0,
         "Use an ABI-incompatible v-table layout that uses relative references")
 
+LANGOPT(OmitVTableRTTI, 1, 0,
+        "Use an ABI-incompatible v-table layout that omits the RTTI component")
+
 LANGOPT(VScaleMin, 32, 0, "Minimum vscale value")
 LANGOPT(VScaleMax, 32, 0, "Maximum vscale value")
 

diff  --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 2d42d05859bc1d3..553c7928c4f949e 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -2671,6 +2671,12 @@ def fno_experimental_relative_cxx_abi_vtables :
   Group<f_clang_Group>, Visibility<[ClangOption, CC1Option]>,
   HelpText<"Do not use the experimental C++ class ABI for classes with virtual tables">;
 
+defm experimental_omit_vtable_rtti : BoolFOption<"experimental-omit-vtable-rtti",
+  LangOpts<"OmitVTableRTTI">, DefaultFalse,
+  PosFlag<SetTrue, [], [CC1Option], "Omit">,
+  NegFlag<SetFalse, [], [CC1Option], "Do not omit">,
+  BothFlags<[], [CC1Option], " the RTTI component from virtual tables">>;
+
 def fcxx_abi_EQ : Joined<["-"], "fc++-abi=">,
                   Group<f_clang_Group>, Visibility<[ClangOption, CC1Option]>,
                   HelpText<"C++ ABI to use. This will override the target C++ ABI.">;

diff  --git a/clang/lib/AST/VTableBuilder.cpp b/clang/lib/AST/VTableBuilder.cpp
index a587f9bdc758529..cce0a507e8077d8 100644
--- a/clang/lib/AST/VTableBuilder.cpp
+++ b/clang/lib/AST/VTableBuilder.cpp
@@ -665,7 +665,11 @@ CharUnits VCallAndVBaseOffsetBuilder::getCurrentOffsetOffset() const {
   // vtable address point. (We subtract 3 to account for the information just
   // above the address point, the RTTI info, the offset to top, and the
   // vcall offset itself).
-  int64_t OffsetIndex = -(int64_t)(3 + Components.size());
+  size_t NumComponentsAboveAddrPoint = 3;
+  if (Context.getLangOpts().OmitVTableRTTI)
+    NumComponentsAboveAddrPoint--;
+  int64_t OffsetIndex =
+      -(int64_t)(NumComponentsAboveAddrPoint + Components.size());
 
   // Under the relative ABI, the offset widths are 32-bit ints instead of
   // pointer widths.
@@ -1669,7 +1673,8 @@ void ItaniumVTableBuilder::LayoutPrimaryAndSecondaryVTables(
   Components.push_back(VTableComponent::MakeOffsetToTop(OffsetToTop));
 
   // Next, add the RTTI.
-  Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass));
+  if (!Context.getLangOpts().OmitVTableRTTI)
+    Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass));
 
   uint64_t AddressPoint = Components.size();
 

diff  --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 531677e92f73252..40e60585a8b8d6e 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -5526,6 +5526,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
   Args.AddLastArg(CmdArgs, options::OPT_fexperimental_relative_cxx_abi_vtables,
                   options::OPT_fno_experimental_relative_cxx_abi_vtables);
 
+  Args.AddLastArg(CmdArgs, options::OPT_fexperimental_omit_vtable_rtti,
+                  options::OPT_fno_experimental_omit_vtable_rtti);
+
   // Handle segmented stacks.
   Args.addOptInFlag(CmdArgs, options::OPT_fsplit_stack,
                     options::OPT_fno_split_stack);
@@ -6007,6 +6010,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
   Args.AddLastArg(CmdArgs, options::OPT_fexperimental_relative_cxx_abi_vtables,
                   options::OPT_fno_experimental_relative_cxx_abi_vtables);
 
+  Args.AddLastArg(CmdArgs, options::OPT_fexperimental_omit_vtable_rtti,
+                  options::OPT_fno_experimental_omit_vtable_rtti);
+
   if (Arg *A = Args.getLastArg(options::OPT_ffuchsia_api_level_EQ))
     A->render(Args, CmdArgs);
 

diff  --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 730db8e394f66f1..2dd299b5d10322d 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -4109,6 +4109,14 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
                    options::OPT_fno_experimental_relative_cxx_abi_vtables,
                    TargetCXXABI::usesRelativeVTables(T));
 
+  // RTTI is on by default.
+  bool HasRTTI = Args.hasFlag(options::OPT_frtti, options::OPT_fno_rtti, true);
+  Opts.OmitVTableRTTI =
+      Args.hasFlag(options::OPT_fexperimental_omit_vtable_rtti,
+                   options::OPT_fno_experimental_omit_vtable_rtti, false);
+  if (Opts.OmitVTableRTTI && HasRTTI)
+    Diags.Report(diag::err_drv_using_omit_rtti_component_without_no_rtti);
+
   for (const auto &A : Args.getAllArgValues(OPT_fmacro_prefix_map_EQ)) {
     auto Split = StringRef(A).split('=');
     Opts.MacroPrefixMap.insert(

diff  --git a/clang/test/CodeGenCXX/OmitRTTIComponentABI/simple-vtable-definition.cpp b/clang/test/CodeGenCXX/OmitRTTIComponentABI/simple-vtable-definition.cpp
new file mode 100644
index 000000000000000..99395ba0e05ec0b
--- /dev/null
+++ b/clang/test/CodeGenCXX/OmitRTTIComponentABI/simple-vtable-definition.cpp
@@ -0,0 +1,32 @@
+/// Check that -fexperimental-omit-vtable-rtti omits the RTTI component from
+/// the vtable.
+
+// RUN: %clang_cc1 %s -triple=aarch64-unknown-linux-gnu -fno-rtti -fexperimental-omit-vtable-rtti -S -o - -emit-llvm | FileCheck -check-prefixes=POINTER,RTTI %s
+// RUN: %clang_cc1 %s -triple=aarch64-unknown-linux-gnu -fexperimental-relative-c++-abi-vtables -fno-rtti -fexperimental-omit-vtable-rtti -S -o - -emit-llvm | FileCheck -check-prefixes=RELATIVE,RTTI %s
+
+/// Normally, the vtable would contain at least three components:
+/// - An offset to top
+/// - A pointer to the RTTI struct
+/// - A virtual function
+///
+/// Now vtables should have just two components.
+// POINTER: @_ZTV1A = unnamed_addr constant { [2 x ptr] } { [2 x ptr] [ptr null, ptr @_ZN1A3fooEv] }, align 8
+// RELATIVE: @_ZTV1A.local = private unnamed_addr constant { [2 x i32] } { [2 x i32] [i32 0, i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @_ZN1A3fooEv to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [2 x i32] }, ptr @_ZTV1A.local, i32 0, i32 0, i32 1) to i64)) to i32)] }, align 4
+// RELATIVE: @_ZTV1A = unnamed_addr alias { [2 x i32] }, ptr @_ZTV1A.local
+
+/// None of these supplementary symbols should be emitted with -fno-rtti, but
+/// as a sanity check lets make sure they're not emitted also.
+// RTTI-NOT: @_ZTVN10__cxxabiv117__class_type_infoE
+// RTTI-NOT: @_ZTS1A
+// RTTI-NOT: @_ZTI1A
+
+class A {
+public:
+  virtual void foo();
+};
+
+void A::foo() {}
+
+void A_foo(A *a) {
+  a->foo();
+}

diff  --git a/clang/test/CodeGenCXX/OmitRTTIComponentABI/vbase-offset.cpp b/clang/test/CodeGenCXX/OmitRTTIComponentABI/vbase-offset.cpp
new file mode 100644
index 000000000000000..d490cc2dbebe52e
--- /dev/null
+++ b/clang/test/CodeGenCXX/OmitRTTIComponentABI/vbase-offset.cpp
@@ -0,0 +1,51 @@
+/// Check that the offset to top calculation is adjusted to account for the
+/// omitted RTTI entry.
+
+// RUN: %clang_cc1 %s -triple=aarch64-unknown-linux-gnu -fexperimental-omit-vtable-rtti -fno-rtti -S -o - -emit-llvm | FileCheck -check-prefixes=POINTER %s
+// RUN: %clang_cc1 %s -triple=aarch64-unknown-linux-gnu -fexperimental-relative-c++-abi-vtables -fexperimental-omit-vtable-rtti -fno-rtti -S -o - -emit-llvm | FileCheck -check-prefixes=RELATIVE %s
+
+/// Some important things to check:
+/// - The n16 here represents the virtual thunk size. Normally this would be 24
+///   to represent 3 components (offset to top, RTTI component, vcall offset),
+///   but since one 8-byte component is removed, this is now 16.
+// POINTER-LABEL: @_ZTv0_n16_N7Derived1fEi(
+// POINTER-NEXT:  entry:
+// POINTER:        [[vtable:%.+]] = load ptr, ptr %this1, align 8
+
+/// Same here - When getting the vbase offset, we subtract 2 pointer sizes
+/// instead of 3.
+// POINTER-NEXT:   [[vbase_offset_ptr:%.+]] = getelementptr inbounds i8, ptr [[vtable]], i64 -16
+// POINTER-NEXT:   [[vbase_offset:%.+]] = load i64, ptr [[vbase_offset_ptr]], align 8
+// POINTER-NEXT:   [[adj_this:%.+]] = getelementptr inbounds i8, ptr %this1, i64 [[vbase_offset]]
+// POINTER:   [[call:%.+]] = tail call noundef i32 @_ZN7Derived1fEi(ptr noundef{{[^,]*}} [[adj_this]], i32 noundef {{.*}})
+// POINTER:   ret i32 [[call]]
+
+/// For relative vtables, it's almost the same except the offset sizes are
+/// halved.
+// RELATIVE-LABEL: @_ZTv0_n8_N7Derived1fEi(
+// RELATIVE-NEXT:  entry:
+// RELATIVE:        [[vtable:%.+]] = load ptr, ptr %this1, align 8
+// RELATIVE-NEXT:   [[vbase_offset_ptr:%.+]] = getelementptr inbounds i8, ptr [[vtable]], i64 -8
+// RELATIVE-NEXT:   [[vbase_offset:%.+]] = load i32, ptr [[vbase_offset_ptr]], align 4
+// RELATIVE-NEXT:   [[adj_this:%.+]] = getelementptr inbounds i8, ptr %this1, i32 [[vbase_offset]]
+// RELATIVE:        [[call:%.+]] = tail call noundef i32 @_ZN7Derived1fEi(ptr noundef{{[^,]*}} [[adj_this]], i32 noundef {{.*}})
+// RELATIVE:        ret i32 [[call]]
+
+class Base {
+public:
+  virtual int f(int x);
+
+private:
+  long x;
+};
+
+class Derived : public virtual Base {
+public:
+  virtual int f(int x);
+
+private:
+  long y;
+};
+
+int Base::f(int x) { return x + 1; }
+int Derived::f(int x) { return x + 2; }

diff  --git a/clang/test/CodeGenCXX/OmitRTTIComponentABI/vtable-layout.cpp b/clang/test/CodeGenCXX/OmitRTTIComponentABI/vtable-layout.cpp
new file mode 100644
index 000000000000000..bcc9264f5e5b84f
--- /dev/null
+++ b/clang/test/CodeGenCXX/OmitRTTIComponentABI/vtable-layout.cpp
@@ -0,0 +1,19 @@
+/// Ensure -fdump-vtable-layout omits the rtti component when passed -fexperimental-omit-vtable-rtti.
+
+// RUN: %clang_cc1 %s -triple=aarch64-unknown-linux-gnu -fno-rtti -fexperimental-omit-vtable-rtti -emit-llvm-only -fdump-vtable-layouts | FileCheck %s
+
+// CHECK:      Vtable for 'A' (2 entries).
+// CHECK-NEXT:    0 | offset_to_top (0)
+// CHECK-NEXT:        -- (A, 0) vtable address --
+// CHECK-NEXT:    1 | void A::foo()
+
+class A {
+public:
+  virtual void foo();
+};
+
+void A::foo() {}
+
+void A_foo(A *a) {
+  a->foo();
+}

diff  --git a/clang/test/Driver/omit-rtti-component-flag.cpp b/clang/test/Driver/omit-rtti-component-flag.cpp
new file mode 100644
index 000000000000000..54b88a8775ef3d2
--- /dev/null
+++ b/clang/test/Driver/omit-rtti-component-flag.cpp
@@ -0,0 +1,5 @@
+// RUN: %clangxx --target=aarch64-unknown-linux -fno-rtti -Xclang -fexperimental-omit-vtable-rtti -c %s -### 2>&1 | FileCheck %s --check-prefix=OMIT
+// RUN: %clangxx --target=aarch64-unknown-linux -fno-rtti -Xclang -fno-experimental-omit-vtable-rtti -c %s -### 2>&1 | FileCheck %s --check-prefix=NO-OMIT
+
+// OMIT: "-fexperimental-omit-vtable-rtti"
+// NO-OMIT-NOT: "-fexperimental-omit-vtable-rtti"

diff  --git a/clang/test/Driver/omit-rtti-component-without-no-rtti.cpp b/clang/test/Driver/omit-rtti-component-without-no-rtti.cpp
new file mode 100644
index 000000000000000..2108c7dea7f3386
--- /dev/null
+++ b/clang/test/Driver/omit-rtti-component-without-no-rtti.cpp
@@ -0,0 +1,12 @@
+/// Ensure that -fexperimental-omit-vtable-rtti is only allowed if rtti is
+/// disabled.
+
+// RUN: not %clang -c -Xclang -fexperimental-omit-vtable-rtti -frtti %s 2>&1 | FileCheck -check-prefix=ERROR %s
+// RUN: not %clang -c -Xclang -fexperimental-omit-vtable-rtti -fno-rtti -frtti %s 2>&1 | FileCheck -check-prefix=ERROR %s
+
+// RUN: %clang -c -Xclang -fexperimental-omit-vtable-rtti -fno-rtti %s 2>&1 | FileCheck -check-prefix=NO-ERROR %s --allow-empty
+// RUN: %clang -c -Xclang -fno-experimental-omit-vtable-rtti -frtti %s 2>&1 | FileCheck -check-prefix=NO-ERROR %s --allow-empty
+// RUN: %clang -c -Xclang -fexperimental-omit-vtable-rtti -Xclang -fno-experimental-omit-vtable-rtti -frtti %s 2>&1 | FileCheck -check-prefix=NO-ERROR %s --allow-empty
+
+// ERROR: -fexperimental-omit-vtable-rtti call only be used with -fno-rtti
+// NO-ERROR-NOT: -fexperimental-omit-vtable-rtti call only be used with -fno-rtti


        


More information about the cfe-commits mailing list