Author: Igor Kudrin Date: 2026-05-26T13:51:23-07:00 New Revision: 4ef6ca40f53fe5ef09b940a3d7d9a92a091dd878
URL: https://github.com/llvm/llvm-project/commit/4ef6ca40f53fe5ef09b940a3d7d9a92a091dd878 DIFF: https://github.com/llvm/llvm-project/commit/4ef6ca40f53fe5ef09b940a3d7d9a92a091dd878.diff LOG: [Clang][AArch64] Fix crash with large arguments to MTE built-ins (#197620) The second argument to `__builtin_arm_irg()` and `__builtin_arm_gmi()` is expected to be 64-bit. When a wider type is passed, the compiler still generates a `zext` instruction, leading to a backend error: ``` > cat test.c unsigned test(void* a, unsigned __int128 m) { return __builtin_arm_gmi(a, m); } > clang -target aarch64 -march=armv9+memtag -S test.c fatal error: error in backend: Cannot select: ... i64,ch = load<... zext from i128> ``` This is fixed by applying the required implicit conversions to the argument in Sema. Added: Modified: clang/include/clang/Basic/DiagnosticSemaKinds.td clang/lib/CodeGen/TargetBuiltins/ARM.cpp clang/lib/Sema/SemaARM.cpp clang/test/AST/ast-dump-aarch64-mte.c clang/test/CodeGen/arm64-mte.c clang/test/Sema/builtins-arm64-mte.c Removed: ################################################################################ diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index abcff004f597b..dffb27c4678dc 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -13284,8 +13284,6 @@ def err_memtag_any2arg_pointer : Error< "at least one argument of MTE builtin function must be a pointer (%0, %1 invalid)">; def err_memtag_arg_must_be_pointer : Error< "%0 argument of MTE builtin function must be a pointer (%1 invalid)">; -def err_memtag_arg_must_be_integer : Error< - "%0 argument of MTE builtin function must be an integer type (%1 invalid)">; def warn_dereference_of_noderef_type : Warning< "dereferencing %0; was declared with a 'noderef' type">, InGroup<NoDeref>; diff --git a/clang/lib/CodeGen/TargetBuiltins/ARM.cpp b/clang/lib/CodeGen/TargetBuiltins/ARM.cpp index f8990ced2a577..b7c7bc8ebf9a0 100644 --- a/clang/lib/CodeGen/TargetBuiltins/ARM.cpp +++ b/clang/lib/CodeGen/TargetBuiltins/ARM.cpp @@ -4914,8 +4914,8 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, if (MTEIntrinsicID == Intrinsic::aarch64_irg) { Value *Pointer = EmitScalarExpr(E->getArg(0)); Value *Mask = EmitScalarExpr(E->getArg(1)); - - Mask = Builder.CreateZExt(Mask, Int64Ty); + assert(Mask->getType()->getScalarSizeInBits() == 64 && + "SemaARM::BuiltinARMMemoryTaggingCall() enforces this"); return Builder.CreateCall(CGM.getIntrinsic(MTEIntrinsicID), {Pointer, Mask}); } @@ -4930,10 +4930,10 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, if (MTEIntrinsicID == Intrinsic::aarch64_gmi) { Value *Pointer = EmitScalarExpr(E->getArg(0)); Value *ExcludedMask = EmitScalarExpr(E->getArg(1)); - - ExcludedMask = Builder.CreateZExt(ExcludedMask, Int64Ty); - return Builder.CreateCall( - CGM.getIntrinsic(MTEIntrinsicID), {Pointer, ExcludedMask}); + assert(ExcludedMask->getType()->getScalarSizeInBits() == 64 && + "SemaARM::BuiltinARMMemoryTaggingCall() enforces this"); + return Builder.CreateCall(CGM.getIntrinsic(MTEIntrinsicID), + {Pointer, ExcludedMask}); } // Although it is possible to supply a diff erent return // address (first arg) to this intrinsic, for now we set diff --git a/clang/lib/Sema/SemaARM.cpp b/clang/lib/Sema/SemaARM.cpp index f57c9c8b87cd5..47e4b4f90485a 100644 --- a/clang/lib/Sema/SemaARM.cpp +++ b/clang/lib/Sema/SemaARM.cpp @@ -42,13 +42,14 @@ bool SemaARM::BuiltinARMMemoryTaggingCall(unsigned BuiltinID, << "first" << FirstArgType << Arg0->getSourceRange(); TheCall->setArg(0, FirstArg.get()); - ExprResult SecArg = SemaRef.DefaultLvalueConversion(Arg1); + InitializedEntity Entity = InitializedEntity::InitializeParameter( + Context, Context.getIntTypeForBitwidth(64, /*Signed=*/false), + /*Consumed=*/false); + ExprResult SecArg = + SemaRef.PerformCopyInitialization(Entity, + /*EqualLoc=*/SourceLocation(), Arg1); if (SecArg.isInvalid()) return true; - QualType SecArgType = SecArg.get()->getType(); - if (!SecArgType->isIntegerType()) - return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_integer) - << "second" << SecArgType << Arg1->getSourceRange(); TheCall->setArg(1, SecArg.get()); // Derive the return type from the pointer argument. @@ -92,13 +93,14 @@ bool SemaARM::BuiltinARMMemoryTaggingCall(unsigned BuiltinID, << "first" << FirstArgType << Arg0->getSourceRange(); TheCall->setArg(0, FirstArg.get()); - ExprResult SecArg = SemaRef.DefaultLvalueConversion(Arg1); + InitializedEntity Entity = InitializedEntity::InitializeParameter( + Context, Context.getIntTypeForBitwidth(64, /*Signed=*/false), + /*Consumed=*/false); + ExprResult SecArg = + SemaRef.PerformCopyInitialization(Entity, + /*EqualLoc=*/SourceLocation(), Arg1); if (SecArg.isInvalid()) return true; - QualType SecArgType = SecArg.get()->getType(); - if (!SecArgType->isIntegerType()) - return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_integer) - << "second" << SecArgType << Arg1->getSourceRange(); TheCall->setArg(1, SecArg.get()); return false; diff --git a/clang/test/AST/ast-dump-aarch64-mte.c b/clang/test/AST/ast-dump-aarch64-mte.c index c5def39676e9a..8e06371cafd77 100644 --- a/clang/test/AST/ast-dump-aarch64-mte.c +++ b/clang/test/AST/ast-dump-aarch64-mte.c @@ -21,8 +21,9 @@ void test() { // CHECK-NEXT: | | | `-DeclRefExpr {{.+}} '<builtin fn type>' Function {{.+}} '__builtin_arm_irg' 'void *(void *, unsigned long)' // CHECK-NEXT: | | |-ImplicitCastExpr {{.+}} 'struct A *' <LValueToRValue> // CHECK-NEXT: | | | `-DeclRefExpr {{.+}} 'struct A *' lvalue Var {{.+}} 'ptr_a' 'struct A *' - // CHECK-NEXT: | | `-ImplicitCastExpr {{.+}} 'unsigned int' <LValueToRValue> - // CHECK-NEXT: | | `-DeclRefExpr {{.+}} 'unsigned int' lvalue Var {{.+}} 'uval' 'unsigned int' + // CHECK-NEXT: | | `-ImplicitCastExpr {{.+}} 'unsigned long' <IntegralCast> + // CHECK-NEXT: | | `-ImplicitCastExpr {{.+}} 'unsigned int' <LValueToRValue> + // CHECK-NEXT: | | `-DeclRefExpr {{.+}} 'unsigned int' lvalue Var {{.+}} 'uval' 'unsigned int' ptr_a = __arm_mte_increment_tag(ptr_a, 5); // CHECK-NEXT: | |-BinaryOperator {{.+}} 'struct A *' '=' @@ -43,8 +44,9 @@ void test() { // CHECK-NEXT: | | | `-DeclRefExpr {{.+}} '<builtin fn type>' Function {{.+}} '__builtin_arm_gmi' 'unsigned long (void *, unsigned long)' // CHECK-NEXT: | | |-ImplicitCastExpr {{.+}} 'struct A *' <LValueToRValue> // CHECK-NEXT: | | | `-DeclRefExpr {{.+}} 'struct A *' lvalue Var {{.+}} 'ptr_a' 'struct A *' - // CHECK-NEXT: | | `-ImplicitCastExpr {{.+}} 'unsigned int' <LValueToRValue> - // CHECK-NEXT: | | `-DeclRefExpr {{.+}} 'unsigned int' lvalue Var {{.+}} 'uval' 'unsigned int' + // CHECK-NEXT: | | `-ImplicitCastExpr {{.+}} 'unsigned long' <IntegralCast> + // CHECK-NEXT: | | `-ImplicitCastExpr {{.+}} 'unsigned int' <LValueToRValue> + // CHECK-NEXT: | | `-DeclRefExpr {{.+}} 'unsigned int' lvalue Var {{.+}} 'uval' 'unsigned int' ptr_a = __arm_mte_get_tag(ptr_a); // CHECK-NEXT: | |-BinaryOperator {{.+}} 'struct A *' '=' diff --git a/clang/test/CodeGen/arm64-mte.c b/clang/test/CodeGen/arm64-mte.c index 9e2b3736ac4c0..6a00f12ce3671 100644 --- a/clang/test/CodeGen/arm64-mte.c +++ b/clang/test/CodeGen/arm64-mte.c @@ -13,7 +13,7 @@ // CHECK-LABEL: define{{.*}} ptr @create_tag1 attribute int *create_tag1(int *a, unsigned b) { -// CHECK: [[T1:%[0-9]+]] = zext i32 %b to i64 +// CHECK: [[T1:%[a-z0-9]+]] = zext i32 %b to i64 // CHECK: [[T2:%[0-9]+]] = tail call ptr @llvm.aarch64.irg(ptr %a, i64 [[T1]]) return __arm_mte_create_random_tag(a,b); } @@ -21,7 +21,7 @@ int *create_tag1(int *a, unsigned b) { // CHECK-LABEL: define{{.*}} ptr @create_tag2 attribute short *create_tag2(short *a, unsigned b) { -// CHECK: [[T1:%[0-9]+]] = zext i32 %b to i64 +// CHECK: [[T1:%[a-z0-9]+]] = zext i32 %b to i64 // CHECK: [[T2:%[0-9]+]] = tail call ptr @llvm.aarch64.irg(ptr %a, i64 [[T1]]) return __arm_mte_create_random_tag(a,b); } @@ -29,7 +29,16 @@ short *create_tag2(short *a, unsigned b) { // CHECK-LABEL: define{{.*}} ptr @create_tag3 attribute char *create_tag3(char *a, unsigned b) { -// CHECK: [[T1:%[0-9]+]] = zext i32 %b to i64 +// CHECK: [[T1:%[a-z0-9]+]] = zext i32 %b to i64 +// CHECK: [[T2:%[0-9]+]] = tail call ptr @llvm.aarch64.irg(ptr %a, i64 [[T1]]) +// CHECK: ret ptr [[T2:%[0-9]+]] + return __arm_mte_create_random_tag(a,b); +} + +// CHECK-LABEL: define{{.*}} ptr @create_tag4 +attribute +char *create_tag4(char *a, unsigned __int128 b) { +// CHECK: [[T1:%[a-z0-9]+]] = trunc i128 %b to i64 // CHECK: [[T2:%[0-9]+]] = tail call ptr @llvm.aarch64.irg(ptr %a, i64 [[T1]]) // CHECK: ret ptr [[T2:%[0-9]+]] return __arm_mte_create_random_tag(a,b); @@ -52,7 +61,7 @@ short *increment_tag2(short *a) { // CHECK-LABEL: define{{.*}} i32 @exclude_tag1 attribute unsigned exclude_tag1(int *a, unsigned m) { -// CHECK: [[T0:%[0-9]+]] = zext i32 %m to i64 +// CHECK: [[T0:%[a-z0-9]+]] = zext i32 %m to i64 // CHECK: [[T2:%[0-9]+]] = tail call i64 @llvm.aarch64.gmi(ptr %a, i64 [[T0]]) // CHECK: trunc i64 [[T2]] to i32 return __arm_mte_exclude_tag(a, m); @@ -61,12 +70,21 @@ unsigned exclude_tag1(int *a, unsigned m) { // CHECK-LABEL: define{{.*}} i32 @exclude_tag2 attribute int exclude_tag2(int *a, unsigned m) { -// CHECK: [[T0:%[0-9]+]] = zext i32 %m to i64 +// CHECK: [[T0:%[a-z0-9]+]] = zext i32 %m to i64 // CHECK: [[T2:%[0-9]+]] = tail call i64 @llvm.aarch64.gmi(ptr %a, i64 [[T0]]) // CHECK: trunc i64 [[T2]] to i32 return __arm_mte_exclude_tag(a, m); } +// CHECK-LABEL: define{{.*}} i128 @exclude_tag3 +attribute +unsigned __int128 exclude_tag3(int *a, unsigned __int128 m) { +// CHECK: [[T0:%[a-z0-9]+]] = trunc i128 %m to i64 +// CHECK: [[T2:%[0-9]+]] = tail call i64 @llvm.aarch64.gmi(ptr %a, i64 [[T0]]) +// CHECK: zext i64 [[T2]] to i128 + return __arm_mte_exclude_tag(a, m); +} + // CHECK-LABEL: define{{.*}} ptr @get_tag1 attribute int *get_tag1(int *a) { diff --git a/clang/test/Sema/builtins-arm64-mte.c b/clang/test/Sema/builtins-arm64-mte.c index 1b0621f3c5e31..252ff88c4fd56 100644 --- a/clang/test/Sema/builtins-arm64-mte.c +++ b/clang/test/Sema/builtins-arm64-mte.c @@ -11,8 +11,13 @@ int *create_tag1(int a, unsigned b) { } int *create_tag2(int *a, unsigned *b) { - // expected-error@+1 {{second argument of MTE builtin function must be an integer type ('unsigned int *' invalid)}} +#ifdef __cplusplus + // expected-error@+1 {{cannot initialize a parameter of type 'unsigned long' with an lvalue of type 'unsigned int *'}} + return __arm_mte_create_random_tag(a,b); +#else + // expected-error@+1 {{incompatible pointer to integer conversion passing 'unsigned int *' to parameter of type 'unsigned long'}} return __arm_mte_create_random_tag(a,b); +#endif } int *create_tag3(const int *a, unsigned b) { @@ -76,8 +81,13 @@ unsigned exclude_tag1(int *ptr, unsigned m) { } unsigned exclude_tag2(int *ptr, int *m) { - // expected-error@+1 {{second argument of MTE builtin function must be an integer type ('int *' invalid)}} +#ifdef __cplusplus + // expected-error@+1 {{cannot initialize a parameter of type 'unsigned long' with an lvalue of type 'int *'}} return __arm_mte_exclude_tag(ptr, m); +#else + // expected-error@+1 {{incompatible pointer to integer conversion passing 'int *' to parameter of type 'unsigned long'}} + return __arm_mte_exclude_tag(ptr, m); +#endif } void get_tag1(void) { @@ -142,4 +152,4 @@ int *create_tag1(int *a, unsigned b) { // expected-error@+1 {{'__builtin_arm_irg' needs target feature mte}} return __arm_mte_create_random_tag(a,b); } -#endif \ No newline at end of file +#endif _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
