wood@dg-rtp.dg.com (Tom Wood) (10/20/89)
I'm thoroughly stumped with this one. We're attempting to rev up to
1.36 with the m88k compiler. The code generated for this procedure
generates a bus error for the line "p->a = 5". Here's the test case:
typedef struct { int a:5; double b; } T;
void set_T(p)
T *p;
{
p->a = 5;
p->b = 2.0;
}
The body of the procedure is wrong when it is optimized. It is:
ld.b r11,r0,r2
st.b r11,r30,0x0008
ld r11,r30,0x0005 ; This is the bug.
mask r11,r11,0x0007
or r11,r11,0x0028
st r11,r30,0x000c
ld.b r11,r30,0x000f
st.b r11,r0,r2
or.u r11,r0,hi16(0x40000000) ; double 2.00000
or r12,r0,r0
st.d r11,r2,0x0008
A number of things are going wrong. I'll work backwards from the bogus
instruction. The instruction comes from the insn,
(insn 20 8 9 (set (reg:SI 11)
(mem:SI (plus:SI (reg:SI 30)
(const_int 5)))) 83 (nil)
(nil))
generated by alter_subreg. final_scan_insn uses alter_subreg on the insn
(insn 20 8 9 (set (reg:SI 11)
(subreg:SI (mem:QI (plus:SI (reg:SI 30)
(const_int 8))) 0)) 83 (nil)
(nil))
What is wrong here? Is this a valid translation? If so, then the insn
being altered is wrong. This insn is produced during global_alloc as a
result of spilling a pseudo register. This in itself is bogus. A
trivial program is causing a register spill!? Anyway, the insn (from
.c.lreg) in question,
(insn 8 6 9 (set (reg:QI 33)
(mem:QI (reg/v:SI 32))) 87 (insn_list 4 (nil))
(nil))
is translated into the three insns (from .c.greg),
(insn 19 6 8 (set (reg:QI 11)
(mem:QI (reg/v:SI 2))) -1 (nil)
(nil))
(insn:QI 8 19 20 (set (mem:QI (plus:SI (reg:SI 30)
(const_int 8)))
(reg:QI 11)) 87 (insn_list 4 (nil))
(nil))
(insn 20 8 9 (set (reg:SI 11)
(subreg:SI (mem:QI (plus:SI (reg:SI 30)
(const_int 8))) 0)) -1 (nil)
(nil))
Here are the insns after reload_as_needed has completed, but before
eliminating all pseudo registers. reload was called as the last action
of global_alloc.
(insn 19 6 8 (set (reg:QI 11)
(mem:QI (reg/v:SI 2))) -1 (nil)
(nil))
(insn:QI 8 19 20 (set (reg:QI 33)
(reg:QI 11)) 87 (insn_list 4 (nil))
(nil))
(insn 20 8 9 (set (reg:SI 11)
(subreg:SI (reg:QI 33) 0)) -1 (nil)
(nil))
I see two problems happening:
1) global_alloc is choosing to spill values it shouldn't.
2) When a register widening subreg is applied to a pseudo register
that is spilled, the subreg should go away.
All comments, suggestions, clues, and patches are welcome!
---
Tom Wood (919) 248-6067
Data General, Research Triangle Park, NC
{the known world}!rti!xyzzy!woodwood@dg-rtp.dg.com (Tom Wood) (10/21/89)
I found more about what is causing the widening subreg problem. A
change to expand_binop\optabs.c attempts to use widening subreg around
narrow operands to logical operators instead of only using convert_move
as was the case in 1.35. This works fine, and in fact saves
instructions in the non-optimized case. The trouble is that combine is
unable to deal with this construct in the same way it deals with
sign_extend & zero_extend. Here again is the test case:
typedef struct { unsigned int a:5; double b; } T;
void set_T(p)
T *p;
{
p->a = 5;
p->b = 2.0;
}
Here's the RTL after flow analysis (just before combine):
(insn 8 6 9 (set (reg:QI 33)
(mem:QI (reg/v:SI 32))) -1 (insn_list 4 (nil))
(nil))
(insn 9 8 10 (set (reg:SI 34)
(and:SI (subreg:SI (reg:QI 33) 0)
(const_int 7))) -1 (insn_list 8 (nil))
(expr_list:REG_DEAD (reg:QI 33)
(nil)))
(insn 10 9 11 (set (reg:QI 35)
(subreg:QI (reg:SI 34) 0)) -1 (insn_list 9 (nil))
(expr_list:REG_DEAD (reg:SI 34)
(nil)))
Combine produces this:
(insn 8 6 9 (set (reg:QI 33)
(mem:QI (reg/v:SI 32))) -1 (insn_list 4 (nil))
(nil))
(insn 9 8 10 (set (reg:SI 34)
(and:SI (subreg:SI (reg:QI 33) 0)
(const_int 7))) -1 (insn_list 8 (nil))
(expr_list:REG_DEAD (reg:QI 33)
(nil)))
The trouble is that unless these are combined further, later passes
go wrong. The RTL wants to look like this.
(insn 12 11 13 (set (reg:SI 38)
(and:SI (subreg:SI (mem:QI (reg/v:SI 32)) 0)
(const_int 7))) 236 (insn_list 11 (insn_list 10
(insn_list 9 (insn_list 8
(insn_list 4 (nil))))))
(nil))
My fix is truly a kludge. If you're not optimizing, go ahead with
the widening subreg form. Otherwise, explictitly use zero_extend or
sign_extend which combine is able to deal with. Here's the patch:
*** optabs.c.orig Fri Oct 20 17:37:58 1989
--- optabs.c Fri Oct 20 17:41:17 1989
***************
*** 308,314 ****
if (no_extend)
{
temp = force_reg (GET_MODE (xop0), xop0);
! xop0 = gen_rtx (optimize ? unsignedp ? ZERO_EXTEND : SIGN_EXTEND : SUBREG, wider_mode, temp, 0);
}
else
{
--- 308,314 ----
if (no_extend)
{
temp = force_reg (GET_MODE (xop0), xop0);
! xop0 = gen_rtx (SUBREG, wider_mode, temp, 0);
}
else
{
***************
*** 322,328 ****
if (no_extend)
{
temp = force_reg (GET_MODE (xop1), xop1);
! xop1 = gen_rtx (optimize ? unsignedp ? ZERO_EXTEND : SIGN_EXTEND : SUBREG, wider_mode, temp, 0);
}
else
{
--- 322,328 ----
if (no_extend)
{
temp = force_reg (GET_MODE (xop1), xop1);
! xop1 = gen_rtx (SUBREG, wider_mode, temp, 0);
}
else
{
Comments?
---
Tom Wood (919) 248-6067
Data General, Research Triangle Park, NC
{the known world}!rti!xyzzy!wood