Hi Sergio.  Here's the interesting parts from my port.  The code's a
bit funny looking as I've edited it for this post.

In <port>.h:

#define BASE_REG_CLASS  ADDR_REGS
#define INDEX_REG_CLASS NO_REGS

#ifdef REG_OK_STRICT
# define <PORT>_REG_OK_STRICT 1
#else
# define <PORT>_REG_OK_STRICT 0
#endif

#define REGNO_OK_FOR_BASE_P(r) <port>_regno_ok_for_base_p(r,
<PORT>_REG_OK_STRICT)
#define REGNO_OK_FOR_INDEX_P(r) 0

In <port>.c:

static bool
<port>_reg_ok(rtx reg, bool strict)
{
  int regno = REGNO(reg);

  bool is_addr = <port>_is_addr_regno(regno);
  bool ok_strict = is_addr;
  bool special = regno == ARG_POINTER_REGNUM
    || regno == TREG_S
    ;

  if (strict)
    {
      return ok_strict || special;
    }
  else
    {
      return ok_strict || special
        || regno >= FIRST_PSEUDO_REGISTER
        ;
    }
}

bool
<port>_legitimate_address (enum machine_mode mode ATTRIBUTE_UNUSED,
                         rtx x,
                         bool strict_checking)
{
  /* (mem reg) */
  if (REG_P (x)
      && <port>_reg_ok (x, strict_checking)
      )
    {
      return 1;
    }

  return 0;
}

Note that this ISA only has indirect addressing and has no indirect +
offset or indirect + register modes.  GCC
handles this just fine by splitting up any other type that fails
legitimate_address into smaller components.

-- Michael

