This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

combine mucking up the PA



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);








Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]