On 12/24/24 2:24 AM, Robin Dapp wrote:
`.MASK_LEN_FOLD_LEFT_PLUS`(or `mask_len_fold_left_plus_m`) is expecting the
return value will be the start value even if the length is 0.

However current code gen in RISC-V backend is not meet that semantic, it will
result a random garbage value if length is 0.

Let example by current code gen for MASK_LEN_FOLD_LEFT_PLUS with f64:
         # _148 = .MASK_LEN_FOLD_LEFT_PLUS (stmp__148.33_134, vect__70.32_138, 
{ -1, ... }, loop_len_161, 0);
         vsetvli zero,a5,e64,m1,ta,ma
         vfmv.s.f        v2,fa5     # insn 1
         vfredosum.vs    v1,v1,v2   # insn 2
         vfmv.f.s        fa5,v1     # insn 3

insn 1:
- vfmv.s.f won't do anything if VL=0, which means v2 will contain garbage value.
insn 2:
- vfredosum.vs won't do anything if VL=0, and keep vd unchanged even TA.
(v-spec say: `If vl=0, no operation is performed and the destination register
  is not updated.`)
insn 3:
- vfmv.f.s will move the value from v1 even VL=0, so this is safe.

So how we fix that? we need two fix for that:

1. insn 1: need always execute with VL=1, so that we can guarantee it will
            always work as expect.
2. insn 2: Add new pattern to force `vd` use same reg as `vs1` (start value) for
            all reduction patterns, then we can guarantee vd[0] will contain the
            start value when vl=0

For 1, it's just a simple change to riscv_vector::expand_reduction, but for 2,
we have to add _AV variant reduction to force `vd` use same reg as `vs1` (start
value).

I think I'm OK with both approaches.  If the second one doesn't negatively
affect register pressure it certainly looks a bit nicer.  On the other hand I
would expect the reduction to dominate latency anyway so an additional vsetvl
shouldn't really matter.

Another thing to consider - can we even hit the vl=0 case with the regular
reductions?  They are VLMAX only so just affected by when we enable SELECT_VL
which we only do with one rgroup so vl=0 shouldn't happen (as opposed to
fold left).  I still need to convince myself that this is correct but the fact
that you only saw fallout with fold left partially confirms it.
No strong opinions either. I had to deal with something in this space a while back on another design. I don't remember the impedance mismatch between the fold-left GCC semantics and the chip, but it was solvable with a single copy and (IIRC) a mask which was all set up in the expander.

In general I wouldn't expect a fold-left reduction to be a significant performance factor -- you still have to do the ops in order which is th performance killer. But supporting fold-left was still useful, even if for no other reason than allowing other parts of a loop to vectorize, even if the reduction step was a performance bottleneck.

jeff

Reply via email to