https://gcc.gnu.org/g:327310ba37c528b18f805c387529c4aa4f5f9bdd
commit r16-5629-g327310ba37c528b18f805c387529c4aa4f5f9bdd Author: Tamar Christina <[email protected]> Date: Wed Nov 26 14:19:43 2025 +0000 middle-end: Correctly detect unsigned vec_cbranch [PR122861] In emit_cmp_and_jump_insns I tried to detect if the operation is signed or unsigned in order to convert the condition code into an unsigned code. However I did this based on the incoming tree compare, which is done on the boolean result. Since booleans are always signed in tree the result was that we never used an unsigned compare when needed. This checks one of the arguments of the compare instead. Bootstrapped Regtested on aarch64-none-linux-gnu, arm-none-linux-gnueabihf, x86_64-pc-linux-gnu -m32, -m64 and no issues. Ok for master? Ok for master? Thanks, Tamar gcc/ChangeLog: PR tree-optimization/122861 * optabs.cc (emit_cmp_and_jump_insns): Check argument instead of result. gcc/testsuite/ChangeLog: PR tree-optimization/122861 * gcc.target/aarch64/sve/vect-early-break-cbranch_10.c: New test. * gcc.target/aarch64/sve/vect-early-break-cbranch_11.c: New test. * gcc.target/aarch64/sve/vect-early-break-cbranch_12.c: New test. * gcc.target/aarch64/sve/vect-early-break-cbranch_13.c: New test. * gcc.target/aarch64/sve/vect-early-break-cbranch_14.c: New test. * gcc.target/aarch64/sve/vect-early-break-cbranch_15.c: New test. * gcc.target/aarch64/sve/vect-early-break-cbranch_9.c: New test. * gcc.target/aarch64/vect-early-break-cbranch_4.c: New test. * gcc.target/aarch64/vect-early-break-cbranch_5.c: New test. Diff: --- gcc/optabs.cc | 8 +- .../aarch64/sve/vect-early-break-cbranch_10.c | 132 ++++++++++++++++++ .../aarch64/sve/vect-early-break-cbranch_11.c | 132 ++++++++++++++++++ .../aarch64/sve/vect-early-break-cbranch_12.c | 132 ++++++++++++++++++ .../aarch64/sve/vect-early-break-cbranch_13.c | 132 ++++++++++++++++++ .../aarch64/sve/vect-early-break-cbranch_14.c | 147 +++++++++++++++++++++ .../aarch64/sve/vect-early-break-cbranch_15.c | 132 ++++++++++++++++++ .../aarch64/sve/vect-early-break-cbranch_9.c | 102 ++++++++++++++ .../aarch64/vect-early-break-cbranch_4.c | 122 +++++++++++++++++ .../aarch64/vect-early-break-cbranch_5.c | 105 +++++++++++++++ 10 files changed, 1141 insertions(+), 3 deletions(-) diff --git a/gcc/optabs.cc b/gcc/optabs.cc index 10989a29c514..9882aac0ba9a 100644 --- a/gcc/optabs.cc +++ b/gcc/optabs.cc @@ -4902,8 +4902,10 @@ emit_cmp_and_jump_insns (rtx x, rtx y, enum rtx_code comparison, rtx size, class expand_operand ops[5]; rtx_insn *tmp = NULL; start_sequence (); - rtx op0c = expand_normal (gimple_assign_rhs1 (def_stmt)); - rtx op1c = expand_normal (gimple_assign_rhs2 (def_stmt)); + tree t_op0 = gimple_assign_rhs1 (def_stmt); + tree t_op1 = gimple_assign_rhs2 (def_stmt); + rtx op0c = expand_normal (t_op0); + rtx op1c = expand_normal (t_op1); machine_mode mode2 = GET_MODE (op0c); int nops = masked_op ? 3 : (len_op ? 5 : 2); @@ -4929,7 +4931,7 @@ emit_cmp_and_jump_insns (rtx x, rtx y, enum rtx_code comparison, rtx size, GET_MODE (len_bias_rtx)); } - int unsignedp2 = TYPE_UNSIGNED (TREE_TYPE (val)); + int unsignedp2 = TYPE_UNSIGNED (TREE_TYPE (t_op0)); auto inner_code = gimple_assign_rhs_code (def_stmt); rtx test2 = NULL_RTX; diff --git a/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_10.c b/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_10.c new file mode 100644 index 000000000000..e74f1fa5bd0d --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_10.c @@ -0,0 +1,132 @@ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-O3 --param aarch64-autovec-preference=asimd-only" } */ +/* { dg-require-effective-target lp64 } */ + +#include <stdio.h> + +#define N 640 +#ifndef TYPE +#define TYPE unsigned int +#endif +#ifndef FMT +#define FMT "u" +#endif + + +TYPE a[N] = {0}; +TYPE b[N] = {0}; + +char *curr_test; + +/* Macro to define a function with a specific comparison */ +#define DEFINE_TEST_FUNC(NAME, OP) \ + __attribute__((noipa)) \ + void NAME(void) { \ + for (int i = 0; i < N; i++) { \ + b[i] += a[i]; \ + if (a[i] OP 0) \ + break; \ + } \ + } + +/* Generate the six comparisons functions using the macro. */ +DEFINE_TEST_FUNC(f1, >) +DEFINE_TEST_FUNC(f2, >=) +DEFINE_TEST_FUNC(f3, ==) +DEFINE_TEST_FUNC(f4, !=) +DEFINE_TEST_FUNC(f5, <) +DEFINE_TEST_FUNC(f6, <=) + +__attribute__((noreturn)) +static inline void __abort_trace (const char *m, int i, TYPE result, TYPE expected) +{ + printf ("*** [%s] FAIL AT %s:%d in %s - expected %" FMT " but got %" FMT " at pos %d\n", + m, __FILE__, __LINE__, curr_test, expected, result, i); + __builtin_abort (); +} + +/* Array setup macro. */ +#define RESET_ARRAYS(_aval, _idx, _force, _bval) \ + do { \ + _Pragma("GCC novector") \ + for (int i = 0; i < N; ++i) { \ + a[i] = _aval; \ + b[i] = _bval; \ + } \ + if (_idx >= 0 && _idx < N) \ + a[_idx] = _force; \ + } while (0) + +/* Value check macros. */ +#define CHECK_EQ(_i, _val) \ + do { \ + if (b[_i] != _val) \ + __abort_trace ("single", _i, b[_i], _val); \ + } while (0) + +#define CHECK_RANGE_EQ(_start, _end, _val) \ + do { \ + _Pragma("GCC novector") \ + for (int i = _start; i < _end; ++i) \ + if (b[i] != _val) \ + __abort_trace ("range", i, b[i], _val); \ + } while (0) + +#define str(s) #s +#define TEST_FUNC(_func, _aval, _idx, _force, _bval, _check_stmt) \ + do { \ + curr_test = str (_func); \ + RESET_ARRAYS((_aval), (_idx), (_force), (_bval)); \ + _func(); \ + _check_stmt; \ + } while (0) + +int main(void) { + /* Break on random intervals. */ + TEST_FUNC (f1, 1, 0, 1, 10, CHECK_EQ (0, 11); CHECK_EQ (1, 10)); + TEST_FUNC (f2, 6, 5, 0, 10, CHECK_EQ (0, 16); CHECK_EQ (5, 10)); + TEST_FUNC (f3, 3, 3, 0, 0, CHECK_EQ (0, 3); CHECK_EQ (3, 0)); + TEST_FUNC (f4, 0, 4, 1, 1, CHECK_EQ (4, 2); CHECK_EQ (5, 1)); + TEST_FUNC (f5, 2, 6, 0, 5, CHECK_EQ (6, 5); CHECK_EQ (7, 7)); + TEST_FUNC (f6, 2, 10, 0, 7, CHECK_EQ (10, 7); CHECK_EQ (11, 7)); + + /* Break on last iteration. */ + TEST_FUNC (f1, 0, N-1, 1, 1, + CHECK_RANGE_EQ (0, N-1, 1); CHECK_EQ (N-1, 2)); + + TEST_FUNC (f2, 0, N-1, 0, 4, + CHECK_RANGE_EQ (0, N-1, 4); CHECK_EQ (N-1, 4)); + + TEST_FUNC (f3, 2, N-1, 0, 0, + CHECK_RANGE_EQ(0, N-1, 2); CHECK_EQ (N-1, 0)); + + TEST_FUNC (f4, 0, N-1, 2, 1, + CHECK_RANGE_EQ (0, N-1, 1); CHECK_EQ (N-1, 3)); + + TEST_FUNC (f5, 4, N-1, 1, 6, + CHECK_RANGE_EQ (0, N-1, 10); CHECK_EQ (N-1, 7)); + + TEST_FUNC (f6, 5, N-1, 0, 7, + CHECK_RANGE_EQ (0, N-1, 12); CHECK_EQ (N-1, 7)); + + /* Condition never met — full loop executes. */ + TEST_FUNC (f1, 0, -1, 0, 2, + CHECK_RANGE_EQ (0, N, 2)); + + TEST_FUNC (f2, 0, -1, 0, 3, + CHECK_RANGE_EQ (0, N, 3)); + + TEST_FUNC (f3, 1, -1, 0, 0, + CHECK_RANGE_EQ (0, N, 1)); + + TEST_FUNC (f4, 0, -1, 0, 7, + CHECK_RANGE_EQ (0, N, 7)); + + TEST_FUNC (f5, 1, -1, 0, 4, + CHECK_RANGE_EQ (0, N, 5)); + + TEST_FUNC (f6, 5, -1, 0, 3, + CHECK_RANGE_EQ (0, N, 8)); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_11.c b/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_11.c new file mode 100644 index 000000000000..72423279f4c6 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_11.c @@ -0,0 +1,132 @@ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-O3 --param aarch64-autovec-preference=sve-only" } */ +/* { dg-require-effective-target lp64 } */ + +#include <stdio.h> + +#define N 640 +#ifndef TYPE +#define TYPE unsigned int +#endif +#ifndef FMT +#define FMT "u" +#endif + + +TYPE a[N] = {0}; +TYPE b[N] = {0}; + +char *curr_test; + +/* Macro to define a function with a specific comparison */ +#define DEFINE_TEST_FUNC(NAME, OP) \ + __attribute__((noipa)) \ + void NAME(void) { \ + for (int i = 0; i < N; i++) { \ + b[i] += a[i]; \ + if (a[i] OP 0) \ + break; \ + } \ + } + +/* Generate the six comparisons functions using the macro. */ +DEFINE_TEST_FUNC(f1, >) +DEFINE_TEST_FUNC(f2, >=) +DEFINE_TEST_FUNC(f3, ==) +DEFINE_TEST_FUNC(f4, !=) +DEFINE_TEST_FUNC(f5, <) +DEFINE_TEST_FUNC(f6, <=) + +__attribute__((noreturn)) +static inline void __abort_trace (const char *m, int i, TYPE result, TYPE expected) +{ + printf ("*** [%s] FAIL AT %s:%d in %s - expected %" FMT " but got %" FMT " at pos %d\n", + m, __FILE__, __LINE__, curr_test, expected, result, i); + __builtin_abort (); +} + +/* Array setup macro. */ +#define RESET_ARRAYS(_aval, _idx, _force, _bval) \ + do { \ + _Pragma("GCC novector") \ + for (int i = 0; i < N; ++i) { \ + a[i] = _aval; \ + b[i] = _bval; \ + } \ + if (_idx >= 0 && _idx < N) \ + a[_idx] = _force; \ + } while (0) + +/* Value check macros. */ +#define CHECK_EQ(_i, _val) \ + do { \ + if (b[_i] != _val) \ + __abort_trace ("single", _i, b[_i], _val); \ + } while (0) + +#define CHECK_RANGE_EQ(_start, _end, _val) \ + do { \ + _Pragma("GCC novector") \ + for (int i = _start; i < _end; ++i) \ + if (b[i] != _val) \ + __abort_trace ("range", i, b[i], _val); \ + } while (0) + +#define str(s) #s +#define TEST_FUNC(_func, _aval, _idx, _force, _bval, _check_stmt) \ + do { \ + curr_test = str (_func); \ + RESET_ARRAYS((_aval), (_idx), (_force), (_bval)); \ + _func(); \ + _check_stmt; \ + } while (0) + +int main(void) { + /* Break on random intervals. */ + TEST_FUNC (f1, 1, 0, 1, 10, CHECK_EQ (0, 11); CHECK_EQ (1, 10)); + TEST_FUNC (f2, 6, 5, 0, 10, CHECK_EQ (0, 16); CHECK_EQ (5, 10)); + TEST_FUNC (f3, 3, 3, 0, 0, CHECK_EQ (0, 3); CHECK_EQ (3, 0)); + TEST_FUNC (f4, 0, 4, 1, 1, CHECK_EQ (4, 2); CHECK_EQ (5, 1)); + TEST_FUNC (f5, 2, 6, 0, 5, CHECK_EQ (6, 5); CHECK_EQ (7, 7)); + TEST_FUNC (f6, 2, 10, 0, 7, CHECK_EQ (10, 7); CHECK_EQ (11, 7)); + + /* Break on last iteration. */ + TEST_FUNC (f1, 0, N-1, 1, 1, + CHECK_RANGE_EQ (0, N-1, 1); CHECK_EQ (N-1, 2)); + + TEST_FUNC (f2, 0, N-1, 0, 4, + CHECK_RANGE_EQ (0, N-1, 4); CHECK_EQ (N-1, 4)); + + TEST_FUNC (f3, 2, N-1, 0, 0, + CHECK_RANGE_EQ(0, N-1, 2); CHECK_EQ (N-1, 0)); + + TEST_FUNC (f4, 0, N-1, 2, 1, + CHECK_RANGE_EQ (0, N-1, 1); CHECK_EQ (N-1, 3)); + + TEST_FUNC (f5, 4, N-1, 1, 6, + CHECK_RANGE_EQ (0, N-1, 10); CHECK_EQ (N-1, 7)); + + TEST_FUNC (f6, 5, N-1, 0, 7, + CHECK_RANGE_EQ (0, N-1, 12); CHECK_EQ (N-1, 7)); + + /* Condition never met — full loop executes. */ + TEST_FUNC (f1, 0, -1, 0, 2, + CHECK_RANGE_EQ (0, N, 2)); + + TEST_FUNC (f2, 0, -1, 0, 3, + CHECK_RANGE_EQ (0, N, 3)); + + TEST_FUNC (f3, 1, -1, 0, 0, + CHECK_RANGE_EQ (0, N, 1)); + + TEST_FUNC (f4, 0, -1, 0, 7, + CHECK_RANGE_EQ (0, N, 7)); + + TEST_FUNC (f5, 1, -1, 0, 4, + CHECK_RANGE_EQ (0, N, 5)); + + TEST_FUNC (f6, 5, -1, 0, 3, + CHECK_RANGE_EQ (0, N, 8)); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_12.c b/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_12.c new file mode 100644 index 000000000000..e2290e9161cf --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_12.c @@ -0,0 +1,132 @@ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-O3 --param aarch64-autovec-preference=asimd-only" } */ +/* { dg-require-effective-target lp64 } */ + +#include <stdio.h> + +#define N 640 +#ifndef TYPE +#define TYPE float +#endif +#ifndef FMT +#define FMT ".6f" +#endif + + +TYPE a[N] = {0}; +TYPE b[N] = {0}; + +char *curr_test; + +/* Macro to define a function with a specific comparison */ +#define DEFINE_TEST_FUNC(NAME, OP) \ + __attribute__((noipa)) \ + void NAME(void) { \ + for (int i = 0; i < N; i++) { \ + b[i] += a[i]; \ + if (a[i] OP 0) \ + break; \ + } \ + } + +/* Generate the six comparisons functions using the macro. */ +DEFINE_TEST_FUNC(f1, >) +DEFINE_TEST_FUNC(f2, >=) +DEFINE_TEST_FUNC(f3, ==) +DEFINE_TEST_FUNC(f4, !=) +DEFINE_TEST_FUNC(f5, <) +DEFINE_TEST_FUNC(f6, <=) + +__attribute__((noreturn)) +static inline void __abort_trace (const char *m, int i, TYPE result, TYPE expected) +{ + printf ("*** [%s] FAIL AT %s:%d in %s - expected %" FMT " but got %" FMT " at pos %d\n", + m, __FILE__, __LINE__, curr_test, expected, result, i); + __builtin_abort (); +} + +/* Array setup macro. */ +#define RESET_ARRAYS(_aval, _idx, _force, _bval) \ + do { \ + _Pragma("GCC novector") \ + for (int i = 0; i < N; ++i) { \ + a[i] = _aval; \ + b[i] = _bval; \ + } \ + if (_idx >= 0 && _idx < N) \ + a[_idx] = _force; \ + } while (0) + +/* Value check macros. */ +#define CHECK_EQ(_i, _val) \ + do { \ + if (b[_i] != _val) \ + __abort_trace ("single", _i, b[_i], _val); \ + } while (0) + +#define CHECK_RANGE_EQ(_start, _end, _val) \ + do { \ + _Pragma("GCC novector") \ + for (int i = _start; i < _end; ++i) \ + if (b[i] != _val) \ + __abort_trace ("range", i, b[i], _val); \ + } while (0) + +#define str(s) #s +#define TEST_FUNC(_func, _aval, _idx, _force, _bval, _check_stmt) \ + do { \ + curr_test = str (_func); \ + RESET_ARRAYS((_aval), (_idx), (_force), (_bval)); \ + _func(); \ + _check_stmt; \ + } while (0) + +int main(void) { + /* Break on random intervals. */ + TEST_FUNC (f1, 1, 0, 1, 10, CHECK_EQ (0, 11); CHECK_EQ (1, 10)); + TEST_FUNC (f2, -1, 5, 0, 10, CHECK_EQ (0, 9); CHECK_EQ (5, 10)); + TEST_FUNC (f3, 3, 3, 0, 0, CHECK_EQ (0, 3); CHECK_EQ (3, 0)); + TEST_FUNC (f4, 0, 4, 1, 1, CHECK_EQ (4, 2); CHECK_EQ (5, 1)); + TEST_FUNC (f5, 1, 6, -1, 5, CHECK_EQ (6, 4); CHECK_EQ (7, 5)); + TEST_FUNC (f6, 2, 10, 0, 7, CHECK_EQ (10, 7); CHECK_EQ (11, 7)); + + /* Break on last iteration. */ + TEST_FUNC (f1, 0, N-1, 1, 1, + CHECK_RANGE_EQ (0, N-1, 1); CHECK_EQ (N-1, 2)); + + TEST_FUNC (f2, -5, N-1, 0, 9, + CHECK_RANGE_EQ (0, N-1, 4); CHECK_EQ (N-1, 9)); + + TEST_FUNC (f3, 2, N-1, 0, 0, + CHECK_RANGE_EQ(0, N-1, 2); CHECK_EQ (N-1, 0)); + + TEST_FUNC (f4, 0, N-1, 2, 1, + CHECK_RANGE_EQ (0, N-1, 1); CHECK_EQ (N-1, 3)); + + TEST_FUNC (f5, 2, N-1, -3, 6, + CHECK_RANGE_EQ (0, N-1, 8); CHECK_EQ (N-1, 3)); + + TEST_FUNC (f6, 5, N-1, 0, 7, + CHECK_RANGE_EQ (0, N-1, 12); CHECK_EQ (N-1, 7)); + + /* Condition never met — full loop executes. */ + TEST_FUNC (f1, 0, -1, 0, 2, + CHECK_RANGE_EQ (0, N, 2)); + + TEST_FUNC (f2, -2, -1, 0, 5, + CHECK_RANGE_EQ (0, N, 3)); + + TEST_FUNC (f3, 1, -1, 0, 0, + CHECK_RANGE_EQ (0, N, 1)); + + TEST_FUNC (f4, 0, -1, 0, 7, + CHECK_RANGE_EQ (0, N, 7)); + + TEST_FUNC (f5, 1, -1, 0, 4, + CHECK_RANGE_EQ (0, N, 5)); + + TEST_FUNC (f6, 5, -1, 0, 3, + CHECK_RANGE_EQ (0, N, 8)); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_13.c b/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_13.c new file mode 100644 index 000000000000..eb2295f8ea93 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_13.c @@ -0,0 +1,132 @@ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-O3 --param aarch64-autovec-preference=sve-only" } */ +/* { dg-require-effective-target lp64 } */ + +#include <stdio.h> + +#define N 640 +#ifndef TYPE +#define TYPE float +#endif +#ifndef FMT +#define FMT ".6f" +#endif + + +TYPE a[N] = {0}; +TYPE b[N] = {0}; + +char *curr_test; + +/* Macro to define a function with a specific comparison */ +#define DEFINE_TEST_FUNC(NAME, OP) \ + __attribute__((noipa)) \ + void NAME(void) { \ + for (int i = 0; i < N; i++) { \ + b[i] += a[i]; \ + if (a[i] OP 0) \ + break; \ + } \ + } + +/* Generate the six comparisons functions using the macro. */ +DEFINE_TEST_FUNC(f1, >) +DEFINE_TEST_FUNC(f2, >=) +DEFINE_TEST_FUNC(f3, ==) +DEFINE_TEST_FUNC(f4, !=) +DEFINE_TEST_FUNC(f5, <) +DEFINE_TEST_FUNC(f6, <=) + +__attribute__((noreturn)) +static inline void __abort_trace (const char *m, int i, TYPE result, TYPE expected) +{ + printf ("*** [%s] FAIL AT %s:%d in %s - expected %" FMT " but got %" FMT " at pos %d\n", + m, __FILE__, __LINE__, curr_test, expected, result, i); + __builtin_abort (); +} + +/* Array setup macro. */ +#define RESET_ARRAYS(_aval, _idx, _force, _bval) \ + do { \ + _Pragma("GCC novector") \ + for (int i = 0; i < N; ++i) { \ + a[i] = _aval; \ + b[i] = _bval; \ + } \ + if (_idx >= 0 && _idx < N) \ + a[_idx] = _force; \ + } while (0) + +/* Value check macros. */ +#define CHECK_EQ(_i, _val) \ + do { \ + if (b[_i] != _val) \ + __abort_trace ("single", _i, b[_i], _val); \ + } while (0) + +#define CHECK_RANGE_EQ(_start, _end, _val) \ + do { \ + _Pragma("GCC novector") \ + for (int i = _start; i < _end; ++i) \ + if (b[i] != _val) \ + __abort_trace ("range", i, b[i], _val); \ + } while (0) + +#define str(s) #s +#define TEST_FUNC(_func, _aval, _idx, _force, _bval, _check_stmt) \ + do { \ + curr_test = str (_func); \ + RESET_ARRAYS((_aval), (_idx), (_force), (_bval)); \ + _func(); \ + _check_stmt; \ + } while (0) + +int main(void) { + /* Break on random intervals. */ + TEST_FUNC (f1, 1, 0, 1, 10, CHECK_EQ (0, 11); CHECK_EQ (1, 10)); + TEST_FUNC (f2, -1, 5, 0, 10, CHECK_EQ (0, 9); CHECK_EQ (5, 10)); + TEST_FUNC (f3, 3, 3, 0, 0, CHECK_EQ (0, 3); CHECK_EQ (3, 0)); + TEST_FUNC (f4, 0, 4, 1, 1, CHECK_EQ (4, 2); CHECK_EQ (5, 1)); + TEST_FUNC (f5, 1, 6, -1, 5, CHECK_EQ (6, 4); CHECK_EQ (7, 5)); + TEST_FUNC (f6, 2, 10, 0, 7, CHECK_EQ (10, 7); CHECK_EQ (11, 7)); + + /* Break on last iteration. */ + TEST_FUNC (f1, 0, N-1, 1, 1, + CHECK_RANGE_EQ (0, N-1, 1); CHECK_EQ (N-1, 2)); + + TEST_FUNC (f2, -5, N-1, 0, 9, + CHECK_RANGE_EQ (0, N-1, 4); CHECK_EQ (N-1, 9)); + + TEST_FUNC (f3, 2, N-1, 0, 0, + CHECK_RANGE_EQ(0, N-1, 2); CHECK_EQ (N-1, 0)); + + TEST_FUNC (f4, 0, N-1, 2, 1, + CHECK_RANGE_EQ (0, N-1, 1); CHECK_EQ (N-1, 3)); + + TEST_FUNC (f5, 2, N-1, -3, 6, + CHECK_RANGE_EQ (0, N-1, 8); CHECK_EQ (N-1, 3)); + + TEST_FUNC (f6, 5, N-1, 0, 7, + CHECK_RANGE_EQ (0, N-1, 12); CHECK_EQ (N-1, 7)); + + /* Condition never met — full loop executes. */ + TEST_FUNC (f1, 0, -1, 0, 2, + CHECK_RANGE_EQ (0, N, 2)); + + TEST_FUNC (f2, -2, -1, 0, 5, + CHECK_RANGE_EQ (0, N, 3)); + + TEST_FUNC (f3, 1, -1, 0, 0, + CHECK_RANGE_EQ (0, N, 1)); + + TEST_FUNC (f4, 0, -1, 0, 7, + CHECK_RANGE_EQ (0, N, 7)); + + TEST_FUNC (f5, 1, -1, 0, 4, + CHECK_RANGE_EQ (0, N, 5)); + + TEST_FUNC (f6, 5, -1, 0, 3, + CHECK_RANGE_EQ (0, N, 8)); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_14.c b/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_14.c new file mode 100644 index 000000000000..5cc4d6a3858d --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_14.c @@ -0,0 +1,147 @@ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-Ofast --param aarch64-autovec-preference=asimd-only" } */ +/* { dg-require-effective-target lp64 } */ + +#include <stdio.h> +#include <math.h> + +#define N 640 +#ifndef TYPE +#define TYPE double +#endif +#ifndef FMT +#define FMT ".6f" +#endif + +TYPE a[N] = {0}; +TYPE b[N] = {0}; + +char *curr_test; + +/* Macro to define a function with a specific comparison */ +#define DEFINE_TEST_FUNC(NAME, OP) \ + __attribute__((noipa)) \ + void NAME(void) { \ + for (int i = 0; i < N; i++) { \ + b[i] += a[i]; \ + if (a[i] OP 0) \ + break; \ + } \ + } + +/* Generate comparison functions */ +DEFINE_TEST_FUNC(f1, >) +DEFINE_TEST_FUNC(f2, >=) +DEFINE_TEST_FUNC(f3, ==) +DEFINE_TEST_FUNC(f4, !=) +DEFINE_TEST_FUNC(f5, <) +DEFINE_TEST_FUNC(f6, <=) + +/* Example unordered-sensitive loop: breaks if a[i] is unordered with 0 */ +__attribute__((noipa)) +void f7(void) { + for (int i = 0; i < N; i++) { + b[i] += a[i]; + if (__builtin_isunordered(a[i], 0.0)) + break; + } +} + +__attribute__((noreturn)) +static inline void __abort_trace(const char *m, int i, TYPE result, TYPE expected) { + printf("*** [%s] FAIL AT %s:%d in %s - expected %" FMT " but got %" FMT " at pos %d\n", + m, __FILE__, __LINE__, curr_test, expected, result, i); + __builtin_abort(); +} + +/* Array setup */ +#define RESET_ARRAYS(_aval, _idx, _force, _bval) \ + do { \ + _Pragma("GCC novector") \ + for (int i = 0; i < N; ++i) { \ + a[i] = _aval; \ + b[i] = _bval; \ + } \ + if (_idx >= 0 && _idx < N) \ + a[_idx] = _force; \ + } while (0) + +/* Floating-point comparison macros (with unordered handling) */ +#define CHECK_EQ(_i, _val) do { \ + if (__builtin_isnan (_val) != __builtin_isnan (b[_i]) \ + && b[_i] != _val) \ + __abort_trace ("single", _i, b[_i], _val); \ +} while (0) + +#define CHECK_RANGE_EQ(_start, _end, _val) do { \ + _Pragma("GCC novector") \ + for (int i = _start; i < _end; ++i) \ + if (__builtin_isnan (_val) != __builtin_isnan (b[i]) \ + && b[i] != _val) \ + __abort_trace ("range", i, b[i], _val); \ +} while (0) + +#define str(s) #s +#define TEST_FUNC(_func, _aval, _idx, _force, _bval, _check_stmt) \ + do { \ + curr_test = str (_func); \ + RESET_ARRAYS((_aval), (_idx), (_force), (_bval)); \ + _func(); \ + _check_stmt; \ + } while (0) + +int main(void) { + /* Break on random intervals. */ + TEST_FUNC(f1, 1.0, 0, 1.0, 10.0, CHECK_EQ(0, 11.0); CHECK_EQ(1, 10.0)); + TEST_FUNC(f2, -1.0, 5, 0.0, 10.0, CHECK_EQ(0, 9.0); CHECK_EQ(5, 10.0)); + TEST_FUNC(f3, 3.0, 3, 0.0, 0.0, CHECK_EQ(0, 3.0); CHECK_EQ(3, 0.0)); + TEST_FUNC(f4, 0.0, 4, 1.0, 1.0, CHECK_EQ(4, 2.0); CHECK_EQ(5, 1.0)); + TEST_FUNC(f5, 1.0, 6, -1.0, 5.0, CHECK_EQ(6, 4.0); CHECK_EQ(7, 5.0)); + TEST_FUNC(f6, 2.0, 10, 0.0, 7.0, CHECK_EQ(10, 7.0); CHECK_EQ(11, 7.0)); + + /* Break on last iteration. */ + TEST_FUNC(f1, 0.0, N - 1, 1.0, 1.0, + CHECK_RANGE_EQ(0, N - 1, 1.0); CHECK_EQ(N - 1, 2.0)); + + TEST_FUNC(f2, -5.0, N - 1, 0.0, 9.0, + CHECK_RANGE_EQ(0, N - 1, 4.0); CHECK_EQ(N - 1, 9.0)); + + TEST_FUNC(f3, 2.0, N - 1, 0.0, 0.0, + CHECK_RANGE_EQ(0, N - 1, 2.0); CHECK_EQ(N - 1, 0.0)); + + TEST_FUNC(f4, 0.0, N - 1, 2.0, 1.0, + CHECK_RANGE_EQ(0, N - 1, 1.0); CHECK_EQ(N - 1, 3.0)); + + TEST_FUNC(f5, 2.0, N - 1, -3.0, 6.0, + CHECK_RANGE_EQ(0, N - 1, 8.0); CHECK_EQ(N - 1, 3.0)); + + TEST_FUNC(f6, 5.0, N - 1, 0.0, 7.0, + CHECK_RANGE_EQ(0, N - 1, 12.0); CHECK_EQ(N - 1, 7.0)); + + /* Condition never met — full loop executes. */ + TEST_FUNC(f1, 0.0, -1, 0.0, 2.0, + CHECK_RANGE_EQ(0, N, 2.0)); + + TEST_FUNC(f2, -2.0, -1, 0.0, 5.0, + CHECK_RANGE_EQ(0, N, 3.0)); + + TEST_FUNC(f3, 1.0, -1, 0.0, 0.0, + CHECK_RANGE_EQ(0, N, 1.0)); + + TEST_FUNC(f4, 0.0, -1, 0.0, 7.0, + CHECK_RANGE_EQ(0, N, 7.0)); + + TEST_FUNC(f5, 1.0, -1, 0.0, 4.0, + CHECK_RANGE_EQ(0, N, 5.0)); + + TEST_FUNC(f6, 5.0, -1, 0.0, 3.0, + CHECK_RANGE_EQ(0, N, 8.0)); + +#if !defined(__FAST_MATH__) + /* Unordered break (NAN in a[i]) */ + TEST_FUNC(f7, 1.0, 123, NAN, 2.0, + CHECK_RANGE_EQ(0, 123, 3.0); CHECK_EQ(123, NAN)); +#endif + + return 0; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_15.c b/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_15.c new file mode 100644 index 000000000000..3dd7a60225e0 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_15.c @@ -0,0 +1,132 @@ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-Ofast --param aarch64-autovec-preference=asimd-only" } */ +/* { dg-require-effective-target lp64 } */ + +#include <stdio.h> + +#define N 640 +#ifndef TYPE +#define TYPE float +#endif +#ifndef FMT +#define FMT ".6f" +#endif + + +TYPE a[N] = {0}; +TYPE b[N] = {0}; + +char *curr_test; + +/* Macro to define a function with a specific comparison */ +#define DEFINE_TEST_FUNC(NAME, OP) \ + __attribute__((noipa)) \ + void NAME(void) { \ + for (int i = 0; i < N; i++) { \ + b[i] += a[i]; \ + if (a[i] OP 0) \ + break; \ + } \ + } + +/* Generate the six comparisons functions using the macro. */ +DEFINE_TEST_FUNC(f1, >) +DEFINE_TEST_FUNC(f2, >=) +DEFINE_TEST_FUNC(f3, ==) +DEFINE_TEST_FUNC(f4, !=) +DEFINE_TEST_FUNC(f5, <) +DEFINE_TEST_FUNC(f6, <=) + +__attribute__((noreturn)) +static inline void __abort_trace (const char *m, int i, TYPE result, TYPE expected) +{ + printf ("*** [%s] FAIL AT %s:%d in %s - expected %" FMT " but got %" FMT " at pos %d\n", + m, __FILE__, __LINE__, curr_test, expected, result, i); + __builtin_abort (); +} + +/* Array setup macro. */ +#define RESET_ARRAYS(_aval, _idx, _force, _bval) \ + do { \ + _Pragma("GCC novector") \ + for (int i = 0; i < N; ++i) { \ + a[i] = _aval; \ + b[i] = _bval; \ + } \ + if (_idx >= 0 && _idx < N) \ + a[_idx] = _force; \ + } while (0) + +/* Value check macros. */ +#define CHECK_EQ(_i, _val) \ + do { \ + if (b[_i] != _val) \ + __abort_trace ("single", _i, b[_i], _val); \ + } while (0) + +#define CHECK_RANGE_EQ(_start, _end, _val) \ + do { \ + _Pragma("GCC novector") \ + for (int i = _start; i < _end; ++i) \ + if (b[i] != _val) \ + __abort_trace ("range", i, b[i], _val); \ + } while (0) + +#define str(s) #s +#define TEST_FUNC(_func, _aval, _idx, _force, _bval, _check_stmt) \ + do { \ + curr_test = str (_func); \ + RESET_ARRAYS((_aval), (_idx), (_force), (_bval)); \ + _func(); \ + _check_stmt; \ + } while (0) + +int main(void) { + /* Break on random intervals. */ + TEST_FUNC (f1, 1, 0, 1, 10, CHECK_EQ (0, 11); CHECK_EQ (1, 10)); + TEST_FUNC (f2, -1, 5, 0, 10, CHECK_EQ (0, 9); CHECK_EQ (5, 10)); + TEST_FUNC (f3, 3, 3, 0, 0, CHECK_EQ (0, 3); CHECK_EQ (3, 0)); + TEST_FUNC (f4, 0, 4, 1, 1, CHECK_EQ (4, 2); CHECK_EQ (5, 1)); + TEST_FUNC (f5, 1, 6, -1, 5, CHECK_EQ (6, 4); CHECK_EQ (7, 5)); + TEST_FUNC (f6, 2, 10, 0, 7, CHECK_EQ (10, 7); CHECK_EQ (11, 7)); + + /* Break on last iteration. */ + TEST_FUNC (f1, 0, N-1, 1, 1, + CHECK_RANGE_EQ (0, N-1, 1); CHECK_EQ (N-1, 2)); + + TEST_FUNC (f2, -5, N-1, 0, 9, + CHECK_RANGE_EQ (0, N-1, 4); CHECK_EQ (N-1, 9)); + + TEST_FUNC (f3, 2, N-1, 0, 0, + CHECK_RANGE_EQ(0, N-1, 2); CHECK_EQ (N-1, 0)); + + TEST_FUNC (f4, 0, N-1, 2, 1, + CHECK_RANGE_EQ (0, N-1, 1); CHECK_EQ (N-1, 3)); + + TEST_FUNC (f5, 2, N-1, -3, 6, + CHECK_RANGE_EQ (0, N-1, 8); CHECK_EQ (N-1, 3)); + + TEST_FUNC (f6, 5, N-1, 0, 7, + CHECK_RANGE_EQ (0, N-1, 12); CHECK_EQ (N-1, 7)); + + /* Condition never met — full loop executes. */ + TEST_FUNC (f1, 0, -1, 0, 2, + CHECK_RANGE_EQ (0, N, 2)); + + TEST_FUNC (f2, -2, -1, 0, 5, + CHECK_RANGE_EQ (0, N, 3)); + + TEST_FUNC (f3, 1, -1, 0, 0, + CHECK_RANGE_EQ (0, N, 1)); + + TEST_FUNC (f4, 0, -1, 0, 7, + CHECK_RANGE_EQ (0, N, 7)); + + TEST_FUNC (f5, 1, -1, 0, 4, + CHECK_RANGE_EQ (0, N, 5)); + + TEST_FUNC (f6, 5, -1, 0, 3, + CHECK_RANGE_EQ (0, N, 8)); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_9.c b/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_9.c new file mode 100644 index 000000000000..ec4f7a647c65 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_9.c @@ -0,0 +1,102 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fno-schedule-insns -fno-reorder-blocks -fno-schedule-insns2" } */ +/* { dg-final { check-function-bodies "**" "" "" { target lp64 } } } */ +#define N 640 +unsigned int a[N] = {0}; +unsigned int b[N] = {0}; +/* +** f1: +** ... +** cmphi p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #1 +** b(\.?eq|\.none) \.L[0-9]+ +** ... +*/ +void f1 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] > 1) + break; + } +} +/* +** f2: +** ... +** cmphi p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #1 +** b(\.?eq|\.none) \.L[0-9]+ +** ... +*/ +void f2 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] >= 2) + break; + } +} +/* +** f3: +** ... +** cmpeq p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #1 +** b(\.?eq|\.none) \.L[0-9]+ +** ... +*/ +void f3 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] == 1) + break; + } +} +/* +** f4: +** ... +** cmpne p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #1 +** b(\.?eq|\.none) \.L[0-9]+ +** ... +*/ +void f4 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] != 1) + break; + } +} +/* +** f5: +** ... +** cmpls p[0-9]+.s, p7/z, z[0-9]+.s, #1 +** b(\.?eq|\.none) .L[0-9]+ +** ... +*/ +void f5 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] < 2) + break; + } +} +/* +** f6: +** ... +** cmpls p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #1 +** b(\.?eq|\.none) \.L[0-9]+ +** ... +*/ +void f6 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] <= 1) + break; + } +} diff --git a/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch_4.c b/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch_4.c new file mode 100644 index 000000000000..a49e7963cfa1 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch_4.c @@ -0,0 +1,122 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fno-schedule-insns -fno-reorder-blocks -fno-schedule-insns2" } */ +/* { dg-final { check-function-bodies "**" "" "" { target lp64 } } } */ + +#pragma GCC target "+nosve" + +#define N 640 +unsigned int a[N] = {0}; +unsigned int b[N] = {0}; + + +/* +** f1: +** ... +** cmhi v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s +** umaxp v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s +** fmov x[0-9]+, d[0-9]+ +** cbn?z x[0-9]+, \.L[0-9]+ +** ... +*/ +void f1 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] > 1) + break; + } +} + +/* +** f2: +** ... +** cmtst v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s +** umaxp v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s +** fmov x[0-9]+, d[0-9]+ +** cbn?z x[0-9]+, \.L[0-9]+ +** ... +*/ +void f2 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] >= 1) + break; + } +} + +/* +** f3: +** ... +** umaxp v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s +** fmov x[0-9]+, d[0-9]+ +** cbn?z x[0-9]+, \.L[0-9]+ +** ... +*/ +void f3 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] == 1) + break; + } +} + +/* +** f4: +** ... +** umaxp v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s +** fmov x[0-9]+, d[0-9]+ +** cbn?z x[0-9]+, \.L[0-9]+ +** ... +*/ +void f4 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] != 1) + break; + } +} + +/* +** f5: +** ... +** cmhs v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s +** umaxp v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s +** fmov x[0-9]+, d[0-9]+ +** cbn?z x[0-9]+, \.L[0-9]+ +** ... +*/ +void f5 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] < 2) + break; + } +} + +/* +** f6: +** ... +** cmhs v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s +** umaxp v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s +** fmov x[0-9]+, d[0-9]+ +** cbn?z x[0-9]+, \.L[0-9]+ +** ... +*/ +void f6 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] <= 2) + break; + } +} diff --git a/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch_5.c b/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch_5.c new file mode 100644 index 000000000000..c28969dde1ff --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch_5.c @@ -0,0 +1,105 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fno-schedule-insns -fno-reorder-blocks -fno-schedule-insns2 --param aarch64-autovec-preference=asimd-only" } */ +/* { dg-final { check-function-bodies "**" "" "" { target lp64 } } } */ + +#pragma GCC target "+sve" + +#define N 640 +unsigned int a[N] = {0}; +unsigned int b[N] = {0}; +/* +** f1: +** ... +** cmphi p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #2 +** b(\.?eq|\.none) \.L[0-9]+ +** ... +*/ +void f1 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] > 2) + break; + } +} +/* +** f2: +** ... +** cmphi p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #1 +** b(\.?eq|\.none) \.L[0-9]+ +** ... +*/ +void f2 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] >= 2) + break; + } +} +/* +** f3: +** ... +** cmpeq p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #1 +** b(\.?eq|\.none) \.L[0-9]+ +** ... +*/ +void f3 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] == 1) + break; + } +} +/* +** f4: +** ... +** cmpne p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #1 +** b(\.?eq|\.none) \.L[0-9]+ +** ... +*/ +void f4 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] != 1) + break; + } +} +/* +** f5: +** ... +** cmpls p[0-9]+.s, p7/z, z[0-9]+.s, #1 +** b(\.?eq|\.none) .L[0-9]+ +** ... +*/ +void f5 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] < 2) + break; + } +} +/* +** f6: +** ... +** cmpls p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #1 +** b(\.?eq|\.none) \.L[0-9]+ +** ... +*/ +void f6 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] <= 1) + break; + } +}
