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.