[cft] Fix pr42269 -- loss of incoming promotions in combine

Richard Sandiford rdsandiford@googlemail.com
Sat Dec 5 13:02:00 GMT 2009


Richard Henderson <rth@redhat.com> writes:
> As best I can tell, the extra sign extension seen in this pr is caused 
> by the patch in
>
>    http://gcc.gnu.org/ml/gcc-patches/2007-09/msg01534.html
>
> The problem is the brushed-over mention of "if the signedness matches", 
> and the addition of the test "uns1 == uns3", a condition that did not 
> exist before the patch.  As far as I can tell, it isn't necessary.
>
> On Alpha (and at least arm, mips, sh), ABI mandated promotions may not 
> match the sign of the real argument.  Which, for the purposes here in 
> combine, is perfectly fine.  We can record that an incoming register is 
> sign/zero extended from SI to DImode without regard to the source-level 
> sign of the SImode value.
>
> I don't have ready access to any target that would be affected by this 
> patch, so I'm asking for volunteers to do some testing.

Tests OK on mips64octeon-linux-gnu (all 3 ABIs).  But I think the
patch is too aggressive.  The case Mark was worried about was when:

   mode1 != mode2 != mode3

and where the mode1->mode2 (language) promotion was different from the
mode2->mode3 (ABI) promotion.  So I think the problem with the earlier
patch was that it checked "uns1 == uns3" unconditionally, rather than
when "mode1 != mode2".  I.e. I think we should be checking something
like this instead:

      if (mode1 != mode3
          && mode3 == mode4
	  && (mode1 == mode2 || (uns1 == uns3 && strictly_local)))

The following test catches the difference, and regresses if we
remove the "uns1 == uns3" check completely:

-----------------------------
static long long __attribute__((noinline)) foo (unsigned short s)
{
  return (short) s;
}

unsigned short s = 0xFFFF;

int
main (void)
{
  return foo (s) + 1 != 0;
}
-----------------------------

Richard



More information about the Gcc-patches mailing list