Bernd Schmidt <[EMAIL PROTECTED]> writes: > Reload insns aren't themselves reloaded. You should look at the > SECONDARY_*_RELOAD_CLASS; they'll probably let you do what you want.
Ah, thank you! I've defined SECONDARY_*_RELOAD_CLASS (and PREFERRED_* to try to help things along), and am now running into more understandable reload problems: "unable to find a register to spill in class" :-/ The problem, as I understand, is that reload doesn't deal with conflicts between secondary and primary reloads -- which are common with my arch because it's an accumulator architecture. For instance, slightly modifying my previous example: Say I've got a mov instruction that only works via an accumulator A, and a two-operand add instruction. "r" regclass includes regs A,X,Y, and "a" regclass only includes reg A. mov has constraints like: 0 = "g,a" 1 = "a,gi" and add3 has constraints: 0 = "a" 1 = "0" 2 = "ri" (say) So if before reload you've got an instruction like: add temp, [sp + 4], [sp + 6] and v2 and v3 are in memory, it will have to have generate something like: mov A, [sp + 4] ; primary reload 1 in X, with secondary reload 0 A mov X, A ; "" mov A, [sp + 6] ; primary reload 2 in A, with no secondary reload add A, X mov temp, A There's really only _one_ register that can be used for many reloads, A. The problem is that reload doesn't seem to be able to produce this kind of output: if it chooses A as a primary reload (common, as most insns use A as a first operand), reload will think it conflicts with secondary reloads that also use A (when it really needn't, as the secondary reloads only use A "temporarily"). This is particularly bad with RELOAD_OTHER reloads, as I kludged around this to some degree by changing `reload_conflicts' (reload1.c) to always think secondary reloads _don't_ conflict [see patch1]. As that will fail in the case where a primary reload is loaded before a secondary reload using the same register, I _also_ modified `emit_reload_insns' to sort the order in which operand reloads are output so that an operand who's secondary reload interferes with another operand's primary reload is always loaded first. However I think this is not guaranteed to always work -- certainly merely disregarding conflicts with secondary reloads will fail for architectures which are slightly less anemic, say with _two_ accumulators... :_) Does anybody have a hint for a way to solve this problem? Reload is very confusing... Thanks, -Miles ===== patch1 ===== --- gcc-3.4.3/gcc/reload1.c 2004-05-02 21:37:17.000000000 +0900 +++ gcc-3.4.3-supk0-20050317/gcc/reload1.c 2005-03-17 19:49:35.935534000 +0900 @@ -1680,7 +1688,7 @@ find_reg (struct insn_chain *chain, int order) { int other = reload_order[k]; - if (rld[other].regno >= 0 && reloads_conflict (other, rnum)) + if (rld[other].regno >= 0 && reloads_conflict (other, rnum, 0)) for (j = 0; j < rld[other].nregs; j++) SET_HARD_REG_BIT (used_by_other_reload, rld[other].regno + j); } @@ -4601,18 +4609,25 @@ } /* Return 1 if the reloads denoted by R1 and R2 cannot share a register. - Return 0 otherwise. + Return 0 otherwise. If SECONDARIES_CAN_CONFLICT is zero, secondary + reloads are considered never to conflict; otherwise they are treated + normally. This function uses the same algorithm as reload_reg_free_p above. */ int -reloads_conflict (int r1, int r2) +reloads_conflict (int r1, int r2, int secondaries_can_conflict) { enum reload_type r1_type = rld[r1].when_needed; enum reload_type r2_type = rld[r2].when_needed; int r1_opnum = rld[r1].opnum; int r2_opnum = rld[r2].opnum; + /* Secondary reloads need not conflict with anything. */ + if (!secondaries_can_conflict + && (rld[r1].secondary_p || rld[r2].secondary_p)) + return 0; + /* RELOAD_OTHER conflicts with everything. */ if (r2_type == RELOAD_OTHER) return 1; ===== patch2 ===== --- gcc-3.4.3/gcc/reload1.c 2004-05-02 21:37:17.000000000 +0900 +++ gcc-3.4.3-supk0-20050317/gcc/reload1.c 2005-03-17 19:49:35.935534000 +0900 @@ -6951,6 +6966,51 @@ emit_reload_insns (struct insn_chain *chain) do_output_reload (chain, rld + j, j); } +#ifdef SECONDARY_INPUT_RELOAD_CLASS + for (j = 0; j < reload_n_operands; j++) + opnum_emit_pos[j] = emit_pos_opnum[j] = j; + + /* Order the operands to avoid conflicts between the primary reload of + one operand and a secondary reload in another operand (which we + ignored before). XXX this only works for input reloads!! */ + for (j = 0; j < n_reloads; j++) + if (rld[j].secondary_p) + /* This is a secondary reload; see if it should go before something + else. */ + { + int i; + int this_opnum = rld[j].opnum; + int cur_emit_pos = opnum_emit_pos[this_opnum]; + int new_emit_pos = cur_emit_pos; + + for (i = j; i >= 0; i--) + if (opnum_emit_pos[rld[i].opnum] < new_emit_pos + && !rld[i].secondary_p + && reloads_conflict (j, i, 1)) + new_emit_pos = opnum_emit_pos[rld[i].opnum]; + + if (new_emit_pos < cur_emit_pos) + { + for (i = cur_emit_pos; i > new_emit_pos; i--) + emit_pos_opnum[i] = emit_pos_opnum[i - 1]; + emit_pos_opnum[new_emit_pos] = this_opnum; + + for (i = 0; i < reload_n_operands; i++) + opnum_emit_pos[emit_pos_opnum[i]] = i; + } + } + + fprintf (stderr, "========================================\n"); + fprintf (stderr, "emit_pos_opnum ="); + for (j = 0; j < reload_n_operands; j++) + fprintf (stderr, " %d", emit_pos_opnum[j]); + putc ('\n', stderr); + fprintf (stderr, "opnum_emit_pos ="); + for (j = 0; j < reload_n_operands; j++) + fprintf (stderr, " %d", opnum_emit_pos[j]); + putc ('\n', stderr); +#endif + /* Now write all the insns we made for reloads in the order expected by the allocation functions. Prior to the insn being reloaded, we write the following reloads: @@ -6975,25 +7035,27 @@ reloads for the operand. The RELOAD_OTHER output reloads are output in descending order by reload number. */ - emit_insn_before (other_input_address_reload_insns, insn); - emit_insn_before (other_input_reload_insns, insn); - for (j = 0; j < reload_n_operands; j++) { - emit_insn_before (inpaddr_address_reload_insns[j], insn); - emit_insn_before (input_address_reload_insns[j], insn); - emit_insn_before (input_reload_insns[j], insn); + int emit = emit_pos_opnum[j]; + emit_insn_before (inpaddr_address_reload_insns[emit], insn); + emit_insn_before (input_address_reload_insns[emit], insn); + emit_insn_before (input_reload_insns[emit], insn); } + emit_insn_before (other_input_address_reload_insns, insn); + emit_insn_before (other_input_reload_insns, insn); + emit_insn_before (other_operand_reload_insns, insn); emit_insn_before (operand_reload_insns, insn); for (j = 0; j < reload_n_operands; j++) { - rtx x = emit_insn_after (outaddr_address_reload_insns[j], insn); - x = emit_insn_after (output_address_reload_insns[j], x); - x = emit_insn_after (output_reload_insns[j], x); - emit_insn_after (other_output_reload_insns[j], x); + int emit = emit_pos_opnum[j]; + rtx x = emit_insn_after (outaddr_address_reload_insns[emit], insn); + x = emit_insn_after (output_address_reload_insns[emit], x); + x = emit_insn_after (output_reload_insns[emit], x); + emit_insn_after (other_output_reload_insns[emit], x); } /* For all the spill regs newly reloaded in this instruction, -- "An atheist doesn't have to be someone who thinks he has a proof that there can't be a god. He only has to be someone who believes that the evidence on the God question is at a similar level to the evidence on the werewolf question." [John McCarthy]