The below patch fixes what I think are a couple of problems with

  First, even if no regno is in_hard_reg_set_p, it goes ahead and
  considers rclass as valid. bad is set only if a regno is in the reg
  class *and* HARD_REGNO_MODE_OK is false - if both are false, bad isn't
  set and the reload gets a wrong rclass. If that happens to be the best
  one, this eventually leads to find_reg running out of registers to
  spill, because the chosen rclass won't have enough regs.

  Second, it expects every regno in rclass to be valid for mode i.e., if
  any regno fails HARD_REGNO_MODE_OK, it rejects the rclass. The
  comments in the original commit for find_valid_class_1 say atleast one
  regno is ok. This was updated to say "class which contains only
  registers" when in_hard_reg_set_p was introduced in place of just

  Is it meant to really test all regs? For the avr target, all regs are
  8 bits wide, and HARD_REGNO_MODE_OK returns false for odd regnos if
  mode != QImode. With the current code, it ignores a bunch of otherwise
  perfectly legal reg classes.

  To fix the first problem, the patch adds regno_in_rclass_mode to track
  whether there's atleast one regno in hard_reg_set_p. To fix the second
  problem, the patch sets bad initially, and resets it if
  HARD_REGNO_MODE_OK succeeded for a regno, thus breaking the loop.

  Of course, if both my points above are valid, we can do away with
  regno_in_rclass_mode, just bad would do.

  Does this make sense? I ran a reg test for the avr target with a
  slightly older version of this patch, it did not show any regressions.
  If this is the right fix, I'll make sure to run reg tests on x86_64
  after backporting to a gcc version where that target used reload.


Index: reload.c
--- reload.c    (revision 240185)
+++ reload.c    (working copy)
@@ -714,17 +714,22 @@
   for (rclass = 1; rclass < N_REG_CLASSES; rclass++)
-      int bad = 0;
-      for (regno = 0; regno < FIRST_PSEUDO_REGISTER && !bad; regno++)
-       {
-         if (in_hard_reg_set_p (reg_class_contents[rclass], mode, regno)
-             && !HARD_REGNO_MODE_OK (regno, mode))
-           bad = 1;
-       }
-      if (bad)
-       continue;
+      int bad = 1;
+      int regno_in_rclass_mode = 0;
+      for (regno = 0; regno < FIRST_PSEUDO_REGISTER && bad; regno++)
+        {
+          if (in_hard_reg_set_p (reg_class_contents[rclass], mode, regno))
+            {
+              regno_in_rclass_mode = 1;
+              if (HARD_REGNO_MODE_OK (regno, mode))
+                bad = 0;
+            }
+        }
+      if (bad || !regno_in_rclass_mode)
+        continue;
       cost = register_move_cost (outer, (enum reg_class) rclass, dest_class);
       if ((reg_class_size[rclass] > best_size

Reply via email to