This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Re: Compact regsiter allocation
----- Original Message ----
> From: Ian Lance Taylor <iant@google.com>
> To: Jamie Prescott <jpresss@yahoo.com>
> Cc: gcc@gcc.gnu.org
> Sent: Thursday, May 14, 2009 10:09:40 PM
> Subject: Re: Compact regsiter allocation
>
> Jamie Prescott writes:
>
> > If not, what is the best spot (in the normal GCC target hooks) to trigger it?
> Where the
> > full insn tree is passed in such hook (if it's not a global)?
>
> TARGET_MACHINE_DEPENDENT_REORG. It will be invoked once for each
> function, and can access and modify the complete RTL insn tree.
It wasn't as easy as I expected. Likely because my knowledge of GCC internals is pretty shallow.
This is what I came up with.
The target reorg is great, but it had two problems for me. One is that it was issued after the
prologue/epilogue, where I had to emit insns based on the already-remapped status, so I
ended up keeping as hash of non-remappable instructions that I fed with the xxx_emit_hashed_insn().
I use the hash to detect which insns do not have to be remapped.
Not only, since REG RTXs can appear multiple times, I need to feed the RTX into the hash, after
having been remapped once.
This seems to be working fine, but my biggest doubt is that way I dig into the single instructions to
find REG RTXs to remap.
I looked around and I ended up with the code below, partially stolen from print_rtx().
Is there a public/non-hackish API to enum all the RTXs contained inside an instruction?
If not, do I handle all the possible cases in xxx_enum_rtx()?
Seem code below, with xxx_reorg() being my reorg function ...
- Jamie
typedef struct s_xxx_reg_remap
{
int from, to;
} xxx_reg_remap_t;
static void
xxx_remap_reg(rtx insn, xxx_reg_remap_t const *rmap, int n)
{
int i, regno = REGNO(insn);
if (xxx_ptrhash_lookup(&insns_hash, (void *) insn, NULL))
return;
for (i = 0; i < n; i++)
if (rmap[i].from == regno) {
xxx_ptrhash_add(&insns_hash, (void *) insn);
SET_REGNO(insn, rmap[i].to);
break;
}
}
static void
xxx_enum_rtx(rtx insn, xxx_reg_remap_t const *rmap, int n,
void (*proc)(rtx, xxx_reg_remap_t const *, int))
{
int i, j, len, vlen;
char const *fmt;
rtx x, y;
if (xxx_ptrhash_lookup(&insns_hash, (void *) insn, NULL))
return;
fmt = GET_RTX_FORMAT(GET_CODE(insn));
len = GET_RTX_LENGTH(GET_CODE(insn));
for (i = 0; i < len; i++, fmt++) {
switch (*fmt) {
case 'e':
if ((x = XEXP(insn, i)) == NULL_RTX)
continue;
if (GET_CODE(x) == REG)
(*proc)(x, rmap, n);
else
xxx_enum_rtx(x, rmap, n, proc);
break;
case 'E':
case 'V':
if (XVEC(insn, i) == NULL)
break;
vlen = XVECLEN(insn, i);
for (j = 0; j < vlen; j++) {
if ((y = XVECEXP(insn, i, j)) != NULL_RTX)
xxx_enum_rtx(y, rmap, n, proc);
}
break;
}
}
}
static void
xxx_reorg(void)
{
rtx insn;
insn = get_insns();
gcc_assert(GET_CODE(insn) == NOTE);
for (insn = next_nonnote_insn(insn); insn != NULL_RTX;
insn = next_nonnote_insn(insn)) {
xxx_enum_rtx(insn, func_rmap, func_nrmap, xxx_remap_reg);
}
xxx_ptrhash_free(&insns_hash);
}
static rtx
xxx_emit_hashed_insn(rtx insn)
{
xxx_ptrhash_add(&insns_hash, (void *) insn);
return emit_insn(insn);
}