On 8/31/26 11:38 PM, [email protected] wrote:
From: Kyrylo Tkachov <[email protected]>

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.
Ok for trunk?
Thanks,
Kyrill

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]>
Thanks for your patience.  This is OK for the trunk.

Jeff

Reply via email to