On Wed, 6 Mar 2024, Jakub Jelinek wrote:
> Hi!
>
> The following patch attempts to fix an optimization regression through
> adding a simple simplification. We already have the
> /* (m1 CMP m2) * d -> (m1 CMP m2) ? d : 0 */
> (if (!canonicalize_math_p ())
> (for cmp (tcc_comparison)
> (simplify
>(mult:c (convert (cmp@0 @1 @2)) @3)
>(if (INTEGRAL_TYPE_P (type)
> && INTEGRAL_TYPE_P (TREE_TYPE (@0)))
> (cond @0 @3 { build_zero_cst (type); })))
> optimization which otherwise triggers during the a * !a multiplication,
> but that is done only late and we aren't able through range assumptions
> optimize it yet anyway.
>
> The patch adds a specific simplification for it.
> If a is zero, then a * !a will be 0 * 1 (or for signed 1-bit 0 * -1)
> and so 0.
> If a is non-zero, then a * !a will be a * 0 and so again 0.
>
> I had to use a hack, TREE_TYPE (@0) in the condition as opposed to
> using just type, because otherwise I get a false positive warning.
> The captures parameter is marked ARG_UNUSED in gimple, but not in
> generic and we end up with
> tree
> generic_simplify_168 (location_t ARG_UNUSED (loc), const tree ARG_UNUSED
> (type),
> tree ARG_UNUSED (_p0), tree ARG_UNUSED (_p1), tree *captures)
> {
> const bool debug_dump = dump_file && (dump_flags & TDF_FOLDING);
> if (INTEGRAL_TYPE_P (type)
> )
> {
> if (TREE_SIDE_EFFECTS (_p1)) goto next_after_fail309;
> if (UNLIKELY (!dbg_cnt (match))) goto next_after_fail309;
> {
> tree _r;
> _r = build_zero_cst (type);
> if (UNLIKELY (debug_dump)) generic_dump_logs ("match.pd", 216,
> __FILE__, __LINE__, true);
> return _r;
> }
> next_after_fail309:;
> }
> return NULL_TREE;
> }
> there. I've looked at similar cases and in
> (simplify
> (mod @0 integer_onep)
> { build_zero_cst (type); })
> case we don't get captures unused because it is used a single time
> and therefore evaluate it for side-effects instead of punting on them,
> and in
> (pointer_diff @@0 @0)
> { build_zero_cst (type); })
> we do so as well. Though, using @@0 instead of @0 on either operand
> of this simplification doesn't help.
>
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
OK, though feel free to add ARG_UNUSED to 'captures' as well.
I think the INTEGRAL_TYPE_P should be redundant - the pattern
should work for vectors and complex as well (with integer components
which integer_zerop constrains).
Thanks,
Richard.
> 2024-03-06 Jakub Jelinek
>
> PR tree-optimization/114009
> * match.pd (a * !a -> 0): New simplification.
>
> * gcc.dg/tree-ssa/pr114009.c: New test.
>
> --- gcc/match.pd.jj 2024-03-01 14:56:42.442810053 +0100
> +++ gcc/match.pd 2024-03-05 22:53:25.202579435 +0100
> @@ -1219,6 +1219,12 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
> && tree_nop_conversion_p (type, TREE_TYPE (@1)))
> (lshift @0 @2)))
>
> +/* Fold a * !a into 0. */
> +(simplify
> + (mult:c @0 (convert? (eq @0 integer_zerop)))
> + (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)))
> + { build_zero_cst (type); }))
> +
> /* Shifts by precision or greater result in zero. */
> (for shift (lshift rshift)
> (simplify
> --- gcc/testsuite/gcc.dg/tree-ssa/pr114009.c.jj 2024-03-05
> 15:18:41.274541636 +0100
> +++ gcc/testsuite/gcc.dg/tree-ssa/pr114009.c 2024-03-05 15:16:09.056589675
> +0100
> @@ -0,0 +1,24 @@
> +/* PR tree-optimization/114009 */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fdump-tree-optimized" } */
> +/* { dg-final { scan-tree-dump-times " return 0;" 3 "optimized" } } */
> +
> +int
> +foo (int x)
> +{
> + x = (x / 2) * 2;
> + return (!x) * x;
> +}
> +
> +int
> +bar (int x, int y)
> +{
> + (void) x;
> + return y * !y;
> +}
> +
> +unsigned long long
> +baz (unsigned long long x)
> +{
> + return (!x) * x;
> +}
>
> Jakub
>
>
--
Richard Biener
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)