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!wood
wood@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