https://gcc.gnu.org/bugzilla/show_bug.cgi?id=125557
--- Comment #17 from GCC Commits <cvs-commit at gcc dot gnu.org> --- The master branch has been updated by Kyrylo Tkachov <[email protected]>: https://gcc.gnu.org/g:62a6880758d410758f43b08cad9fa9d159ec8583 commit r17-3867-g62a6880758d410758f43b08cad9fa9d159ec8583 Author: Kyrylo Tkachov <[email protected]> Date: Sat Jul 18 01:16:02 2026 +0200 ifcvt: Extend noce_convert_multiple_sets to diamonds [PR125557] noce_convert_multiple_sets handles multi-set IF-THEN-JOIN regions but not IF-THEN-ELSE-JOIN diamonds. After GIMPLE factors a value shared by both arms, such a diamond can still define several live-out values and retain a data-dependent branch. Validate both arms with the existing multiple-set checks and collect the distinct pseudo destinations that they define and that are live out. Choose as primary an arm with at least two such destinations whose bitmap is a superset of the secondary arm's bitmap. This leaves single-result diamonds to the existing specialized transforms. For each live-out destination, also classify the raw source of its last RTL definition in the arm. A constant is a non-register source. Require at least one destination shared by both arms to have a non-register final source in at least one arm. This allows one arm to forward a value that the other arm computes. The classification is deliberately not transitive through arm-local register copies. Evaluate each secondary-arm SET_SRC in original instruction order into a fresh pseudo with copy_to_mode_reg. Rewire reads of earlier secondary definitions to their temporaries and preserve each SET's source location. When the secondary arm defines a primary destination more than once, use the temporary for its last definition as the alternate value. Use the incoming value if the secondary arm does not define that destination. The secondary arm now executes unconditionally. Limit its instruction count with MAX_CONDITIONAL_EXECUTE. This preserves target policies such as Arm's short IT restriction. Either CFG arm may be primary. When the branch-target arm is primary, swap the arms in a local noce_if_info and reverse the select orientation. Reject secondary speculation that modifies canonical condition inputs. When it clobbers a reusable condition-code comparison, stop sharing the comparison and form later conditional moves from the canonical condition, rematerializing comparisons as needed. In outline, convert secondary: (set advance secondary_advance) primary: (set next primary_next) (set advance primary_advance) to (set secondary_tmp secondary_advance) (set next (if_then_else primary_p primary_next incoming_next)) (set advance (if_then_else primary_p primary_advance secondary_tmp)) where primary_p selects the primary arm. The existing simple conditional-move handling owns assignments whose sources are constants or registers. Factor that operand classification into noce_simple_cmove_operand_p and use it in both paths. Apply the dependency-aware diamond conversion only when at least one arm contains a non-simple source. All-simple diamonds therefore continue through the existing handling, while register-copy permutations that it cannot safely convert retain their branch. For speed, weight arm costs by edge probability. For size, sum them. The target noce_conversion_profitable_p hook retains the final profitability decision. Add execution and code-generation tests for symmetric and asymmetric diamonds, arm dependencies, repeated definitions, unmatched live-outs, condition-code clobbers, both arm orientations, constant-only fallback, the all-simple ownership boundary, and mixed forwarding and computed arms. With this patch the Snappy hot loop for decompression is if-converted and gives a 20% improvement on aarch64. Bootstrapped and tested on aarch64-none-linux-gnu and x86_64-linux. gcc/ChangeLog: PR tree-optimization/125557 * ifcvt.cc: Include "explow.h". (noce_simple_cmove_operand_p): New function. (noce_try_cmove): Use it. (noce_convert_multiple_sets): Handle diamond CFG cleanup. (noce_convert_multiple_sets_1): Evaluate secondary-arm values in fresh pseudos, preserve their source locations, and use their final values as conditional-move inputs. Use copy_to_mode_reg. Reject secondary sequences that modify condition inputs and handle condition-code clobbers. (bb_ok_for_noce_convert_multiple_sets): Add REQUIRE_MULTIPLE, LIVE_OUT_DESTS, HAS_NON_SIMPLE_SRC, NONREG_LIVE_OUT_DESTS, and INSN_COUNT. Record distinct live-out destinations, non-simple sources, the raw source class of each final live-out definition, and the number of active sets. (noce_process_if_block): Recognize and cost multi-set diamonds. Choose the compatible primary arm from the validated live-out destinations. Require a shared destination with a non-register final source in at least one arm. Limit unconditional secondary-arm evaluation with MAX_CONDITIONAL_EXECUTE. Defer all-simple diamonds to existing conditional-move handling. (check_cond_move_block): Use noce_simple_cmove_operand_p. gcc/testsuite/ChangeLog: PR tree-optimization/125557 * gcc.c-torture/execute/ifcvt-diamond-1.c: New test. * gcc.target/aarch64/ifcvt_multiple_sets_diamond.c: New test. * gcc.target/aarch64/ifcvt_multiple_sets_diamond_2.c: New test. * gcc.target/aarch64/ifcvt_multiple_sets_diamond_3.c: New test. * gcc.target/aarch64/ifcvt_multiple_sets_diamond_4.c: New test. * gcc.target/aarch64/ifcvt_multiple_sets_diamond_5.c: New test. * gcc.target/aarch64/ifcvt_multiple_sets_diamond_9.c: New test. * gcc.target/aarch64/ifcvt_multiple_sets_diamond_10.c: New test. * gcc.target/i386/ifcvt-multiple-sets-diamond-1.c: New test. Signed-off-by: Kyrylo Tkachov <[email protected]>
