Re: Unexpected offsets when eliminating SP
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 micha...@juju.net.nz: 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 [0xfff8])) [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
Re: Unexpected offsets when eliminating SP
Michael Hope wrote: (define_expand reload_outsi [(parallel [(match_operand 0 memory_operand =m) Perhaps the problem is that the output operand is an unallocated pseudo-reg instead of a MEM. Looking at other targets that have reload_out* patterns, I see that they have predicates that accept both mem and pseudo-regs here. I'm a bit confused with the documentation versus the ports. For example, REGNO_MODE_CODE_OK_FOR_BASE_P doesn't appear to need a strict form according to the documentation but the bfin port has a strict and non-strict version. Most of the ports have a REG_OK_FOR_BASE_P macro with strict and non-strict versions macro but it's not documented, isn't used, and might have been removed around gcc 4.0. The current docs say that REGNO_MODE_CODE_OK_FOR_BASE_P has strict and non-strict variants. The REG_OK_FOR_BASE_P stuff is obsolete. That is something that could be cleaned up. However, since most ports are both defining it and using it in the GO_IF_LEGITIMATE_ADDRESS macros, it is something that will take some work, and it might be simpler to just leave the macros there. Jim
Re: Unexpected offsets when eliminating SP
Thanks Jim and Ian. I've added a secondary_reload which does this: ... if (code == MEM) { if (fp_plus_const_operand(XEXP(x, 0), mode)) { sri-icode = in_p ? CODE_FOR_reload_insi : CODE_FOR_reload_outsi; return NO_REGS; } where fp_plus_const_operand is taken from the bfin port - it checks that this is RTL of the form ((plus (reg const)). The .md file contains: --- (define_expand reload_insi [(parallel [(set (match_operand:SI 0 register_operand =r) (match_operand:SI 1 memory_operand m)) (clobber (match_operand:SI 2 register_operand =a))])] { fprintf(stderr, reload_insi\n); rtx plus_op = XEXP(operands[1], 0); rtx fp_op = XEXP (plus_op, 0); rtx const_op = XEXP (plus_op, 1); rtx primary = operands[0]; rtx scratch = operands[2]; emit_move_insn (scratch, fp_op); emit_insn (gen_addsi3 (scratch, scratch, const_op)); emit_move_insn (primary, gen_rtx_MEM(Pmode, scratch)); DONE; } ) (define_expand reload_outsi [(parallel [(match_operand 0 memory_operand =m) (match_operand 1 register_operand r) (match_operand:SI 2 register_operand =a)])] { fprintf(stderr, reload_outsi\n); rtx plus_op = XEXP(operands[0], 0); rtx fp_op = XEXP (plus_op, 0); rtx const_op = XEXP (plus_op, 1); rtx primary = operands[1]; rtx scratch = operands[2]; emit_move_insn (scratch, fp_op); emit_insn (gen_addsi3 (scratch, scratch, const_op)); emit_move_insn (gen_rtx_MEM(Pmode, scratch), primary); DONE; } ) --- The reload_insi is being called and is expanding into the correct code but for some reason the reload_outsi never gets called. sri-icode is being set correctly and propagates a few levels up but I couldn't track it any further. The s390 port does the reload in the same way as me. The bfin is similar. I haven't looked further into GO_IF_LEGITIMATE_ADDRESS but it's the next part to look at. It's a stripped down version of the mmix one so it should be roughly OK. I'm a bit confused with the documentation versus the ports. For example, REGNO_MODE_CODE_OK_FOR_BASE_P doesn't appear to need a strict form according to the documentation but the bfin port has a strict and non-strict version. Most of the ports have a REG_OK_FOR_BASE_P macro with strict and non-strict versions macro but it's not documented, isn't used, and might have been removed around gcc 4.0. Any ideas on why the reload_outsi above is being eaten? Thanks, -- Michael 2009/4/30 Jim Wilson wil...@codesourcery.com: Michael Hope wrote: HI there. I'm working on porting gcc to a new architecture which only does indirect addressing - there is no indirect with displacement. The IA-64 target also has only indirect addressing. Well, it has some auto-increment addressing modes too, but that isn't relevant here. You could try looking at the IA-64 port to see why it works and yours doesn't. 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. Since this is happening inside reload, first thing I would check is to make sure you handle REG_OK_STRICT correctly. Before reload, a pseudo-reg is a valid memory address. Inside reload, an unallocated pseudo-reg is actually a memory location, and hence can not be a valid memory address. This is controlled by REG_OK_STRICT. Jim
Re: Unexpected offsets when eliminating SP
Michael Hope micha...@juju.net.nz writes: 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. It sounds like you need to use a secondary reload with a scratch register, so that you have a register that you can set to the stack frame address to use. Look at the docs for TARGET_SECONDARY_RELOAD. Could someone point me in the right direction please? Is it appropriate to ask such questions on this list? Yes, questions about porting gcc are appropriate for this mailing list. Ian
Re: Unexpected offsets when eliminating SP
Michael Hope wrote: HI there. I'm working on porting gcc to a new architecture which only does indirect addressing - there is no indirect with displacement. The IA-64 target also has only indirect addressing. Well, it has some auto-increment addressing modes too, but that isn't relevant here. You could try looking at the IA-64 port to see why it works and yours doesn't. 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. Since this is happening inside reload, first thing I would check is to make sure you handle REG_OK_STRICT correctly. Before reload, a pseudo-reg is a valid memory address. Inside reload, an unallocated pseudo-reg is actually a memory location, and hence can not be a valid memory address. This is controlled by REG_OK_STRICT. Jim