https://gcc.gnu.org/g:ac3b21e53c4b392e8a72b30f1c81f2339a8d6b21
commit r17-5277-gac3b21e53c4b392e8a72b30f1c81f2339a8d6b21 Author: Igor Shevlyakov <[email protected]> Date: Sat Oct 17 17:39:40 2026 +0100 simplify-rtx: Do a subreg'd vector comparison in its operands' mode [PR127903] simplify_subreg turns (subreg:OUTER (cmp:INNER a b)) for a vector comparison into (cmp:OUTER a b), but passes INNERMODE -- the mode of the comparison *result* -- as the comparison mode to simplify_gen_relational. That argument is the mode of the operands. For floating-point operands with an integer mask result, e.g. (subreg:V4SF (unordered:V4SI x y)), simplify_const_relational_operation then decides whether NaNs are honored from V4SI and folds x unord y to false (and x ord y to true). On LoongArch fwprop propagates such a comparison into a bit-cast and the function returns zero. Pass VOIDmode so the mode is taken from the operands, and add a selftest for the unordered/ordered case. The problem was found by asserting in simplify_const_relational_operation that MODE matches the mode of the operands. Assisted-by: Claude Opus 5.5 PR rtl-optimization/127903 gcc/ChangeLog: * simplify-rtx.cc (simplify_context::simplify_subreg): Pass VOIDmode, not INNERMODE, as the comparison mode of a subreg'd vector comparison. (test_vector_subreg_of_fp_comparison): New selftest. (test_vector_ops): Call it for float vector modes. gcc/testsuite/ChangeLog: * gcc.dg/torture/pr127903.c: New test. Signed-off-by: Igor Shevlyakov <[email protected]> Diff: --- gcc/simplify-rtx.cc | 28 ++++++++++++++++++++++- gcc/testsuite/gcc.dg/torture/pr127903.c | 39 +++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/gcc/simplify-rtx.cc b/gcc/simplify-rtx.cc index 77c44616616f..6b19008c0d32 100644 --- a/gcc/simplify-rtx.cc +++ b/gcc/simplify-rtx.cc @@ -9059,7 +9059,9 @@ simplify_context::simplify_subreg (machine_mode outermode, rtx op, && known_eq (GET_MODE_NUNITS (outermode), GET_MODE_NUNITS (innermode)) && known_eq (GET_MODE_UNIT_SIZE (outermode), GET_MODE_UNIT_SIZE (innermode))) - return simplify_gen_relational (GET_CODE (op), outermode, innermode, + /* INNERMODE is the mode of the comparison result; the comparison is + still done in the mode of its operands. */ + return simplify_gen_relational (GET_CODE (op), outermode, VOIDmode, XEXP (op, 0), XEXP (op, 1)); /* Distribute non-paradoxical subregs through logic ops in cases where @@ -10065,6 +10067,28 @@ test_vector_subregs (machine_mode inner_mode) test_vector_subregs_stepped (inner_mode); } +/* A subreg of a vector comparison is simplified to a comparison in the + subreg's mode. Check that the comparison is still done in the mode of + its operands, not of its integer result: with floating-point operands + that may be NaNs, x unord x and x ord x must not fold to constants. */ + +static void +test_vector_subreg_of_fp_comparison (machine_mode mode) +{ + machine_mode int_mode; + if (!HONOR_NANS (mode) + || !related_int_vector_mode (mode).exists (&int_mode)) + return; + + rtx reg = make_test_reg (mode); + rtx unord = gen_rtx_UNORDERED (int_mode, reg, reg); + rtx ord = gen_rtx_ORDERED (int_mode, reg, reg); + rtx x = simplify_subreg (mode, unord, int_mode, 0); + ASSERT_TRUE (x == NULL_RTX || !CONSTANT_P (x)); + x = simplify_subreg (mode, ord, int_mode, 0); + ASSERT_TRUE (x == NULL_RTX || !CONSTANT_P (x)); +} + /* Verify some simplifications involving vectors. */ static void @@ -10086,6 +10110,8 @@ test_vector_ops () test_vector_rotate (vector_reg); } test_vec_merge (mode); + if (GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT) + test_vector_subreg_of_fp_comparison (mode); } } } diff --git a/gcc/testsuite/gcc.dg/torture/pr127903.c b/gcc/testsuite/gcc.dg/torture/pr127903.c new file mode 100644 index 000000000000..494be2439868 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr127903.c @@ -0,0 +1,39 @@ +/* PR rtl-optimization/127903 */ +/* { dg-do run } */ +/* { dg-require-effective-target int32 } */ +/* { dg-additional-options "-Wno-psabi" } */ + +typedef float v4sf __attribute__((vector_size (16))); +typedef int v4si __attribute__((vector_size (16))); + +__attribute__((noipa)) v4sf +unord (v4sf a, v4sf b) +{ + v4si m; + for (int i = 0; i < 4; i++) + m[i] = __builtin_isunordered (a[i], b[i]) ? -1 : 0; + return (v4sf) m; +} + +__attribute__((noipa)) v4sf +ord (v4sf a, v4sf b) +{ + v4si m; + for (int i = 0; i < 4; i++) + m[i] = __builtin_isunordered (a[i], b[i]) ? 0 : -1; + return (v4sf) m; +} + +int +main () +{ + v4sf a = { __builtin_nanf (""), 1.0f, 2.0f, 3.0f }; + v4sf b = { 0.0f, 1.0f, 2.0f, __builtin_nanf ("") }; + v4si u = (v4si) unord (a, b); + v4si o = (v4si) ord (a, b); + if (u[0] != -1 || u[1] != 0 || u[2] != 0 || u[3] != -1) + __builtin_abort (); + if (o[0] != 0 || o[1] != -1 || o[2] != -1 || o[3] != 0) + __builtin_abort (); + return 0; +}
