Add more rtx comparison folds

Richard Sandiford richard.sandiford@arm.com
Fri Jul 12 08:16:00 GMT 2019


This patch adds rtx folds for:

  (and (cmp1 x y) (cmp2 x y)) -> (cmp3 x y)
  (ior (cmp1 x y) (cmp2 x y)) -> (cmp3 x y)
  (if_then_else (cmp1 x y) (cmp2 x y) (const_int 0))
    -> (and (cmp1 x y) (cmp2 x y))

As always, there are plenty of other things that could be added.
This just happened to be the set I need for the SVE ACLE.

Tested on aarch64-linux-gnu, aarch64_be-elf and x86_64-linux-gnu.
OK to install?

Richard


2019-07-12  Richard Sandiford  <richard.sandiford@arm.com>

gcc/
	* rtl.h (bit_and_conditions, bit_ior_conditions): Declare.
	* jump.c (flags_to_condition): Add an honor_nans_p argument.
	(bit_ior_conditions, bit_and_conditions): New functions.
	* simplify-rtx.c (simplify_binary_operation_1): Try to fold an
	AND or IOR of two comparisons into a single comparison.
	(simplify_ternary_operation): Try to fold an if_then_else involving
	two conditions into an AND of two conditions.
	(test_merged_comparisons): New function.
	(simplify_rtx_c_tests): Call it.

Index: gcc/rtl.h
===================================================================
--- gcc/rtl.h	2019-07-12 08:53:06.000000000 +0100
+++ gcc/rtl.h	2019-07-12 09:11:08.765147590 +0100
@@ -3315,6 +3315,8 @@ extern enum rtx_code reverse_condition_m
 extern enum rtx_code swap_condition (enum rtx_code);
 extern enum rtx_code unsigned_condition (enum rtx_code);
 extern enum rtx_code signed_condition (enum rtx_code);
+extern rtx_code bit_and_conditions (rtx_code, rtx_code, machine_mode);
+extern rtx_code bit_ior_conditions (rtx_code, rtx_code, machine_mode);
 extern void mark_jump_label (rtx, rtx_insn *, int);
 
 /* Return true if integer comparison operator CODE interprets its operands
Index: gcc/jump.c
===================================================================
--- gcc/jump.c	2019-07-12 09:06:52.043241422 +0100
+++ gcc/jump.c	2019-07-12 09:11:08.765147590 +0100
@@ -134,13 +134,23 @@ #define CASE(CODE, ORDER, SIGNEDNESS, CA
 }
 
 /* Return the comparison code that implements FLAGS_* bitmask FLAGS.
+   HONOR_NANS_P is true if the result must handle NaNs correctly,
+   both in terms of ordering and in terms of trapping behavior.
+
    Assert on failure if FORCE, otherwise return UNKNOWN.  */
 
 static rtx_code
