This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: RFA: reload infrastructure to fix PR target/21623


Ian Lance Taylor wrote:

OK, fair enough. I personally think the reload inheritance stuff
should be removed, and handled in a separate CSE pass.


reload_cse can't undo bad reload register choices, or excess spilling.

But you're
right that with the current scheme we need the modes, and we need to
describe which register hold the intermediate value. Would it really
help to fill in an rtx? I'm not sure, because I don't see what reload
would usefully do with that.


Together with the dependency information, it can use this for more intelligent
reload inheritance. If you load clztab+4 into a C_REG by loading clztab into
A_REG, then use that to load clztab+4 into a B_REG, to move that into the,
C_REG, and you perform such a reload again and find the right value in the B_REG,
you know you can use that because the value matches and your C_REG load
can be satisfied by that one dependency. You couldn't do that if the value was,
say, clztab+5. But the value in the A_REG could be reused, if it still is valid.


I think reload in general ought to have a dependency graph. It would
be useful in, e.g., merge_assigned_reloads and no doubt other places.
It's not clear to me that we should introduce a dependency graph here
in advance of one used generally in reload. In particular, what would
reload do with it today?


When we define a completely new interface, it should provide the information
that is useful after such a reload rewrite. We don't want to rewrite every target
port twice.






We should try to avoid merging everything into one big blob, as
SECONDARY_RELOAD_CLASS does. I think this can be accomplished
assigning the actual subtarget-specific target hook in OVERRIDE_OPTIONS,
and inside the hook using a switch statement using the reload_mode
(as a substitute for reload_in_optab / reload_out_optab).



I actually don't like changing the target hook in OVERRIDE_OPTIONS,
because I would prefer that targetm be a const variable. But I know
that targets do this today for various reasons, e.g., ARM for
rtx_costs. But that is a minor detail--for example, it's easy enough
to have the single function call through a function pointer.


But these extra indirections cost more processing time.  What do you gain
making targetm const?

Or, even simpler, have default_emit_secondary_reload insist on having
a single scratch [sic (1)] register, and emit instructions to copy from FROM to
the scratch register, and then from the scratch register to TO.


No, that is completely besides the point. You can use the default function
only when there is no secondary reload that needs to be handled in a non-default
way. You could call this default function from your hook, but you'd have to
decide first if you should do that. That means duplicating decision logic from
the time when you select the reload classes.
Indeed, it could make sense not to have a target hook for the insn emitting at all,
but have the regclass calculating code set a function pointer for that.
We could have more than one, so that separate steps can be described with
separate functions - which might even be gen_* function generated by the md
file. This might me interwoven with the dependency information. E.g. we
could specify that the value in a particular scratch register is to be calculated
by using the addsi_mark3 expander with two specified inputs. The calculation
of the scratch register is then dependent on these two inputs.
Using separate patterns for separate steps can not only make it easier to break up
the task and reuse already existing expanders, it is also necessary in order to
elide steps that become unnecessary because of reload inheritance.
So, each of these expansions has a function pointer to call, a number of
values that it sets, and likely / possibly some inputs and/or internal scratch
registers. A possible refinement here is also that where convenient,
information about the number and kind of operands can be specified with an
instruction name, and translated into the appropriate assignments with some
gen* magic.
It seems that basically we want to actually write reloads. The one that sets the
main result value can have the function pointer. If we have a straight copy,
we can use the move expander. To describe all but the one argument directly
mentioned in the reload, we can use a linked list of other reloads. Not all of
them need to be reloads in the current sense - we could have special nodes to
indicate an extra piece of the instruction, some unconnected rtl (e.g. a magic
constant needed to make a more general purpose instruction perform the right
specific operation), or simply a node that says to re-use another reload that is
in another linked chain.


To actually do the expander dispatch with our linked list, we can do something
along the lines of:


if (!list)
 return (*f) (operand0);
operand1 = list->in.rtx
list = list->next;
if (!list)
 return (*f) (operand0, operand1);
...

(1) And FWIW, if the value is only copied, we call this a temporary register,
not a scratch register, in secondary reload parlance.



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]