I found the source of my problems!

The prologue()/epilogue() functions (*) I took from the tutorial written
for SPIM/MIPS emit a number of move insn to/from "invalid" memory
addresses (reg+off) that do not go through LEGITIMIZE_ADDRESS(), and
this freaks out GCC, so I have to rewrite these in some ways...

It seems that prologue()/epilogue() are called quite late in the
compiling process, thus new registers cannot be created (no_new_pseudos
assert fires) and/or emit_move_insn() does not go through
LEGITIMIZE_ADDRESS()... will work on this tomorrow...

Thanks for the support so far!

        Sergio

(*)
void
spim_prologue(void)
{
        int i,j;
        
emit_move_insn(gen_rtx_MEM(HImode,plus_constant(stack_pointer_rtx,0)),return_addr_rtx);
emit_move_insn(gen_rtx_MEM(HImode,plus_constant(stack_pointer_rtx,-2)),stack_pointer_rtx);
emit_move_insn(gen_rtx_MEM(HImode,plus_constant(stack_pointer_rtx,-4)),hard_frame_pointer_rtx);


...

}



Sergio Ruocco wrote:
> 
> Thanks Micheal for your code, I will try it... however, I think the
> problem that crashes my compiler may not lie in my LEGITIMATE/LEGITIMIZE
> ADDRESS macros, which are equivalent to many others (yours included),
> but in the GCC which - in some corner cases - does not like being told
> that an register+offset is an invalid address.
> 
> While investigating this hypothesis, I found this tutorial
> 
> http://spindazzle.org/ggx/
> 
> which discusses a GCC port with the same constraints I am battling with,
> but solved in a different way.
> 
> In this port, the register indirect addressing is enforced through a
> custom constraint in the MD (details below).
> 
> What do you think of this approach?
> 
>       Sergio
> 
> (from the patch to the MD)
> 
> -------------------------------------------------------------------------
> ;; Constraints
> ;; -------------------------------------------------------------------------
> (define_constraint "W"
>   "A register indirect memory operand."
>   (and (match_code "mem")
>        (match_test "REG_P (XEXP (op, 0))
>                   && REGNO_OK_FOR_BASE_P (REGNO (XEXP (op, 0)))")))
> 
> 
> which is then specified by the define_insn
> 
>  (define_insn "*movsi"
>    [(set (match_operand:SI 0 "general_operand" "=r,r,W,m,r,r")
>       (match_operand:SI 1 "ggx_general_movsrc_operand" "r,i,r,r,W,m"))]
>    "register_operand (operands[0], SImode)
>     || register_operand (operands[1], SImode)"
>    "@
>     mov    %0, %1
>     ldi.l  %0, %1
>     st.l   %0, %1
>     sta.l  %0, %1
>     ld.l   %0, %1
>     lda.l  %0, %1")
> 
> http://spindazzle.org/ggx/gcc/add-load-store.patch.txt
> 
> 
> The GO_IF_LEGITIMATE_ADDRESS() macro is plain and simple:
> 
> /* A C compound statement with a conditional `goto LABEL;' executed
>    if X (an RTX) is a legitimate memory address on the target machine
>    for a memory operand of mode MODE.  */
> #define GO_IF_LEGITIMATE_ADDRESS(MODE,X,LABEL)                \
>   do {                                                  \
>     if (REG_P (X) && REGNO_OK_FOR_BASE_P (REGNO (X))) \
>       goto LABEL;                                     \
>     if (GET_CODE (X) == SYMBOL_REF                    \
>       || GET_CODE (X) == LABEL_REF                    \
>       || GET_CODE (X) == CONST)                       \
>       goto LABEL;                                     \
>   } while (0)
> 
> http://spindazzle.org/ggx/gcc/add-ggx-config.patch.txt
> 
> 
> 
> 
> Michael Hope wrote:
>> 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