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