On Mon, Jun 8, 2026 at 12:38 AM Kyrylo Tkachov <[email protected]> wrote:
>
> Hi all,
>
> In the sink pass, if-convert a diamond that selects between two loads at
> data-dependent addresses (PHI <*P, *Q>) into a single reg-offset load behind
> branchless selects, reusing phi-opt's factoring helpers (now exported) to 
> common
> the load and its address.  Guarded so it only fires on non-vectorisable 
> in-loop
> load-address recurrences, leaving affine vectorisable loops alone.  This was 
> needed
> to avoid regressing the marian benchmark in SPEC2026 that otherwise ended up 
> using
> expensive gathers to vectorise.  We can look to relax this condition in the 
> future
> for cases where we think it's beneficial.
>
> The load is commoned only when both arms are guaranteed to reduce to pure
> speculatable scalar (scc_arms_speculatable_p), so the branchless finish always
> succeeds and no commoned-but-still-branching diamond is ever left behind.  The
> recurrence walk is bounded by a new --param=sink-diamond-recurrence-limit
> (default 256).  factor_out_conditional_load checks the MEM_REF operand-1 
> types with
> alias_ptr_types_compatible_p so loads with incompatible TBAA are never 
> commoned.
>
> With this patch the Snappy hot loop gets if-converted optimally and 
> performance
> improves by 25% on my aarch64 machine, making it a bit better than what LLVM 
> gets
> today.
>
> It depends on Andrea's phiopt patch [1] that generalizes commoning out
> operations beyond unary so they need to go in one after the other.
>
> The code goes from:
>   .L8:                          ; ---type==0 arm
>           lsr     x3, x1, 2     ;   tag >> 2
>           add     x1, x0, x3
>           add     x3, x3, 2
>           add     x0, x0, x3    ;   ip += (tag>>2)+2
>           ldrb    w1, [x1, 1]   ;   LOAD #1: tag = ip[(tag>>2)+1]
>           cmp     x2, x0
>           bls     .L2
>   .L5:                          ;   loop head / else arm
>           ands    x3, x1, 3     ;   type = tag & 3
>           beq     .L8           ; <-- DATA-DEPENDENT BRANCH (mispredicts)
>           ldrb    w1, [x0, x3]  ;   LOAD #2: tag = ip[type]
>           add     w3, w3, 1
>           add     x0, x0, x3    ;   ip += type+1
>           cmp     x2, x0
>           bhi     .L5
>
> to:
>   .L3:                          ; --- single loop body, no diamond branch
>           lsr     x4, x1, 2     ;   tag >> 2
>           ands    x3, x1, 3     ;   type = tag & 3   (Z = type==0)
>           csinc   x1, x3, x4, ne ;  offset = (type!=0) ? type : (tag>>2)+1
>           ldrb    w1, [x0, x1]  ;   ONE reg-offset LOAD: tag = ip[offset]
>           add     x4, x4, 2
>           csinc   x3, x4, x3, eq ;  advance = (type==0) ? (tag>>2)+2 : type+1
>           add     x0, x0, x3    ;   ip += advance
>           cmp     x2, x0
>           bhi     .L3
>
> crucially avoiding the badly-predicted branch.
>
> Bootstrapped and tested on aarch64-none-linux-gnu.
>
> Signed-off-by: Kyrylo Tkachov <[email protected]>
>
> gcc/
>
>         PR tree-optimization/125557
>         * params.opt (sink-diamond-recurrence-limit): New param.
Just some quick review notes:
params should be documented in doc/params.texi .

>         * tree-ssa-phiopt.h (factor_out_conditional_load): Declare.
>         (factor_out_conditional_operation): Declare.
>         * tree-ssa-phiopt.cc: Include "alias.h".
>         (remove_factored_arm_defs): New.
>         (factor_out_conditional_load): New.
>         (factor_out_conditional_operation): No longer static.
>         * tree-ssa-sink.cc (scc_recurrence_p, scc_arms_speculatable_p)
>         (scc_try_ifconvert, sink_common_computations_to_bb): New.
>         (pass_sink_code::execute): Call it at the early sink.

I have an already approved patch which handles:
```
if (a) {
  if (c) t = abs<d>
  else t = abs<e>
}
```
which seemingly will break the sink code here. The only reason why it
was not applied yet is because I am still convincing myself that the
order of bb processing in phiopt will work.
That is it handles number of operands to PHI != 2.
So can you split this into 2 patches. One for the phiopt piece and one
for the sink code?

>
> gcc/testsuite/
>
>         PR tree-optimization/125557
>         * gcc.dg/tree-ssa/scc-diamond-1.c: New test.
>         * gcc.dg/tree-ssa/scc-diamond-3.c: New test.
>         * gcc.target/aarch64/scc-diamond-2.c: New test.
>
> [1] https://gcc.gnu.org/pipermail/gcc-patches/2026-June/719612.html
>

Reply via email to