On Aug 8, 2012, at 8:38 AM, DJ Delorie wrote:
> The RL78 devirtualization pass is *not* a reorg pass, it has to happen
> after reload but before debug info is set up. The RL78 does not have
> a consistent register set or addressing scheme, GCC cannot practically
> support it.
Gosh, we got one of those two, though, I don't know how much worse your machine
is than mine, in at all. For example, $fp is in register N, where N is
calculated differently for each function and isn't known until
compute_frame_size time. Which registers can be used isn't known until then
either. Also, different parts of the prologue use totally different numbering.
We handle this by having many different copies of all the registers, one copy
for each possible category of use, and the once we get a feel for the
landscape, we pin everything (that's a lie, we only pin some things) down, mark
up which registers are going to be disappeared or put into service,
essentially, for a given register, it can only ever be live in one category.
Some of the categories have variable mappings (computed mappings) to the actual
register, it isn't the case that the first register of category Y, maps to the
same register as the first register of category Z. We also have different
mappings depending where in the instruction stream the instruction falls, just
for fun. Now, we do all this, with no reorg or devirtualization pass. I'd
like to think what you do would be a proper subset of what we do.
So, for example, we have one category for call clobbered registers, one for
caller saved register, one for inbound argument register, one for outbound
argument registers, gosh, so many, I can't recall all the others... The only
magic we do have, is an extra call to reinit_regs in gimple_expand_cfg right
before the if () fixup_tail_calls() code, so that
TARGET_CONDITIONAL_REGISTER_USAGE has a chance to fire at just the right time.
That firing pins some of the aspects of argument registers and some of the
other registers. The rest of the pinning down is done at compute_frame_size
time. So, there isn't just one pinning, but two. We handle the second pinning
by dynamic code in print_operand. regno = func (regno, codegen_state); printf
("%s", reg_name[regno]); The style allows for an arbitrarily computed register
number, based upon anything one wants. We merely happen to use the frame
information, leaf information, where in the instruction stream we are and a few
other bits. Our usual func, is something like:
switch CATEGORY (regno)
case 1:
regno = regno-CATEGORY_BASE[1] + actual_start_category[1]; break;
case 2:
regno = regno-category_base[2] + actual_start_category[2]; break;
[ ... ]
where the various category_bases are the start of the given categories and the
actual_start_categories are the place to actually put the category in the
actual register file.
So, if you want to explore how to redo the port, or if it is even possible,
just let me know... I like puzzles, but only if they aren't trivial. :-) The
line count to switch your port is roughly O(NC*(ARPC/4 + 20) + 80), I suspect;
where NC are the number of classes, and ARPC is the average registers per class.
Now, all that said, the code is pretty basic and clean and we think interfaces
well with the rest of the compiler. We don't violate gcc notion of codegen
(though, we might get the DBX_REGISTER_NUMBER slightly wrong in the first part
of the prologue). I think even that problem can be fixed, if we want.
As we move to C++, I'd love for port maintainers to be able to get together and
hoist _up_ code from the port so other ports can use it and thus, have more
sharing. We make heavily stylized uses, which could be wrapped into a prettier
api, given a reasonably powerful language. C++ might be powerful enough. I'd
love to see someone improve the FIXED_REGISTERS, REGISTER_NAMES,
REG_CLASS_CONTENTS, REGNO_REG_CLASS, REGNO_GLOBAL_BASE_REG_P, CLASS_MAX_NREGS
experience, as the current api sucks; for example. I dread the slightest
change to any of my registers, as the change ripples throughout a ton of
disparate places, and it is currently too easy to forget one of them. Bonus
points for cleaning up TARGET_SECONDARY_RELOAD at the same time as the above.
I find that api sucks in ways I can't begin to describe.