Hi,

I'm working on a GCC (4.3.0) backend for a custom 16 bit microcontroller
we're designing at work, and I'm facing a reload problem. After having
lost many hours trying to make it work, I decided to ask for some
help :)

I'll try to summarize the situation below, but by all means please ask
for more if something is missing.

The error I'm encountering happens when compiling _divdi3 in libgcc
(note that before compiling this one, several functions from libgcc
compiled fine):

../../../../src/gcc-4.3.0/libgcc/../gcc/libgcc2.c: In function ‘__divhi3’:
../../../../src/gcc-4.3.0/libgcc/../gcc/libgcc2.c:1106: error: insn does not 
satisfy its constraints:
(insn 1117 16 1118 2 ../../../../src/gcc-4.3.0/libgcc/../gcc/libgcc2.c:1090 
(set (reg:QI 10 r10)
        (const_int 24 [0x18])) 1 {*movqi_imm} (nil))
../../../../src/gcc-4.3.0/libgcc/../gcc/libgcc2.c:1106: internal compiler 
error: in reload_cse_simplify_operands, at postreload.c:395

The microcontroller in question is a 16 bit one, and addresses the
memory only in 16 bit words:
        #define BITS_PER_UNIT   16
        #define UNITS_PER_WORD  1

This microcontroller has 32 hard registers. Immediate constants can only
be loaded into the first 8 registers. There are no index registers. All
the even registers can serve as a base register. However, the base
register addressing is reduced to its simplest form, where the offset is
always 0.

Based on the above, I have defined:
        enum reg_class
        {
          NO_REGS,
          STACK_REGS,
          EIGHT_REGS,
          EVEN_REGS,
          ALL_REGS,
          LIM_REG_CLASSES
        };

        #define GENERAL_REGS ALL_REGS

        ...

        #define REG_CLASS_CONTENTS                      \
        {                                               \
          { 0x00000000 },                               \
          { 0x80000000 },                               \
          { 0x000000FF },                               \
          { 0x55555555 },                               \
          { (1LL << FIRST_PSEUDO_REGISTER) - 1 }        \
        }

        #define REGNO_REG_CLASS(REGNO)                  \
          ((REGNO) > 30   ? STACK_REGS                  \
           : (REGNO) < 8  ? EIGHT_REGS                  \
           : (REGNO % 2) == 0  ? EVEN_REGS              \
           : GENERAL_REGS)

        #define BASE_REG_CLASS EVEN_REGS

        #define INDEX_REG_CLASS NO_REGS

        #define REGNO_OK_FOR_BASE_P(NUM) (NUM % 2 == 0)

        #define REGNO_OK_FOR_INDEX_P(NUM) 0

        #define PREFERRED_RELOAD_CLASS(X, CLASS)        \
          ((CONSTANT_P(X)) ? EIGHT_REGS :               \
           (MEM_P(X)) ? EVEN_REGS : CLASS)

        #define PREFERRED_OUTPUT_RELOAD_CLASS(X, CLASS) \
          ((CONSTANT_P(X)) ? EIGHT_REGS :               \
           (MEM_P(X)) ? EVEN_REGS : CLASS)

        ...

        #define STACK_POINTER_REGNUM 31

        #define FRAME_POINTER_REGNUM 30

        ....

        #ifdef REG_OK_STRICT
        #define REG_OK_FOR_BASE_P(X)                            \
                (REGNO_OK_FOR_BASE_P (REGNO (X)) && (REGNO (X) 
<FIRST_PSEUDO_REGISTER))
        #else
        #define REG_OK_FOR_BASE_P(X)                            \
                (REGNO_OK_FOR_BASE_P (REGNO (X)) || REGNO (X) >= 
FIRST_PSEUDO_REGISTER)
        #endif

        #define GO_IF_LEGITIMATE_ADDRESS(MODE, X, LABEL)        \
        do {                                                    \
          if (GET_CODE (X) == REG && (REG_OK_FOR_BASE_P(X)))    \
            goto LABEL;                                         \
          else if (GET_CODE(X) == PLUS &&                       \
                   REG_OK_FOR_BASE_P (XEXP (X, 0)) &&           \
                   GET_CODE(XEXP(X,1)) == CONST_INT &&          \
                   INTVAL(XEXP(X,1)) == 0)                      \
            goto LABEL;                                         \
        } while (0)


