new file mode 100644
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-O2" } */
+
+extern int use (int * b);
+
+int foo (int n)
+{
+ int * b = __builtin_alloca (n);
+ int a = use (b);
+ return a;
+}
+
+/* { dg-final { scan-assembler-times {\tirg\t} 1 } } */
+/* { dg-final { scan-assembler-times {\tstg\t} 2 } } */
new file mode 100644
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-O2" } */
+
+extern int use (int * b);
+
+extern int n1;
+extern int n2;
+extern int n3;
+
+int foo (void)
+{
+ int * b1 = __builtin_alloca (n1);
+ int * b2 = __builtin_alloca (n2);
+ int * b3 = __builtin_alloca (n3);
+ int a1 = use (b1);
+ int a2 = use (b2);
+ int a3 = use (b3);
+
+ return a1+a2+a3;
+}
+
+/* { dg-final { scan-assembler-times {\tirg\t} 1 } } */
+/* { dg-final { scan-assembler-times {\taddg\t} 3 } } */
+/* { dg-final { scan-assembler-times {\tstg\t} 4 } } */
new file mode 100644
@@ -0,0 +1,3 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fsanitize=kernel-hwaddress" } */
+/* { dg-error ".*'-fsanitize=memtag' is incompatible with '-fsanitize=kernel-hwaddress'.*" "" { target *-*-* } 0 } */
new file mode 100644
@@ -0,0 +1,3 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fsanitize=kernel-address" } */
+/* { dg-error ".*'-fsanitize=memtag' is incompatible with '-fsanitize=kernel-address'.*" "" { target *-*-* } 0 } */
new file mode 100644
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-O2 -fno-sanitize=memtag" } */
+
+int use (int * x);
+
+void foo (int n)
+{
+ int x = 99;
+ use (&x);
+}
+
+/* { dg-final { scan-assembler-not "irg" } } */
+/* { dg-final { scan-assembler-not "stg" } } */
+/* { dg-final { scan-assembler-not "st2g" } } */
+/* { dg-final { scan-assembler-not "subg" } } */
+/* { dg-final { scan-assembler-not "addg" } } */
new file mode 100644
@@ -0,0 +1,3 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fsanitize=address" } */
+/* { dg-error ".*'-fsanitize=memtag' is incompatible with '-fsanitize=address'.*" "" { target *-*-* } 0 } */
new file mode 100644
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-O2" } */
+/* FIXME - scan-assembler-times-not subg ? */
+/* FIXME - generate stgp instead of stg + str ? */
+
+int use (int * x);
+
+void foo (int n)
+{
+ int x = 99;
+ use (&x);
+}
+
+/* { dg-final { scan-assembler-times {\tirg\t} 1 } } */
+/* { dg-final { scan-assembler-times {\tstg\t} 2 } } */
new file mode 100644
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-O2" } */
+
+int use (int * x);
+
+void foo (int n)
+{
+ int a, b, c;
+ use(&a);
+ use(&b);
+ use(&c);
+}
+
+/* { dg-final { scan-assembler-times {\tirg\t} 1 } } */
+/* { dg-final { scan-assembler-times {\tstg\t} 3 } } */
+/* { dg-final { scan-assembler-times {\tst2g\t} 1 } } */
new file mode 100644
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-O2" } */
+/* FIXME - scan-assembler-times stz2p ? */
+
+struct A
+{
+ long a;
+ long b;
+ long c;
+ long d;
+};
+
+extern void use (struct A *a);
+
+long f (void)
+{
+ struct A a = {0, 0, 64, (long)&a};
+ use (&a);
+ return a.b;
+}
+
+/* { dg-final { scan-assembler-times {\tirg\t} 1 } } */
+/* { dg-final { scan-assembler-times {\tst2g\t} 2 } } */
new file mode 100644
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-O2" } */
+/* FIXME - add other checks later. For now make sure this does not ICE. */
+
+#define ARRAY_LEN 12000
+
+int create (void);
+
+void sort (int *data, int n);
+
+void sort_array()
+{
+ int data[ARRAY_LEN], i;
+
+ for (i=0; i<ARRAY_LEN; ++i)
+ {
+ data[i] = create ();
+ }
+
+ sort(data, ARRAY_LEN);
+}
+
+/* { dg-final { scan-assembler-times {\tirg\t} 1 } } */
+/* { dg-final { scan-assembler-times {\tst2g\t} 2 } } */
new file mode 100644
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-O0" } */
+
+/* FIXME - If x doesnt escape the function, why should MTE tagging be done for
+ x ? */
+
+extern int use (int *x);
+extern int bar (int *x);
+extern int baz (int *x);
+
+int a[10];
+
+int foo (int n)
+{
+ int x = use (a);
+ if (x)
+ return bar (a);
+ else
+ return baz (a);
+}
new file mode 100644
@@ -0,0 +1,32 @@
+# Copyright (C) 2024 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+# GCC testsuite that uses the `dg.exp' driver.
+
+# Load support procs.
+load_lib gcc-dg.exp
+
+# Initialize `dg'.
+dg-init
+
+# Main loop.
+if [check_effective_target_aarch64_mte] {
+ dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cCS\]]] \
+ "" "-fsanitize=memtag -march=armv8.5-a+memtag"
+}
+
+# All done.
+dg-finish
new file mode 100644
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-O2" } */
+
+int use (int * x);
+
+__attribute__((no_sanitize("memtag")))
+void foo (int n)
+{
+ int x = 99;
+ use (&x);
+}
+
+/* { dg-final { scan-assembler-not "irg" } } */
+/* { dg-final { scan-assembler-not "stg" } } */
+/* { dg-final { scan-assembler-not "st2g" } } */
+/* { dg-final { scan-assembler-not "subg" } } */
+/* { dg-final { scan-assembler-not "addg" } } */
new file mode 100644
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fdump-tree-asan -O2" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */
+
+extern int *use (int *b, int n);
+
+int* foo (int n)
+{
+ int b[n];
+ return use (b, n);
+}
+
+/* HWASAN_ALLOCA_POISON is used for alloca and VLAs when MEMTAG is in effect.
+ Although HWASAN_ALLOCA_UNPOISON is (also) used for untagging frame, it
+ doesnt hurt to check it in context of the current test. */
+/* { dg-final { scan-tree-dump "HWASAN_ALLOCA_POISON" "asan1" } } */
+/* { dg-final { scan-tree-dump "HWASAN_ALLOCA_UNPOISON" "asan1" } } */
new file mode 100644
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-O2" } */
+/* FIXME - scan-assembler-times-not addg ? */
+
+extern int *use (int *b, int n);
+
+int* foo (int n)
+{
+ int b[n];
+ return use (b, n);
+}
+
+/* { dg-final { scan-assembler-times {\tirg\t} 1 } } */
+/* { dg-final { scan-assembler-times {\tstg\t} 3 } } */
@@ -4698,6 +4698,18 @@ proc check_effective_target_aarch64_sve1_only { } {
&& ![check_effective_target_aarch64_sve2] }]
}
+# Return 1 if this is an AArch64 target supporting MTE.
+# FIXME what is aarch64_mte. more stubs needed ?
+proc check_effective_target_aarch64_mte { } {
+ if { ![istarget aarch64*-*-*] } {
+ return 0
+ }
+ return [check_no_compiler_messages aarch64_mte assembly {
+ #if !defined (__ARM_FEATURE_MEMORY_TAGGING)
+ #error FOO
+ #endif
+ } "-march=armv8.5-a+memtag"]
+}
# Return the size in bits of an SVE vector, or 0 if the size is variable.
proc aarch64_sve_bits { } {
return [check_cached_effective_target aarch64_sve_bits {