> Am 11.04.2025 um 21:06 schrieb Jakub Jelinek <ja...@redhat.com>:
>
> Hi!
>
> The following patch is miscompiled, because during the limited
> SSA name coalescing the bitintlower pass does we incorrectly don't
> register a conflict.
> This is on
> <bb 4> [local count: 1073741824]:
> # b_17 = PHI <b_19(3), 8(2)>
> g.4_13 = g;
> _14 = g.4_13 >> 50;
> _15 = (unsigned int) _14;
> _21 = b_17;
> _16 = (unsigned int) _21;
> s_22 = _15 + _16;
> return s_22;
> basic block where in the map->bitint bitmap we track 14, 17 and 19.
> The build_bitint_stmt_ssa_conflicts "hook" has special code where
> it tracks uses at the final statements of mergeable operations, so
> e.g. the
> _16 = (unsigned int) _21;
> statement is considered to be use of b_17 because _21 is not in
> map->bitmap (or large_huge.m_names), i.e. is mergeable.
> The problem is that build_ssa_conflict_graph has special code to handle
> SSA_NAME copies and _21 = b_17; is gimple_assign_copy_p. In such cases
> it calls live_track_clear_var on the rhs1. The problem is that
> on the above bb, after we note in the _16 = (unsigned int) _21;
> stmt we need b_17 the generic code makes us forget that because
> of the copy statement, and then build_bitint_stmt_ssa_conflicts
> ignores it completely (because _21 is large/huge bitint and is
> not in map->bitint, so assumed to be handled by a later stmt in the
> bb, for backwards walk like this before this one).
> As the b_17 use is ignored, the coalescing thinks it can put
> all of b_17, b_19 and _14 into the same partition, which is wrong,
> while we can and should coalesce b_17 and b_19, _14 needs to be a different
> temporary because b_17 is set before and used after _14 has been written.
>
> The following patch fixes it by handling gimple_assign_copy_p in two
> separate spots, move the generic coalesce handling of it after
> build_ssa_conflict_graph (where build_ssa_conflict_graph handling
> doesn't fall through to that, it does continue after the call) and
> inside of build_ssa_conflict_graph it performs it too, but only if
> the lhs is not mergeable large/huge bitint.
>
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
Ok
Richard
> 2025-04-11 Jakub Jelinek <ja...@redhat.com>
>
> PR tree-optimization/119722
> * gimple-lower-bitint.h (build_bitint_stmt_ssa_conflicts): Add
> CLEAR argument.
> * gimple-lower-bitint.cc (build_bitint_stmt_ssa_conflicts): Add
> CLEAR argument. Call clear on gimple_assign_copy_p rhs1 if lhs
> is large/huge bitint unless lhs is not in names.
> * tree-ssa-coalesce.cc (build_ssa_conflict_graph): Adjust
> build_bitint_stmt_ssa_conflicts caller. Move gimple_assign_copy_p
> handling to after the build_bitint_stmt_ssa_conflicts call.
>
> * gcc.dg/torture/bitint-77.c: New test.
>
> --- gcc/gimple-lower-bitint.h.jj 2025-04-08 14:08:51.644276395 +0200
> +++ gcc/gimple-lower-bitint.h 2025-04-11 13:03:12.231981283 +0200
> @@ -26,6 +26,7 @@ extern void build_bitint_stmt_ssa_confli
> ssa_conflicts *, bitmap,
> void (*) (live_track *, tree,
> ssa_conflicts *),
> + void (*) (live_track *, tree),
> void (*) (live_track *, tree));
>
> #endif /* GCC_GIMPLE_LOWER_BITINT_H */
> --- gcc/gimple-lower-bitint.cc.jj 2025-04-11 08:27:47.841168976 +0200
> +++ gcc/gimple-lower-bitint.cc 2025-04-11 13:07:14.396626536 +0200
> @@ -5919,7 +5919,8 @@ build_bitint_stmt_ssa_conflicts (gimple
> ssa_conflicts *graph, bitmap names,
> void (*def) (live_track *, tree,
> ssa_conflicts *),
> - void (*use) (live_track *, tree))
> + void (*use) (live_track *, tree),
> + void (*clear) (live_track *, tree))
> {
> bool muldiv_p = false;
> tree lhs = NULL_TREE;
> @@ -5936,6 +5937,25 @@ build_bitint_stmt_ssa_conflicts (gimple
> {
> if (!bitmap_bit_p (names, SSA_NAME_VERSION (lhs)))
> return;
> +
> + /* A copy between 2 partitions does not introduce an interference
> + by itself. If they did, you would never be able to coalesce
> + two things which are copied. If the two variables really do
> + conflict, they will conflict elsewhere in the program.
> +
> + This is handled by simply removing the SRC of the copy from
> + the live list, and processing the stmt normally.
> +
> + Don't do this if lhs is not in names though, in such cases
> + it is actually used at some point later in the basic
> + block. */
> + if (gimple_assign_copy_p (stmt))
> + {
> + tree rhs1 = gimple_assign_rhs1 (stmt);
> + if (TREE_CODE (rhs1) == SSA_NAME)
> + clear (live, rhs1);
> + }
> +
> switch (gimple_assign_rhs_code (stmt))
> {
> case MULT_EXPR:
> --- gcc/tree-ssa-coalesce.cc.jj 2025-04-08 14:09:29.282752418 +0200
> +++ gcc/tree-ssa-coalesce.cc 2025-04-11 13:00:13.120462546 +0200
> @@ -896,6 +896,18 @@ build_ssa_conflict_graph (tree_live_info
> tree var;
> gimple *stmt = gsi_stmt (gsi);
>
> + if (is_gimple_debug (stmt))
> + continue;
> +
> + if (map->bitint)
> + {
> + build_bitint_stmt_ssa_conflicts (stmt, live, graph, map->bitint,
> + live_track_process_def,
> + live_track_process_use,
> + live_track_clear_var);
> + continue;
> + }
> +
> /* A copy between 2 partitions does not introduce an interference
> by itself. If they did, you would never be able to coalesce
> two things which are copied. If the two variables really do
> @@ -912,16 +924,6 @@ build_ssa_conflict_graph (tree_live_info
> && TREE_CODE (rhs1) == SSA_NAME)
> live_track_clear_var (live, rhs1);
> }
> - else if (is_gimple_debug (stmt))
> - continue;
> -
> - if (map->bitint)
> - {
> - build_bitint_stmt_ssa_conflicts (stmt, live, graph, map->bitint,
> - live_track_process_def,
> - live_track_process_use);
> - continue;
> - }
>
> /* For stmts with more than one SSA_NAME definition pretend all the
> SSA_NAME outputs but the first one are live at this point, so
> --- gcc/testsuite/gcc.dg/torture/bitint-77.c.jj 2025-04-11
> 13:13:49.286137937 +0200
> +++ gcc/testsuite/gcc.dg/torture/bitint-77.c 2025-04-11 13:13:21.815523489
> +0200
> @@ -0,0 +1,26 @@
> +/* PR tree-optimization/119722 */
> +/* { dg-do run { target bitint } } */
> +/* { dg-options "-O2 -fno-tree-forwprop -fno-tree-copy-prop -fno-tree-fre" }
> */
> +
> +#if __BITINT_MAXWIDTH__ >= 33300
> +unsigned _BitInt(33300) g;
> +
> +unsigned
> +foo (long c)
> +{
> + unsigned _BitInt(33300) b
> + = __builtin_stdc_rotate_left ((unsigned _BitInt(13)) 8, c);
> + return ((unsigned _BitInt(50)) (g >> 50)
> + + ({ unsigned _BitInt(300) unused; b; }));
> +}
> +#endif
> +
> +int
> +main ()
> +{
> +#if __BITINT_MAXWIDTH__ >= 33300
> + unsigned x = foo (0);
> + if (x != 8)
> + __builtin_abort ();
> +#endif
> +}
>
> Jakub
>