Author: PiJoules
Date: 2025-02-28T12:26:29-08:00
New Revision: d9edca4fe05245ace93f7f1577a2eb79ec6898b1

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

LOG: [CodeGen] Ensure relative vtables use llvm.type.checked.load.relative 
(#126785)

This intrinsic is used when whole program vtables is used in conjunction
with either CFI or virtual function elimination. The
`llvm.type.checked.load` is unconditionally used, but we need to use the
relative intrinsic for WPD and CFI to work correctly.

Added: 
    

Modified: 
    clang/lib/CodeGen/CGClass.cpp
    clang/lib/CodeGen/CGVTables.h
    clang/lib/CodeGen/ItaniumCXXABI.cpp
    clang/test/CodeGen/fat-lto-objects-cfi.cpp
    clang/test/CodeGenCXX/type-metadata.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp
index 7a1096fcbca82..fa69caa41936c 100644
--- a/clang/lib/CodeGen/CGClass.cpp
+++ b/clang/lib/CodeGen/CGClass.cpp
@@ -2937,9 +2937,13 @@ llvm::Value *CodeGenFunction::EmitVTableTypeCheckedLoad(
       CGM.CreateMetadataIdentifierForType(QualType(RD->getTypeForDecl(), 0));
   llvm::Value *TypeId = llvm::MetadataAsValue::get(CGM.getLLVMContext(), MD);
 
+  auto CheckedLoadIntrinsic = CGM.getVTables().useRelativeLayout()
+                                  ? llvm::Intrinsic::type_checked_load_relative
+                                  : llvm::Intrinsic::type_checked_load;
   llvm::Value *CheckedLoad = Builder.CreateCall(
-      CGM.getIntrinsic(llvm::Intrinsic::type_checked_load),
+      CGM.getIntrinsic(CheckedLoadIntrinsic),
       {VTable, llvm::ConstantInt::get(Int32Ty, VTableByteOffset), TypeId});
+
   llvm::Value *CheckResult = Builder.CreateExtractValue(CheckedLoad, 1);
 
   std::string TypeName = RD->getQualifiedNameAsString();

diff  --git a/clang/lib/CodeGen/CGVTables.h b/clang/lib/CodeGen/CGVTables.h
index c06bf7a525d9f..5c45e355fb145 100644
--- a/clang/lib/CodeGen/CGVTables.h
+++ b/clang/lib/CodeGen/CGVTables.h
@@ -75,10 +75,6 @@ class CodeGenVTables {
                             bool vtableHasLocalLinkage,
                             bool isCompleteDtor) const;
 
-  bool useRelativeLayout() const;
-
-  llvm::Type *getVTableComponentType() const;
-
 public:
   /// Add vtable components for the given vtable layout to the given
   /// global initializer.
@@ -151,6 +147,12 @@ class CodeGenVTables {
 
   /// Specify a global should not be instrumented with hwasan.
   void RemoveHwasanMetadata(llvm::GlobalValue *GV) const;
+
+  /// Return the type used as components for a vtable.
+  llvm::Type *getVTableComponentType() const;
+
+  /// Return true if the relative vtable layout is used.
+  bool useRelativeLayout() const;
 };
 
 } // end namespace CodeGen

diff  --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp 
b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index a84412bd5c045..bb9b6fd210667 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -2189,12 +2189,14 @@ CGCallee 
ItaniumCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF,
   uint64_t VTableIndex = 
CGM.getItaniumVTableContext().getMethodVTableIndex(GD);
   llvm::Value *VFunc, *VTableSlotPtr = nullptr;
   auto &Schema = CGM.getCodeGenOpts().PointerAuth.CXXVirtualFunctionPointers;
+
+  llvm::Type *ComponentTy = CGM.getVTables().getVTableComponentType();
+  uint64_t ByteOffset =
+      VTableIndex * CGM.getDataLayout().getTypeSizeInBits(ComponentTy) / 8;
+
   if (!Schema && CGF.ShouldEmitVTableTypeCheckedLoad(MethodDecl->getParent())) 
{
-    VFunc = CGF.EmitVTableTypeCheckedLoad(
-        MethodDecl->getParent(), VTable, PtrTy,
-        VTableIndex *
-            CGM.getContext().getTargetInfo().getPointerWidth(LangAS::Default) /
-            8);
+    VFunc = CGF.EmitVTableTypeCheckedLoad(MethodDecl->getParent(), VTable,
+                                          PtrTy, ByteOffset);
   } else {
     CGF.EmitTypeMetadataCodeForVCall(MethodDecl->getParent(), VTable, Loc);
 
@@ -2202,7 +2204,7 @@ CGCallee 
ItaniumCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF,
     if (CGM.getItaniumVTableContext().isRelativeLayout()) {
       VFuncLoad = CGF.Builder.CreateCall(
           CGM.getIntrinsic(llvm::Intrinsic::load_relative, {CGM.Int32Ty}),
-          {VTable, llvm::ConstantInt::get(CGM.Int32Ty, 4 * VTableIndex)});
+          {VTable, llvm::ConstantInt::get(CGM.Int32Ty, ByteOffset)});
     } else {
       VTableSlotPtr = CGF.Builder.CreateConstInBoundsGEP1_64(
           PtrTy, VTable, VTableIndex, "vfn");

diff  --git a/clang/test/CodeGen/fat-lto-objects-cfi.cpp 
b/clang/test/CodeGen/fat-lto-objects-cfi.cpp
index 6eee88884229f..a41412e0d5148 100644
--- a/clang/test/CodeGen/fat-lto-objects-cfi.cpp
+++ b/clang/test/CodeGen/fat-lto-objects-cfi.cpp
@@ -70,9 +70,9 @@ void foo(const void* ptr, size_t len, long disp_addr,
 // COM: llvm.type.checked.load, so we need to match the function body first.
 // NO_CHECKED_LOAD-LABEL: entry:
 // NO_CHECKED_LOAD-NEXT:    %vtable = load ptr, ptr %p1
-// NO_CHECKED_LOAD-NOT:   llvm.type.checked.load
-// NO_CHECKED_LOAD-NEXT:    %vfunc = load ptr, ptr %vtable
-// NO_CHECKED_LOAD-NEXT:    %call = tail call {{.*}} %vfunc(ptr {{.*}} %p1)
+// NO_CHECKED_LOAD-NOT:   llvm.type.checked.load.relative
+// NO_CHECKED_LOAD-NEXT:    %rel_load = tail call ptr 
@llvm.load.relative.i32(ptr %vtable, i32 0)
+// NO_CHECKED_LOAD-NEXT:    %call = tail call {{.*}} %rel_load(ptr {{.*}} %p1)
 // NO_CHECKED_LOAD-NEXT:    ret void
 
 // COM: Ensure that we don't crash in the backend anymore when clang uses

diff  --git a/clang/test/CodeGenCXX/type-metadata.cpp 
b/clang/test/CodeGenCXX/type-metadata.cpp
index 4ddfc3c2e3a8f..1cb2fed8db3e6 100644
--- a/clang/test/CodeGenCXX/type-metadata.cpp
+++ b/clang/test/CodeGenCXX/type-metadata.cpp
@@ -30,7 +30,7 @@
 // RUN: %clang_cc1 -fexperimental-relative-c++-abi-vtables -O2 -flto 
-flto-unit -triple x86_64-unknown-linux -fwhole-program-vtables -emit-llvm -o - 
%s | FileCheck --check-prefix=ITANIUM-OPT --check-prefix=RV-OPT-LAYOUT %s
 
 // Tests for cfi + whole-program-vtables:
-// RUN: %clang_cc1 -fexperimental-relative-c++-abi-vtables -flto -flto-unit 
-triple x86_64-unknown-linux -fvisibility=hidden -fsanitize=cfi-vcall 
-fsanitize-trap=cfi-vcall -fwhole-program-vtables -emit-llvm -o - %s | 
FileCheck --check-prefix=CFI --check-prefix=CFI-VT 
--check-prefix=ITANIUM-HIDDEN --check-prefix=ITANIUM-COMMON-MD 
--check-prefix=RV-MD --check-prefix=TC-ITANIUM %s
+// RUN: %clang_cc1 -fexperimental-relative-c++-abi-vtables -flto -flto-unit 
-triple x86_64-unknown-linux -fvisibility=hidden -fsanitize=cfi-vcall 
-fsanitize-trap=cfi-vcall -fwhole-program-vtables -emit-llvm -o - %s | 
FileCheck --check-prefix=CFI --check-prefix=CFI-VT 
--check-prefix=ITANIUM-HIDDEN --check-prefix=ITANIUM-COMMON-MD 
--check-prefix=RV-MD --check-prefix=TC-ITANIUM-RV %s
 
 // Tests that type metadata are annotated on vtables with 
`-profile-instrument=llvm` (which is equivalent to clang driver option 
`-fprofile-generate` without `-fcs-profile-generate`):
 // - In clang driver, `-fprofile-instrument` cc1 option is set to 'llvm' iff 
clang driver option `-fprofile-generate{,=}` is taking effect.
@@ -178,7 +178,8 @@ void af(A *a) {
   // TT-ITANIUM-HIDDEN: [[P:%[^ ]*]] = call i1 @llvm.type.test(ptr [[VT:%[^ 
]*]], metadata !"_ZTS1A")
   // TT-ITANIUM-DEFAULT: [[P:%[^ ]*]] = call i1 @llvm.public.type.test(ptr 
