https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82180

            Bug ID: 82180
           Summary: assign_spill_hard_regs spills to unaligned register
                    pair
           Product: gcc
           Version: unknown
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: rtl-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: vries at gcc dot gnu.org
  Target Milestone: ---

Consider the gcn target (currently only available upstream on the gcn branch).
For SGPR regs, it requires aligned register pairs, in other words (r0, r1) is
ok, but (r1, r2) is not ok, and gcn_hard_regno_mode_ok is setup accordingly.

However, I'm running into spills being generated by lra using an unaligned
register pair (in this case, it's (r67, r77)):
...
;(insn 53501 58177 3793 633 (set (reg:DI 67 s67)
;        (reg:DI 42 s42 [4460])) "minlocval_3.f90":59 16 {*movdi_insn}
;     (nil))
...
The compiler finishes without problems, but the assembler complains.

I've traced the introduction of the unaligned register pair back to
assign_spill_hard_regs. Using this patch, I can detect the problem at runtime:
...
diff --git a/gcc/lra-spills.c b/gcc/lra-spills.c
index 492fc18..476ce3d 100644
--- a/gcc/lra-spills.c
+++ b/gcc/lra-spills.c
@@ -71,6 +71,7 @@ along with GCC; see the file COPYING3.        If not see
 #include "cfgrtl.h"
 #include "lra.h"
 #include "lra-int.h"
+#include "tm_p.h"


 /* Max regno at the start of the pass. */
@@ -292,6 +293,7 @@ assign_spill_hard_regs (int *pseudo_regnos, int n)
        for (p = r->start; p <= r->finish; p++)
          add_to_hard_reg_set (&reserved_hard_regs[p],
                               lra_reg_info[regno].biggest_mode, hard_regno);
+      gcc_assert (HARD_REGNO_MODE_OK (hard_regno, PSEUDO_REGNO_MODE (regno)));
       spill_hard_reg[regno]
        = gen_raw_REG (PSEUDO_REGNO_MODE (regno), hard_regno);
       for (nr = 0;
...

Trying a bit harder, I can fix the problem by skipping over the unaligned
register here:
...
diff --git a/gcc/lra-spills.c b/gcc/lra-spills.c
index 492fc18..6ecfad2 100644
--- a/gcc/lra-spills.c
+++ b/gcc/lra-spills.c
@@ -276,7 +276,10 @@ assign_spill_hard_regs (int *pseudo_regnos, int n)
       for (k = 0; k < spill_class_size; k++)
        {
          hard_regno = ira_class_hard_regs[spill_class][k];
-         if (! overlaps_hard_reg_set_p (conflict_hard_regs, mode, hard_regno))
+         if (! ira_prohibited_class_mode_regs[spill_class][PSEUDO_REGNO_MODE
(regno)]
+             && ! overlaps_hard_reg_set_p (conflict_hard_regs, mode,
+                                           hard_regno))
            break;
        }
       if (k >= spill_class_size)
...

Unfortunately, I've not yet managed to reproduce this problem on an upstream
branch.

Reply via email to