The following example: #define N 640 int a[N] = {}; int b[N] = {}; int c[N] = {};
void f1 (int d) { for (int i = 0; i < N; i++) { b[i] += a[i]; if (a[i] != d) break; } } today generates with -Ofast -march=armv8-a+sve --param aarch64-autovec-preference=asimd-only .L6: ldr q30, [x3, x1] cmeq v31.4s, v30.4s, v27.4s not v31.16b, v31.16b umaxp v31.4s, v31.4s, v31.4s fmov x4, d31 cbz x4, .L2 Where an we use an Adv. SIMD compare and a reduction sequence to implement early break. This patch implements the new optabs vec_cbranch_any and vec_cbranch_all in order to replace the Adv. SIMD compare and reduction with an SVE flag-setting compare. With this patch the above generates: ptrue p7.b, vl16 .L6: ldr q30, [x3, x1] cmpne p15.s, p7/z, z30.s, z27.s b.none .L2 This optab could also be used for optimizing the Adv. SIMD Sequence when SVE is not available. I have a separate patch for that and will send depending on if this approach is accepted or not. Note that for floating-point we still need the ptest as floating point SVE compares don't set flags. In addition because SVE doesn't have a CMTST equivalent instruction we have to do an explicit AND before the compares. These two cases don't have a speed advantage, but do have a codesize one so I've left them enabled. Bootstrapped Regtested on aarch64-none-linux-gnu and no issues. Ok for master? Thanks, Tamar gcc/ChangeLog: PR target/118974 * config/aarch64/aarch64-simd.md (<optab><mode>4): New. * config/aarch64/aarch64-sve.md (aarch64_ptest<mode>): Rename to.. (@aarch64_ptest<mode>): ... This. * config/aarch64/iterators.md (UNSPEC_CMP_ALL, UNSPEC_CMP_ANY): New. (optab): Add them. (VALL_PRED, sve_cmp_suff, CBRANCH_CMP, cbranch_op): New. (NE): * genemit.cc: Include rtx-vector-builder.h. gcc/testsuite/ChangeLog: PR target/118974 * gcc.target/aarch64/vect-early-break-cbranch_2.c: New test. * gcc.target/aarch64/vect-early-break-cbranch_3.c: New test. * gcc.target/aarch64/sve/vect-early-break-cbranch_2.c: New test. * gcc.target/aarch64/sve/vect-early-break-cbranch_3.c: New test. * gcc.target/aarch64/sve/vect-early-break-cbranch_4.c: New test. * gcc.target/aarch64/sve/vect-early-break-cbranch_5.c: New test. --- diff --git a/gcc/config/aarch64/aarch64-simd.md b/gcc/config/aarch64/aarch64-simd.md index 1099e742cbf7418b75a16ec68f4243fc55e96506..965fab43294ee80d907f2eced820f3cedc0938a6 100644 --- a/gcc/config/aarch64/aarch64-simd.md +++ b/gcc/config/aarch64/aarch64-simd.md @@ -3952,6 +3952,47 @@ (define_expand "cbranch<mode>4" DONE; }) +;; Define vec_cbranch_any and vec_cbranch_all +;; Vector comparison and branch for Adv. SIMD types using SVE instructions. +(define_expand "<optab><mode>4" + [(set (pc) + (unspec:VALL + [(if_then_else + (match_operator 0 "aarch64_comparison_operator" + [(match_operand:VALL 1 "register_operand") + (match_operand:VALL 2 "aarch64_simd_reg_or_zero")]) + (label_ref (match_operand 3 "")) + (pc))] + CBRANCH_CMP))] + "TARGET_SVE" +{ + auto code = GET_CODE (operands[0]); + machine_mode full_mode = aarch64_full_sve_mode (<VEL>mode).require (); + rtx in1 = force_lowpart_subreg (full_mode, operands[1], <MODE>mode); + rtx in2 = force_lowpart_subreg (full_mode, operands[2], <MODE>mode); + + unsigned lanes = exact_div (GET_MODE_BITSIZE (<MODE>mode), 8).to_constant (); + machine_mode pred_mode = aarch64_sve_pred_mode (full_mode); + rtx_vector_builder builder (VNx16BImode, lanes, 2); + for (unsigned int i = 0; i < lanes; ++i) + builder.quick_push (CONST1_RTX (BImode)); + for (unsigned int i = 0; i < lanes; ++i) + builder.quick_push (CONST0_RTX (BImode)); + + rtx ptrue = force_reg (VNx16BImode, builder.build ()); + rtx cast_ptrue = gen_lowpart (pred_mode, ptrue); + rtx ptrue_flag = gen_int_mode (SVE_KNOWN_PTRUE, SImode); + + rtx tmp = gen_reg_rtx (pred_mode); + aarch64_expand_sve_vec_cmp<sve_cmp_suff> (tmp, code, in1, in2); + emit_insn (gen_aarch64_ptest (pred_mode, ptrue, cast_ptrue, ptrue_flag, tmp)); + + rtx cc_reg = gen_rtx_REG (CC_NZCmode, CC_REGNUM); + rtx cmp_reg = gen_rtx_<cbranch_op> (VOIDmode, cc_reg, const0_rtx); + emit_jump_insn (gen_condjump (cmp_reg, cc_reg, operands[3])); + DONE; +}) + ;; Patterns comparing two vectors to produce a mask. (define_expand "vec_cmp<mode><mode>" diff --git a/gcc/config/aarch64/aarch64-sve.md b/gcc/config/aarch64/aarch64-sve.md index fe7f52ee1ed400b4eda28e3f90edc0044a5aa7a9..4582e12540e93a72fb5baadd77d2470793486346 100644 --- a/gcc/config/aarch64/aarch64-sve.md +++ b/gcc/config/aarch64/aarch64-sve.md @@ -8955,7 +8955,7 @@ (define_expand "cbranch<mode>4" ) ;; See "Description of UNSPEC_PTEST" above for details. -(define_insn "aarch64_ptest<mode>" +(define_insn "@aarch64_ptest<mode>" [(set (reg:CC_NZC CC_REGNUM) (unspec:CC_NZC [(match_operand:VNx16BI 0 "register_operand" "Upa") (match_operand 1) diff --git a/gcc/config/aarch64/iterators.md b/gcc/config/aarch64/iterators.md index 146453b0516848acd40e5f34fd8843fe74c18dbf..9d01305dd63cdba3a5079efbe1680e5715d1a96e 100644 --- a/gcc/config/aarch64/iterators.md +++ b/gcc/config/aarch64/iterators.md @@ -799,6 +799,8 @@ (define_c_enum "unspec" UNSPEC_SSHLL ; Used in aarch64-simd.md. UNSPEC_USHLL ; Used in aarch64-simd.md. UNSPEC_ADDP ; Used in aarch64-simd.md. + UNSPEC_CMP_ALL ; Used in aarch64-simd.md. + UNSPEC_CMP_ANY ; Used in aarch64-simd.md. UNSPEC_TBL ; Used in vector permute patterns. UNSPEC_TBLQ ; Used in vector permute patterns. UNSPEC_TBX ; Used in vector permute patterns. @@ -2502,6 +2504,19 @@ (define_mode_attr vpred [(VNx16QI "vnx16bi") (VNx8QI "vnx8bi") (VNx16SI "vnx4bi") (VNx16SF "vnx4bi") (VNx8DI "vnx2bi") (VNx8DF "vnx2bi")]) +;; Map an Adv. SIMD mode to an SVE BI mask that corresponds to the same number +;; of bits as the Adv. SIMD mode +(define_mode_attr VALL_PRED [(V8QI "VNx8BI") (V16QI "VNx16BI") + (V4HI "VNx8BI") (V8HI "VNx16BI") (V2SI "VNx8BI") + (V4SI "VNx16BI") (V2DI "VNx16BI") + (V2SF "VNx8BI") (V4SF "VNx16BI") (V2DF "VNx16BI")]) + +;; Map mode to suffix for using an SVE comparison +(define_mode_attr sve_cmp_suff [(V8QI "_int") (V16QI "_int") + (V4HI "_int") (V8HI "_int") (V2SI "_int") + (V4SI "_int") (V2DI "_int") + (V2SF "_float") (V4SF "_float") (V2DF "_float")]) + (define_mode_attr VDOUBLE [(VNx16QI "VNx32QI") (VNx8HI "VNx16HI") (VNx8HF "VNx16HF") (VNx8BF "VNx16BF") @@ -3131,6 +3146,8 @@ (define_int_iterator HADD [UNSPEC_SHADD UNSPEC_UHADD]) (define_int_iterator RHADD [UNSPEC_SRHADD UNSPEC_URHADD]) +(define_int_iterator CBRANCH_CMP [UNSPEC_CMP_ALL UNSPEC_CMP_ANY]) + (define_int_iterator BSL_DUP [1 2]) (define_int_iterator DOTPROD [UNSPEC_SDOT UNSPEC_UDOT]) @@ -4064,7 +4081,11 @@ (define_int_attr optab [(UNSPEC_ANDF "and") (UNSPEC_COND_SCVTF "float") (UNSPEC_COND_SMAX "smax") (UNSPEC_COND_SMIN "smin") - (UNSPEC_COND_UCVTF "floatuns")]) + (UNSPEC_COND_UCVTF "floatuns") + (UNSPEC_CMP_ALL "vec_cbranch_all") + (UNSPEC_CMP_ANY "vec_cbranch_any")]) + +(define_int_attr cbranch_op [(UNSPEC_CMP_ALL "EQ") (UNSPEC_CMP_ANY "NE")]) (define_int_attr fmaxmin [(UNSPEC_FMAX "fmax_nan") (UNSPEC_FMAXNM "fmax") diff --git a/gcc/genemit.cc b/gcc/genemit.cc index 9f92364d9062f7685780a8b0ddc98c4a1c22242b..c69affdb67322d405a887ac0d22652c06e14f19c 100644 --- a/gcc/genemit.cc +++ b/gcc/genemit.cc @@ -907,6 +907,7 @@ from the machine description file `md'. */\n\n"); fprintf (file, "#include \"tm-constrs.h\"\n"); fprintf (file, "#include \"ggc.h\"\n"); fprintf (file, "#include \"target.h\"\n\n"); + fprintf (file, "#include \"rtx-vector-builder.h\"\n\n"); } auto_vec<FILE *, 10> output_files; diff --git a/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_2.c b/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_2.c new file mode 100644 index 0000000000000000000000000000000000000000..7c996a893d99f7462c980140d12ab2711738597c --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_2.c @@ -0,0 +1,132 @@ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-O3 -fno-schedule-insns -fno-reorder-blocks -fno-schedule-insns2 --param aarch64-autovec-preference=asimd-only" } */ +/* { dg-require-effective-target lp64 } */ + +#include <stdio.h> + +#define N 640 +#ifndef TYPE +#define TYPE int +#endif +#ifndef FMT +#define FMT "d" +#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_3.c b/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_3.c new file mode 100644 index 0000000000000000000000000000000000000000..75927abb09479712760a60b0f6a11135d9be9502 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_3.c @@ -0,0 +1,132 @@ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-O3 -fno-schedule-insns -fno-reorder-blocks -fno-schedule-insns2 --param aarch64-autovec-preference=sve-only" } */ +/* { dg-require-effective-target lp64 } */ + +#include <stdio.h> + +#define N 640 +#ifndef TYPE +#define TYPE int +#endif +#ifndef FMT +#define FMT "d" +#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_4.c b/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_4.c new file mode 100644 index 0000000000000000000000000000000000000000..68a5d0a09fdfd5664562e1bac3b5e586a37b3a6f --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_4.c @@ -0,0 +1,132 @@ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-O3 -fno-schedule-insns -fno-reorder-blocks -fno-schedule-insns2 --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_5.c b/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_5.c new file mode 100644 index 0000000000000000000000000000000000000000..52d95e9a71b7999376731e47a224936d4253ac2f --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_5.c @@ -0,0 +1,132 @@ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-O3 -fno-schedule-insns -fno-reorder-blocks -fno-schedule-insns2 --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/vect-early-break-cbranch_2.c b/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch_2.c new file mode 100644 index 0000000000000000000000000000000000000000..218349311d9044c0c0c195c72b0cc6ad43022448 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch_2.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 +int a[N] = {0}; +int b[N] = {0}; +/* +** f1: +** ... +** cmpgt p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0 +** b.none \.L[0-9]+ +** ... +*/ +void f1 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] > 0) + break; + } +} +/* +** f2: +** ... +** cmpge p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0 +** b.none \.L[0-9]+ +** ... +*/ +void f2 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] >= 0) + break; + } +} +/* +** f3: +** ... +** cmpeq p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0 +** b.none \.L[0-9]+ +** ... +*/ +void f3 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] == 0) + break; + } +} +/* +** f4: +** ... +** cmpne p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0 +** b.none \.L[0-9]+ +** ... +*/ +void f4 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] != 0) + break; + } +} +/* +** f5: +** ... +** cmplt p[0-9]+.s, p7/z, z[0-9]+.s, #0 +** b.none .L[0-9]+ +** ... +*/ +void f5 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] < 0) + break; + } +} +/* +** f6: +** ... +** cmple p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0 +** b.none \.L[0-9]+ +** ... +*/ +void f6 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] <= 0) + break; + } +} diff --git a/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch_3.c b/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch_3.c new file mode 100644 index 0000000000000000000000000000000000000000..d4885b02c4a4c1338119c05bf812cfa521c3515b --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch_3.c @@ -0,0 +1,112 @@ +/* { 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 +float a[N] = {0}; +float b[N] = {0}; + +/* +** f1: +** ... +** fcmgt p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0.0 +** ptest p[0-9]+, p[0-9]+\.b +** b.none \.L[0-9]+ +** ... +*/ +void f1 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] > 0) + break; + } +} +/* +** f2: +** ... +** fcmge p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0.0 +** ptest p[0-9]+, p[0-9]+\.b +** b.none \.L[0-9]+ +** ... +*/ +void f2 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] >= 0) + break; + } +} +/* +** f3: +** ... +** fcmeq p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0.0 +** ptest p[0-9]+, p[0-9]+\.b +** b.none \.L[0-9]+ +** ... +*/ +void f3 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] == 0) + break; + } +} +/* +** f4: +** ... +** fcmne p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0.0 +** ptest p[0-9]+, p[0-9]+\.b +** b.none \.L[0-9]+ +** ... +*/ +void f4 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] != 0) + break; + } +} +/* +** f5: +** ... +** fcmlt p[0-9]+.s, p7/z, z[0-9]+.s, #0.0 +** ptest p[0-9]+, p[0-9]+\.b +** b.none .L[0-9]+ +** ... +*/ +void f5 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] < 0) + break; + } +} +/* +** f6: +** ... +** fcmle p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0.0 +** ptest p[0-9]+, p[0-9]+\.b +** b.none \.L[0-9]+ +** ... +*/ +void f6 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] <= 0) + break; + } +} --
diff --git a/gcc/config/aarch64/aarch64-simd.md b/gcc/config/aarch64/aarch64-simd.md index 1099e742cbf7418b75a16ec68f4243fc55e96506..965fab43294ee80d907f2eced820f3cedc0938a6 100644 --- a/gcc/config/aarch64/aarch64-simd.md +++ b/gcc/config/aarch64/aarch64-simd.md @@ -3952,6 +3952,47 @@ (define_expand "cbranch<mode>4" DONE; }) +;; Define vec_cbranch_any and vec_cbranch_all +;; Vector comparison and branch for Adv. SIMD types using SVE instructions. +(define_expand "<optab><mode>4" + [(set (pc) + (unspec:VALL + [(if_then_else + (match_operator 0 "aarch64_comparison_operator" + [(match_operand:VALL 1 "register_operand") + (match_operand:VALL 2 "aarch64_simd_reg_or_zero")]) + (label_ref (match_operand 3 "")) + (pc))] + CBRANCH_CMP))] + "TARGET_SVE" +{ + auto code = GET_CODE (operands[0]); + machine_mode full_mode = aarch64_full_sve_mode (<VEL>mode).require (); + rtx in1 = force_lowpart_subreg (full_mode, operands[1], <MODE>mode); + rtx in2 = force_lowpart_subreg (full_mode, operands[2], <MODE>mode); + + unsigned lanes = exact_div (GET_MODE_BITSIZE (<MODE>mode), 8).to_constant (); + machine_mode pred_mode = aarch64_sve_pred_mode (full_mode); + rtx_vector_builder builder (VNx16BImode, lanes, 2); + for (unsigned int i = 0; i < lanes; ++i) + builder.quick_push (CONST1_RTX (BImode)); + for (unsigned int i = 0; i < lanes; ++i) + builder.quick_push (CONST0_RTX (BImode)); + + rtx ptrue = force_reg (VNx16BImode, builder.build ()); + rtx cast_ptrue = gen_lowpart (pred_mode, ptrue); + rtx ptrue_flag = gen_int_mode (SVE_KNOWN_PTRUE, SImode); + + rtx tmp = gen_reg_rtx (pred_mode); + aarch64_expand_sve_vec_cmp<sve_cmp_suff> (tmp, code, in1, in2); + emit_insn (gen_aarch64_ptest (pred_mode, ptrue, cast_ptrue, ptrue_flag, tmp)); + + rtx cc_reg = gen_rtx_REG (CC_NZCmode, CC_REGNUM); + rtx cmp_reg = gen_rtx_<cbranch_op> (VOIDmode, cc_reg, const0_rtx); + emit_jump_insn (gen_condjump (cmp_reg, cc_reg, operands[3])); + DONE; +}) + ;; Patterns comparing two vectors to produce a mask. (define_expand "vec_cmp<mode><mode>" diff --git a/gcc/config/aarch64/aarch64-sve.md b/gcc/config/aarch64/aarch64-sve.md index fe7f52ee1ed400b4eda28e3f90edc0044a5aa7a9..4582e12540e93a72fb5baadd77d2470793486346 100644 --- a/gcc/config/aarch64/aarch64-sve.md +++ b/gcc/config/aarch64/aarch64-sve.md @@ -8955,7 +8955,7 @@ (define_expand "cbranch<mode>4" ) ;; See "Description of UNSPEC_PTEST" above for details. -(define_insn "aarch64_ptest<mode>" +(define_insn "@aarch64_ptest<mode>" [(set (reg:CC_NZC CC_REGNUM) (unspec:CC_NZC [(match_operand:VNx16BI 0 "register_operand" "Upa") (match_operand 1) diff --git a/gcc/config/aarch64/iterators.md b/gcc/config/aarch64/iterators.md index 146453b0516848acd40e5f34fd8843fe74c18dbf..9d01305dd63cdba3a5079efbe1680e5715d1a96e 100644 --- a/gcc/config/aarch64/iterators.md +++ b/gcc/config/aarch64/iterators.md @@ -799,6 +799,8 @@ (define_c_enum "unspec" UNSPEC_SSHLL ; Used in aarch64-simd.md. UNSPEC_USHLL ; Used in aarch64-simd.md. UNSPEC_ADDP ; Used in aarch64-simd.md. + UNSPEC_CMP_ALL ; Used in aarch64-simd.md. + UNSPEC_CMP_ANY ; Used in aarch64-simd.md. UNSPEC_TBL ; Used in vector permute patterns. UNSPEC_TBLQ ; Used in vector permute patterns. UNSPEC_TBX ; Used in vector permute patterns. @@ -2502,6 +2504,19 @@ (define_mode_attr vpred [(VNx16QI "vnx16bi") (VNx8QI "vnx8bi") (VNx16SI "vnx4bi") (VNx16SF "vnx4bi") (VNx8DI "vnx2bi") (VNx8DF "vnx2bi")]) +;; Map an Adv. SIMD mode to an SVE BI mask that corresponds to the same number +;; of bits as the Adv. SIMD mode +(define_mode_attr VALL_PRED [(V8QI "VNx8BI") (V16QI "VNx16BI") + (V4HI "VNx8BI") (V8HI "VNx16BI") (V2SI "VNx8BI") + (V4SI "VNx16BI") (V2DI "VNx16BI") + (V2SF "VNx8BI") (V4SF "VNx16BI") (V2DF "VNx16BI")]) + +;; Map mode to suffix for using an SVE comparison +(define_mode_attr sve_cmp_suff [(V8QI "_int") (V16QI "_int") + (V4HI "_int") (V8HI "_int") (V2SI "_int") + (V4SI "_int") (V2DI "_int") + (V2SF "_float") (V4SF "_float") (V2DF "_float")]) + (define_mode_attr VDOUBLE [(VNx16QI "VNx32QI") (VNx8HI "VNx16HI") (VNx8HF "VNx16HF") (VNx8BF "VNx16BF") @@ -3131,6 +3146,8 @@ (define_int_iterator HADD [UNSPEC_SHADD UNSPEC_UHADD]) (define_int_iterator RHADD [UNSPEC_SRHADD UNSPEC_URHADD]) +(define_int_iterator CBRANCH_CMP [UNSPEC_CMP_ALL UNSPEC_CMP_ANY]) + (define_int_iterator BSL_DUP [1 2]) (define_int_iterator DOTPROD [UNSPEC_SDOT UNSPEC_UDOT]) @@ -4064,7 +4081,11 @@ (define_int_attr optab [(UNSPEC_ANDF "and") (UNSPEC_COND_SCVTF "float") (UNSPEC_COND_SMAX "smax") (UNSPEC_COND_SMIN "smin") - (UNSPEC_COND_UCVTF "floatuns")]) + (UNSPEC_COND_UCVTF "floatuns") + (UNSPEC_CMP_ALL "vec_cbranch_all") + (UNSPEC_CMP_ANY "vec_cbranch_any")]) + +(define_int_attr cbranch_op [(UNSPEC_CMP_ALL "EQ") (UNSPEC_CMP_ANY "NE")]) (define_int_attr fmaxmin [(UNSPEC_FMAX "fmax_nan") (UNSPEC_FMAXNM "fmax") diff --git a/gcc/genemit.cc b/gcc/genemit.cc index 9f92364d9062f7685780a8b0ddc98c4a1c22242b..c69affdb67322d405a887ac0d22652c06e14f19c 100644 --- a/gcc/genemit.cc +++ b/gcc/genemit.cc @@ -907,6 +907,7 @@ from the machine description file `md'. */\n\n"); fprintf (file, "#include \"tm-constrs.h\"\n"); fprintf (file, "#include \"ggc.h\"\n"); fprintf (file, "#include \"target.h\"\n\n"); + fprintf (file, "#include \"rtx-vector-builder.h\"\n\n"); } auto_vec<FILE *, 10> output_files; diff --git a/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_2.c b/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_2.c new file mode 100644 index 0000000000000000000000000000000000000000..7c996a893d99f7462c980140d12ab2711738597c --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_2.c @@ -0,0 +1,132 @@ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-O3 -fno-schedule-insns -fno-reorder-blocks -fno-schedule-insns2 --param aarch64-autovec-preference=asimd-only" } */ +/* { dg-require-effective-target lp64 } */ + +#include <stdio.h> + +#define N 640 +#ifndef TYPE +#define TYPE int +#endif +#ifndef FMT +#define FMT "d" +#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_3.c b/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_3.c new file mode 100644 index 0000000000000000000000000000000000000000..75927abb09479712760a60b0f6a11135d9be9502 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_3.c @@ -0,0 +1,132 @@ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-O3 -fno-schedule-insns -fno-reorder-blocks -fno-schedule-insns2 --param aarch64-autovec-preference=sve-only" } */ +/* { dg-require-effective-target lp64 } */ + +#include <stdio.h> + +#define N 640 +#ifndef TYPE +#define TYPE int +#endif +#ifndef FMT +#define FMT "d" +#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_4.c b/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_4.c new file mode 100644 index 0000000000000000000000000000000000000000..68a5d0a09fdfd5664562e1bac3b5e586a37b3a6f --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_4.c @@ -0,0 +1,132 @@ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-O3 -fno-schedule-insns -fno-reorder-blocks -fno-schedule-insns2 --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_5.c b/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_5.c new file mode 100644 index 0000000000000000000000000000000000000000..52d95e9a71b7999376731e47a224936d4253ac2f --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_5.c @@ -0,0 +1,132 @@ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-O3 -fno-schedule-insns -fno-reorder-blocks -fno-schedule-insns2 --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/vect-early-break-cbranch_2.c b/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch_2.c new file mode 100644 index 0000000000000000000000000000000000000000..218349311d9044c0c0c195c72b0cc6ad43022448 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch_2.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 +int a[N] = {0}; +int b[N] = {0}; +/* +** f1: +** ... +** cmpgt p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0 +** b.none \.L[0-9]+ +** ... +*/ +void f1 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] > 0) + break; + } +} +/* +** f2: +** ... +** cmpge p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0 +** b.none \.L[0-9]+ +** ... +*/ +void f2 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] >= 0) + break; + } +} +/* +** f3: +** ... +** cmpeq p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0 +** b.none \.L[0-9]+ +** ... +*/ +void f3 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] == 0) + break; + } +} +/* +** f4: +** ... +** cmpne p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0 +** b.none \.L[0-9]+ +** ... +*/ +void f4 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] != 0) + break; + } +} +/* +** f5: +** ... +** cmplt p[0-9]+.s, p7/z, z[0-9]+.s, #0 +** b.none .L[0-9]+ +** ... +*/ +void f5 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] < 0) + break; + } +} +/* +** f6: +** ... +** cmple p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0 +** b.none \.L[0-9]+ +** ... +*/ +void f6 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] <= 0) + break; + } +} diff --git a/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch_3.c b/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch_3.c new file mode 100644 index 0000000000000000000000000000000000000000..d4885b02c4a4c1338119c05bf812cfa521c3515b --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch_3.c @@ -0,0 +1,112 @@ +/* { 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 +float a[N] = {0}; +float b[N] = {0}; + +/* +** f1: +** ... +** fcmgt p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0.0 +** ptest p[0-9]+, p[0-9]+\.b +** b.none \.L[0-9]+ +** ... +*/ +void f1 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] > 0) + break; + } +} +/* +** f2: +** ... +** fcmge p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0.0 +** ptest p[0-9]+, p[0-9]+\.b +** b.none \.L[0-9]+ +** ... +*/ +void f2 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] >= 0) + break; + } +} +/* +** f3: +** ... +** fcmeq p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0.0 +** ptest p[0-9]+, p[0-9]+\.b +** b.none \.L[0-9]+ +** ... +*/ +void f3 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] == 0) + break; + } +} +/* +** f4: +** ... +** fcmne p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0.0 +** ptest p[0-9]+, p[0-9]+\.b +** b.none \.L[0-9]+ +** ... +*/ +void f4 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] != 0) + break; + } +} +/* +** f5: +** ... +** fcmlt p[0-9]+.s, p7/z, z[0-9]+.s, #0.0 +** ptest p[0-9]+, p[0-9]+\.b +** b.none .L[0-9]+ +** ... +*/ +void f5 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] < 0) + break; + } +} +/* +** f6: +** ... +** fcmle p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0.0 +** ptest p[0-9]+, p[0-9]+\.b +** b.none \.L[0-9]+ +** ... +*/ +void f6 () +{ + for (int i = 0; i < N; i++) + { + b[i] += a[i]; + if (a[i] <= 0) + break; + } +}