[[VT:%[^ ]*]], metadata !"_ZTS1A")
   // TT-MS: [[P:%[^ ]*]] = call i1 @llvm.type.test(ptr [[VT:%[^ ]*]], metadata 
!"?AUA@@")
-  // TC-ITANIUM: [[PAIR:%[^ ]*]] = call { ptr, i1 } 
@llvm.type.checked.load(ptr {{%[^ ]*}}, i32 0, metadata !"_ZTS1A")
+  // TC-ITANIUM:    [[PAIR:%[^ ]*]] = call { ptr, i1 } 
@llvm.type.checked.load(ptr {{%[^ ]*}}, i32 0, metadata !"_ZTS1A")
+  // TC-ITANIUM-RV: [[PAIR:%[^ ]*]] = call { ptr, i1 } 
@llvm.type.checked.load.relative(ptr {{%[^ ]*}}, i32 0, metadata !"_ZTS1A")
   // TC-MS: [[PAIR:%[^ ]*]] = call { ptr, i1 } @llvm.type.checked.load(ptr 
{{%[^ ]*}}, i32 0, metadata !"?AUA@@")
   // CFI-VT: [[P:%[^ ]*]] = extractvalue { ptr, i1 } [[PAIR]], 1
   // DIAG-NEXT: [[VTVALID0:%[^ ]*]] = call i1 @llvm.type.test(ptr [[VT]], 
