[clang] [clang] Add builtin_get_vtable_pointer and virtual_member_address (PR #135469)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Apr 11 20:25:06 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-codegen
Author: Oliver Hunt (ojhunt)
<details>
<summary>Changes</summary>
These are a pair of builtins to support particularly weird edge case operations while correctly handling the non-trivial implicit pointer authentication schemas applied to polymorphic members.
---
Patch is 39.14 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/135469.diff
9 Files Affected:
- (modified) clang/docs/LanguageExtensions.rst (+33)
- (modified) clang/include/clang/Basic/Builtins.td (+12)
- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+15)
- (modified) clang/lib/CodeGen/CGBuiltin.cpp (+30)
- (modified) clang/lib/Sema/SemaChecking.cpp (+90)
- (added) clang/test/CodeGenCXX/builtin-get-vtable-pointer.cpp (+304)
- (added) clang/test/CodeGenCXX/builtin_virtual_member_address.cpp (+41)
- (added) clang/test/SemaCXX/builtin-get-vtable-pointer.cpp (+123)
- (added) clang/test/SemaCXX/builtin_virtual_member_address.cpp (+57)
``````````diff
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index 3b8a9cac6587a..643dea3c6cbf7 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -3031,6 +3031,39 @@ following way:
Query for this feature with ``__has_builtin(__builtin_offsetof)``.
+``__builtin_get_vtable_pointer``
+--------------------------------
+
+``__builtin_get_vtable_pointer`` loads and authenticates the primary vtable
+pointer from an instance of a polymorphic C++ class.
+
+**Syntax**:
+
+.. code-block:: c++
+
+ __builtin_get_vtable_pointer(PolymorphicClass*)
+
+**Example of Use**:
+
+.. code-block:: c++
+
+ struct PolymorphicClass {
+ virtual ~PolymorphicClass();
+ };
+
+ PolymorphicClass anInstance;
+ const void* vtablePointer = __builtin_get_vtable_pointer(&anInstance);
+
+**Description**:
+
+The ``__builtin_get_vtable_pointer`` builtin loads the primary vtable
+pointer from a polymorphic C++ type. If the target platform authenticates
+vtable pointers, this builtin will perform the authentication and produce
+the underlying raw pointer. The object being queried must be polymorphic,
+and so must also be a complete type.
+
+Query for this feature with ``__has_builtin(__builtin_get_vtable_pointer)``.
+
``__builtin_call_with_static_chain``
------------------------------------
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 868e5b92acdc9..a55f411343c2d 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -970,6 +970,18 @@ def IsWithinLifetime : LangBuiltin<"CXX_LANG"> {
let Prototype = "bool(void*)";
}
+def GetVtablePointer : LangBuiltin<"CXX_LANG"> {
+ let Spellings = ["__builtin_get_vtable_pointer"];
+ let Attributes = [CustomTypeChecking, NoThrow, Const];
+ let Prototype = "void*(void*)";
+}
+
+def VirtualMemberAddress : Builtin {
+ let Spellings = ["__builtin_virtual_member_address"];
+ let Attributes = [CustomTypeChecking, NoThrow, Const];
+ let Prototype = "void*(void*,void*)";
+}
+
// GCC exception builtins
def EHReturn : Builtin {
let Spellings = ["__builtin_eh_return"];
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 180ca39bc07e9..8c534850696d9 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1013,6 +1013,13 @@ def err_ptrauth_indirect_goto_addrlabel_arithmetic : Error<
"%select{subtraction|addition}0 of address-of-label expressions is not "
"supported with ptrauth indirect gotos">;
+def err_virtual_member_lhs_cxxrec : Error<
+ "first argument to __builtin_virtual_member_address must have C++ class type">;
+def err_virtual_member_addrof : Error<
+ "second argument to __builtin_virtual_member_address must be the address of a virtual C++ member function: for example '&Foo::func'">;
+def err_virtual_member_inherit : Error<
+ "first argument to __builtin_virtual_member_address must have a type deriving from class where second argument was defined">;
+
/// main()
// static main() is not an error in C, just in C++.
def warn_static_main : Warning<"'main' should not be declared static">,
@@ -12547,6 +12554,14 @@ def err_bit_cast_non_trivially_copyable : Error<
def err_bit_cast_type_size_mismatch : Error<
"size of '__builtin_bit_cast' source type %0 does not match destination type %1 (%2 vs %3 bytes)">;
+
+def err_get_vtable_pointer_incorrect_type : Error<
+ "__builtin_get_vtable_pointer requires an argument of%select{| polymorphic}0 class pointer type"
+ ", but %1 %select{was provided|has no virtual methods}0"
+>;
+def err_get_vtable_pointer_requires_complete_type : Error<
+ "__builtin_get_vtable_pointer requires an argument with a complete type, but %0 is incomplete">;
+
// SYCL-specific diagnostics
def warn_sycl_kernel_num_of_template_params : Warning<
"'sycl_kernel' attribute only applies to a function template with at least"
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index fe55dfffc1cbe..316f5debf89d7 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -17,6 +17,7 @@
#include "CGDebugInfo.h"
#include "CGObjCRuntime.h"
#include "CGOpenCLRuntime.h"
+#include "CGPointerAuthInfo.h"
#include "CGRecordLayout.h"
#include "CGValue.h"
#include "CodeGenFunction.h"
@@ -5349,6 +5350,35 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
return RValue::get(Result);
}
+ case Builtin::BI__builtin_virtual_member_address: {
+ Address This = EmitLValue(E->getArg(0)).getAddress();
+ APValue ConstMemFun;
+ E->getArg(1)->isCXX11ConstantExpr(getContext(), &ConstMemFun, nullptr);
+ const CXXMethodDecl *CXXMethod =
+ cast<CXXMethodDecl>(ConstMemFun.getMemberPointerDecl());
+ const CGFunctionInfo &FInfo =
+ CGM.getTypes().arrangeCXXMethodDeclaration(CXXMethod);
+ llvm::FunctionType *Ty = CGM.getTypes().GetFunctionType(FInfo);
+ CGCallee VCallee = CGM.getCXXABI().getVirtualFunctionPointer(
+ *this, CXXMethod, This, Ty, E->getBeginLoc());
+ llvm::Value *Callee = VCallee.getFunctionPointer();
+ if (const CGPointerAuthInfo &Schema = VCallee.getPointerAuthInfo())
+ Callee = EmitPointerAuthAuth(Schema, Callee);
+ return RValue::get(Callee);
+ }
+
+ case Builtin::BI__builtin_get_vtable_pointer: {
+ auto target = E->getArg(0);
+ auto type = target->getType();
+ auto decl = type->getPointeeCXXRecordDecl();
+ assert(decl);
+ auto thisAddress = EmitPointerWithAlignment(target);
+ assert(thisAddress.isValid());
+ auto vtablePointer =
+ GetVTablePtr(thisAddress, Int8PtrTy, decl, VTableAuthMode::MustTrap);
+ return RValue::get(vtablePointer);
+ }
+
case Builtin::BI__exception_code:
case Builtin::BI_exception_code:
return RValue::get(EmitSEHExceptionCode());
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index bffd0dd461d3d..77b8b304f7f0a 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -1764,6 +1764,57 @@ static ExprResult PointerAuthAuthAndResign(Sema &S, CallExpr *Call) {
return Call;
}
+static ExprResult VirtualMemberAddress(Sema &S, CallExpr *Call) {
+ if (S.checkArgCount(Call, 2))
+ return ExprError();
+
+ for (int i = 0; i < 2; ++i) {
+ auto ArgRValue = S.DefaultFunctionArrayLvalueConversion(Call->getArg(1));
+ if (ArgRValue.isInvalid())
+ return ExprError();
+
+ auto Arg = ArgRValue.get();
+ Call->setArg(1, Arg);
+ }
+
+ if (Call->getArg(0)->isTypeDependent() || Call->getArg(1)->isValueDependent())
+ return Call;
+
+ auto ThisArg = Call->getArg(0);
+ auto ThisTy = ThisArg->getType();
+ if (!ThisTy->getAsCXXRecordDecl()) {
+ S.Diag(ThisArg->getExprLoc(), diag::err_virtual_member_lhs_cxxrec);
+ return ExprError();
+ }
+
+ auto MemFunArg = Call->getArg(1);
+ APValue Result;
+ if (!MemFunArg->isCXX11ConstantExpr(S.getASTContext(), &Result, nullptr)) {
+ S.Diag(MemFunArg->getExprLoc(), diag::err_virtual_member_addrof);
+ return ExprError();
+ }
+
+ if (!Result.isMemberPointer() ||
+ !isa<CXXMethodDecl>(Result.getMemberPointerDecl())) {
+ S.Diag(MemFunArg->getExprLoc(), diag::err_virtual_member_addrof);
+ return ExprError();
+ }
+
+ auto CXXMethod = cast<CXXMethodDecl>(Result.getMemberPointerDecl());
+ if (!CXXMethod->isVirtual()) {
+ S.Diag(MemFunArg->getExprLoc(), diag::err_virtual_member_addrof);
+ return ExprError();
+ }
+
+ if (ThisTy->getAsCXXRecordDecl() != CXXMethod->getParent() &&
+ !S.IsDerivedFrom(Call->getBeginLoc(), ThisTy,
+ CXXMethod->getFunctionObjectParameterType())) {
+ S.Diag(ThisArg->getExprLoc(), diag::err_virtual_member_inherit);
+ return ExprError();
+ }
+ return Call;
+}
+
static ExprResult PointerAuthStringDiscriminator(Sema &S, CallExpr *Call) {
if (checkPointerAuthEnabled(S, Call))
return ExprError();
@@ -1782,6 +1833,39 @@ static ExprResult PointerAuthStringDiscriminator(Sema &S, CallExpr *Call) {
return Call;
}
+static ExprResult GetVTablePointer(Sema &S, CallExpr *call) {
+ if (S.checkArgCount(call, 1))
+ return ExprError();
+ auto rvalue = S.DefaultFunctionArrayLvalueConversion(call->getArg(0));
+ if (rvalue.isInvalid())
+ return ExprError();
+ call->setArg(0, rvalue.get());
+ auto expression = call->getArg(0);
+ QualType expressionType = expression->getType();
+ const CXXRecordDecl *objectType = expressionType->getPointeeCXXRecordDecl();
+ if (!expressionType->isPointerType() || !objectType) {
+ S.Diag(expression->getBeginLoc(),
+ diag::err_get_vtable_pointer_incorrect_type)
+ << 0 << expressionType;
+ return ExprError();
+ }
+ if (S.RequireCompleteType(
+ expression->getBeginLoc(), expressionType->getPointeeType(),
+ diag::err_get_vtable_pointer_requires_complete_type)) {
+ return ExprError();
+ }
+
+ if (!objectType->isPolymorphic()) {
+ S.Diag(expression->getBeginLoc(),
+ diag::err_get_vtable_pointer_incorrect_type)
+ << 1 << objectType;
+ return ExprError();
+ }
+ QualType returnType = S.Context.getPointerType(S.Context.VoidTy.withConst());
+ call->setType(returnType);
+ return call;
+}
+
static ExprResult BuiltinLaunder(Sema &S, CallExpr *TheCall) {
if (S.checkArgCount(TheCall, 1))
return ExprError();
@@ -2625,6 +2709,12 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
return PointerAuthAuthAndResign(*this, TheCall);
case Builtin::BI__builtin_ptrauth_string_discriminator:
return PointerAuthStringDiscriminator(*this, TheCall);
+
+ case Builtin::BI__builtin_get_vtable_pointer:
+ return GetVTablePointer(*this, TheCall);
+ case Builtin::BI__builtin_virtual_member_address:
+ return VirtualMemberAddress(*this, TheCall);
+
// OpenCL v2.0, s6.13.16 - Pipe functions
case Builtin::BIread_pipe:
case Builtin::BIwrite_pipe:
diff --git a/clang/test/CodeGenCXX/builtin-get-vtable-pointer.cpp b/clang/test/CodeGenCXX/builtin-get-vtable-pointer.cpp
new file mode 100644
index 0000000000000..5577e01a09f6f
--- /dev/null
+++ b/clang/test/CodeGenCXX/builtin-get-vtable-pointer.cpp
@@ -0,0 +1,304 @@
+// RUN: %clang_cc1 %s -x c++ -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -O1 -disable-llvm-passes -no-enable-noundef-analysis -o - | FileCheck --check-prefix=CHECK-NOAUTH %s
+// RUN: %clang_cc1 %s -x c++ -std=c++11 -triple arm64-apple-ios -fptrauth-calls -fptrauth-vtable-pointer-type-discrimination -emit-llvm -O1 -disable-llvm-passes -no-enable-noundef-analysis -o - | FileCheck --check-prefix=CHECK-TYPEAUTH %s
+// RUN: %clang_cc1 %s -x c++ -std=c++11 -triple arm64-apple-ios -fptrauth-calls -fptrauth-vtable-pointer-address-discrimination -emit-llvm -O1 -disable-llvm-passes -no-enable-noundef-analysis -o - | FileCheck --check-prefix=CHECK-ADDRESSAUTH %s
+// RUN: %clang_cc1 %s -x c++ -std=c++11 -triple arm64-apple-ios -fptrauth-calls -fptrauth-vtable-pointer-type-discrimination -fptrauth-vtable-pointer-address-discrimination -emit-llvm -O1 -disable-llvm-passes -no-enable-noundef-analysis -o - | FileCheck --check-prefix=CHECK-BOTHAUTH %s
+// FIXME: Assume load should not require -fstrict-vtable-pointers
+
+namespace test1 {
+struct A {
+ A();
+ virtual void bar();
+};
+
+struct B : A {
+ B();
+ virtual void foo();
+};
+
+struct Z : A {};
+struct C : Z, B {
+ C();
+ virtual void wibble();
+};
+
+struct D : virtual A {
+};
+
+struct E : D, B {
+};
+
+const void *a(A *o) {
+ // CHECK-NOAUTH: define ptr @_ZN5test11aEPNS_1AE(ptr %o) #0 {
+ // CHECK-TYPEAUTH: define ptr @_ZN5test11aEPNS_1AE(ptr %o) #0 {
+ return __builtin_get_vtable_pointer(o);
+ // CHECK-NOAUTH: %vtable = load ptr, ptr %0, align 8
+ // CHECK-TYPEAUTH: %0 = load ptr, ptr %o.addr, align 8
+ // CHECK-TYPEAUTH: %vtable = load ptr, ptr %0, align 8
+ // CHECK-TYPEAUTH: %1 = ptrtoint ptr %vtable to i64
+ // CHECK-TYPEAUTH: %2 = call i64 @llvm.ptrauth.auth(i64 %1, i32 2, i64 48388)
+ // CHECK-TYPEAUTH: %3 = inttoptr i64 %2 to ptr
+ // CHECK-TYPEAUTH: %4 = load volatile i8, ptr %3, align 8
+ // CHECK-ADDRESSAUTH: %2 = ptrtoint ptr %vtable to i64
+ // CHECK-ADDRESSAUTH: %3 = call i64 @llvm.ptrauth.auth(i64 %2, i32 2, i64 %1)
+ // CHECK-ADDRESSAUTH: %4 = inttoptr i64 %3 to ptr
+ // CHECK-ADDRESSAUTH: %5 = load volatile i8, ptr %4, align 8
+ // CHECK-BOTHAUTH: [[T1:%.*]] = ptrtoint ptr %0 to i64
+ // CHECK-BOTHAUTH: [[T2:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T1]], i64 48388)
+ // CHECK-BOTHAUTH: [[T3:%.*]] = ptrtoint ptr %vtable to i64
+ // CHECK-BOTHAUTH: [[T4:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[T3]], i32 2, i64 [[T2]])
+ // CHECK-BOTHAUTH: [[T5:%.*]] = inttoptr i64 [[T4]] to ptr
+ // CHECK-BOTHAUTH: [[T6:%.*]] = load volatile i8, ptr [[T5]], align 8
+}
+
+const void *b(B *o) {
+ // CHECK-TYPEAUTH: define ptr @_ZN5test11bEPNS_1BE(ptr %o) #0 {
+ // CHECK-NOAUTH: define ptr @_ZN5test11bEPNS_1BE(ptr %o) #0 {
+ return __builtin_get_vtable_pointer(o);
+ // CHECK-NOAUTH: %vtable = load ptr, ptr %0, align 8
+ // CHECK-TYPEAUTH: %vtable = load ptr, ptr %0, align 8
+ // CHECK-TYPEAUTH: %1 = ptrtoint ptr %vtable to i64
+ // CHECK-TYPEAUTH: %2 = call i64 @llvm.ptrauth.auth(i64 %1, i32 2, i64 48388)
+ // CHECK-TYPEAUTH: %3 = inttoptr i64 %2 to ptr
+ // CHECK-TYPEAUTH: %4 = load volatile i8, ptr %3, align 8
+ // CHECK-ADDRESSAUTH: %2 = ptrtoint ptr %vtable to i64
+ // CHECK-ADDRESSAUTH: %3 = call i64 @llvm.ptrauth.auth(i64 %2, i32 2, i64 %1)
+ // CHECK-ADDRESSAUTH: %4 = inttoptr i64 %3 to ptr
+ // CHECK-ADDRESSAUTH: %5 = load volatile i8, ptr %4, align 8
+ // CHECK-BOTHAUTH: [[T2:%.*]] = call i64 @llvm.ptrauth.blend(i64 %1, i64 48388)
+ // CHECK-BOTHAUTH: [[T3:%.*]] = ptrtoint ptr %vtable to i64
+ // CHECK-BOTHAUTH: [[T4:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[T3]], i32 2, i64 [[T2]])
+ // CHECK-BOTHAUTH: [[T5:%.*]] = inttoptr i64 [[T4]] to ptr
+ // CHECK-BOTHAUTH: [[T6:%.*]] = load volatile i8, ptr [[T5]], align 8
+}
+
+const void *b_as_A(B *o) {
+ // CHECK-NOAUTH: define ptr @_ZN5test16b_as_AEPNS_1BE(ptr %o) #0 {
+ return __builtin_get_vtable_pointer((A *)o);
+ // CHECK-NOAUTH: %vtable = load ptr, ptr %0, align 8
+ // CHECK-TYPEAUTH: %vtable = load ptr, ptr %0, align 8
+ // CHECK-TYPEAUTH: %1 = ptrtoint ptr %vtable to i64
+ // CHECK-TYPEAUTH: %2 = call i64 @llvm.ptrauth.auth(i64 %1, i32 2, i64 48388)
+ // CHECK-TYPEAUTH: %3 = inttoptr i64 %2 to ptr
+ // CHECK-TYPEAUTH: %4 = load volatile i8, ptr %3, align 8
+ // CHECK-ADDRESSAUTH: %2 = ptrtoint ptr %vtable to i64
+ // CHECK-ADDRESSAUTH: %3 = call i64 @llvm.ptrauth.auth(i64 %2, i32 2, i64 %1)
+ // CHECK-ADDRESSAUTH: %4 = inttoptr i64 %3 to ptr
+ // CHECK-ADDRESSAUTH: %5 = load volatile i8, ptr %4, align 8
+ // CHECK-BOTHAUTH: [[T2:%.*]] = call i64 @llvm.ptrauth.blend(i64 %1, i64 48388)
+ // CHECK-BOTHAUTH: [[T3:%.*]] = ptrtoint ptr %vtable to i64
+ // CHECK-BOTHAUTH: [[T4:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[T3]], i32 2, i64 [[T2]])
+ // CHECK-BOTHAUTH: [[T5:%.*]] = inttoptr i64 [[T4]] to ptr
+ // CHECK-BOTHAUTH: [[T6:%.*]] = load volatile i8, ptr [[T5]], align 8
+}
+
+const void *c(C *o) {
+ // CHECK-NOAUTH: define ptr @_ZN5test11cEPNS_1CE(ptr %o) #0 {
+ return __builtin_get_vtable_pointer(o);
+ // CHECK-NOAUTH: %vtable = load ptr, ptr %0, align 8
+ // CHECK-TYPEAUTH: %vtable = load ptr, ptr %0, align 8
+ // CHECK-TYPEAUTH: %1 = ptrtoint ptr %vtable to i64
+ // CHECK-TYPEAUTH: %2 = call i64 @llvm.ptrauth.auth(i64 %1, i32 2, i64 48388)
+ // CHECK-TYPEAUTH: %3 = inttoptr i64 %2 to ptr
+ // CHECK-TYPEAUTH: %4 = load volatile i8, ptr %3, align 8
+ // CHECK-ADDRESSAUTH: %2 = ptrtoint ptr %vtable to i64
+ // CHECK-ADDRESSAUTH: %3 = call i64 @llvm.ptrauth.auth(i64 %2, i32 2, i64 %1)
+ // CHECK-ADDRESSAUTH: %4 = inttoptr i64 %3 to ptr
+ // CHECK-ADDRESSAUTH: %5 = load volatile i8, ptr %4, align 8
+ // CHECK-BOTHAUTH: [[T2:%.*]] = call i64 @llvm.ptrauth.blend(i64 %1, i64 48388)
+ // CHECK-BOTHAUTH: [[T3:%.*]] = ptrtoint ptr %vtable to i64
+ // CHECK-BOTHAUTH: [[T4:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[T3]], i32 2, i64 [[T2]])
+ // CHECK-BOTHAUTH: [[T5:%.*]] = inttoptr i64 [[T4]] to ptr
+ // CHECK-BOTHAUTH: [[T6:%.*]] = load volatile i8, ptr [[T5]], align 8
+}
+
+const void *c_as_Z(C *o) {
+ // CHECK-NOAUTH: define ptr @_ZN5test16c_as_ZEPNS_1CE(ptr %o) #0 {
+ return __builtin_get_vtable_pointer((Z *)o);
+ // CHECK-NOAUTH: %0 = load ptr, ptr %o.addr, align 8
+ // CHECK-NOAUTH: %vtable = load ptr, ptr %0, align 8
+ // CHECK-TYPEAUTH: %vtable = load ptr, ptr %0, align 8
+ // CHECK-TYPEAUTH: %1 = ptrtoint ptr %vtable to i64
+ // CHECK-TYPEAUTH: %2 = call i64 @llvm.ptrauth.auth(i64 %1, i32 2, i64 48388)
+ // CHECK-TYPEAUTH: %3 = inttoptr i64 %2 to ptr
+ // CHECK-TYPEAUTH: %4 = load volatile i8, ptr %3, align 8
+ // CHECK-ADDRESSAUTH: %2 = ptrtoint ptr %vtable to i64
+ // CHECK-ADDRESSAUTH: %3 = call i64 @llvm.ptrauth.auth(i64 %2, i32 2, i64 %1)
+ // CHECK-ADDRESSAUTH: %4 = inttoptr i64 %3 to ptr
+ // CHECK-ADDRESSAUTH: %5 = load volatile i8, ptr %4, align 8
+ // CHECK-BOTHAUTH: [[T2:%.*]] = call i64 @llvm.ptrauth.blend(i64 %1, i64 48388)
+ // CHECK-BOTHAUTH: [[T3:%.*]] = ptrtoint ptr %vtable to i64
+ // CHECK-BOTHAUTH: [[T4:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[T3]], i32 2, i64 [[T2]])
+ // CHECK-BOTHAUTH: [[T5:%.*]] = inttoptr i64 [[T4]] to ptr
+ // CHECK-BOTHAUTH: [[T6:%.*]] = load volatile i8, ptr [[T5]], align 8
+}
+
+const void *c_as_B(C *o) {
+ // CHECK-NOAUTH: define ptr @_ZN5test16c_as_BEPNS_1CE(ptr %o) #0 {
+ return __builtin_get_vtable_pointer((B *)o);
+ // CHECK-NOAUTH: %add.ptr = getelementptr inbounds i8, ptr %0, i64 8
+ // CHECK-NOAUTH: br label %cast.end
+ // CHECK-NOAUTH: %cast.result = phi ptr [ %add.ptr, %cast.notnull ], [ null, %entry ]
+ // CHECK-NOAUTH: %vtable = load ptr, ptr %cast.result, align 8
+ // CHECK-TYPEAUTH: %cast.result = phi ptr [ %add.ptr, %cast.notnull ], [ null, %entry ]
+ // CHECK-TYPEAUTH: %vtable = load ptr, ptr %cast.result, align 8
+ // CHECK-TYPEAUTH: %2 = ptrtoint ptr %vtable to i64
+ // CHECK-TYPEAUTH: %3 = call i64 @llvm.ptrauth.auth(i64 %2, i32 2, i64 48388)
+ // CHECK-TYPEAUTH: %4 = inttoptr i64 %3 to ptr
+ // CHECK-TYPEAUTH: %5 = load volatile i8, ptr %4, align 8
+ // CHECK-ADDRESSAUTH: %2 = ptrtoint ptr %cast.result to i64
+ // CHECK-ADDRESSAUTH: %3 = ptrtoint ptr %vtable to i64
+ // CHECK-ADDRESSAUTH: %4 = call i64 @llvm.ptrauth.auth(i64 %3, i32 2, i64 %2)
+ // CHECK-ADDRESSAUTH: %5 = inttoptr i64 %4 to ptr
+ // CHECK-ADDRESSAUTH: %6 = load volatile i8, ptr %5, align 8
+ // CHECK-BOTHAUTH: [[T2:%.*]] = call i64 @llvm.ptrauth.blend(i64 %2, i64 48388)
+ // CHECK-BOTHAUTH: [[T3:%.*]] = ptrtoint ptr %vtable to i64
+ // CHECK-BOTHAUTH: [[T4:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[T3]], i32 2, i64 [[T2]])
+ // CHECK-BOTHAUTH: [[T5:%.*]] = inttoptr i64 [[T4]] to ptr
+ // CHECK-BOTHAUTH: [[T6:%.*]] = load volatile i8, ptr [[T5]], align 8
+}
+
+const void *d(D *o) {
+ // CHECK-NOAUTH: define ptr @_ZN5test11dEPNS_1DE(ptr %o) #0 {
+ return __builtin_get_vtable_pointer(o);
+ // CHECK-NOAUTH: %vtable = load ptr, ptr %0, align 8
+ // CHECK-TYPEAUTH: %vtable = load ptr, ptr %0, align 8
+ // CHECK-TYPEAUTH: %1 = ptrtoint ptr %vtable to i64
+ // CHECK-TYPEAUTH: %2 = call i64 @llvm.ptrauth.auth(i64 %1, i32 2, i64 48388)
+ // CHECK-TYPEAUTH: %3 = inttoptr i64 %2 to ptr
+ // CHECK-TYPEAUTH: %4 = load volatile i8, ptr %3, align 8
+ // CHECK-ADDRESSAUTH: %1 = ptrtoint ptr %0 to i64
+ // CHECK-ADDRESSAUTH: %2 = ptrtoint ptr %vtable to i64
+ // CHECK-ADDRESSAUTH: %3 = call i64 @llvm.ptrauth.auth(i64 %2, i32 2, i64 %1)
+ // CHECK-ADDRESSAUTH: %4 = inttoptr i64 %3 to ptr
+ // CHECK-ADDRESSAUTH: %5 = load volatile i8, ptr %4, align 8
+ // CHECK-BOTHAUTH: [[T1:%.*]] = ptrtoint ptr %0 to i64
+ // CHECK-BOTHAUTH: [[T2:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T1]], i64 48388)
+ // CHECK-BOTHAUTH: [[T3:%.*]] = ptrtoint ptr %vtable to i64
+ // CHECK-BOTHAUTH: [[T4:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[T3]], i32 2, i64 [[T2]])
+ // CHECK-BOTHAUTH: [[T5:%.*]] = inttoptr i64 [[T4]] to ptr
+ // CHECK-BOTHAUTH: [[T6:%.*]] = load volatile i8, ptr [[T5]], align 8
+}
+
+const void *d_as_A(D *o) {
+ // CHECK-NOAUTH: define ptr @_ZN5test16d_as_AEPNS_1DE(ptr %o...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/135469
More information about the cfe-commits
mailing list