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]