metadata !"all-vtables")
@@ -211,7 +212,8 @@ void df1(D *d) {
   // TT-ITANIUM-HIDDEN: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, 
metadata ![[DTYPE:[0-9]+]])
   // TT-ITANIUM-DEFAULT: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, 
metadata ![[DTYPE:[0-9]+]])
   // TT-MS: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, metadata 
!"?AUA@@")
-  // TC-ITANIUM: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr 
{{%[^ ]*}}, i32 0, metadata ![[DTYPE:[0-9]+]])
+  // TC-ITANIUM:    {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr 
{{%[^ ]*}}, i32 0, metadata ![[DTYPE:[0-9]+]])
+  // TC-ITANIUM-RV: {{%[^ ]*}} = call { ptr, i1 } 
@llvm.type.checked.load.relative(ptr {{%[^ ]*}}, i32 0, metadata 
![[DTYPE:[0-9]+]])
   // TC-MS: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ 
]*}}, i32 0, metadata !"?AUA@@")
   d->f();
 }
@@ -222,7 +224,8 @@ void dg1(D *d) {
   // TT-ITANIUM-HIDDEN: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, 
metadata !"_ZTS1B")
   // TT-ITANIUM-DEFAULT: {{%[^ ]*}} = call i1 @llvm.public.type.test(ptr {{%[^ 
]*}}, metadata !"_ZTS1B")
   // TT-MS: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, metadata 
!"?AUB@@")
-  // TC-ITANIUM: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr 
{{%[^ ]*}}, i32 8, metadata !"_ZTS1B")
+  // TC-ITANIUM:    {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr 
{{%[^ ]*}}, i32 8, metadata !"_ZTS1B")
+  // TC-ITANIUM-RV: {{%[^ ]*}} = call { ptr, i1 } 
@llvm.type.checked.load.relative(ptr {{%[^ ]*}}, i32 4, metadata !"_ZTS1B")
   // TC-MS: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ 
]*}}, i32 0, metadata !"?AUB@@")
   d->g();
 }
@@ -233,7 +236,8 @@ void dh1(D *d) {
   // TT-ITANIUM-HIDDEN: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, 
metadata ![[DTYPE]])
   // TT-ITANIUM-DEFAULT: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, 
metadata ![[DTYPE]])
   // TT-MS: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, metadata 
![[DTYPE:[0-9]+]])
-  // TC-ITANIUM: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr 
{{%[^ ]*}}, i32 16, metadata ![[DTYPE]])
+  // TC-ITANIUM:    {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr 
{{%[^ ]*}}, i32 16, metadata ![[DTYPE]])
+  // TC-ITANIUM-RV: {{%[^ ]*}} = call { ptr, i1 } 
@llvm.type.checked.load.relative(ptr {{%[^ ]*}}, i32 8, metadata ![[DTYPE]])
   // TC-MS: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ 
]*}}, i32 8, metadata ![[DTYPE:[0-9]+]])
   d->h();
 }
@@ -293,7 +297,8 @@ void f(D *d) {
   // TT-ITANIUM-HIDDEN: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, 
metadata !"_ZTSN5test21DE")
   // TT-ITANIUM-DEFAULT: {{%[^ ]*}} = call i1 @llvm.public.type.test(ptr {{%[^ 
]*}}, metadata !"_ZTSN5test21DE")
   // TT-MS: {{%[^ ]*}} = call i1 @llvm.type.test(ptr {{%[^ ]*}}, metadata 
!"?AUA@test2@@")
-  // TC-ITANIUM: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr 
{{%[^ ]*}}, i32 8, metadata !"_ZTSN5test21DE")
+  // TC-ITANIUM:    {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr 
{{%[^ ]*}}, i32 8, metadata !"_ZTSN5test21DE")
+  // TC-ITANIUM-RV: {{%[^ ]*}} = call { ptr, i1 } 
@llvm.type.checked.load.relative(ptr {{%[^ ]*}}, i32 4, metadata 
!"_ZTSN5test21DE")
   // TC-MS: {{%[^ ]*}} = call { ptr, i1 } @llvm.type.checked.load(ptr {{%[^ 
]*}}, i32 0, metadata !"?AUA@test2@@")
   d->m_fn1();
 }


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to