Re: Unexpected offsets when eliminating SP

2009-05-09 Thread Michael Hope
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

2009-05-04 Thread Jim Wilson

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

2009-05-03 Thread Michael Hope
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

2009-04-29 Thread Ian Lance Taylor
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

2009-04-29 Thread Jim Wilson

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