llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang-codegen Author: Jon Roelofs (jroelofs) <details> <summary>Changes</summary> The new builtin behaves like __builtin_ptrauth_auth_and_resign, but incorporates the address of the signing instruction (i.e. the `pacibsppc`/`paciasppc`) when performing the auth side, and subsequently re-signs using a different scheme. Authenticating the re-signed value will fail if and only if authenticating the original value with the incorporated pc would have failed. --- Patch is 29.92 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/202742.diff 14 Files Affected: - (modified) clang/docs/PointerAuthentication.rst (+16) - (modified) clang/include/clang/Basic/Builtins.td (+6) - (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+3-1) - (modified) clang/lib/CodeGen/CGBuiltin.cpp (+14) - (modified) clang/lib/Headers/ptrauth.h (+38) - (modified) clang/lib/Sema/SemaChecking.cpp (+39-2) - (modified) clang/test/CodeGen/ptrauth-intrinsics.c (+14) - (modified) clang/test/Sema/ptrauth-intrinsics-macro.c (+5) - (modified) clang/test/Sema/ptrauth.c (+27) - (modified) llvm/include/llvm/IR/Intrinsics.td (+13) - (modified) llvm/lib/IR/Verifier.cpp (+9) - (modified) llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp (+47) - (modified) llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp (+61) - (added) llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-with-pc-and-resign.ll (+93) ``````````diff diff --git a/clang/docs/PointerAuthentication.rst b/clang/docs/PointerAuthentication.rst index bf2520b32a3a4..9f0a30caf5343 100644 --- a/clang/docs/PointerAuthentication.rst +++ b/clang/docs/PointerAuthentication.rst @@ -687,6 +687,22 @@ computations may still be attackable. In the future, Clang should be enhanced to guarantee non-attackability if these expressions are :ref:`safely-derived<Safe derivation>`. +``ptrauth_auth_with_pc_and_resign`` + +.. code-block:: c + + ptrauth_auth_with_pc_and_resign(pointer, oldKey, oldDiscriminator, oldPC, newKey, newDiscriminator) + +Similar to :ref:`ptrauth_auth_and_resign`, but additionally requires that the +signature includes the address of the signing instruction (i.e. uses `paciasppc` +/ `pacibsppc` instead of `paciasp` / `pacibsp`). This authenticates ``pointer`` +signed with ``oldKey`` and ``oldDiscriminator`` at ``oldPC``, then resigns the +raw-pointer result with ``newKey`` and ``newDiscriminator``. + +Note: ``oldKey`` must be ``ptrauth_key_asia`` (IA) or ``ptrauth_key_asib`` (IB), +as only these keys support PC-based authentication instructions. Data keys +(``ptrauth_key_asda`` / ``ptrauth_key_asdb``) are not supported. + ``ptrauth_auth_function`` ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index e7fb43be8794e..d8a3215cd8627 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -5013,6 +5013,12 @@ def PtrauthAuthAndResign : Builtin { let Prototype = "void*(void*,int,void*,int,void*)"; } +def PtrauthAuthWithPCAndResign : Builtin { + let Spellings = ["__builtin_ptrauth_auth_with_pc_and_resign"]; + let Attributes = [CustomTypeChecking, NoThrow]; + let Prototype = "void*(void*,int,void*,void*,int,void*)"; +} + def PtrauthAuthLoadRelativeAndSign : Builtin { let Spellings = ["__builtin_ptrauth_auth_load_relative_and_sign"]; let Attributes = [CustomTypeChecking, NoThrow]; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index d3e2d616a8b80..224726d35f294 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1010,7 +1010,7 @@ def err_ptrauth_invalid_key : "the current target">; def err_ptrauth_value_bad_type : Error<"%select{signed value|extra discriminator|blended pointer|blended " - "integer}0 must have %select{pointer|integer|pointer or integer}1 " + "integer|blended pc}0 must have %select{pointer|integer|pointer or integer}1 " "type; type here is %2">; def err_ptrauth_bad_constant_pointer : Error<"argument to ptrauth_sign_constant must refer to a global variable " @@ -1025,6 +1025,8 @@ def warn_ptrauth_sign_null_pointer : def warn_ptrauth_auth_null_pointer : Warning<"authenticating a null pointer will almost certainly trap">, InGroup<PtrAuthNullPointers>; +def err_ptrauth_auth_with_pc_and_resign_invalid_key : + Error<"ptrauth_auth_with_pc_and_resign only supports auth with IA and IB keys, not %0">; def err_ptrauth_string_not_literal : Error< "argument must be a string literal%select{| of char type}0">; def err_ptrauth_type_disc_undiscriminated : Error< diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 682b125890fe1..5f2ba6412da78 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -6249,6 +6249,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_ptrauth_auth: case Builtin::BI__builtin_ptrauth_auth_and_resign: + case Builtin::BI__builtin_ptrauth_auth_with_pc_and_resign: case Builtin::BI__builtin_ptrauth_auth_load_relative_and_sign: case Builtin::BI__builtin_ptrauth_blend_discriminator: case Builtin::BI__builtin_ptrauth_sign_generic_data: @@ -6265,6 +6266,17 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, Args[0] = Builder.CreatePtrToInt(Args[0], IntPtrTy); switch (BuiltinID) { + case Builtin::BI__builtin_ptrauth_auth_with_pc_and_resign: + // Convert oldDiscriminator (arg 2), oldPC (arg 3) and newDiscriminator + // (arg 5) to intptr_t + if (Args[2]->getType()->isPointerTy()) + Args[2] = Builder.CreatePtrToInt(Args[2], IntPtrTy); + if (Args[3]->getType()->isPointerTy()) + Args[3] = Builder.CreatePtrToInt(Args[3], IntPtrTy); + if (Args[5]->getType()->isPointerTy()) + Args[5] = Builder.CreatePtrToInt(Args[5], IntPtrTy); + break; + case Builtin::BI__builtin_ptrauth_auth_and_resign: case Builtin::BI__builtin_ptrauth_auth_load_relative_and_sign: if (Args[4]->getType()->isPointerTy()) @@ -6294,6 +6306,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, return Intrinsic::ptrauth_auth; case Builtin::BI__builtin_ptrauth_auth_and_resign: return Intrinsic::ptrauth_resign; + case Builtin::BI__builtin_ptrauth_auth_with_pc_and_resign: + return Intrinsic::ptrauth_auth_with_pc_and_resign; case Builtin::BI__builtin_ptrauth_auth_load_relative_and_sign: return Intrinsic::ptrauth_resign_load_relative; case Builtin::BI__builtin_ptrauth_blend_discriminator: diff --git a/clang/lib/Headers/ptrauth.h b/clang/lib/Headers/ptrauth.h index cde1b3c4ebbe2..3b34c42b22fb3 100644 --- a/clang/lib/Headers/ptrauth.h +++ b/clang/lib/Headers/ptrauth.h @@ -178,6 +178,33 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t; __builtin_ptrauth_auth_and_resign(__value, __old_key, __old_data, __new_key, \ __new_data) +/* Authenticate a pointer using a PC-based signature scheme and resign + it using a different scheme. + + If the result is subsequently authenticated using the new scheme, that + authentication is guaranteed to fail if and only if the initial + authentication failed. + + The value must be an expression of pointer type. + The key must be a constant expression of type ptrauth_key. + The extra data must be an expression of pointer or integer type; + if an integer, it will be coerced to ptrauth_extra_data_t. + The oldpc must be an expression of pointer or integer type representing + the PC value where the original signature was created. + The result will have the same type as the original value. + + This operation is guaranteed to not leave the intermediate value + available for attack before it is re-signed. The authentication is + performed using autia171615/autib171615 instructions which include the + PC value in the signature. + + Do not pass a null pointer to this function. A null pointer + will not successfully authenticate. */ +#define ptrauth_auth_with_pc_and_resign(__value, __old_key, __old_data, \ + __old_pc, __new_key, __new_data) \ + __builtin_ptrauth_auth_with_pc_and_resign(__value, __old_key, __old_data, \ + __old_pc, __new_key, __new_data) + /* Authenticate a pointer using one scheme, load 32bit value at offset addend from the pointer, and add this value to the pointer, sign using specified scheme. @@ -396,6 +423,17 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t; __value; \ }) +#define ptrauth_auth_with_pc_and_resign(__value, __old_key, __old_data, \ + __old_pc, __new_key, __new_data) \ + ({ \ + (void)__old_key; \ + (void)__old_data; \ + (void)__old_pc; \ + (void)__new_key; \ + (void)__new_data; \ + __value; \ + }) + #define ptrauth_auth_load_relative_and_sign(__value, __old_key, __old_data, \ __new_key, __new_data, __offset) \ __extension__({ \ diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index b8a3f48a32f24..1d64f666d347e 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -1550,7 +1550,8 @@ enum PointerAuthOpKind { PAO_SignGeneric, PAO_Discriminator, PAO_BlendPointer, - PAO_BlendInteger + PAO_BlendInteger, + PAO_BlendPC }; } @@ -1676,7 +1677,7 @@ static bool checkPointerAuthValue(Sema &S, Expr *&Arg, PointerAuthOpKind OpKind, }; auto AllowsInteger = [](PointerAuthOpKind OpKind) { return OpKind == PAO_Discriminator || OpKind == PAO_BlendInteger || - OpKind == PAO_SignGeneric; + OpKind == PAO_SignGeneric || OpKind == PAO_BlendPC; }; // Require the value to have the right range of type. @@ -1695,6 +1696,7 @@ static bool checkPointerAuthValue(Sema &S, Expr *&Arg, PointerAuthOpKind OpKind, << unsigned(OpKind == PAO_Discriminator ? 1 : OpKind == PAO_BlendPointer ? 2 : OpKind == PAO_BlendInteger ? 3 + : OpKind == PAO_BlendPC ? 4 : 0) << unsigned(AllowsInteger(OpKind) ? (AllowsPointer(OpKind) ? 2 : 1) : 0) << Arg->getType() << Arg->getSourceRange(); @@ -1861,6 +1863,39 @@ static ExprResult PointerAuthAuthAndResign(Sema &S, CallExpr *Call) { return Call; } +static ExprResult PointerAuthAuthWithPCAndResign(Sema &S, CallExpr *Call) { + if (S.checkArgCount(Call, 6)) + return ExprError(); + if (checkPointerAuthEnabled(S, Call)) + return ExprError(); + if (checkPointerAuthValue(S, Call->getArgs()[0], PAO_Auth) || + checkPointerAuthKey(S, Call->getArgs()[1]) || + checkPointerAuthValue(S, Call->getArgs()[2], PAO_Discriminator) || + checkPointerAuthValue(S, Call->getArgs()[3], PAO_BlendPC) || + checkPointerAuthKey(S, Call->getArgs()[4]) || + checkPointerAuthValue(S, Call->getArgs()[5], PAO_Discriminator)) + return ExprError(); + + // Validate that the oldKey is IA or IB, not DA or DB. + // This enforces the constraint that auth_with_pc_and_resign only supports + // IA/IB keys for authentication, as only those keys support the PC-based + // signing instructions (paciasppc/pacibsppc). + unsigned OldKey = 0; + if (!S.checkConstantPointerAuthKey(Call->getArgs()[1], OldKey)) { + using AK = PointerAuthSchema::ARM8_3Key; + if (OldKey != static_cast<unsigned>(AK::ASIA) && + OldKey != static_cast<unsigned>(AK::ASIB)) { + S.Diag(Call->getArgs()[1]->getExprLoc(), + diag::err_ptrauth_auth_with_pc_and_resign_invalid_key) + << OldKey << Call->getArgs()[1]->getSourceRange(); + return ExprError(); + } + } + + Call->setType(Call->getArgs()[0]->getType()); + return Call; +} + static ExprResult PointerAuthAuthLoadRelativeAndSign(Sema &S, CallExpr *Call) { if (S.checkArgCount(Call, 6)) return ExprError(); @@ -3498,6 +3533,8 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, return PointerAuthSignGenericData(*this, TheCall); case Builtin::BI__builtin_ptrauth_auth_and_resign: return PointerAuthAuthAndResign(*this, TheCall); + case Builtin::BI__builtin_ptrauth_auth_with_pc_and_resign: + return PointerAuthAuthWithPCAndResign(*this, TheCall); case Builtin::BI__builtin_ptrauth_auth_load_relative_and_sign: return PointerAuthAuthLoadRelativeAndSign(*this, TheCall); case Builtin::BI__builtin_ptrauth_string_discriminator: diff --git a/clang/test/CodeGen/ptrauth-intrinsics.c b/clang/test/CodeGen/ptrauth-intrinsics.c index bd348f9b3551a..c98ce60dc9fc9 100644 --- a/clang/test/CodeGen/ptrauth-intrinsics.c +++ b/clang/test/CodeGen/ptrauth-intrinsics.c @@ -67,6 +67,20 @@ void test_auth_load_relative_and_sign() { fnptr = __builtin_ptrauth_auth_load_relative_and_sign(fnptr, 0, ptr_discriminator, 3, 15, 16L); } +// CHECK-LABEL: define {{.*}}void @test_auth_with_pc_and_resign() +void test_auth_with_pc_and_resign() { + // CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr, + // CHECK-NEXT: [[DISC0:%.*]] = load ptr, ptr @ptr_discriminator, + // CHECK-NEXT: [[PC:%.*]] = load ptr, ptr @ptr_discriminator, + // CHECK-NEXT: [[T0:%.*]] = ptrtoint ptr [[PTR]] to i64 + // CHECK-NEXT: [[DISC:%.*]] = ptrtoint ptr [[DISC0]] to i64 + // CHECK-NEXT: [[PCVAL:%.*]] = ptrtoint ptr [[PC]] to i64 + // CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.auth.with.pc.and.resign(i64 [[T0]], i32 0, i64 [[DISC]], i64 [[PCVAL]], i32 3, i64 15) + // CHECK-NEXT: [[RESULT:%.*]] = inttoptr i64 [[T1]] to ptr + // CHECK-NEXT: store ptr [[RESULT]], ptr @fnptr, + fnptr = __builtin_ptrauth_auth_with_pc_and_resign(fnptr, 0, ptr_discriminator, ptr_discriminator, 3, 15); +} + // CHECK-LABEL: define {{.*}}void @test_blend_discriminator() void test_blend_discriminator() { // CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr, diff --git a/clang/test/Sema/ptrauth-intrinsics-macro.c b/clang/test/Sema/ptrauth-intrinsics-macro.c index adbb71a9d6e50..fbe1149eec786 100644 --- a/clang/test/Sema/ptrauth-intrinsics-macro.c +++ b/clang/test/Sema/ptrauth-intrinsics-macro.c @@ -16,12 +16,17 @@ void test(int *dp, int value) { (void)t0; dp = ptrauth_sign_unauthenticated(dp, VALID_DATA_KEY, 0); dp = ptrauth_auth_and_resign(dp, VALID_DATA_KEY, dp, VALID_DATA_KEY, dp); + dp = ptrauth_auth_with_pc_and_resign(dp, VALID_CODE_KEY, dp, dp, VALID_DATA_KEY, dp); dp = ptrauth_auth_data(dp, VALID_DATA_KEY, 0); int pu0 = 0, pu1 = 0, pu2 = 0, pu3 = 0, pu4 = 0, pu5 = 0, pu6 = 0, pu7 = 0; ptrauth_blend_discriminator(&pu0, value); ptrauth_auth_and_resign(&pu1, VALID_DATA_KEY, dp, VALID_DATA_KEY, dp); ptrauth_auth_and_resign(dp, VALID_DATA_KEY, &pu2, VALID_DATA_KEY, dp); ptrauth_auth_and_resign(dp, VALID_DATA_KEY, dp, VALID_DATA_KEY, &pu3); + ptrauth_auth_with_pc_and_resign(&pu1, VALID_CODE_KEY, dp, dp, VALID_DATA_KEY, dp); + ptrauth_auth_with_pc_and_resign(dp, VALID_CODE_KEY, &pu2, dp, VALID_DATA_KEY, dp); + ptrauth_auth_with_pc_and_resign(dp, VALID_CODE_KEY, dp, &pu3, VALID_DATA_KEY, dp); + ptrauth_auth_with_pc_and_resign(dp, VALID_CODE_KEY, dp, dp, VALID_DATA_KEY, &pu4); ptrauth_sign_generic_data(pu4, dp); ptrauth_sign_generic_data(dp, pu5); ptrauth_auth_data(&pu6, VALID_DATA_KEY, value); diff --git a/clang/test/Sema/ptrauth.c b/clang/test/Sema/ptrauth.c index 59c18a3ef5e40..5aae042f50c96 100644 --- a/clang/test/Sema/ptrauth.c +++ b/clang/test/Sema/ptrauth.c @@ -145,6 +145,33 @@ void test_auth_load_relative_and_sign(int *dp, int (*fp)(int)) { float *mismatch = __builtin_ptrauth_auth_load_relative_and_sign(dp, VALID_DATA_KEY, 0, VALID_DATA_KEY, dp,0); // expected-error {{incompatible pointer types initializing 'float *' with an expression of type 'int *'}} } +void test_auth_with_pc_and_resign(int *dp, int (*fp)(int), void *pc) { + __builtin_ptrauth_auth_with_pc_and_resign(dp, VALID_DATA_KEY, 0, pc, VALID_DATA_KEY); // expected-error {{too few arguments}} + __builtin_ptrauth_auth_with_pc_and_resign(dp, VALID_DATA_KEY, dp, pc, VALID_DATA_KEY, dp, 0); // expected-error {{too many arguments}} + + __builtin_ptrauth_auth_with_pc_and_resign(mismatched_type, VALID_DATA_KEY, 0, pc, VALID_DATA_KEY, dp); // expected-error {{signed value must have pointer type; type here is 'struct A'}} + __builtin_ptrauth_auth_with_pc_and_resign(dp, mismatched_type, 0, pc, VALID_DATA_KEY, dp); // expected-error {{passing 'struct A' to parameter of incompatible type 'int'}} + __builtin_ptrauth_auth_with_pc_and_resign(dp, VALID_DATA_KEY, mismatched_type, pc, VALID_DATA_KEY, dp); // expected-error {{extra discriminator must have pointer or integer type; type here is 'struct A'}} + __builtin_ptrauth_auth_with_pc_and_resign(dp, VALID_DATA_KEY, 0, mismatched_type, VALID_DATA_KEY, dp); // expected-error {{blended pc must have pointer or integer type; type here is 'struct A'}} + __builtin_ptrauth_auth_with_pc_and_resign(dp, VALID_DATA_KEY, 0, pc, mismatched_type, dp); // expected-error {{passing 'struct A' to parameter of incompatible type 'int'}} + __builtin_ptrauth_auth_with_pc_and_resign(dp, VALID_DATA_KEY, 0, pc, VALID_DATA_KEY, mismatched_type); // expected-error {{extra discriminator must have pointer or integer type; type here is 'struct A'}} + + (void) __builtin_ptrauth_auth_with_pc_and_resign(NULL, VALID_DATA_KEY, 0, pc, VALID_DATA_KEY, dp); // expected-error {{ptrauth_auth_with_pc_and_resign only supports auth with IA and IB keys, not 2}} expected-warning {{authenticating a null pointer will almost certainly trap}} + + // Test that data keys (DA/DB) are rejected for oldKey + int *dr = __builtin_ptrauth_auth_with_pc_and_resign(dp, VALID_DATA_KEY, 0, pc, VALID_DATA_KEY, dp); // expected-error {{ptrauth_auth_with_pc_and_resign only supports auth with IA and IB keys, not 2}} + dr = __builtin_ptrauth_auth_with_pc_and_resign(dp, 3, 0, pc, VALID_DATA_KEY, dp); // expected-error {{ptrauth_auth_with_pc_and_resign only supports auth with IA and IB keys, not 3}} + dr = __builtin_ptrauth_auth_with_pc_and_resign(dp, INVALID_KEY, 0, pc, VALID_DATA_KEY, dp); // expected-error {{does not identify a valid pointer authentication key for the current target}} + dr = __builtin_ptrauth_auth_with_pc_and_resign(dp, VALID_CODE_KEY, 0, pc, INVALID_KEY, dp); // expected-error {{does not identify a valid pointer authentication key for the current target}} + + // Test with valid IA/IB keys + int (*fr)(int) = __builtin_ptrauth_auth_with_pc_and_resign(fp, VALID_CODE_KEY, 0, pc, VALID_CODE_KEY, dp); + fr = __builtin_ptrauth_auth_with_pc_and_resign(fp, INVALID_KEY, 0, pc, VALID_CODE_KEY, dp); // expected-error {{does not identify a valid pointer authentication key for the current target}} + fr = __builtin_ptrauth_auth_with_pc_and_resign(fp, VALID_CODE_KEY, 0, pc, INVALID_KEY, dp); // expected-error {{does not identify a valid pointer authentication key for the current target}} + + float *mismatch = __builtin_ptrauth_auth_with_pc_and_resign(dp, VALID_CODE_KEY, 0, pc, VALID_DATA_KEY, dp); // expected-error {{incompatible pointer types initializing 'float *' with an expression of type 'int *'}} +} + void test_sign_generic_data(int *dp) { __builtin_ptrauth_sign_generic_data(dp); // expected-error {{too few arguments}} __builtin_ptrauth_sign_generic_data(dp, 0, 0); // expected-error {{too many arguments}} diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td index b1b2bb2a72c65..b6d41fb543af9 100644 --- a/llvm/include/llvm/IR/Intrinsics.td +++ b/llvm/include/llvm/IR/Intrinsics.td @@ -1839,6 +1839,19 @@ def int_experimental_patchpoint : Intrinsic<[llvm_any_ty], ImmArg<ArgIndex<1>>, ImmArg<ArgIndex<3>>]>; +// Authenticate a signed pointer using a PC-based signature and resign it. +// The second (key) and third (discriminator) arguments specify the signing +// schema used for authenticating. +// The fourth argument specifies the signing PC value. +// The fifth and sixth arguments specify the schema used for resigning. +// The signature must be valid. +// This uses autia171615/autib171615 for authentication with PC, then signs normally. +def int_ptrauth_auth_with_pc_and_resign : Intrinsic<[llvm_i64_ty], + [llvm_i64_ty, llvm_i32_ty, llvm_i64_ty, + llvm_i64_ty, llvm_i32_ty, llvm_i64_ty], + [IntrNoMem, ImmArg<ArgIndex<1>>, + ImmArg<ArgIndex<4>>]>; + //===------------------------ Garbage Collection Intrinsics ---------------===// // These are documented in docs/Statepoint.rst diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index f0363b6553440..ca681cb4b572c 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -7458,6 +7458,15 @@ void Verifie... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/202742 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
