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 >>>>>> > >