Hi.
In my i8086 backend experiments, I seem to have come across a corner case
which confuses reload. While building libgcc2 for one of the multilib
variants, GCC crashes:
libgcc2.c: In function '__muldc3':
libgcc2.c:1854: error: insn does not satisfy its constraints:
(insn:HI 2485 2483 2604 39 libgcc2.c:1825 (set (reg:HI 5 dh)
(ashiftrt:HI (reg:HI 2 a [641])
(const_int 15 [0xf]))) 31 {*ashrhi3_const15}
(insn_list:REG_DEP_TRUE 2480 (nil))
(nil))
libgcc2.c:1854: internal compiler error: in reload_cse_simplify_operands, at
postreload.c:393
The "*ashrhi3_const15" instruction is defined like this:
(define_insn "*ashrhi3_const15"
[(set (match_operand:HI 0 "single_register_operand" "=d")
(ashiftrt:HI (match_operand:HI 1 "single_register_operand" "a")
(const_int 15)))]
...
)
The constraints are not met because the constraint "d" is register class
DX_REGS consisting of register 4 and 5, and (reg:HI 5 dh) spans register 5
and 6. Also, HARD_REGNO_NREGS (5, HImode) returns 0.
The lreg and greg dumps provide the clue that reload got the mode wrong:
(insn:HI 2485 2483 2486 39 libgcc2.c:1825 (set (subreg:HI (reg:QI 178) 0)
(ashiftrt:HI (reg:HI 641)
(const_int 15 [0xf]))) 31 {*ashrhi3_const15}
(insn_list:REG_DEP_TRUE 2480 (nil))
(expr_list:REG_DEAD (reg:HI 641)
(nil)))
Reloads for insn # 2485
Reload 0: reload_out (QI) = (reg:QI 178)
DX_REGS, RELOAD_FOR_OUTPUT (opnum = 0)
reload_out_reg: (reg:QI 178)
reload_reg_rtx: (reg:QI 5 dh)
Reload of course need to provide a HImode (or larger) register for a
HImode operand. Notice the paradoxical subreg as output operand before
reload.
At around reload.c line 1083, in push_reload(), we have:
if (out != 0 && GET_CODE (out) == SUBREG
&& (subreg_lowpart_p (out) || strict_low)
[skipping the rest of the if() condition until line 1125]
{
out_subreg_loc = outloc;
outloc = &SUBREG_REG (out);
out = *outloc;
#if ! defined (LOAD_EXTEND_OP) && ! defined (WORD_REGISTER_OPERATIONS)
gcc_assert (!MEM_P (out)
|| GET_MODE_SIZE (GET_MODE (out))
<= GET_MODE_SIZE (outmode));
#endif
outmode = GET_MODE (out);
}
IOW, we set outmode to QImode. Later on, from around line 1298, we have:
i = n_reloads;
rld[i].in = in;
rld[i].out = out;
rld[i].class = class;
rld[i].inmode = inmode;
rld[i].outmode = outmode;
rld[i].reg_rtx = 0;
rld[i].optional = optional;
rld[i].inc = 0;
rld[i].nocombine = 0;
rld[i].in_reg = inloc ? *inloc : 0;
rld[i].out_reg = outloc ? *outloc : 0;
rld[i].opnum = opnum;
rld[i].when_needed = type;
rld[i].secondary_in_reload = secondary_in_reload;
rld[i].secondary_out_reload = secondary_out_reload;
rld[i].secondary_in_icode = secondary_in_icode;
rld[i].secondary_out_icode = secondary_out_icode;
rld[i].secondary_p = 0;
We still have a few uninitialized fields. When returning to find_reloads(),
from around line 4410, this happens:
/* Compute reload_mode and reload_nregs. */
for (i = 0; i < n_reloads; i++)
{
rld[i].mode
= (rld[i].inmode == VOIDmode
|| (GET_MODE_SIZE (rld[i].outmode)
> GET_MODE_SIZE (rld[i].inmode)))
? rld[i].outmode : rld[i].inmode;
rld[i].nregs = CLASS_MAX_NREGS (rld[i].class, rld[i].mode);
}
Both rld[i].outmode and rld[i].mode are now set to QImode and rld[i].nregs
becomes 1 instead of 2 because CLASS_MAX_NREGS() gets the wrong mode.
Later, we get to choose_reload_regs(), which calls allocate_reload_regs(),
which has some sort of spill reg round-robing caching mechanism and by pure
fluke picks register 5 the first time around. There are tests to filter out
invalid registers:
&& TEST_HARD_REG_BIT (reg_class_contents[class], regnum)
&& HARD_REGNO_MODE_OK (regnum, rld[r].mode)
HARD_REGNO_MODE_OK (5, HImode) returns 0, but we got the mode wrong
previously, so the test becomes HARD_REGNO_MODE_OK (5, QImode) which
returns 1. Finally, allocate_reload_regs() call set_reload_reg() to commit
the register choice.
It seems necessary to recover the mode of the operand when computing
rld[i].mode. There is operand_mode[rld[i].opnum] and in case of a "0"
constraint, I'm sure it is possible to find the matching operand too
somehow. Then that information can be used to ensure rld[i].mode is large
enough. Is there any reason that operand_mode[] would not be reliable?
--
Rask Ingemann Lambertsen