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;
+}

Reply via email to