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