Hi!

Im writing a backend for GCC 4.0-2 for a simple machine with a rather limited 
instruction set. With the kind help of Ian Lance Taylor I was already able to 
solve a few big problems I had earlier. Now I am stuck on another problem 
that IMHO concerns reloading. 

Most of the instructions of the target machine only support registers as 
operands. E.g., a store to a memory location (STO) must always take a 
register containing the address of the memory location and another register 
with the data to be written to that location as arguments. The assembler does 
not support any arithmetic expressions. The only way to get a constant 
directly into a register is to load the high and low part of it with two 
instructions (LDH/LDL).

However, GCC kept generating instructions like these:

;#(insn 9 7 95 (set (mem/i:HI (plus:HI (reg/f:HI 6 BP)
;#                (const_int -6 [0xfffffffa])) [0 x+0 S2 A16])
;#        (const_int 0 [0x0])) 13 {movhi} (nil)
;#    (nil))

I needed GCC to put "BP-6" into a register first and then do sth. like (set 
(mem (reg REG)) (const_int 0)).

From what I understood when reading the GCC internals 
docs "GO_IF_LEGITIMATE_ADDRESS" might be the right place to tackle this 
problem. I took that macro from the PDP-11 backend and tried to adjust it to 
my needs. There was a part that looked like this:

[...]
    if (GET_CODE (operand) == PLUS                                      \
        && GET_CODE (XEXP (operand, 0)) == REG                          \
        && REG_OK_FOR_BASE_P (XEXP (operand, 0))                        \
        && CONSTANT_ADDRESS_P (XEXP (operand, 1)))                      \
      goto ADDR;                                                        \
[...]

I removed those lines so that it now rejects "PLUS" operands. When I compile 
GCC I now get the following message:

[...]
make[2]: Entering directory `/usr/local/src/gcc-4.0-4.0.2/objdir-zykluno/gcc'
/usr/local/src/gcc-4.0-4.0.2/objdir/gcc/xgcc 
-B/usr/local/src/gcc-4.0-4.0.2/objdir/gcc/ 
-B/usr/local/zykluno/bin/ -B/usr/local/zykluno/lib/ -isystem 
/usr/local/zykluno/include 
-isystem /usr/local/zykluno/sys-include -O2  -DIN_GCC -DCROSS_COMPILE   -W 
-Wall 
-Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -Wold-style-definition 
 
-isystem ./include   -g  -DIN_LIBGCC2 -D__GCC_FLOAT_NOT_NEEDED -Dinhibit_libc 
-I. -I. -I../../gcc-4.0.2/gcc -I../../gcc-4.0.2/gcc/. 
-I../../gcc-4.0.2/gcc/../include 
-I../../gcc-4.0.2/gcc/../libcpp/include  -DL_muldi3 -c 
../../gcc-4.0.2/gcc/libgcc2.c -o 
libgcc/./_muldi3.o

cc1: warning: target system does not support debug output
../../gcc-4.0.2/gcc/libgcc2.c: In function '__muldi3':
../../gcc-4.0.2/gcc/libgcc2.c:533: error: unable to find a register to spill 
in class 'GENERAL_REGS'
../../gcc-4.0.2/gcc/libgcc2.c:533: error: this is the insn:

(insn 260 259 266 4 ../../gcc-4.0.2/gcc/libgcc2.c:533 (set (reg/f:HI 5 R[5] 
[+6 ])
        (subreg:HI (reg:SI 102) 2)) 14 {movhi} (nil)
    (expr_list:REG_DEAD (reg:SI 102)
        (nil)))

../../gcc-4.0.2/gcc/libgcc2.c:533: confused by earlier errors, bailing out
[...]


If it helps, I have eight registers of which half of them need to be fixed 
(first 2 fixed by hardware, last 2 BP/SP):

#define FIXED_REGISTERS  {1, 1, 0, 0, 0, 0, 1, 1}
#define REGISTER_NAMES 
{"R[0]", "R[1]", "R[2]", "R[3]", "R[4]", "R[5]", "BP", "SP"}

#define REG_CLASS_NAMES {"NO_REGS", "GENERAL_REGS", "ALL_REGS" }
#define REG_CLASS_CONTENTS {{0x00}, {0xfc}, {0xff}}

However, it built gcc-cross, I tried it out and it seems to do just what I 
want it to now:

;#(insn 136 7 10 (set (reg:HI 3 R[3])
;#        (const_int -6 [0xfffffffa])) 14 {movhi} (nil)
;#    (nil))
        LDH     R[3], 65280     ;# 136  movhi/4
        LDL     R[3], 250
;#(insn 10 136 137 (set (reg/f:HI 2 R[2] [25])
;#        (plus:HI (reg/f:HI 6 BP)
;#            (reg:HI 3 R[3]))) 19 {addhi3} (nil)
;#    (nil))
        ADD     R[2], BP, R[3]  ;# 10   addhi3
;#(insn 137 10 11 (set (reg:HI 4 R[4])
;#        (const_int 0 [0x0])) 14 {movhi} (nil)
;#    (nil))
        LDH     R[4], 0 ;# 137  movhi/4
        LDL     R[4], 0
;#(insn 11 137 133 (set (mem/i:HI (reg/f:HI 2 R[2] [25]) [0 x+0 S2 A16])
;#        (reg:HI 4 R[4])) 14 {movhi} (nil)
;#    (nil))
        STO     R[2], R[4]      ;# 11   movhi/3

The generated code seems to be still correct.

So, I am wondering: how does that error affect the generated compiler and what 
is the reason for it? 

>From what I understood, the problem is related to realoading. IMHO the 
compiler needs additional registers for the constants that it previously 
directly used as operands and now has to store into registers before passing 
one as an argument to an instructions. I'm not sure though and I would 
appreciate any thoughts on that. 

If the reason really is the pressure on the already scarce registers, would it 
be a good idea to get GCC to use the stack in order to temporarily free up 
registers for such things? If so, could somebody point me into the right 
direction on how to do that, please? 

I defined push and pop instructions and the compiler uses them to pass 
function arguments just fine, but it does not make any use of them in this 
case. Besides, I'm not even sure where I should start looking - do I need to 
adjust <machine>.h or am I missing instructions in <machine>.md?

I read in other posts that reloading is supposed to be one of the trickiest 
parts to get right with an initial port. I still have a hard time 
understanding how reloading works. The information I found in the gcc 
internals docs and other parts of the inet are pretty widespread. I would be 
glad if someone knows a page that specifically discusses reloading.

I tried to post everything of relevance to the problem. If you need anything 
else, please ask and I will post it.

Cheers,
Frank

Reply via email to