[gcc r17-2602] AArch64: use ranger to fold WHILE_ULT to ptrue
Tamar Christina via Gcc-cvs <[email protected]>
| Newsgroups | gmane.comp.gcc.cvs |
|---|---|
| Message-ID | <[email protected]> |
https://gcc.gnu.org/g:fe724b27ce6dadb82d0a51b8232bca13405d7abc commit r17-2602-gfe724b27ce6dadb82d0a51b8232bca13405d7abc Author: Tamar Christina <[email protected]> Date: Tue Jul 21 20:49:19 2026 +0100 AArch64: use ranger to fold WHILE_ULT to ptrue Consider the following simple loop: void foo (int *x) { for (int i = 0; i < 1000; i++) x[i] *= 2; } compiled at -Ofast -march=armv8-a+sve generates foo: mov w1, 0 cntw x3 mov w2, 1000 whilelo p7.s, wzr, w2 .L2: ld1w z31.s, p7/z, [x0, x1, lsl 2] add z31.s, z31.s, z31.s st1w z31.s, p7, [x0, x1, lsl 2] add x1, x1, x3 whilelo p7.s, w1, w2 b.any .L2 ret Which is nice, but the whilelo in the pre-header is unneeded. Due to the architecturally defined minimum and maximum vector lengths[1] we know that at any vector length the predicate is an all lanes active predicate, i.e. p7 is always ptrue. We can use gimple-isel these days while we still have range information on the operands of .WHILE_ULTs to do this folding. As such this patch folds whenever possible WHILE_ULTs into ptrue which are cheaper to execute and so lowers our costs for entering the loops. i.e. the above generates: foo: mov w1, 0 cntw x3 mov w2, 1000 ptrue p7.b, all .L2: ld1w z31.s, p7/z, [x0, x1, lsl 2] add z31.s, z31.s, z31.s st1w z31.s, p7, [x0, x1, lsl 2] add x1, x1, x3 whilelo p7.s, w1, w2 b.any .L2 ret [1] https://developer.arm.com/documentation/102476/0101/Introducing-SVE gcc/ChangeLog: * config/aarch64/aarch64.cc (aarch64_fold_while_ult_to_ptrue): New. (aarch64_instruction_selection): Use it. gcc/testsuite/ChangeLog: * gcc.target/aarch64/sve/fmaxnm_2.c: Update output. * gcc.target/aarch64/sve/fmaxnm_3.c: Likewise. * gcc.target/aarch64/sve/fminnm_2.c: Likewise. * gcc.target/aarch64/sve/fminnm_3.c: Likewise. * gcc.target/aarch64/sve/slp_12.c: Likewise. * gcc.target/aarch64/sve/unpacked_fadd_2.c: Likewise. * gcc.target/aarch64/sve/unpacked_fmul_2.c: Likewise. * gcc.target/aarch64/sve/unpacked_fsubr_2.c: Likewise. * gfortran.dg/pr88833.f90: Likewise. * gcc.target/aarch64/sve/while_ult_1.c: New test. * gcc.target/aarch64/sve/while_ult_2.c: New test. * gcc.target/aarch64/sve/while_ult_1_run.c: New test. Diff: --- gcc/config/aarch64/aarch64.cc | 78 ++++++++++++++++- gcc/testsuite/gcc.target/aarch64/sve/fmaxnm_2.c | 4 +- gcc/testsuite/gcc.target/aarch64/sve/fmaxnm_3.c | 2 +- gcc/testsuite/gcc.target/aarch64/sve/fminnm_2.c | 4 +- gcc/testsuite/gcc.target/aarch64/sve/fminnm_3.c | 2 +- gcc/testsuite/gcc.target/aarch64/sve/slp_12.c | 6 +- .../gcc.target/aarch64/sve/unpacked_fadd_2.c | 2 +- .../gcc.target/aarch64/sve/unpacked_fmul_2.c | 2 +- .../gcc.target/aarch64/sve/unpacked_fsubr_2.c | 2 +- gcc/testsuite/gcc.target/aarch64/sve/while_ult_1.c | 99 ++++++++++++++++++++++ .../gcc.target/aarch64/sve/while_ult_1_run.c | 66 +++++++++++++++ gcc/testsuite/gcc.target/aarch64/sve/while_ult_2.c | 18 ++++ gcc/testsuite/gfortran.dg/pr88833.f90 | 2 +- 13 files changed, 273 insertions(+), 14 deletions(-) diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc index 1d7d6fa6a2a9..93c00c23a50d 100644 --- a/gcc/config/aarch64/aarch64.cc +++ b/gcc/config/aarch64/aarch64.cc @@ -4462,15 +4462,91 @@ aarch64_fold_sve_ptrue_vl (tree vectype, unsigned int vl, return builder.build (); } +/* Fold a WHILE_ULT whose bounds are known enough to be expressed as a PTRUE. + Generic folding cannot do this because it cannot assume an architectural + maximum for a scalable vector. */ + +static bool +aarch64_fold_while_ult_to_ptrue (function *fun, gcall *call, + gimple_stmt_iterator *gsi) +{ + if (!gimple_call_internal_p (call, IFN_WHILE_ULT)) + return false; + + tree lhs = gimple_call_lhs (call); + if (!lhs) + return false; + + tree lhs_type = TREE_TYPE (lhs); + if (!VECTOR_BOOLEAN_TYPE_P (lhs_type) + || !aarch64_sve_pred_mode_p (TYPE_MODE (lhs_type)) + /* VLS shouldn't get here as we shouldn't have WHILE_ULT for it. */ + || TYPE_VECTOR_SUBPARTS (lhs_type).is_constant ()) + return false; + + int_range_max min, max; + range_query *query = get_range_query (fun); + if (!query->range_of_expr (min, gimple_call_arg (call, 0), call) + || !query->range_of_expr (max, gimple_call_arg (call, 1), call) + || min.undefined_p () + || max.undefined_p () + || !min.nonnegative_p () + || !max.nonnegative_p ()) + return false; + + widest_int min_upper = widest_int::from (min.upper_bound (), UNSIGNED); + widest_int min_lower = widest_int::from (min.lower_bound (), UNSIGNED); + widest_int max_lower = widest_int::from (max.lower_bound (), UNSIGNED); + widest_int max_upper = widest_int::from (max.upper_bound (), UNSIGNED); + if (wi::leu_p (max_lower, min_upper)) + return false; + + unsigned int min_nelts + = constant_lower_bound (TYPE_VECTOR_SUBPARTS (lhs_type)); + widest_int max_sve_nelts = min_nelts * 16; + widest_int min_gap = max_lower - min_upper; + widest_int max_gap = max_upper - min_lower; + + tree pred_cst = NULL_TREE; + unsigned HOST_WIDE_INT gap = 0; + if (min_gap >= max_sve_nelts) + pred_cst = build_all_ones_cst (lhs_type); + else if (min_gap == max_gap + && wi::fits_uhwi_p (min_gap)) + { + gap = min_gap.to_uhwi (); + machine_mode pred_mode = TYPE_MODE (lhs_type); + if (gap <= UINT_MAX + && (aarch64_svpattern_for_vl (pred_mode, (int) gap) + != AARCH64_NUM_SVPATTERNS)) + pred_cst = aarch64_fold_sve_ptrue_vl (lhs_type, + (unsigned int) gap, 1); + } + + if (!pred_cst) + { + if (wi::ltu_p (min_gap, max_sve_nelts)) + return false; + pred_cst = build_all_ones_cst (lhs_type); + } + + gassign *assign = gimple_build_assign (lhs, pred_cst); + gsi_replace (gsi, assign, false); + return true; +} + /* Implement TARGET_INSTRUCTION_SELECTION. The target hook is used to change generic sequences to a form AArch64 has an easier time expanding instructions for. It's not supposed to be used for generic rewriting that all targets would benefit from. */ static bool -aarch64_instruction_selection (function * /* fun */, gimple_stmt_iterator *gsi) +aarch64_instruction_selection (function *fun, gimple_stmt_iterator *gsi) { auto stmt = gsi_stmt (*gsi); + if (gcall *call = dyn_cast<gcall *> (stmt)) + return aarch64_fold_while_ult_to_ptrue (fun, call, gsi); + gassign *assign = dyn_cast<gassign *> (stmt); if (!assign) diff --git a/gcc/testsuite/gcc.target/aarch64/sve/fmaxnm_2.c b/gcc/testsuite/gcc.target/aarch64/sve/fmaxnm_2.c index ee3cdc20f965..3f1dfdd60d23 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/fmaxnm_2.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/fmaxnm_2.c @@ -16,7 +16,7 @@ f2 (double x, double *ptr) return x; } -/* { dg-final { scan-assembler {\twhilelo\t(p[0-7])\.s,.*\tfmaxnm\tz[0-9]+\.s, \1/m, z[0-9]+\.s, z[0-9]+\.s\n} } } */ +/* { dg-final { scan-assembler-not {\twhilelo\t(p[0-7])\.s,.*\tfmaxnm\tz[0-9]+\.s, \1/m, z[0-9]+\.s, z[0-9]+\.s\n} } } */ /* { dg-final { scan-assembler-times {\tfmaxnmv\ts[0-9]+, p[0-7], z[0-9]+\.s\n} 1 } } */ -/* { dg-final { scan-assembler {\twhilelo\t(p[0-7])\.d,.*\tfmaxnm\tz[0-9]+\.d, \1/m, z[0-9]+\.d, z[0-9]+\.d\n} } } */ +/* { dg-final { scan-assembler-not {\twhilelo\t(p[0-7])\.d,.*\tfmaxnm\tz[0-9]+\.d, \1/m, z[0-9]+\.d, z[0-9]+\.d\n} } } */ /* { dg-final { scan-assembler-times {\tfmaxnmv\td[0-9]+, p[0-7], z[0-9]+\.d\n} 1 } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/fmaxnm_3.c b/gcc/testsuite/gcc.target/aarch64/sve/fmaxnm_3.c index a8eee0f4b269..2548e55f2841 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/fmaxnm_3.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/fmaxnm_3.c @@ -14,5 +14,5 @@ f (double *restrict res, double *restrict ptr) res[1] = x1; } -/* { dg-final { scan-assembler {\twhilelo\t(p[0-7])\.d,.*\tfmaxnm\tz[0-9]+\.d, \1/m, z[0-9]+\.d, z[0-9]+\.d\n} } } */ +/* { dg-final { scan-assembler-not {\twhilelo\t(p[0-7])\.d,.*\tfmaxnm\tz[0-9]+\.d, \1/m, z[0-9]+\.d, z[0-9]+\.d\n} } } */ /* { dg-final { scan-assembler-times {\tfmaxnmv\td[0-9]+, p[0-7], z[0-9]+\.d\n} 2 } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/fminnm_2.c b/gcc/testsuite/gcc.target/aarch64/sve/fminnm_2.c index 10aced05f1af..ed657d58fdfe 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/fminnm_2.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/fminnm_2.c @@ -16,7 +16,7 @@ f2 (double x, double *ptr) return x; } -/* { dg-final { scan-assembler {\twhilelo\t(p[0-7])\.s,.*\tfminnm\tz[0-9]+\.s, \1/m, z[0-9]+\.s, z[0-9]+\.s\n} } } */ +/* { dg-final { scan-assembler-not {\twhilelo\t(p[0-7])\.s,.*\tfminnm\tz[0-9]+\.s, \1/m, z[0-9]+\.s, z[0-9]+\.s\n} } } */ /* { dg-final { scan-assembler-times {\tfminnmv\ts[0-9]+, p[0-7], z[0-9]+\.s\n} 1 } } */ -/* { dg-final { scan-assembler {\twhilelo\t(p[0-7])\.d,.*\tfminnm\tz[0-9]+\.d, \1/m, z[0-9]+\.d, z[0-9]+\.d\n} } } */ +/* { dg-final { scan-assembler-not {\twhilelo\t(p[0-7])\.d,.*\tfminnm\tz[0-9]+\.d, \1/m, z[0-9]+\.d, z[0-9]+\.d\n} } } */ /* { dg-final { scan-assembler-times {\tfminnmv\td[0-9]+, p[0-7], z[0-9]+\.d\n} 1 } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/fminnm_3.c b/gcc/testsuite/gcc.target/aarch64/sve/fminnm_3.c index 80ad01602491..1f2fc76640fb 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/fminnm_3.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/fminnm_3.c @@ -14,5 +14,5 @@ f (double *restrict res, double *restrict ptr) res[1] = x1; } -/* { dg-final { scan-assembler {\twhilelo\t(p[0-7])\.d,.*\tfminnm\tz[0-9]+\.d, \1/m, z[0-9]+\.d, z[0-9]+\.d\n} } } */ +/* { dg-final { scan-assembler-not {\twhilelo\t(p[0-7])\.d,.*\tfminnm\tz[0-9]+\.d, \1/m, z[0-9]+\.d, z[0-9]+\.d\n} } } */ /* { dg-final { scan-assembler-times {\tfminnmv\td[0-9]+, p[0-7], z[0-9]+\.d\n} 2 } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/slp_12.c b/gcc/testsuite/gcc.target/aarch64/sve/slp_12.c index 0b9f8d9bdfaa..6ba4c9651b67 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/slp_12.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/slp_12.c @@ -47,9 +47,9 @@ TEST_ALL (VEC_PERM) /* We should use WHILEs for all accesses. */ /* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.b} 20 } } */ -/* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.h} 20 } } */ -/* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.s} 30 } } */ -/* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.d} 30 } } */ +/* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.h} 18 } } */ +/* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.s} 27 } } */ +/* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.d} 24 } } */ /* 6 for the 8-bit types and 2 for the 16-bit types. */ /* { dg-final { scan-assembler-times {\tuqdecb\t} 8 } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fadd_2.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fadd_2.c index 7a74efd129cb..7ebee0fff776 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fadd_2.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fadd_2.c @@ -5,7 +5,7 @@ /* { dg-final { scan-assembler-not {\tptrue\tp[0-7]\.s} } } */ /* { dg-final { scan-assembler-not {\tptrue\tp[0-7]\.d} } } */ -/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.b} 12 } } */ +/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.b} 15 } } */ /* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 11 } } */ /* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 11 } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fmul_2.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fmul_2.c index eb05600e98a0..98617a90260a 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fmul_2.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fmul_2.c @@ -5,7 +5,7 @@ /* { dg-final { scan-assembler-not {\tptrue\tp[0-7]\.s} } } */ /* { dg-final { scan-assembler-not {\tptrue\tp[0-7]\.d} } } */ -/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.b} 3 } } */ +/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.b} 6 } } */ /* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 5 } } */ /* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 5 } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fsubr_2.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fsubr_2.c index de9325ccacb0..286a1282c402 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fsubr_2.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fsubr_2.c @@ -5,7 +5,7 @@ /* { dg-final { scan-assembler-not {\tptrue\tp[0-7]\.s} } } */ /* { dg-final { scan-assembler-not {\tptrue\tp[0-7]\.d} } } */ -/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.b} 6 } } */ +/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.b} 9 } } */ /* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 7 } } */ /* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 7 } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/while_ult_1.c b/gcc/testsuite/gcc.target/aarch64/sve/while_ult_1.c new file mode 100644 index 000000000000..ba44e367c82c --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/while_ult_1.c @@ -0,0 +1,99 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -ftree-vectorize -march=armv8-a+sve -msve-vector-bits=scalable -mautovec-preference=sve-only -fdump-tree-vect-details --save-temps" } */ +/* { dg-final { scan-tree-dump-times "LOOP VECTORIZED" 14 "vect" } } */ + +#include <arm_sve.h> +#include <stdint.h> + +#define NOIPA __attribute__ ((noipa)) + +#define ADD_LOOP(TYPE, NAME, N) \ + void NOIPA \ + NAME (TYPE *__restrict a, const TYPE *__restrict b) \ + { \ + for (unsigned int i = 0; i < N; ++i) \ + a[i] = b[i] + (TYPE) 1; \ + } + +ADD_LOOP (uint8_t, full_b, 300) +ADD_LOOP (uint16_t, full_h, 1000) +ADD_LOOP (uint32_t, full_s, 100) +ADD_LOOP (uint64_t, full_d, 40) + +ADD_LOOP (uint8_t, exact_b, 256) +ADD_LOOP (uint16_t, exact_h, 128) +ADD_LOOP (uint32_t, exact_s, 64) +ADD_LOOP (uint64_t, exact_d, 32) + +svbool_t NOIPA +finite_b (void) +{ + return svptrue_pat_b8 (SV_VL8); +} + +svbool_t NOIPA +finite_h (void) +{ + return svptrue_pat_b16 (SV_VL4); +} + +svbool_t NOIPA +finite_s (void) +{ + return svptrue_pat_b32 (SV_VL2); +} + +svbool_t NOIPA +finite_d (void) +{ + return svptrue_pat_b64 (SV_VL1); +} + + +ADD_LOOP (uint8_t, partial_b, 255) +ADD_LOOP (uint16_t, partial_h, 127) +ADD_LOOP (uint32_t, partial_s, 63) +ADD_LOOP (uint64_t, partial_d, 31) + +void NOIPA +full_range_h (uint16_t *__restrict a, const uint16_t *__restrict b, + unsigned int n) +{ + if (n < 1000) + __builtin_unreachable (); + for (unsigned int i = 0; i < n; ++i) + a[i] = b[i] + (uint16_t) 1; +} + +void NOIPA +partial_range_h (uint16_t *__restrict a, const uint16_t *__restrict b, + unsigned int n) +{ + if (n < 100 || n > 127) + __builtin_unreachable (); + for (unsigned int i = 0; i < n; ++i) + a[i] = b[i] + (uint16_t) 1; +} + +/* The first WHILELO in the "full" loops should fold to an all-true + predicate. GCC prints all-true predicates as .b, regardless of the + element size of the consuming instruction. */ +/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.b, all\n} 9 } } */ + +/* The finite loops should fold to finite PTRUE patterns. */ +/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.b, vl8\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.h, vl4\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.s, vl2\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.b, vl1\n} 1 } } */ + +/* The "partial" loops should keep their initial WHILELO. */ +/* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.b, wzr, w[0-9]+} 1 } } */ +/* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.h, wzr, w[0-9]+} 2 } } */ +/* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.s, wzr, w[0-9]+} 1 } } */ +/* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.d, wzr, w[0-9]+} 1 } } */ + +/* All loops still need a latch WHILELO. */ +/* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.b, [wx][0-9]+, [wx][0-9]+} 3 } } */ +/* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.h, [wx][0-9]+, [wx][0-9]+} 5 } } */ +/* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.s, [wx][0-9]+, [wx][0-9]+} 3 } } */ +/* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.d, [wx][0-9]+, [wx][0-9]+} 3 } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/while_ult_1_run.c b/gcc/testsuite/gcc.target/aarch64/sve/while_ult_1_run.c new file mode 100644 index 000000000000..24066dae23c1 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/while_ult_1_run.c @@ -0,0 +1,66 @@ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-O3 -ftree-vectorize -march=armv8-a+sve -msve-vector-bits=scalable -mautovec-preference=sve-only" } */ + +#include "while_ult_1.c" + +#define CHECK_LOOP(TYPE, NAME, N) \ + do \ + { \ + TYPE a[N], b[N]; \ + for (unsigned int i = 0; i < N; ++i) \ + { \ + a[i] = 0; \ + b[i] = (TYPE) (i * 3 + i % 7); \ + } \ + NAME (a, b); \ + for (unsigned int i = 0; i < N; ++i) \ + if (a[i] != (TYPE) (b[i] + (TYPE) 1)) \ + __builtin_abort (); \ + } \ + while (0) + +#define CHECK_LOOP_ARG(TYPE, NAME, N) \ + do \ + { \ + TYPE a[N], b[N]; \ + for (unsigned int i = 0; i < N; ++i) \ + { \ + a[i] = 0; \ + b[i] = (TYPE) (i * 3 + i % 7); \ + } \ + NAME (a, b, N); \ + for (unsigned int i = 0; i < N; ++i) \ + if (a[i] != (TYPE) (b[i] + (TYPE) 1)) \ + __builtin_abort (); \ + } \ + while (0) + +int __attribute__ ((optimize (1))) +main (void) +{ + CHECK_LOOP (uint8_t, full_b, 300); + CHECK_LOOP (uint16_t, full_h, 1000); + CHECK_LOOP (uint32_t, full_s, 100); + CHECK_LOOP (uint64_t, full_d, 40); + + CHECK_LOOP (uint8_t, exact_b, 256); + CHECK_LOOP (uint16_t, exact_h, 128); + CHECK_LOOP (uint32_t, exact_s, 64); + CHECK_LOOP (uint64_t, exact_d, 32); + + svbool_t pg = svptrue_b8 (); + if (svcntp_b8 (pg, finite_b ()) != 8 + || svcntp_b16 (pg, finite_h ()) != 4 + || svcntp_b32 (pg, finite_s ()) != 2 + || svcntp_b64 (pg, finite_d ()) != 1) + __builtin_abort (); + + CHECK_LOOP (uint8_t, partial_b, 255); + CHECK_LOOP (uint16_t, partial_h, 127); + CHECK_LOOP (uint32_t, partial_s, 63); + CHECK_LOOP (uint64_t, partial_d, 31); + + CHECK_LOOP_ARG (uint16_t, full_range_h, 1000); + CHECK_LOOP_ARG (uint16_t, partial_range_h, 127); + return 0; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/while_ult_2.c b/gcc/testsuite/gcc.target/aarch64/sve/while_ult_2.c new file mode 100644 index 000000000000..be1697acad69 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/while_ult_2.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -ftree-vectorize -march=armv8-a+sve -msve-vector-bits=scalable -mautovec-preference=sve-only -fdump-tree-vect-details --save-temps" } */ +/* { dg-final { scan-tree-dump-times "LOOP VECTORIZED" 1 "vect" } } */ + +#include <arm_sve.h> +#include <stdint.h> + +void +large_exact_gap (int *__restrict a, const int *__restrict b) +{ + for (unsigned long long i = 0; i < 0x80000000ULL; ++i) + a[i] = b[i] + 1; +} + +/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.b, all\n} 1 } } */ + +/* All loops still need a latch WHILELO. */ +/* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.s, [wx][0-9]+, [wx][0-9]+} 1 } } */ diff --git a/gcc/testsuite/gfortran.dg/pr88833.f90 b/gcc/testsuite/gfortran.dg/pr88833.f90 index 224e6ce5f3d5..5959cb1d16bf 100644 --- a/gcc/testsuite/gfortran.dg/pr88833.f90 +++ b/gcc/testsuite/gfortran.dg/pr88833.f90 @@ -6,4 +6,4 @@ subroutine foo(x) x = x + 10 end subroutine foo -! { dg-final { scan-assembler {\twhilelo\tp[0-9]+\.s, wzr, (w[0-9]+).*\twhilelo\tp[0-9]+\.s, w[0-9]+, \1} } } +! { dg-final { scan-assembler-not {\twhilelo\tp[0-9]+\.s, wzr, (w[0-9]+).*\twhilelo\tp[0-9]+\.s, w[0-9]+, \1} } }