On 10 February 2010 09:02, Sergio Ruocco <sergio.ruo...@gmail.com> wrote:
>
> Michael Hope wrote:
>> Hi Sergio.  Any luck so far?
>
> Micheal, thanks for your inquiry. I made some progress, in fact.
>
> I got the GO_IF_LEGITIMATE_ADDRESS() macro to detect correctly REG+IMM
> addresses, and then the LEGITIMIZE_ADDRESS() macro to force them to be
> pre-computed in a register.
>
> However, now the compiler freaks out with an ICE.. :-/ I put some
> details below. Thanks for any clue that you or others can give me.
>
> Cheers,
>
>        Sergio
>
> ==========================================================================
>
>
> This is a fragment of my LEGITIMIZE_ADDRESS():
> -----------------------------------------------------------------
>
> rtx
> legitimize_address(rtx X,rtx OLDX, enum machine_mode MODE)
> {
>        rtx op1,op2,op,sum;
>        op=NULL;
> ...
>        if(GET_CODE(X)==PLUS && !no_new_pseudos)
>        {
>                op1=XEXP(X,0);
>                op2=XEXP(X,1);
>                if(GET_CODE(op1) == CONST_INT && (GET_CODE(op2) == REG ||
> GET_CODE(op2) == SUBREG)) // base displacement
>                {
>                        sum = gen_rtx_PLUS (MODE, op1, op2);
>                        op = force_reg(MODE, sum);
>                }
> ...
> -----------------------------------------------------------------
>
>
> Now when compiling a simple program such as:
>
> void foobar(int par1, int par2, int parN)
> {
>        int a,b;
>        a = 0x1234;
>        b = a;
> }
>
> the instructions (n. 8,12,13) which compute the addresses in registers
> seem to be generated correctly:
>
> -----------------------------------------------------------------
> ;; Function foobar
>
> ;; Register dispositions:
> 37 in 4  38 in 2  39 in 4  40 in 2  41 in 2
>
> ;; Hard regs used:  2 4 30
>
> (note 2 0 3 NOTE_INSN_DELETED)
>
> (note 3 2 6 0 NOTE_INSN_FUNCTION_BEG)
>
> ;; Start of basic block 1, registers live: 1 [A1] 29 [B13] 30 [B14]
> (note 6 3 8 1 [bb 1] NOTE_INSN_BASIC_BLOCK)
>
> (insn 8 6 9 1 (set (reg/f:HI 4 A4 [37])
>        (plus:HI (reg/f:HI 30 B14)
>            (const_int -16 [0xfffffffffffffff0]))) 9 {addhi3} (nil)
>    (nil))
>
> (insn 9 8 10 1 (set (reg:HI 2 A2 [38])
>        (const_int 4660 [0x1234])) 5 {*constant_load} (nil)
>    (nil))
>
> (insn 10 9 12 1 (set (mem/i:HI (reg/f:HI 4 A4 [37]) [0 a+0 S2 A32])
>        (reg:HI 2 A2 [38])) 7 {*store_word} (nil)
>    (nil))
>
> (insn 12 10 13 1 (set (reg/f:HI 4 A4 [39])
>        (plus:HI (reg/f:HI 30 B14)
>            (const_int -14 [0xfffffffffffffff2]))) 9 {addhi3} (nil)
>    (nil))
>
> (insn 13 12 14 1 (set (reg/f:HI 2 A2 [40])
>        (plus:HI (reg/f:HI 30 B14)
>            (const_int -16 [0xfffffffffffffff0]))) 9 {addhi3} (nil)
>    (nil))
>
> (insn 14 13 15 1 (set (reg:HI 2 A2 [orig:41 a ] [41])
>        (mem/i:HI (reg/f:HI 2 A2 [40]) [0 a+0 S2 A32])) 4 {*load_word} (nil)
>    (nil))
>
> (insn 15 14 16 1 (set (mem/i:HI (reg/f:HI 4 A4 [39]) [0 b+0 S2 A16])
>        (reg:HI 2 A2 [orig:41 a ] [41])) 7 {*store_word} (nil)
>    (nil))
> ;; End of basic block 1, registers live:
>  1 [A1] 29 [B13] 30 [B14]
>
> (note 16 15 25 NOTE_INSN_FUNCTION_END)
>
> (note 25 16 0 NOTE_INSN_DELETED)
> -----------------------------------------------------------------
>
> However, when I compile it
>
> $ hcc -da foobar8.c
>
> I get an ICE at the end of the compilation, and the assembly source is
> not produced:
>
> [ lots of my debugging output removed ]
>
> legitimate_address2(non-strict, soft-reg allowed), X=
> (reg/f:HI 29 B13)
> legitimate_address2() yes: (X)==REG && non_strict_base_reg(REGNO(X))
>
> -----------------MOVHI--------------- [generating a MOV X, Y insn]
> MOVHI: operands[0]
> (mem:HI (reg/f:HI 29 B13) [0 S2 A8])
> MOVHI: operands[1]
> (reg:HI 31 B15)
> MOVHI --- END
>
>
> [then checking if -2(B13) is legitimate, it is not...]
>
> legitimate_address2(non-strict, soft-reg allowed), X=
> (plus:HI (reg/f:HI 29 B13)
>    (const_int -2 [0xfffffffffffffffe]))
> legitimate_address2(): FOUND register+offset --> FAIL!
>
> legitimate_address2(non-strict, soft-reg allowed), X=
> (plus:HI (reg/f:HI 29 B13)
>    (const_int -2 [0xfffffffffffffffe]))
> legitimate_address2(): FOUND register+offset --> FAIL!
>
> legitimate_address2(non-strict, soft-reg allowed), X=
> (plus:HI (reg/f:HI 29 B13)
>    (const_int -2 [0xfffffffffffffffe]))
> legitimate_address2(): FOUND register+offset --> FAIL!
>
> legitimate_address2(non-strict, soft-reg allowed), X=
> (plus:HI (reg/f:HI 29 B13)
>    (const_int -2 [0xfffffffffffffffe]))
> legitimate_address2(): FOUND register+offset --> FAIL!
>
>
> [and after four check of the add above, gcc 4.0.2 freaks out with ]
>
> foobar8.c: In function ‘foobar’:
> foobar8.c:7: internal compiler error: in change_address_1, at
> emit-rtl.c:1800
> Please submit a full bug report,
>
> with preprocessed source if appropriate.
> See <URL:http://gcc.gnu.org/bugs.html> for instructions.
>
>
> The failed assertion is in line 1800: some "addr" is not an address.
>
>   1784 change_address_1 (rtx memref, enum machine_mode mode, rtx addr,
> int validate)
>   1785 {
>   1786   rtx new;
>   1787
>   1788   gcc_assert (MEM_P (memref));
>   1789   if (mode == VOIDmode)
>   1790     mode = GET_MODE (memref);
>   1791   if (addr == 0)
>   1792     addr = XEXP (memref, 0);
>   1793   if (mode == GET_MODE (memref) && addr == XEXP (memref, 0)
>   1794       && (!validate || memory_address_p (mode, addr)))
>   1795     return memref;
>   1796
>   1797   if (validate)
>   1798     {
>   1799       if (reload_in_progress || reload_completed)
>   1800         gcc_assert (memory_address_p (mode, addr));
>   1801       else
>   1802         addr = memory_address (mode, addr);
>   1803     }
>   1804
>   1805   if (rtx_equal_p (addr, XEXP (memref, 0)) && mode == GET_MODE
> (memref))
>   1806     return memref;
>   1807
>   1808   new = gen_rtx_MEM (mode, addr);
>   1809   MEM_COPY_ATTRIBUTES (new, memref);
>   1810   return new;
>   1811 }
>
>
> Could it be the REG+OFF which the LEGITIMATE_ADDRESS() rejects above?
>
> But then why all the others before it get re-written by a call to
> LEGITIMIZE_ ADDRESS() ?!
>
> What is calling change_address_1() at the end of the compilation phase?
>
> Thanks
>
>        Sergio
>
> ==========================================================================
>
>
>
>
>
>
> Sergio Ruocco wrote:
>>
>> Now my GO_IF_LEGITIMATE_ADDRESS refuses anything that is not a REG
>> or a CONSTANT_ADDRESS:
>>
>> int legitimate_address1(enum machine_mode MODE,rtx X)
>> {
>>       if(CONSTANT_ADDRESS_P(X))
>>                 return 1;
>>       if(GET_CODE(X)==REG && is_base_reg(REGNO(X)))
>>                 return 1;
>>
>>       return 0; /* fails everything else */
>>
>> } /* this is the strict version, the non strict version is similar */
>>
>> but GCC (4.0.2, just in case the version is relevant) still aborts the
>> compilation.
>>
>>
>> Then I found this wiki note about forcing complex addresses into
>> registers: http://gcc.gnu.org/wiki/WritingANewBackEnd
>>
>> ...
>> rtx copy_addr_to_reg (rtx x)
>>     Equivalent to copy_to_mode_reg (Pmode, x). For example, this
>> function can be used to compute a complex address X in a register for an
>> instruction which supports only register indirect addressing. See also
>> replace_equiv_address() below.
>> ...
>>
>>
>> Thus I changed in the .md file the movXX RTL expand macro to force any
>> MEM expression into a register:
>>
>> (define_expand "movhi" /*  my micro is 16 bit... */
>>         [(set (match_operand:HI 0 "nonimmediate_operand" "")
>>               (match_operand:HI 1 "general_operand" "")
>>         )]
>>         ""
>>       {
>>       if(!no_new_pseudos && GET_CODE(operands[0])==MEM) {
>>               if( /* addr in operands[0] == base reg + offset */ )
>>                       operands[0] = copy_addr_to_reg ( operands[0] );
>>       }
>> )
>>
>> The GCC still fails to generate the assembly code to do the arithmetic
>> computation of the baseReg+offset-->tempReg, and then use (tempReg) as
>> address.
>>
>> Note that with the current MD GCC is able to generate simple sums like
>> R1 = R2 + R3 and R1 = R2 + IMM, thus the basic math to compute an
>> address is there.
>>
>> Any suggestion on what I am doing wrong ?
>>
>>       Sergio
>>
>>
>> Michael Hope wrote:
>>> Hi Sergio.  My port has similar addressing modes - all memory must be
>>> accessed by one of two registers and can only be accessed indirectly,
>>> indirect with pre increment, and indirect with post increment.  The
>>> key is GO_IF_LEGITIMATE_ADDRESS and the legitimate address helper
>>> function.  Mine looks like this:
>>>
>>> /* Return 1 if the address is OK, otherwise 0.
>>>    Used by GO_IF_LEGITIMATE_ADDRESS.  */
>>>
>>> bool
>>> tomi_legitimate_address (enum machine_mode mode ATTRIBUTE_UNUSED,
>>>                       rtx x,
>>>                       bool strict_checking)
>>> {
>>>   /* (mem reg) */
>>>   if (REG_P (x)
>>>       && tomi_reg_ok (x, strict_checking)
>>>       )
>>>     {
>>>       return 1;
>>>     }
>>>
>>>   if (GET_CODE(x) == PRE_DEC)
>>>     {
>>> ...
>>>     }
>>>
>>>   if (GET_CODE(x) == POST_INC)
>>>     {
>>> ...
>>>     }
>>>
>>>   return 0;
>>> }
>>>
>>> tomi_reg_ok returns true if x is any register when strict checking is
>>> clear and true if x is one of my addressing registers when strict
>>> checking is set.
>>>
>>> GCC will feed any memory accesses through this function to see if they
>>> are directly supported, and if not it will break them up into
>>> something smaller and try again.
>>>
>>> Hope that helps,
>>>
>>> -- Michael
>>>
>>>
>>> 2010/1/26 Sergio Ruocco <sergio.ruo...@gmail.com>:
>>>> Gabriel Paubert wrote:
>>>>> On Mon, Jan 25, 2010 at 01:34:09PM +0100, Sergio Ruocco wrote:
>>>>>> Hi everyone,
>>>>>>
>>>>>> I am porting GCC to a custom 16-bit microcontroller with very limited
>>>>>> addressing modes. Basically, it can only load/store using a (general
>>>>>> purpose) register as the address, without any offset:
>>>>>>
>>>>>>      LOAD (R2) R1    ; load R1 from memory at address (R2)
>>>>>>      STORE R1 (R2)   ; store R1 to memory at address (R2)
>>>>>>
>>>>>> As far as I can understand, this is more limited than the current
>>>>>> architectures supported by GCC that I found in the current gcc/config/*.
>>>>> The Itanium (ia64) has the same limited choice of addressing modes.
>>>>>
>>>>>       Gabriel
>>>> Thanks Gabriel.
>>>>
>>>> I dived into the ia64 md, but it is still unclear to me how the various
>>>> parts (macros, define_expand and define_insn in MD etc.) work together
>>>> to force the computation of a source/dest address plus offset into a
>>>> register... can anyone help me with this ?
>>>>
>>>> Thanks,
>>>>
>>>>        Sergio
>>>>
>>
>>
>
>

Reply via email to