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 <[email protected]> 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 <[email protected]>:
>>>> 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
>>>>
>>
>>
>
>