From: Indu Bhagat <indu.bha...@oracle.com>

Add basic tests for memtag-stack sanitizer.  Memtag stack sanitizer
uses target hooks to emit AArch64 specific MTE instructions.

gcc/testsuite:

        * lib/target-supports.exp:
        * gcc.target/aarch64/memtag/alloca-1.c: New test.
        * gcc.target/aarch64/memtag/alloca-3.c: New test.
        * gcc.target/aarch64/memtag/arguments-1.c: New test.
        * gcc.target/aarch64/memtag/arguments-2.c: New test.
        * gcc.target/aarch64/memtag/arguments-3.c: New test.
        * gcc.target/aarch64/memtag/arguments-4.c: New test.
        * gcc.target/aarch64/memtag/arguments.c: New test.
        * gcc.target/aarch64/memtag/basic-1.c: New test.
        * gcc.target/aarch64/memtag/basic-3.c: New test.
        * gcc.target/aarch64/memtag/basic-struct.c: New test.
        * gcc.target/aarch64/memtag/large-array.c: New test.
        * gcc.target/aarch64/memtag/local-no-escape.c: New test.
        * gcc.target/aarch64/memtag/memtag.exp: New file.
        * gcc.target/aarch64/memtag/no-sanitize-attribute.c: New test.
        * gcc.target/aarch64/memtag/value-init.c: New test.
        * gcc.target/aarch64/memtag/vararray-gimple.c: New test.
        * gcc.target/aarch64/memtag/vararray.c: New test.
        * gcc.target/aarch64/memtag/zero-init.c: New test.
        * gcc.target/aarch64/memtag/texec-1.c: New test.
        * gcc.target/aarch64/memtag/texec-2.c: New test.
        * gcc.target/aarch64/memtag/vla-1.c: New test.
        * gcc.target/aarch64/memtag/vla-2.c: New test.
        * testsuite/lib/target-supports.exp
        (check_effective_target_aarch64_mte): New funcction.

Co-authored-by: Indu Bhagat <indu.bha...@oracle.com>
Signed-off-by: Claudiu Zissulescu <claudiu.zissulescu-iancule...@oracle.com>
---
 .../gcc.target/aarch64/memtag/alloca-1.c      | 14 ++++
 .../gcc.target/aarch64/memtag/alloca-3.c      | 27 ++++++++
 .../gcc.target/aarch64/memtag/arguments-1.c   |  3 +
 .../gcc.target/aarch64/memtag/arguments-2.c   |  3 +
 .../gcc.target/aarch64/memtag/arguments-3.c   |  3 +
 .../gcc.target/aarch64/memtag/arguments-4.c   | 16 +++++
 .../gcc.target/aarch64/memtag/arguments.c     |  3 +
 .../gcc.target/aarch64/memtag/basic-1.c       | 15 +++++
 .../gcc.target/aarch64/memtag/basic-3.c       | 21 ++++++
 .../gcc.target/aarch64/memtag/basic-struct.c  | 22 +++++++
 .../aarch64/memtag/cfi-mte-memtag-frame-1.c   | 11 ++++
 .../gcc.target/aarch64/memtag/large-array.c   | 24 +++++++
 .../aarch64/memtag/local-no-escape.c          | 20 ++++++
 .../gcc.target/aarch64/memtag/memtag.exp      | 64 +++++++++++++++++++
 .../gcc.target/aarch64/memtag/mte-sig.h       | 15 +++++
 .../aarch64/memtag/no-sanitize-attribute.c    | 17 +++++
 .../gcc.target/aarch64/memtag/texec-1.c       | 27 ++++++++
 .../gcc.target/aarch64/memtag/texec-2.c       | 22 +++++++
 .../gcc.target/aarch64/memtag/value-init.c    | 14 ++++
 .../aarch64/memtag/vararray-gimple.c          | 17 +++++
 .../gcc.target/aarch64/memtag/vararray.c      | 14 ++++
 .../gcc.target/aarch64/memtag/vla-1.c         | 39 +++++++++++
 .../gcc.target/aarch64/memtag/vla-2.c         | 48 ++++++++++++++
 .../gcc.target/aarch64/memtag/zero-init.c     | 14 ++++
 gcc/testsuite/lib/target-supports.exp         | 12 ++++
 25 files changed, 485 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/alloca-1.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/alloca-3.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/arguments-1.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/arguments-2.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/arguments-3.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/arguments-4.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/arguments.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/basic-1.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/basic-3.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/basic-struct.c
 create mode 100644 
