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? 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