I also defined some constraints for the register classes:

        (define_register_constraint "x" "STACK_REGS"
          "Stack registers (r30--r31)")

        (define_register_constraint "y" "EIGHT_REGS"
          "Low eight registers (r0--r7)")

        (define_register_constraint "z" "EVEN_REGS"
          "Even registers (r0,r2,r4, @dots{} r30)")


The movqi_imm pattern which constraints doesn't match has been defined
with (note the 'y' constrant):

        (define_insn "*movqi_imm"
          [(set (match_operand:QI 0 "register_operand" "=y")
                (match_operand:QI 1 "const_int_operand" ""))]
          ""  
          {
                output_asm_insn ("ldih %0, hi(%1)", operands);
                output_asm_insn ("ldil %0, lo(%1)", operands);
                return "";
          }
          [(set_attr "cc" "none")]
        )

Now, I'm trying to figure out why the error happens, with GCC choosing
to put an immediate into r10 instead of an EIGHT_REGS. It all seems to
come (I do not know why) from insn 16 in libgcc2.c.175r.lreg:

        Register 453 costs: EIGHT_REGS:0 EVEN_REGS:0 ALL_REGS:0 MEM:4175
        Register 466 costs: EIGHT_REGS:600 EVEN_REGS:600 ALL_REGS:600 MEM:5200
        ...
        Register 453 pref EVEN_REGS
        Register 466 pref EVEN_REGS
        ...
        (insn 16 15 21 2 ../../../../src/gcc-4.3.0/libgcc/../gcc/libgcc2.c:1090 
(set (reg:QI 453 [ uu+1 ])
                (reg:QI 466 [ v ])) 0 {*movqi_reg} (nil))

In libgcc2.c.176.greg I see:

        Reloads for insn # 16
        Reload 0: reload_in (QI) = (plus:QI (reg/f:QI 30 r30)
                                                            (const_int 24 
[0x18]))
                EVEN_REGS, RELOAD_FOR_OUTPUT_ADDRESS (opnum = 0), can't combine 
                reload_in_reg: (plus:QI (reg/f:QI 30 r30)
                                                    (const_int 24 [0x18]))
                reload_reg_rtx: (reg:QI 10 r10)
        Reload 1: reload_out (QI) = (mem/c:QI (plus:QI (reg/f:QI 30 r30)
                                                                (const_int 24 
[0x18])) [31 S1 A16])
                EVEN_REGS, RELOAD_FOR_OUTPUT (opnum = 0)
                reload_out_reg: (reg:QI 453 [ uu+1 ])
                reload_reg_rtx: (reg:QI 14 r14)


        ...

        (insn 16 1115 1117 2 
../../../../src/gcc-4.3.0/libgcc/../gcc/libgcc2.c:1090 (set (reg:QI 14 r14)
                (reg:QI 2 r2 [orig:466 v ] [466])) 0 {*movqi_reg} (nil))

        (insn 1117 16 1118 2 
../../../../src/gcc-4.3.0/libgcc/../gcc/libgcc2.c:1090 (set (reg:QI 10 r10)
                (const_int 24 [0x18])) 1 {*movqi_imm} (nil))

        (insn 1118 1117 1119 2 
../../../../src/gcc-4.3.0/libgcc/../gcc/libgcc2.c:1090 (set (reg:QI 10 r10)
                (plus:QI (reg:QI 10 r10)
                    (reg/f:QI 30 r30))) 13 {addqi3} (expr_list:REG_EQUIV 
(plus:QI (reg/f:QI 30 r30)
                    (const_int 24 [0x18]))
                (nil)))

        (insn 1119 1118 21 2 
../../../../src/gcc-4.3.0/libgcc/../gcc/libgcc2.c:1090 (set (mem/c:QI (reg:QI 
10 r10) [31 S1 A16])
                (reg:QI 14 r14)) 8 {*movqi_tomem} (nil))

I tried playing with different definitions for PREFERRED_RELOAD_CLASS,
PREFERRED_OUTPUT_RELOAD_CLASS, TARGET_SECONDARY_RELOAD, with no luck.

Thanks to anybody who can explain to me what's wrong here, and give a clue
on what I must do to fix it.

Stelian.
-- 
Stelian Pop <[EMAIL PROTECTED]>


Reply via email to