Thanks for everybodys help. I've gotten things working so I thought
I'd quickly write it up.
The architecture I'm working on is deliberatly simple. It has:
* An accumulator
* Fourteen general purpose registers R10 to R1E
* X and Y cache registers each backed by non-coherent (!) caches
* A stack backed by the S cache
Memory can only be accessed by the X or Y registers. The
cache-coherency problem means you can really only use X unless you can
tell Y is far away - but that's a problem for another time. It also
means you can't use the S stack as a data stack as you can't address
it using X.
The only addressing is 32 bit word indirect, 8 bit with pre-decrement,
and 8 bit with post increment.
I allocated R1E to the data stack and R1D to the frame pointer. The
general purpose registers are in the DATA_REGS class while X and Y are
in ADDR_REGS. Y is marked as fixed to prevent it being used.
The implementation is:
* Set BASE_REG_CLASS to ADDR_REGS
* Set INDEX_REG_CLASS to NO_REGS to reject index addressing
* Implement GO_IF_LEGITIMATE_ADDRESS so that it accepts (mem x) but
rejects (mem (plus (reg const)) and the others
You can't set BASE_REG_CLASS to NO_REGS as (mem x) is treated as (mem
(plus (reg 0))
This works fine until you spill a variable. Spills generate offsets
relative to the frame pointer. This is OK providing your frame
pointer is a member of ADDR_REGS - mine isn't so the resulting fixup
generates a offset address which kills the compiler.
You can't pretend and put the FP in ADDR_REGS. A non-zero offset will
correctly be rejected by GO_IF_LEGITIMATE_ADDRESS and loaded into X,
but a zero offset will try to load from R1D.
The solution here is to copy the mc68hc11 and use
LEGITIMIZE_RELOAD_ADDRESS to recognise the offset and cause another
reload. This code:
if (GET_CODE (x) == PLUS
&& GET_CODE (XEXP (x, 0)) == REG
&& GET_CODE(XEXP(x, 1)) == CONST_INT)
{
HOST_WIDE_INT value = INTVAL (XEXP (x, 1));
push_reload(x, NULL_RTX, px, NULL,
ADDR_REGS, GET_MODE(x), VOIDmode, 0, 0, opnum, reload_type);
return true;
}
does that.
I tried TARGET_SECONDARY_RELOAD as well. Similar code to above would
correclty generate the code on an 'in' reload but for some reason the
code for the 'out' reload would never get inserted.
-- Michael
2009/4/29 Michael Hope <[email protected]>:
> HI there. I'm working on porting gcc to a new architecture which only
> does indirect addressing - there is no indirect with displacement.
>
> The problem is with spill locations in GCC 4.4.0. The elimination
> code correctly elimates the frame and args pointer and replaces it
> with register X. The problem is that it then generates indirect with
> offset loads to load spilt values.
>
> Normal usage such as:
>
> struct foo
> {
> int a;
> int b;
> }
>
> int bar(struct foo* p)
> {
> return p->b;
> }
>
> is correctly split into load X with p, add four, and then de-references.
>
> The RTL is generated after the IRA stage. GCC aborts in post reload
> with a 'instruction does not satisfy constraints' on:
> (insn 183 181 75 3 mandelbrot.c:117 (set (reg:SI 6 R11)
> (mem/c:SI (plus:SI (reg:SI 3 X)
> (const_int -8 [0xfffffffffffffff8])) [0 %sfp+-8 S4
> A32])) -1 (nil))
>
> The movsi it matches against is:
>
> (define_insn "movsi_insn"
> [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r,rm,rm,rm,C, rm")
> (match_operand:SI 1 "general_operand" "r, m,I, i ,n, rm,C"))]
> ""
> "@
> LOADACC, %1\;STOREACC, %0
> LOADACC, %1\;STOREACC, %0
> LOADI, #%1\;STOREACC, %0
> LOADLONG, #%1\;STOREACC, %0
> LOADLONG, %1\;STOREACC, %0
> Foo
> Bar"
> )
>
> I believe it fails on the constraints as the 'm' constraint misses as
> go_if_legitimate_address only supports (mem (reg)) and not (mem (plus
> (reg...)))
>
> I don't think I had this problem when working against 4.3.3 but I'm not sure.
>
> Could someone point me in the right direction please? Is it
> appropriate to ask such questions on this list?
>
> -- Michael
>