This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: Implement more rtx vector folds on variable-length vectors
- From: Richard Sandiford <richard dot sandiford at arm dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Mon, 15 Jul 2019 16:30:24 +0100
- Subject: Re: Implement more rtx vector folds on variable-length vectors
- References: <mptwogpkndf.fsf@arm.com>
Richard Sandiford <richard.sandiford@arm.com> writes:
> This patch extends the tree-level folding of variable-length vectors
> so that it can also be used on rtxes. The first step is to move
> the tree_vector_builder new_unary/binary_operator routines to the
> parent vector_builder class (which in turn means adding a new
> template parameter). The second step is to make simplify-rtx.c
> use a direct rtx analogue of the VECTOR_CST handling in fold-const.c.
>
> Tested on aarch64-linux-gnu, aarch64_be-elf and x86_64-linux-gnu.
> OK to install?
>
> Richard
Here's a version updated for the earlier patch, so that we take
both HONOR_NANS and HONOR_SNANS into account. Tested on
aarch64-linux-gnu to far.
Thanks,
Richard
2019-07-15 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 09:14:06.000000000 +0100
+++ gcc/rtl.h 2019-07-15 16:24:30.685937855 +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-15 16:22:55.342699887 +0100
+++ gcc/jump.c 2019-07-15 16:24:30.685937855 +0100
@@ -138,13 +138,28 @@ #define CASE(CODE, ORDER, SIGNEDNESS, TR
}
/* Return the comparison code that implements FLAGS_* bitmask FLAGS.
+ If MODE is not VOIDmode, it gives the mode of the values being compared.
+
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,
+ machine_mode mode = VOIDmode)
{
+ unsigned int order_mask = FLAGS_ORDER;
+ if (mode != VOIDmode)
+ {
+ if (!HONOR_NANS (mode))
+ {
+ flags |= FLAGS_TRAP_NANS;
+ order_mask &= ~FLAGS_UNORDERED;
+ }
+ else if (!HONOR_SNANS (mode))
+ flags |= FLAGS_TRAP_SNANS;
+ }
+
#define TEST(CODE, ORDER, SIGNEDNESS, TRAPS) \
- if (((flags ^ (ORDER)) & FLAGS_ORDER) == 0 \
+ if (((flags ^ (ORDER)) & order_mask) == 0 \
&& (FLAGS_##SIGNEDNESS == 0 \
|| ((FLAGS_##SIGNEDNESS ^ flags) & FLAGS_SIGNEDNESS) == 0) \
&& (FLAGS_##TRAPS & ~flags & FLAGS_TRAPS) == 0) \
@@ -722,6 +737,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 whenever 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, 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 whenever 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 flags = ((flags1 & flags2 & FLAGS_ORDER)
+ | ((flags1 | flags2) & ~FLAGS_ORDER));
+ return flags_to_condition (flags, false, mode);
+}
/* Return 1 if INSN is an unconditional jump and nothing else. */
Index: gcc/simplify-rtx.c
===================================================================
--- gcc/simplify-rtx.c 2019-07-12 09:14:06.000000000 +0100
+++ gcc/simplify-rtx.c 2019-07-15 16:24:30.689937823 +0100
@@ -2889,6 +2889,20 @@ 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)))
+ {
+ machine_mode cmp_mode = GET_MODE (XEXP (op0, 0));
+ rtx_code cond = bit_ior_conditions (GET_CODE (op0),
+ GET_CODE (op1), cmp_mode);
+ if (cond != UNKNOWN)
+ return simplify_gen_relational (cond, mode, cmp_mode,
+ XEXP (op0, 0), XEXP (op0, 1));
+ }
+
tem = simplify_byte_swapping_operation (code, mode, op0, op1);
if (tem)
return tem;
@@ -3321,6 +3335,20 @@ 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)))
+ {
+ machine_mode cmp_mode = GET_MODE (XEXP (op0, 0));
+ rtx_code cond = bit_and_conditions (GET_CODE (op0),
+ GET_CODE (op1), cmp_mode);
+ if (cond != UNKNOWN)
+ return simplify_gen_relational (cond, mode, cmp_mode,
+ XEXP (op0, 0), XEXP (op0, 1));
+ }
+
tem = simplify_byte_swapping_operation (code, mode, op0, op1);
if (tem)
return tem;
@@ -5832,6 +5860,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 +6894,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 +7254,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 ();
}