This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
combine mucking up the PA
- To: gcc-patches at gcc dot gnu dot org
- Subject: combine mucking up the PA
- From: Jeffrey A Law <law at cygnus dot com>
- Date: Thu, 13 Jan 2000 02:33:31 -0700
- Reply-To: law at cygnus dot com
Compile the attached testcase with -O1 on the PA (I'll be installing it
into the testsuite in a few minutes).
The basic problem is during substitution & simplification combine created
this ugly hunk of RTL:
(plus:SI (subreg:SI (if_then_else:DI (ne (reg:SI 107)
(const_int 0 [0x0]))
(mult:DI (zero_extend:DI (plus:SI (reg:SI 106)
(const_int -1 [0xffffffff])))
(zero_extend:DI (reg:SI 110)))
(mult:DI (zero_extend:DI (reg:SI 106))
(zero_extend:DI (reg:SI 110)))) 1)
(reg:SI 105))
Note carefully the embedded subreg.
We call if_then_else_cond on that mess. It ends up recursively calling
itself with this RTL:
(subreg:SI (if_then_else:DI (ne (reg:SI 107)
(const_int 0 [0x0]))
(mult:DI (zero_extend:DI (plus:SI (reg:SI 106)
(const_int -1 [0xffffffff])))
(zero_extend:DI (reg:SI 110)))
(mult:DI (zero_extend:DI (reg:SI 106))
(zero_extend:DI (reg:SI 110)))) 1)
We then call if_then_else_cond on SUBREG_REG (x) which returns the RTL
expressions for the true/false arms if the IF_THEN_ELSE.
true0 will be:
(mult:DI (zero_extend:DI (plus:SI (reg:SI 106)
(const_int -1 [0xffffffff])))
(zero_extend:DI (reg:SI 110)))
false0 will be:
(mult:DI (zero_extend:DI (reg:SI 106))
(zero_extend:DI (reg:SI 110)))) 1)
We then call operand_subword (true0, 1, 0, SImode). Since we're asking
for a word outside of SImode operand_subword returns const0_rtx. Similarly
for the call using false0.
So, we substitute const0_rtx for the two MULT expressions. This allows us
to simplify the initial big RTL expression to:
(if_then_else:SI (ne (reg:SI 107)
(const_int 0 [0x0]))
(reg:SI 105)
(reg:SI 105))
Which of course simplifies to (reg:SI 105). Which is horribly wrong.
Phew.
Here's the testcase:
struct x {
unsigned x1:1;
unsigned x2:2;
unsigned x3:3;
};
foobar (int x, int y, int z)
{
struct x a = {x, y, z};
struct x b = {x, y, z};
struct x *c = &b;
c->x3 += (a.x2 - a.x1) * c->x2;
if (a.x1 != 1 || c->x3 != 5)
abort ();
exit (0);
}
main()
{
foobar (1, 2, 3);
}
Here's the fix.
[BTW, one could argue operand_subword should have returned NULL instead of
const0_rtx in this case, but that doesn't actually fix the problem. ]
* combine.c (if_then_else_cond): Be careful about what kinds
of RTL expressions are passed to operand_subword.
Index: combine.c
===================================================================
RCS file: /cvs/cvsfiles/devo/gcc/combine.c,v
retrieving revision 1.213
diff -c -3 -p -r1.213 combine.c
*** combine.c 2000/01/11 14:58:56 1.213
--- combine.c 2000/01/13 09:31:50
*************** if_then_else_cond (x, ptrue, pfalse)
*** 7322,7328 ****
&& 0 != (cond0 = if_then_else_cond (SUBREG_REG (x),
&true0, &false0)))
{
! if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))) > UNITS_PER_WORD
&& (WORDS_BIG_ENDIAN || SUBREG_WORD (x) != 0))
{
true0 = operand_subword (true0, SUBREG_WORD (x), 0, mode);
--- 7322,7331 ----
&& 0 != (cond0 = if_then_else_cond (SUBREG_REG (x),
&true0, &false0)))
{
! if ((GET_CODE (SUBREG_REG (x)) == REG
! || GET_CODE (SUBREG_REG (x)) == MEM
! || CONSTANT_P (SUBREG_REG (x)))
! && GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))) > UNITS_PER_WORD
&& (WORDS_BIG_ENDIAN || SUBREG_WORD (x) != 0))
{
true0 = operand_subword (true0, SUBREG_WORD (x), 0, mode);