new file mode 100644
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-vectorize -march=armv9-a+sve --param=aarch64-autovec-preference=sve-only -msve-vector-bits=scalable" } */
+
+#include <stdint.h>
+
+/* Test that we can vectorize with SVE predication when generating vector-length
+ agnostic code if the minimum possible vector length (of 16 bytes) is larger
+ than the number of elements to be processed. */
+
+void
+f (uint8_t *x)
+{
+ x[0] += 1;
+ x[1] += 2;
+ x[2] += 1;
+ x[3] += 2;
+ x[4] += 1;
+ x[5] += 2;
+ x[6] += 1;
+ x[7] += 2;
+ x[8] += 1;
+ x[9] += 2;
+ x[10] += 1;
+ x[11] += 2;
+ x[12] += 1;
+ x[13] += 2;
+ x[14] += 1; // one less than the minimum vector length
+}
+
+/* { dg-final { scan-assembler-times {\twhilelo\tp[0-7].b, xzr, x[0-9]\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tld1b\tz[0-9]+\.b, p[0-7]/z, \[x[0-9]\]\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tadd\tz[0-9]+\.b, z[0-9]+\.b, z[0-9]+\.b\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tst1b\tz[0-9]+\.b, p[0-7], \[x[0-9]\]\n} 1 } } */
new file mode 100644
@@ -0,0 +1,6 @@
+/* { dg-do run { target aarch64_sve_hw } } */
+/* { dg-options "-O2 -ftree-vectorize -march=armv9-a+sve --param=aarch64-autovec-preference=sve-only -msve-vector-bits=scalable" } */
+#include "slp_pred_harness.h"
+#include "slp_pred_1.c"
+
+HARNESS (15)
new file mode 100644
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-vectorize -march=armv9-a+sve --param=aarch64-autovec-preference=sve-only -msve-vector-bits=128" } */
+
+#include <stdint.h>
+
+/* Test that we can vectorize with SVE predication when generating vector-length
+ specific code if the configured vector length is larger than the number of
+ elements to be processed. */
+
+void
+f (uint8_t *x)
+{
+ x[0] += 1;
+ x[1] += 2;
+ x[2] += 1;
+ x[3] += 2;
+ x[4] += 1;
+ x[5] += 2;
+ x[6] += 1;
+ x[7] += 2;
+ x[8] += 1;
+ x[9] += 2;
+ x[10] += 1;
+ x[11] += 2;
+ x[12] += 1;
+ x[13] += 2;
+ x[14] += 1; // one less than the configured vector length
+}
+
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7].b, mul3\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tld1b\tz[0-9]+\.b, p[0-7]/z, \[x[0-9]\]\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tadd\tz[0-9]+\.b, z[0-9]+\.b, z[0-9]+\.b\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tst1b\tz[0-9]+\.b, p[0-7], \[x[0-9]\]\n} 1 } } */
new file mode 100644
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-vectorize -march=armv9-a+sve --param=aarch64-autovec-preference=sve-only -msve-vector-bits=scalable" } */
+
+#include <stdint.h>
+
+/* Test that we can vectorize with SVE predication when generating vector-length
+ agnostic code if the minimum possible vector length (of 16 bytes) is equal to
+ the number of elements to be processed. */
+
+void
+f (uint8_t *x)
+{
+ x[0] += 1;
+ x[1] += 2;
+ x[2] += 1;
+ x[3] += 2;
+ x[4] += 1;
+ x[5] += 2;
+ x[6] += 1;
+ x[7] += 2;
+ x[8] += 1;
+ x[9] += 2;
+ x[10] += 1;
+ x[11] += 2;
+ x[12] += 1;
+ x[13] += 2;
+ x[14] += 1;
+ x[15] += 2; // exactly fits the minimum vector length
+}
+
+/* { dg-final { scan-assembler-times {\tldr\tq[0-9]+, \[x[0-9]\]\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tadd\tz[0-9]+\.b, z[0-9]+\.b, z[0-9]+\.b\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tstr\tq[0-9]+, \[x[0-9]\]\n} 1 } } */
new file mode 100644
@@ -0,0 +1,6 @@
+/* { dg-do run { target aarch64_sve_hw } } */
+/* { dg-options "-O2 -ftree-vectorize -march=armv9-a+sve --param=aarch64-autovec-preference=sve-only -msve-vector-bits=scalable" } */
+#include "slp_pred_harness.h"
+#include "slp_pred_3.c"
+
+HARNESS (16)
new file mode 100644
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-vectorize -march=armv9-a+sve --param=aarch64-autovec-preference=sve-only -msve-vector-bits=128" } */
+
+#include <stdint.h>
+
+/* Test that we can vectorize with SVE predication when generating vector-length
+ specific code if the configured vector length is equal to the number of
+ elements to be processed. */
+
+void
+f (uint8_t *x)
+{
+ x[0] += 1;
+ x[1] += 2;
+ x[2] += 1;
+ x[3] += 2;
+ x[4] += 1;
+ x[5] += 2;
+ x[6] += 1;
+ x[7] += 2;
+ x[8] += 1;
+ x[9] += 2;
+ x[10] += 1;
+ x[11] += 2;
+ x[12] += 1;
+ x[13] += 2;
+ x[14] += 1;
+ x[15] += 2; // exactly fits the configured vector length
+}
+
+/* { dg-final { scan-assembler-times {\tldr\tq[0-9]+, \[x[0-9]\]\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tadd\tz[0-9]+\.b, z[0-9]+\.b, z[0-9]+\.b\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tstr\tq[0-9]+, \[x[0-9]\]\n} 1 } } */
new file mode 100644
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-vectorize -march=armv9-a+sve --param=aarch64-autovec-preference=sve-only -msve-vector-bits=256" } */
+
+#include <stdint.h>
+
+/* Test that we can vectorize with SVE predication when generating
+ vector-length specific code if the number of elements to be
+ processed is greater than the minimum possible vector length
+ (of 16 bytes) but less the configured vector length. */
+
+void
+f (uint8_t *x)
+{
+ x[0] += 1;
+ x[1] += 2;
+ x[2] += 1;
+ x[3] += 2;
+ x[4] += 1;
+ x[5] += 2;
+ x[6] += 1;
+ x[7] += 2;
+ x[8] += 1;
+ x[9] += 2;
+ x[10] += 1;
+ x[11] += 2;
+ x[12] += 1;
+ x[13] += 2;
+ x[14] += 1;
+ x[15] += 2;
+ x[16] += 1; // one more than the minimum vector length
+}
+
+/* { dg-final { scan-assembler-times {\twhilelo\tp[0-7].b, xzr, x[0-9]+\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tld1b\tz[0-9]+\.b, p[0-7]/z, \[x[0-9]+\]\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tadd\tz[0-9]+\.b, z[0-9]+\.b, z[0-9]+\.b\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tst1b\tz[0-9]+\.b, p[0-7], \[x[0-9]+\]\n} 1 } } */
new file mode 100644
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-vectorize -march=armv9-a+sve --param=aarch64-autovec-preference=sve-only -msve-vector-bits=scalable" } */
+
+#include <stdint.h>
+
+/* Test that we do not attempt to vectorize with SVE predication when
+ generating vector-length agnostic code if the minimum possible
+ vector length (of 16 bytes) is smaller than the number of elements
+ to be processed. */
+
+void
+f (uint8_t *x)
+{
+ x[0] += 1;
+ x[1] += 2;
+ x[2] += 1;
+ x[3] += 2;
+ x[4] += 1;
+ x[5] += 2;
+ x[6] += 1;
+ x[7] += 2;
+ x[8] += 1;
+ x[9] += 2;
+ x[10] += 1;
+ x[11] += 2;
+ x[12] += 1;
+ x[13] += 2;
+ x[14] += 1;
+ x[15] += 2;
+ x[16] += 1; // one more than the minimum vector length
+}
+
+/* { dg-final { scan-assembler-times {\tldr\tq[0-9]+, \[x[0-9]\]\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tadd\tz[0-9]+\.b, z[0-9]+\.b, z[0-9]+\.b\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tstr\tq[0-9]+, \[x[0-9]\]\n} 1 } } */
+
+/* { dg-final { scan-assembler-times {\tldrb\tw[0-9]+, \[x[0-9], 16\]\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tadd\tw[0-9]+, w[0-9]+, 1\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tstrb\tw[0-9]+, \[x[0-9], 16\]\n} 1 } } */
new file mode 100644
@@ -0,0 +1,6 @@
+/* { dg-do run { target aarch64_sve_hw } } */
+/* { dg-options "-O2 -ftree-vectorize -march=armv9-a+sve --param=aarch64-autovec-preference=sve-only -msve-vector-bits=scalable" } */
+#include "slp_pred_harness.h"
+#include "slp_pred_6.c"
+
+HARNESS (17)
new file mode 100644
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-vectorize -march=armv9-a+sve --param=aarch64-autovec-preference=sve-only -msve-vector-bits=128" } */
+
+#include <stdint.h>
+
+/* Test that we do not attempt to vectorize with SVE predication when
+ generating vector-length specific code if the configured vector
+ length is smaller than the number of elements to be processed. */
+
+void
+f (uint8_t *x)
+{
+ x[0] += 1;
+ x[1] += 2;
+ x[2] += 1;
+ x[3] += 2;
+ x[4] += 1;
+ x[5] += 2;
+ x[6] += 1;
+ x[7] += 2;
+ x[8] += 1;
+ x[9] += 2;
+ x[10] += 1;
+ x[11] += 2;
+ x[12] += 1;
+ x[13] += 2;
+ x[14] += 1;
+ x[15] += 2;
+ x[16] += 1; // one more than the configured vector length
+}
+
+/* { dg-final { scan-assembler-times {\tldr\tq[0-9]+, \[x[0-9]\]\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tadd\tz[0-9]+\.b, z[0-9]+\.b, z[0-9]+\.b\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tstr\tq[0-9]+, \[x[0-9]\]\n} 1 } } */
+
+/* { dg-final { scan-assembler-times {\tldrb\tw[0-9]+, \[x[0-9], 16\]\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tadd\tw[0-9]+, w[0-9]+, 1\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tstrb\tw[0-9]+, \[x[0-9], 16\]\n} 1 } } */
new file mode 100644
@@ -0,0 +1,28 @@
+/* Test harness shared between tests for vectorization with SVE predication. */
+
+#define HARNESS(N) \
+ int __attribute__ ((optimize (1))) main (void) \
+ { \
+ uint8_t a[N], b[N]; \
+ for (unsigned int i = 0; i < N; ++i) \
+ { \
+ a[i] = i * 2 + i % 5; \
+ b[i] = a[i]; \
+ asm volatile ("" ::: "memory"); \
+ } \
+ f (a); \
+ for (unsigned int i = 0; i < N; i += 2) \
+ { \
+ b[i]++; \
+ if (a[i] != b[i]) \
+ __builtin_abort (); \
+ if (i + 1 < N) \
+ { \
+ b[i + 1] += 2; \
+ if (a[i + 1] != b[i + 1]) \
+ __builtin_abort (); \
+ } \
+ asm volatile ("" ::: "memory"); \
+ } \
+ return 0; \
+ }