"Amker.Cheng" <[email protected]> writes:
> Hi:
> as to page http://gcc.gnu.org/ml/gcc/2010-05/msg00091.html,
> If the fpu register can not copied to/from memory directly, I have
> to use intermediate GPR registers.
>
> In fact, I return GP_REGS if copying x to a register in class FP_REGS
> in any mode(including CCmode), this results in infinite recursive calling
> of memory_move_secondary_cost.
>
> After tracing cc1, I found the calling sequence is like:
>
> memory_move_secondary_cost (CCmode, ST_REGS, 1) -->
> memory_move_secondary_cost (CCmode, FP_REGS, 1) -->
> memory_move_secondary_cost (CCmode, ST_REGS, 1) -->
> memory_move_secondary_cost (CCmode, FP_REGS, 1) -->
> ....... infinite recursive....
>
> It seems function default_secondary_reload always use ST_REGS as intermediate
> register for FP_REGS:CCmode according to reload_incc pattern.
> This is all what i found, and I have totally no idea about how reload
> pass works .
Hmm. I think that's a flaw in memory_move_secondary_cost. This call:
memory_move_secondary_cost (CCmode, ST_REGS, 1)
asks for the cost of using reload_incc on a stack memory rtx:
(define_expand "reload_incc"
[(set (match_operand:CC 0 "fcc_reload_operand" "=z")
(match_operand:CC 1 "general_operand" ""))
(clobber (match_operand:TF 2 "register_operand" "=&f"))]
And secondary_reload_class rightly returns FP_REGS for this, since we
need an FP_REGS scratch register. But memory_move_reload_cost then
thinks that the cost of loading a memory into ST_REGS is:
cost of loading a mem into FP_REGS
+ cost of moving FP_REGS into ST_REGS
That's fine for moves via temporary registers (i.e. when the secondary
reload does not use reload_{in,out}cc) but a bit dubious for scratch
operand registers (when reload_{in,out}cc are used). There's no telling
in general what the target is doing with the scratch register it has asked
for, and if the reload* pattern really was a simple move via a temporary,
the target probably wouldn't be defining it in the first place.
In this particular case, it might make more sense to replace:
altclass = secondary_reload_class (in ? 1 : 0, rclass, mode, mem);
with:
altclass = targetm.secondary_reload (in ? 1 : 0, mem, rclass, mode, &sri);
for some new temporary sri. But that might adversely affect other targets
(as reload changes often do!). I also might be talking gibberish; it's
thankfully a while since I had to work on reload stuff....
Anyway, I suppose the reason that this works on mainline is that:
memory_move_secondary_cost (CCmode, FP_REGS, 1)
calls:
default_secondary_reload (1, mem, FP_REGS, CCmode, &sri)
which in turn calls:
SECONDARY_INPUT_RELOAD_CLASS (FP_REGS, CC_MODE, mem)
This returns NO_REGS in FSF sources but GR_REGS with your changes.
"mem" matches the predicate for operand 1 of reload_incc (namely
general_operand), so when default_secondary_reload processes the
reload_incc pattern, I suppose we have:
reload_class == FP_REGS
rclass == GR_REGS
insn_class == ST_REGS
scratch_class == FP_REGS
And because reload_class (FP_REGS) is not a subset of insn_class
(ST_REGS), default_secondary_reload thinks that you need:
FP_REGS <- ST_REGS <- mem
with FP_REGS <- ST_REGS being done by a move and the ST_REGS <- mem
being done by reload_incc.
This is a genuine problem with the modified MIPS backend, regardless of
whether the current memory_move_secondary_cost is right. You'll need
to override TARGET_SECONDARY_RELOAD with a MIPS-specific version that
does _not_ use reload_incc for CCmode loads into FP_REGS. You want
a normal move via a temporary instead.
I had plans for a different approach to handling CCmode reloads,
but I don't know when/if I'll get round to them...
Richard