This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
Reload bug for PRE/POST INC/DEC targets, need advice
- To: gcc-bugs at gcc dot gnu dot org
- Subject: Reload bug for PRE/POST INC/DEC targets, need advice
- From: Toshiyasu Morita <tm at netcom dot com>
- Date: Sat, 22 Jan 2000 04:19:08 -0800 (PST)
I believe I have found a bug in reload for pre/post dec/inc targets.
I found this bug in an older source tree, but I have looked at the
egcs-current code, and it appears the problem still exists in the
current cosebase.
The problem is, I don't see an easy way to fix it, so advice would
be greatly appreciated.
Here is the tesetcase where I originally found the problem:
23646:m3dprep.ii **** int FaceFlags = (FacePtr->flags & (GlobalFaceFlags >> 16)) | (GlobalFaceFlags & 0xFFFF);
52350 20a8 5090 mov.w .L1973,r0
52351 20aa 0279 add #2,r9
52352 20ac 960E mov.l r9,@(r0,r14)
52353 20ae FE79 add #-2,r9
52354 20b0 4D90 mov.w .L1974,r0
52355 20b2 9561 mov.w @r9+,r1 <- here
52356 20b4 1D63 extu.w r1,r3
52357 20b6 036C mov r0,r12
52358 20b8 EE01 mov.l @(r0,r14),r1
52359 20ba EC3C add r14,r12
52360 20bc C16C mov.w @r12,r12
52361 20be 2941 shlr16 r1
52362 20c0 1923 and r1,r3
52363 20c2 CD61 extu.w r12,r1
52364 20c4 1B23 or r1,r3
...
23655:m3dprep.ii **** *TextureIdxPtr = FacePtr->textureidx&0x003FF;
52424 .L_B777:
52425 20e0 3791 mov.w .L1977,r1
52426 20e2 2790 mov.w .L1959,r0
52427 20e4 9452 mov.l @(16,r9),r2 <- here
52428 20e6 1922 and r1,r2
52429 20e8 EE0D mov.l @(r0,r14),r13
As you can see above, r9 is used for a post-increment word read,
then subsequently used for a longword read. The Hitachi SH series is a
STRICT_ALIGNMENT target, so an exception is triggered on the second
access.
Here is the pre-greg (post-lreg) dump of the relevant insns:
(note 7752 7751 10736 ("m3dprep.ii") 23646)
(insn 10736 7752 7754 (set (reg:SI 4099)
(reg/v:SI 2973)) 123 {movsi_ie} (nil)
(nil))
(insn 7754 10736 7755 (set (reg:HI 2989)
(mem/s:HI (post_inc:SI (reg:SI 4099)))) 130 {movhi_i} (insn_list 10736 (nil))
(expr_list:REG_INC (reg:SI 4099)
(nil)))
...
(insn 7787 7785 7789 (set (reg:SI 2998)
(mem/s:SI (plus:SI (reg/v:SI 2973)
(const_int 16)))) 123 {movsi_ie} (nil)
(nil))
Here's the dump post-greg:
(note 7752 7751 13367 ("m3dprep.ii") 23646)
(insn 13367 7752 13368 (set (reg:SI 13 r13)
(const_int 700)) -1 (nil)
(nil))
(insn 13368 13367 10736 (set (reg:SI 13 r13)
(plus:SI (reg:SI 13 r13)
(reg:SI 14 r14))) 18 {addsi3} (nil)
(expr_list:REG_EQUIV (plus:SI (reg:SI 14 r14)
(const_int 700))
(nil)))
(note:HI 10736 13368 13369 "" NOTE_INSN_DELETED)
(insn 13369 10736 13372 (set (reg/v:SI 9 r9)
(plus:SI (reg/v:SI 9 r9)
(const_int 2))) -1 (nil)
(nil))
(insn 13372 13369 13373 (set (mem:SI (plus:SI (reg:SI 13 r13)
(const_int 20)))
(reg/v:SI 9 r9)) -1 (nil)
(nil))
(insn 13373 13372 7754 (set (reg/v:SI 9 r9)
(plus:SI (reg/v:SI 9 r9)
(const_int -2))) -1 (nil)
(nil))
(insn:HI 7754 13373 7755 (set (reg:HI 1 r1)
(mem/s:HI (post_inc:SI (reg/v:SI 9 r9)))) 130 {movhi_i} (insn_list 10736 (nil))
(expr_list:REG_INC (reg/v:SI 9 r9)
(nil)))
...
(note 7784 7783 7785 ("m3dprep.ii") 23655)
(note 7785 7784 7787 "" NOTE_INSN_DELETED)
;; Start of basic block 21, registers live: 14 [r14] 15 [r15] 48 [fpscr] 58 59 2973 2974 2975 2976 2977 2981 2986 2987 3006 3016 3017 3020 3083 3390 3553 3555 3744 4074 4096 4097 4098 4101 4108 4139 4143 4147 4151 4155 4159 4163
(insn:HI 7787 7785 7789 (set (reg:SI 2 r2)
(mem/s:SI (plus:SI (reg/v:SI 9 r9)
(const_int 16)))) 123 {movsi_ie} (nil)
(nil))
Basically, greg is signing both pseudos 2973 and 4099
to r9. The bug isn't in global_conflicts, because a check of the
conflict graph reveals that a conflict is properly detected:
;; 2973 conflicts: 53 58 59 2973 2974 2975 2976 2977 2981 2986 2987 2998 3000 3002 3006 3016 3017 3020 3083 3299 3300 3319 3331 3332 3333 3334 3335 3362 3390 3408 3442 3476 3510 3538 3540 3544 3546 3548 3553 3555 3575 3606 3637 3744 4074 4096 4097 4098 40
99 4101 4108 4139 4143 4147 4151 4155 4159 4163 1 2 3 4 5 6 15 22 25 48
...
;; 4099 conflicts: 58 59 2973 2974 2975 2976 2977 2981 2986 2987 3006 3016 3017 3020 3083 3299 3319 3331 3332 3333 3334 3335 3362 3390 3408 3442 3476 3510 3538 3540 3544 3546 3548 3553 3555 3575 3606 3637 3744 4074 4096 4097 4098 4099 4101 4108 4139 4143
4147 4151 4155 4159 4163 1 2 3 4 5 6 15 22 25 48
After a lot of debugging, I've determined that the real problem is actually
in emit_reload_insns(). The gist of the problem is that emit_reload_insns()
does not differentiate between a pseudo being spilled to the stack
and a pseudo being copied to another pseudo which is on the stack,
and in the latter case sets reg_last_reload_reg[] incorrectly.
What happens in this particular sample is:
pseudo 2973 = allocated to r9
pseudo 4099 = on stack, at r14 + 720
So, as emit_reload_insns() is entered the insn looks like:
(insn:HI 10736 13368 7754 (set (mem:SI (plus:SI (reg:SI 14 r14)
(const_int 700))
(const_int 20)))
(reg/v SI 9 r9)) 123 {movsi_ie} (nil)
(nil))
Execution proceeds through the function to this code sequence:
if (src_reg && GET_CODE (src_reg) == REG
&& REGNO (src_reg) < FIRST_PSEUDO_REGISTER)
{
int src_regno = REGNO (src_reg);
int nr = HARD_REGNO_NREGS (src_regno, reload_mode[r]);
/* The place where to find a death note varies with
PRESERVE_DEATH_INFO_REGNO_P . The condition is not
necessarily checked exactly in the code that moves
notes, so just check both locations. */
rtx note = find_regno_note (insn, REG_DEAD, src_regno);
if (! note)
note = find_regno_note (store_insn, REG_DEAD, src_regno);
while (nr-- > 0)
{
spill_reg_store[src_regno + nr] = store_insn;
spill_reg_stored_to[src_regno + nr] = out;
reg_reloaded_contents[src_regno + nr] = nregno;
SET_HARD_REG_BIT (reg_reloaded_valid, src_regno + nr);
SET_HARD_REG_BIT (reg_is_output_reload, src_regno + nr);
if (note)
SET_HARD_REG_BIT (reg_reloaded_died, src_regno);
else
CLEAR_HARD_REG_BIT (reg_reloaded_died, src_regno);
}
reg_last_reload_reg[nregno] = src_reg; <- here
}
When execution reaches the last assignment in this code:
regno = 4099
src_reg = (reg/v:SI 9 r9)
Basically, this code is recording that pseudo 4099 is currently in r9,
which is wrong!
This is why it's important to differentiate between a pseudo spilled to
the stack versus a pseudo copied to a pseudo in a stack slot.
In the former case, this code is correct, because the hard reg does
currently hold the value of the destination pseudo reg.
However, in the latter case, the hard reg does NOT hold the value
of the destination reg. The hard reg contains the value of the source
pseudo reg, and this is not changed by the copy. The hard reg needs
to retain equivalance with the source pseudo reg.
After this incorrect data is generated, choose_reload_regs() is called
for insn 7754, which looks like:
(insn 7754 10736 7755 (set (reg:HI 2989)
(mem/s:HI (post_inc:SI (reg:SI 4099)))) 130 {movhi_i} (insn_list 10736 (nil))
(expr_list:REG_INC (reg:SI 4099)
(nil)))
Code execution reaches this block of code in choose_reload_regs():
if (regno >= 0 && reg_last_reload_reg[regno] != 0)
{
enum reg_class class = reload_reg_class[r], last_class;
rtx last_reg = reg_last_reload_reg[regno];
...(lots of code deleted here, including conditionals)...
else
{
int k;
/* We can use this as a reload reg. */
/* Mark the register as in use for this part of
the insn. */
mark_reload_reg_in_use (i,
reload_opnum[r],
reload_when_needed[r],
reload_mode[r]);
reload_reg_rtx[r]
= (GET_MODE (last_reg) == mode
? last_reg
: gen_rtx_REG (mode,
REGNO (last_reg) + word));
reload_inherited[r] = 1;
reload_inheritance_insn[r]
= reg_reloaded_insn[i];
reload_spill_index[r] = i;
for (k = 0; k < nr; k++)
SET_HARD_REG_BIT (reload_reg_used_for_inherit,
i + k);
}
Basically, all the conditionals are evaluated as true and reload_inherited[4099]
is set to 1, and later in emit_reload_insns() the inherited reload is detected
and the incorrect substitution queued.
I can think of two ways to fix this bug:
1) Properly record r9 as containing pseudo 2973.
This doesn't appear to be possible because the information that r9 currently
contains pseudo 2973 isn't retained anywhere by reload?
2) Record the equivalence only if r9 is being copied to its assigned stack slot.
The only problem I see is that reg_equiv_memory_location looks like:
(mem:SI (plus:SI (reg:SI 14 r14)
(const int 720)))
but our insn rtx contains:
(mem:SI (plus:SI (reg:SI 14 r14)
(const_int 700))
(const_int 20)
Given this data, what's the best way to fix this bug?
Toshi