https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116429
Michael Matz <matz at gcc dot gnu.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
CC| |matz at gcc dot gnu.org
--- Comment #1 from Michael Matz <matz at gcc dot gnu.org> ---
This is a problem in LRAs setup_sp_offset. The per-insn sp_offset item is
supposed to reflect the sp_offset before the insn in question. So, we
(correctly) start with this sequence of insns before LRA, and figure out
(again,
correctly) the sp_offsets noted:
we start at sp_off = 0
550: [--sp] = 0 sp_off = 0 {pushexthisi_const}
551: [--sp] = 37 sp_off = -4 {pushexthisi_const}
552: [--sp] = r37 sp_off = -8 {movsi_m68k2}
554: [--sp] = r116 - r37 sp_off = -12 {subsi3}
556: call sp_off = -16
Now, insn 554 (subsi3) doesn't match constraints, the destination is a reg,
needs to match the first input. So we generate reloads:
Creating newreg=262, assigning class DATA_REGS to r262
554: r262:SI=r262:SI-r37:SI
REG_ARGS_SIZE 0x10
Inserting insn reload before:
996: r262:SI=r116:SI
Inserting insn reload after:
997: [--%sp:SI]=r262:SI
Considering alt=0 of insn 997: (0) =g (1) damSKT
1 Non pseudo reload: reject++
overall=1,losers=0,rld_nregs=0
Choosing alt 0 in insn 997: (0) =g (1) damSKT {*movsi_m68k2}
(sp_off=-16)
Note how insn 997 (the after-reload) now has sp_off=-16 already. It all
goes downhill from there. We end up with these insns:
552: [--sp] = r37 sp_off = -8 {movsi_m68k2}
996: r262 = r116 sp_off = -12
554: r262 = r262 - r37 sp_off = -12
997: [--sp] = r262 sp_off = -16 (!!! should be -12)
556: call sp_off = -16
The call insn sp_off remains at the correct -16, but internally it's already
inconsistent here. If the sp_off before and insn is -16, and that insn
pre_decs sp, then the after-insn sp_off should be -20.
This is all because setup_sp_offset updates the sp_offset for new insns
incorrectly. It tries to setup it for the whole (new) insn sequence in order,
but for mysterious reasons starts off with the given sp_offset from the
_next_ instruction after the last insn in the new seq. That can't ever be
right. The sp-offset simulation runs in a forward direction (via NEXT_INSN).
The only connection to sp_offset of the next insn after the sequence is that
the offset should end up being equal to that one after simulating the sequence.
(Note how the local varname for the startup point is called 'before' :) )
It's possible that sometime it is correct that the sp_off of the after-last
insn is the correct one to start with. But then also the simulation of the
insn sequence needs to run backward, not forward. Generally that probably
can only be decided if setup_sp_offset is given information about on which
of the borders of the sequence it can rely. But as written it's internally
inconsistent. Making it consistent as per below fixes this instance of
the problem. I wouldn't be surprised if it introduces bugs elsewhere,
in which case setup_sp_offset really needs to be amended by more information.
diff --git a/gcc/lra.cc b/gcc/lra.cc
index fb32e134004..5afb21c3ea6 100644
--- a/gcc/lra.cc
+++ b/gcc/lra.cc
@@ -1868,9 +1868,13 @@ push_insns (rtx_insn *from, rtx_insn *to)
static poly_int64
setup_sp_offset (rtx_insn *from, rtx_insn *last)
{
- rtx_insn *before = next_nonnote_nondebug_insn_bb (last);
- poly_int64 offset = (before == NULL_RTX || ! INSN_P (before)
- ? 0 : lra_get_insn_recog_data (before)->sp_offset);
+ //rtx_insn *before = next_nonnote_nondebug_insn_bb (last);
+ rtx_insn *before = prev_nonnote_nondebug_insn_bb (from);
+ poly_int64 offset = 0;
+
+ if (before && INSN_P (before))
+ offset = lra_update_sp_offset (PATTERN (before),
+ lra_get_insn_recog_data
(before)->sp_offset);
for (rtx_insn *insn = from; insn != NEXT_INSN (last); insn = NEXT_INSN
(insn))
{