> On 11/12/26 1:47 AM, Jin Ma wrote:
> > Implement TARGET_CALLEE_SAVE_COST and TARGET_FRAME_ALLOCATION_COST so
> > IRA weighs callee saves against spills at their marginal execution
> > cost: reusing an already-required save is free, completing an odd
> > save count is discounted by half the memory cost (the fusion-aware
> > scheduling keeps the pair adjacent), and the first spill of a
> > frameless leaf is charged the separate SP adjustment.
> >
> > This is a first, deliberately simple attempt, posted as a draft to
> > collect suggestions on the approach.  The model is unweighted and
> > knows nothing about emission; with more precise modeling (call and
> > spill frequency weighting, awareness of the final save layout) the
> > fusion characteristics of the target should translate into more
> > reliable gains.
> >
> > Assisted-by: qwen3.8-max
> >
> > gcc/ChangeLog:
> >
> >     * config/riscv/riscv.cc (riscv_ira_save_mask): New.
> >     (riscv_frame_allocation_cost): New.
> >     (riscv_callee_save_cost): New.
> >     (TARGET_FRAME_ALLOCATION_COST, TARGET_CALLEE_SAVE_COST): Define.
> >
> > gcc/testsuite/ChangeLog:
> >
> >     * gcc.target/riscv/callee-save-cost-mempair.c: New test.
> >     * gcc.target/riscv/callee-save-cost-fusion.c: New test.
> Interesting.    I like the basic idea.   Obviously it needs to test that
> load/store pair fusion is supported.
>
> Does aarch64 do something similar and if so are we roughly following
> what they did?

Yes.  aarch64 already implements both hooks (aarch64_callee_save_cost
and aarch64_frame_allocation_cost), and i386 likewise implements
callee_save_cost (ix86_callee_save_cost, modeling its push/pop: a push
is much shorter than a typical spill and does its own stack allocation
and deallocation).  The middle-end wiring (the callee-save cost query
in ira-color.cc with entry/exit frequency weighting) came in with
PR117477.  I follow the same structure: mask-based marginal costs,
free reuse of registers that must be saved anyway, and frame costs
charged symmetrically on the spill and callee-save sides.

RISC-V also has single-instruction pairing extensions in the same
family as aarch64's stp/ldp and i386's push/pop: XTheadMemPair
(th.sdd/th.ldd, already covered by the discount condition in this
RFC), Zcmp (cm.push/cm.pop), and XTheadInt (th.int.push/th.int.pop).
For extensions of this kind the aarch64/i386 style of modeling
applies directly; both that path and the macro-fusion path need more
thorough experimentation, which is why this went out as an RFC.

For fusion the key difference is that aarch64's ldp/stp are real
single instructions, so a pair can be folded at full value, whereas
a RISC-V macro-fused pair is still two instructions, but decodes to
a single uop: it saves decode bandwidth and backend resources such
as issue-queue and ROB entries, and executes as one merged memory
operation.  However, the pair only forms when the two instructions
are emitted adjacently (-fshrink-wrap-separate, for example, can
split and relocate individual saves), which IRA cannot guarantee at
decision time.  So I conservatively discount the completing save by
half of mem_cost: when the pair materializes the benefit is close to
full value, when it does not there is none, and the half is a hedge
on the formation probability.  Admittedly this is a very preliminary
idea and may well not be the right tradeoff; call and spill
frequencies are not weighted either.

I would also like to ask whether you think fusion-aware cost modeling
in IRA is a viable direction and worth pursuing, and whether there
are risks I have not considered or a better way to model this.

BR,
Jin

Reply via email to