gcc/testsuite/gcc.target/aarch64/memtag/cfi-mte-memtag-frame-1.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/large-array.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/local-no-escape.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/memtag.exp
 create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/mte-sig.h
 create mode 100644 
gcc/testsuite/gcc.target/aarch64/memtag/no-sanitize-attribute.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/texec-1.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/texec-2.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/value-init.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/vararray-gimple.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/vararray.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/vla-1.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/vla-2.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/zero-init.c

diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/alloca-1.c 
b/gcc/testsuite/gcc.target/aarch64/memtag/alloca-1.c
new file mode 100644
index 00000000000..649ade7f9c9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/alloca-1.c
@@ -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 {stg\t...?, \[...?\], 16\n} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/alloca-3.c 
b/gcc/testsuite/gcc.target/aarch64/memtag/alloca-3.c
new file mode 100644
index 00000000000..c3be277b2e3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/alloca-3.c
@@ -0,0 +1,27 @@
+/* { 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;
+}
+
+/* With HWASAN_ALLOCA_POISON now calling irg of its own,  the number of
+   expected irg is 3 and stg is 4 (3 for tag, 1 for untag each in their
+   respective loop).  */
+
+/* { dg-final { scan-assembler-times {\tirg\t} 3 } } */
+/* { dg-final { scan-assembler-times {stg\t...?, \[...?\], 16\n} 4 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/arguments-1.c 
b/gcc/testsuite/gcc.target/aarch64/memtag/arguments-1.c
new file mode 100644
index 00000000000..f95b148d9f0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/arguments-1.c
@@ -0,0 +1,3 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fsanitize=kernel-hwaddress" } */
+/* { dg-error ".*'-fsanitize=memtag-stack' is incompatible with 
'-fsanitize=kernel-hwaddress'.*" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/arguments-2.c 
b/gcc/testsuite/gcc.target/aarch64/memtag/arguments-2.c
new file mode 100644
index 00000000000..9a76c5e2d71
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/arguments-2.c
@@ -0,0 +1,3 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fsanitize=kernel-address" } */
+/* { dg-error ".*'-fsanitize=memtag-stack' is incompatible with 
'-fsanitize=kernel-address'.*" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/arguments-3.c 
b/gcc/testsuite/gcc.target/aarch64/memtag/arguments-3.c
new file mode 100644
index 00000000000..e4eaee8edf2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/arguments-3.c
@@ -0,0 +1,3 @@
+/* { dg-do compile } */
+/* { dg-additional-options "--param hwasan-random-frame-tag=0" } */
+/* { dg-warning "is ignored when \'-fsanitize=memtag-stack\' is present" "" { 
target *-*-* } 0 } */
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/arguments-4.c 
b/gcc/testsuite/gcc.target/aarch64/memtag/arguments-4.c
new file mode 100644
index 00000000000..c952997db89
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/arguments-4.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-O2 -fno-sanitize=memtag-stack" } */
+
+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" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/arguments.c 
b/gcc/testsuite/gcc.target/aarch64/memtag/arguments.c
new file mode 100644
index 00000000000..ea1209f6a37
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/arguments.c
@@ -0,0 +1,3 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fsanitize=address" } */
+/* { dg-error ".*'-fsanitize=memtag-stack' is incompatible with 
'-fsanitize=address'.*" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/basic-1.c 
b/gcc/testsuite/gcc.target/aarch64/memtag/basic-1.c
new file mode 100644
index 00000000000..70b790c6c3e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/basic-1.c
@@ -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 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/basic-3.c 
b/gcc/testsuite/gcc.target/aarch64/memtag/basic-3.c
new file mode 100644
index 00000000000..2838c934a62
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/basic-3.c
@@ -0,0 +1,21 @@
+/* { 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);
+}
+
+/* 3 stack vars need 48 bytes. Expected: 3 stg to tag, 1 st2g + 1 stg to
+   untag.  */
+
+/* { dg-final { scan-assembler-times {\tirg\t} 1 } } */
+/* { dg-final { scan-assembler-times {stg\t...?, \[sp, 48\]\n} 1 } } */
+/* { dg-final { scan-assembler-times {st2g\t...?, \[sp, 32\]\n} 1 } } */
+/* { dg-final { scan-assembler-times {stg\t...?, \[sp, 32\]\n} 1 } } */
+/* { dg-final { scan-assembler-times {stg\t...?, \[sp, 64\]\n} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/basic-struct.c 
b/gcc/testsuite/gcc.target/aarch64/memtag/basic-struct.c
new file mode 100644
index 00000000000..32c1ad7832e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/basic-struct.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-O2" } */
+
+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 {st2g\t} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/cfi-mte-memtag-frame-1.c 
b/gcc/testsuite/gcc.target/aarch64/memtag/cfi-mte-memtag-frame-1.c
new file mode 100644
index 00000000000..07cd03c2fd0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/cfi-mte-memtag-frame-1.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+
+int use (int *x);
+
+void foo (int n)
+{
+  int x = 99;
+  use (&x);
+}
+
+/* { dg-final { scan-assembler-times ".cfi_mte_tagged_frame" 1 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/large-array.c 
b/gcc/testsuite/gcc.target/aarch64/memtag/large-array.c
new file mode 100644
index 00000000000..f233ce04d35
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/large-array.c
@@ -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 (void)
+{
+  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 {st2g\t...?, \[...?\], 32\n} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/local-no-escape.c 
b/gcc/testsuite/gcc.target/aarch64/memtag/local-no-escape.c
new file mode 100644
index 00000000000..173fe1135bf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/local-no-escape.c
@@ -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);
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/memtag.exp 
b/gcc/testsuite/gcc.target/aarch64/memtag/memtag.exp
new file mode 100644
index 00000000000..ba32f43d846
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/memtag.exp
@@ -0,0 +1,64 @@
+# 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
+
+# Return 1 if target can compile and run binary for stack
+# sanitization, 0 otherwise.
+
+proc check_effective_target_memtag_exec {} {
+    if ![check_runtime memtag_exec {
+       #ifdef __cplusplus
+       extern "C" {
+       #endif
+       extern int prctl(int, unsigned long, unsigned long, unsigned long, 
unsigned long);
+       #ifdef __cplusplus
+       }
+       #endif
+       int main (void) {
+       #define PR_SET_TAGGED_ADDR_CTRL 55
+       #define PR_GET_TAGGED_ADDR_CTRL 56
+       #define PR_TAGGED_ADDR_ENABLE (1UL << 0)
+       #define PR_MTE_TCF_SYNC (1UL << 1)
+       #define PR_MTE_TAG_SHIFT 3
+         if (prctl (PR_GET_TAGGED_ADDR_CTRL, 0,0,0,0) == -1)
+           return -1;
+         if (prctl (PR_SET_TAGGED_ADDR_CTRL,
+                    PR_TAGGED_ADDR_ENABLE | PR_MTE_TCF_SYNC
+                    | (0xfffe << PR_MTE_TAG_SHIFT), 0, 0, 0) == -1
+             || !prctl (PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0))
+           return 1;
+         return 0;
+       }
+      }] {
+       return 0;
+      }
+    return 1;
+}
+# Initialize `dg'.
+dg-init
+
+# Main loop.
+if [check_effective_target_aarch64_mte] {
+  dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cCS\]]] \
+       "" "-fsanitize=memtag-stack -march=armv8.5-a+memtag"
+}
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/mte-sig.h 
b/gcc/testsuite/gcc.target/aarch64/memtag/mte-sig.h
new file mode 100644
index 00000000000..efb3c6d187c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/mte-sig.h
@@ -0,0 +1,15 @@
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+
+void handler (int nSig)
+{
+  /* We hit the exception.  Return error.  */
+  exit (1);
+}
+
+
+static void setHandler (void)
+{
+  signal (SIGSEGV, handler);
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/no-sanitize-attribute.c 
b/gcc/testsuite/gcc.target/aarch64/memtag/no-sanitize-attribute.c
new file mode 100644
index 00000000000..0d40063dc08
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/no-sanitize-attribute.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-O2" } */
+
+int use (int *x);
+
+__attribute__((no_sanitize("memtag-stack")))
+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" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/texec-1.c 
b/gcc/testsuite/gcc.target/aarch64/memtag/texec-1.c
new file mode 100644
index 00000000000..b63619b04d3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/texec-1.c
@@ -0,0 +1,27 @@
+/* { dg-do run { xfail *-*-* } } */
+/* { dg-require-effective-target memtag_exec } */
+/* { dg-additional-options "-O2" } */
+
+#include "mte-sig.h"
+
+void  __attribute__((noinline))
+use (volatile unsigned char *ptr)
+{
+  ptr[0] = 0x41;
+  ptr[1] = 0x42;
+}
+
+int main(void)
+{
+  volatile unsigned char array[15];
+  volatile unsigned char *ptr = &array[0];
+
+  setHandler();
+  use (ptr);
+
+  /* Write to memory beyond the 16 byte granule (offsest 0x10) MTE should
+     generate an exception If the offset is less than 0x10 no SIGSEGV will
+     occur.  */
+  ptr[0x10] = 0x55;
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/texec-2.c 
b/gcc/testsuite/gcc.target/aarch64/memtag/texec-2.c
new file mode 100644
index 00000000000..0fbbe2f0778
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/texec-2.c
@@ -0,0 +1,22 @@
+/* { dg-do run { xfail *-*-* } } */
+/* { dg-require-effective-target memtag_exec } */
+/* { dg-additional-options "-O2" } */
+#include "mte-sig.h"
+
+void  __attribute__((noinline))
+use (volatile unsigned char *ptr)
+{
+  ptr[0] = 0x41;
+  ptr[1] = 0x42;
+}
+
+int main (void)
+{
+  volatile unsigned char *ptr = __builtin_alloca (15);
+
+  setHandler();
+
+  use (ptr);
+  ptr[0x10] = 0x55;
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/value-init.c 
b/gcc/testsuite/gcc.target/aarch64/memtag/value-init.c
new file mode 100644
index 00000000000..7f2c9d3123e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/value-init.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-O2" } */
+
+void use (int *);
+
+void foo (void)
+{
+  int x = 42;
+  use(&x);
+}
+
+/* { dg-final { scan-assembler-times {\tirg\t} 1 } } */
+/* { dg-final { scan-assembler-times {stg\t...?, \[sp, 16\]\n} 2 } } */
+
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/vararray-gimple.c 
b/gcc/testsuite/gcc.target/aarch64/memtag/vararray-gimple.c
new file mode 100644
index 00000000000..c960048d670
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/vararray-gimple.c
@@ -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" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/vararray.c 
b/gcc/testsuite/gcc.target/aarch64/memtag/vararray.c
new file mode 100644
index 00000000000..a01a5cd8a8b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/vararray.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-O2" } */
+
+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 {stg\t...?, \[...?\], 16\n} 3 } } */
+/* { dg-final { scan-assembler-times {\taddg\t} 0 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/vla-1.c 
b/gcc/testsuite/gcc.target/aarch64/memtag/vla-1.c
new file mode 100644
index 00000000000..1ad74fe67d5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/vla-1.c
@@ -0,0 +1,39 @@
+/* { dg-do run } */
+/* { dg-require-effective-target memtag_exec } */
+/* { dg-additional-options "-O2" } */
+
+#include <string.h>
+#include "mte-sig.h"
+
+void
+bar (int i, char *b)
+{
+  __builtin_printf ("i = %d, b+i = %s \n", i, b + i);
+}
+
+void
+foo (int size)
+{
+  int i;
+  for (i = 0; i < size; i++)
+    {
+      char temp[size];
+      memset (temp, 'B', size);
+      temp[size-1] = '\0';
+      {
+       char temp2[size];
+       memset (temp2, 'A', size);
+       temp2[size-1] = '\0';
+       bar (i, temp2);
+      }
+      bar (i, temp);
+    }
+}
+
+int main (void)
+{
+  setHandler ();
+  foo (10);
+  foo (3);
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/vla-2.c 
b/gcc/testsuite/gcc.target/aarch64/memtag/vla-2.c
new file mode 100644
index 00000000000..526306a5e60
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/vla-2.c
@@ -0,0 +1,48 @@
+
+/* { dg-do run { xfail *-*-* } } */
+/* { dg-require-effective-target memtag_exec } */
+/* { dg-additional-options "-O2" } */
+
+#include "mte-sig.h"
+
+/* Testing that a function with outgoing arguments correctly decrements the
+   stack pointer when a vararray goes out of scope.  */
+
+const char * __attribute__((noinline))
+other (int argc, int a, int b, int c, int d, int e, int f,
+       int g, int h, int i, int j, int k, int l)
+{
+  const char ** other;
+    {
+      const char * test_array[argc];
+      test_array[0] = "test string";
+      test_array[argc - 1] = "hello";
+      /* To prevent optimisation.  */
+      __builtin_printf ("While the value stored in our test_array is: %s\n",
+                       test_array[argc - 1]);
+      other = test_array;
+    }
+  /* With the below function call (the one with many arguments), some of the
+     arguments have to be put on the stack, which means we have to reserve some
+     space on the stack for these arguments and that the VLA is stored at a
+     position that is not the stack pointer. */
+  __builtin_printf ("Our numbers today are: %d, %d, %d, %d, %d, %d, %d, %d, \
+%d, %d, %d, %d\n",
+                   a, b, c, d, e, f, g, h, i, j, k, l);
+  /* This should fail due to a bad read access.  */
+  return other[0];
+}
+
+int
+main (void)
+{
+  int a, b, c, d, e, f, g, h, i, j, k, l;
+
+  setHandler();
+  const char * retval = other (1, a, b, c, d, e, f, g, h, i, j, k, l);
+  /* Numbers don't matter here, just want to ensure the program is reading them
+     so we know they won't be optimised out.  */
+  if (retval)
+    return 1;
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/memtag/zero-init.c 
b/gcc/testsuite/gcc.target/aarch64/memtag/zero-init.c
new file mode 100644
index 00000000000..75980e8d430
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/memtag/zero-init.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-O2" } */
+
+void use (int *);
+
+void foo (void)
+{
+  int x = 0;
+  use (&x);
+}
+
+/* { dg-final { scan-assembler-times {\tirg\t} 1 } } */
+/* { dg-final { scan-assembler-times {stg\t...?, \[sp, 16\]\n} 2 } } */
+
diff --git a/gcc/testsuite/lib/target-supports.exp 
b/gcc/testsuite/lib/target-supports.exp
index 956bc0bc7ca..bae37828a0a 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -4944,6 +4944,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 {
-- 
2.50.0


Reply via email to