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

Reply via email to