Building the following test case with current mainline on i386: unsigned short test (unsigned char val) __attribute__ ((noinline)); unsigned short test (unsigned char val) { return val * 255; } int main(int argc, char**argv) { printf ("test(val=40) = %x\n", test(0x40)); return 0; } We get the following (correct) output with -O0: test(val=40) = 3fc0 and the following incorrect output with -O2: test(val=40) = ffc0 The problem appears to be related to this piece of code in expand_expr_real2, case WIDEN_MULT_EXPR: expand_operands (treeop0, treeop1, NULL_RTX, &op0, &op1, EXPAND_NORMAL); temp = expand_widening_mult (mode, op0, op1, target, unsignedp, this_optab); expand_operands will expand the constant 255 into QImode and return a (const_int -1) for op1. Passing this constant into expand_widening_mult then apparently generates a simple negation operation in HImode instead (via expand_const_mult) ... It seems this code came in here: http://gcc.gnu.org/ml/gcc-patches/2010-04/msg01327.html Any suggestions how this ought to be handled?
On Fri, 14 Jan 2011, uweigand at gcc dot gnu.org wrote: > http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47299 > > Summary: Widening multiply optimization generates bad code > Product: gcc > Version: 4.5.0 > Status: UNCONFIRMED > Keywords: wrong-code > Severity: normal > Priority: P3 > Component: rtl-optimization > AssignedTo: unassigned@gcc.gnu.org > ReportedBy: uweigand@gcc.gnu.org > CC: bernds@codesourcery.com, rguenther@suse.de > > > Building the following test case with current mainline on i386: > > unsigned short test (unsigned char val) __attribute__ ((noinline)); > > unsigned short > test (unsigned char val) > { > return val * 255; > } > > int > main(int argc, char**argv) > { > printf ("test(val=40) = %x\n", test(0x40)); > return 0; > } > > We get the following (correct) output with -O0: > test(val=40) = 3fc0 > > and the following incorrect output with -O2: > test(val=40) = ffc0 > > The problem appears to be related to this piece of code in expand_expr_real2, > case WIDEN_MULT_EXPR: > > expand_operands (treeop0, treeop1, NULL_RTX, &op0, &op1, > EXPAND_NORMAL); > temp = expand_widening_mult (mode, op0, op1, target, > unsignedp, this_optab); > > expand_operands will expand the constant 255 into QImode and return a > (const_int -1) for op1. Passing this constant into expand_widening_mult then > apparently generates a simple negation operation in HImode instead (via > expand_const_mult) ... > > It seems this code came in here: > http://gcc.gnu.org/ml/gcc-patches/2010-04/msg01327.html > Any suggestions how this ought to be handled? I think we need to pass the narrow mode explicitly. Richard.
4.5/4.6 regression
It is a 4.6 regression. 4.5 branch is OK.
Created attachment 22994 [details] gcc46-pr47299.patch Untested fix.
a biarch build for yesterday's trunk on i686 with the proposed patch applied succeeds and doesn't show any regressions.
Author: jakub Date: Tue Jan 18 07:45:12 2011 New Revision: 168944 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=168944 Log: PR rtl-optimization/47299 * expr.c (expand_expr_real_2) <case WIDEN_MULT_EXPR>: Don't use subtarget. Use normal multiplication if both operands are constants. * expmed.c (expand_widening_mult): Don't try to optimize constant multiplication if op0 has VOIDmode. Convert op1 constant to mode before using it. * gcc.c-torture/execute/pr47299.c: New test. Added: trunk/gcc/testsuite/gcc.c-torture/execute/pr47299.c Modified: trunk/gcc/ChangeLog trunk/gcc/expmed.c trunk/gcc/expr.c trunk/gcc/testsuite/ChangeLog
Fixed.