-flags_to_condition (unsigned int flags, bool force)
+flags_to_condition (unsigned int flags, bool force, bool honor_nans_p = true)
 {
+  unsigned int order_mask = FLAGS_ORDER;
+  if (!honor_nans_p)
+    {
+      flags |= FLAGS_CAN_TRAP;
+      order_mask &= ~FLAGS_UNORDERED;
+    }
+
 #define TEST(CODE, ORDER, SIGNEDNESS, CAN_TRAP)			\
-  if (((flags ^ (ORDER)) & FLAGS_ORDER) == 0			\
+  if (((flags ^ (ORDER)) & order_mask) == 0			\
       && (!SIGNEDNESS						\
 	  || (flags & ~SIGNEDNESS & FLAGS_SIGNEDNESS) == 0)	\
       && (!CAN_TRAP || (flags & FLAGS_CAN_TRAP) != 0))		\
@@ -718,6 +728,33 @@ comparison_dominates_p (enum rtx_code co
   return (((flags1 | flags2) & FLAGS_SIGNEDNESS) != FLAGS_SIGNEDNESS
 	  && (flags1 & ~flags2 & FLAGS_ORDER) == 0);
 }
+
+/* Return the comparison code that tests whether CODE1 | CODE2 is
+   true for mode MODE.  Return UNKNOWN if no such comparison exists.
+   The result can trap if either CODE1 or CODE2 traps.  */
+
+rtx_code
+bit_ior_conditions (rtx_code code1, rtx_code code2, machine_mode mode)
+{
+  unsigned int flags1 = condition_to_flags (code1);
+  unsigned int flags2 = condition_to_flags (code2);
+  unsigned int flags = flags1 | flags2;
+  return flags_to_condition (flags, false, HONOR_NANS (mode));
+}
+
+/* Return the comparison code that tests whether CODE1 & CODE2 is
+   true for mode MODE.  Return UNKNOWN if no such comparison exists.
+   The result can trap if either CODE1 or CODE2 traps.  */
+
+rtx_code
+bit_and_conditions (rtx_code code1, rtx_code code2, machine_mode mode)
+{
+  unsigned int flags1 = condition_to_flags (code1);
+  unsigned int flags2 = condition_to_flags (code2);
+  unsigned int order = (flags1 & flags2) & FLAGS_ORDER;
+  unsigned int rest = (flags1 | flags2) & ~FLAGS_ORDER;
+  return flags_to_condition (order | rest, false, HONOR_NANS (mode));
+}
 
 /* Return 1 if INSN is an unconditional jump and nothing else.  */
 
Index: gcc/simplify-rtx.c
===================================================================
--- gcc/simplify-rtx.c	2019-07-12 08:53:06.000000000 +0100
+++ gcc/simplify-rtx.c	2019-07-12 09:11:08.769147559 +0100
@@ -2889,6 +2889,19 @@ simplify_binary_operation_1 (enum rtx_co
 	    }
 	}
 
+      /* (ior (cmp1 x y) (cmp2 x y)) -> (cmp3 x y).  */
+      if (COMPARISON_P (op0)
+	  && COMPARISON_P (op1)
+	  && rtx_equal_p (XEXP (op0, 0), XEXP (op1, 0))
+	  && rtx_equal_p (XEXP (op0, 1), XEXP (op1, 1)))
+	{
+	  rtx_code cond = bit_ior_conditions (GET_CODE (op0),
+					      GET_CODE (op1), mode);
+	  if (cond != UNKNOWN)
+	    return simplify_gen_relational (cond, mode, mode, XEXP (op0, 0),
+					    XEXP (op0, 1));
+	}
+
       tem = simplify_byte_swapping_operation (code, mode, op0, op1);
       if (tem)
 	return tem;
@@ -3321,6 +3334,19 @@ simplify_binary_operation_1 (enum rtx_co
 	  && rtx_equal_p (op1, XEXP (XEXP (op0, 1), 0)))
 	return simplify_gen_binary (AND, mode, op1, XEXP (op0, 0));
 
+      /* (and (cmp1 x y) (cmp2 x y)) -> (cmp3 x y).  */
+      if (COMPARISON_P (op0)
+	  && COMPARISON_P (op1)
+	  && rtx_equal_p (XEXP (op0, 0), XEXP (op1, 0))
+	  && rtx_equal_p (XEXP (op0, 1), XEXP (op1, 1)))
+	{
+	  rtx_code cond = bit_and_conditions (GET_CODE (op0),
+					      GET_CODE (op1), mode);
+	  if (cond != UNKNOWN)
+	    return simplify_gen_relational (cond, mode, mode, XEXP (op0, 0),
+					    XEXP (op0, 1));
+	}
+
       tem = simplify_byte_swapping_operation (code, mode, op0, op1);
       if (tem)
 	return tem;
@@ -5832,6 +5858,14 @@ simplify_ternary_operation (enum rtx_cod
 	    return simplified;
 	}
 
+      /* (if_then_else (cmp1 X1 Y1) (cmp X2 Y2) (const_int 0))
+	 -> (and (cmp1 X1 Y1) (cmp2 X2 Y2)).  */
+      if (COMPARISON_P (op0)
+	  && COMPARISON_P (op1)
+	  && op2 == const0_rtx
+	  && GET_MODE (op0) == GET_MODE (op1))
+	return simplify_gen_binary (AND, mode, op0, op1);
+
       if (COMPARISON_P (op0) && ! side_effects_p (op0))
 	{
 	  machine_mode cmp_mode = (GET_MODE (XEXP (op0, 0)) == VOIDmode
@@ -6858,6 +6892,75 @@ make_test_reg (machine_mode mode)
   return gen_rtx_REG (mode, test_reg_num++);
 }
 
+/* Test ANDs and IORs of two comparisons.  */
+
+static void
+test_merged_comparisons (machine_mode mode)
+{
+  rtx reg1 = make_test_reg (mode);
+  rtx reg2 = make_test_reg (mode);
+
+  rtx eq = gen_rtx_EQ (mode, reg1, reg2);
+  rtx ne = gen_rtx_NE (mode, reg1, reg2);
+  rtx le = gen_rtx_LE (mode, reg1, reg2);
+  rtx leu = gen_rtx_LEU (mode, reg1, reg2);
+  rtx lt = gen_rtx_LT (mode, reg1, reg2);
+  rtx ltu = gen_rtx_LTU (mode, reg1, reg2);
+  rtx ge = gen_rtx_GE (mode, reg1, reg2);
+  rtx geu = gen_rtx_GEU (mode, reg1, reg2);
+  rtx gt = gen_rtx_GT (mode, reg1, reg2);
+  rtx gtu = gen_rtx_GTU (mode, reg1, reg2);
+
+  ASSERT_FALSE (simplify_binary_operation (AND, mode, le, leu));
+  ASSERT_FALSE (simplify_binary_operation (AND, mode, lt, ltu));
+  ASSERT_FALSE (simplify_binary_operation (AND, mode, gt, gtu));
+  ASSERT_FALSE (simplify_binary_operation (AND, mode, ge, geu));
+
+  ASSERT_RTX_EQ (eq, simplify_binary_operation (AND, mode, eq, leu));
+  ASSERT_RTX_EQ (eq, simplify_binary_operation (AND, mode, eq, geu));
+  ASSERT_RTX_EQ (eq, simplify_binary_operation (AND, mode, eq, le));
+  ASSERT_RTX_EQ (eq, simplify_binary_operation (AND, mode, eq, ge));
+
+  ASSERT_RTX_EQ (eq, simplify_binary_operation (AND, mode, geu, leu));
+  ASSERT_RTX_EQ (eq, simplify_binary_operation (AND, mode, ge, le));
+
+  ASSERT_RTX_EQ (ltu, simplify_binary_operation (AND, mode, leu, ltu));
+  ASSERT_RTX_EQ (gtu, simplify_binary_operation (AND, mode, geu, gtu));
+  ASSERT_RTX_EQ (lt, simplify_binary_operation (AND, mode, le, lt));
+  ASSERT_RTX_EQ (gt, simplify_binary_operation (AND, mode, ge, gt));
+
+  ASSERT_RTX_EQ (ltu, simplify_binary_operation (AND, mode, ne, leu));
+  ASSERT_RTX_EQ (gtu, simplify_binary_operation (AND, mode, ne, geu));
+  ASSERT_RTX_EQ (lt, simplify_binary_operation (AND, mode, ne, le));
+  ASSERT_RTX_EQ (gt, simplify_binary_operation (AND, mode, ne, ge));
+
+  ASSERT_FALSE (simplify_binary_operation (IOR, mode, le, leu));
+  ASSERT_FALSE (simplify_binary_operation (IOR, mode, lt, ltu));
+  ASSERT_FALSE (simplify_binary_operation (IOR, mode, gt, gtu));
+  ASSERT_FALSE (simplify_binary_operation (IOR, mode, ge, geu));
+
+  ASSERT_RTX_EQ (leu, simplify_binary_operation (IOR, mode, eq, leu));
+  ASSERT_RTX_EQ (geu, simplify_binary_operation (IOR, mode, eq, geu));
+  ASSERT_RTX_EQ (le, simplify_binary_operation (IOR, mode, eq, le));
+  ASSERT_RTX_EQ (ge, simplify_binary_operation (IOR, mode, eq, ge));
+
+  ASSERT_RTX_EQ (ne, simplify_binary_operation (IOR, mode, gtu, ltu));
+  ASSERT_RTX_EQ (ne, simplify_binary_operation (IOR, mode, gt, lt));
+
+  ASSERT_RTX_EQ (leu, simplify_binary_operation (IOR, mode, eq, ltu));
+  ASSERT_RTX_EQ (geu, simplify_binary_operation (IOR, mode, eq, gtu));
+  ASSERT_RTX_EQ (le, simplify_binary_operation (IOR, mode, eq, lt));
+  ASSERT_RTX_EQ (ge, simplify_binary_operation (IOR, mode, eq, gt));
+
+  ASSERT_RTX_EQ (ne, simplify_binary_operation (IOR, mode, ne, ltu));
+  ASSERT_RTX_EQ (ne, simplify_binary_operation (IOR, mode, ne, gtu));
+  ASSERT_RTX_EQ (ne, simplify_binary_operation (IOR, mode, ne, lt));
+  ASSERT_RTX_EQ (ne, simplify_binary_operation (IOR, mode, ne, gt));
+
+  ASSERT_RTX_EQ (eq, simplify_ternary_operation (IF_THEN_ELSE, mode, mode,
+						 geu, leu, const0_rtx));
+}
+
 /* Test vector simplifications involving VEC_DUPLICATE in which the
    operands and result have vector mode MODE.  SCALAR_REG is a pseudo
    register that holds one element of MODE.  */
@@ -7149,6 +7252,7 @@ simplify_const_poly_int_tests<N>::run ()
 void
 simplify_rtx_c_tests ()
 {
+  test_merged_comparisons (HImode);
   test_vector_ops ();
   simplify_const_poly_int_tests<NUM_POLY_INT_COEFFS>::run ();
 }



More information about the Gcc-patches mailing list