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]

Reply via email to