Hi Alfie,
before I get to the rest of the series, a question about the codegen
strategy. It would probably have been a better fit for the v1
discussion but... :)
> +/* Inserts fixup block for HSSR controls.
> +
> + This inserts the following logic:
> +
> + <bb 0>:
> + v1 = .MASK_FF_HSSR_LOAD (src1, 64B, loop_mask, { 0, ... });
> + v2 = .MASK_FF_HSSR_LOAD (src2, 64B, loop_mask, { 0, ... });
> + hssr_mask = .READ_FAULT_STATE ();
> + if (hssr_mask == { -1, ... })
> + goto <bb 2>; [99.95%]
> + else
> + goto <bb 1>; [0.05%]
> +
> + <bb 1>:
> + .SET_FAULT_STATE ({ -1, ... });
> + hssr_loop_mask = loop_mask & hssr_mask;
> + num_iters = .COUNT_ACTIVE (hssr_mask);
> +
> + <bb 2>:
> + # loop_mask_1 = PHI <loop_mask(0), hssr_loop_mask(1)>
> + # num_iters_56 = PHI <POLY_INT_CST [4, 4](0), num_iters (1)>
> +
> + ... Logic using loop_mask_1 and incrementing IV's by num_iters_56
> + */
So from what I figure, the decision for the fixup approach is based on
the assumption that READ_FAULT_STATE can be slow and dependencies on it
would limit throughput?
I'm asking because for riscv, the only relevant dependency would be on
the pointer bump and READ_FAULT_STATE isn't necessarily slow.
Therefore, for RVV, I'd favor a third approach (beside full duplication
and fixup) that would roughly look just like
v1 = .MASK_FF_HSSR_LOAD (src1, 64B, loop_mask, { 0, ... });
v2 = .MASK_FF_HSSR_LOAD (src2, 64B, loop_mask, { 0, ... });
hssr_mask = .READ_FAULT_STATE ();
.SET_FAULT_STATE ({ -1, ... });
hssr_loop_mask = loop_mask & hssr_mask;
num_iters = .COUNT_ACTIVE (hssr_mask);
(only with length instead of mask of course)
Is that something that would work for aarch64 cores as well? Or is that
rather an optimization that you deliberately skipped for now?
--
Regards
Robin