Hi! Several places in wi::mul_internal didn't handle high parameter and would return the low bits instead of high bits.
Fixed thusly, bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2014-07-03 Jakub Jelinek <ja...@redhat.com> PR tree-optimization/61682 * wide-int.cc (wi::mul_internal): Handle high correctly for umul_ppmm using cases and when one of the operands is equal to 1. * gcc.c-torture/execute/pr61682.c: New test. --- gcc/wide-int.cc.jj 2014-05-30 10:51:11.000000000 +0200 +++ gcc/wide-int.cc 2014-07-03 09:35:11.084228924 +0200 @@ -1,5 +1,5 @@ /* Operations with very long integers. - Copyright (C) 2012-2013 Free Software Foundation, Inc. + Copyright (C) 2012-2014 Free Software Foundation, Inc. Contributed by Kenneth Zadeck <zad...@naturalbridge.com> This file is part of GCC. @@ -1282,6 +1282,12 @@ wi::mul_internal (HOST_WIDE_INT *val, co && wi::fits_uhwi_p (op1) && wi::fits_uhwi_p (op2)) { + /* This case never overflows. */ + if (high) + { + val[0] = 0; + return 1; + } umul_ppmm (val[1], val[0], op1.ulow (), op2.ulow ()); return 1 + (val[1] != 0 || val[0] < 0); } @@ -1294,6 +1300,8 @@ wi::mul_internal (HOST_WIDE_INT *val, co umul_ppmm (upper, val[0], op1.ulow (), op2.ulow ()); if (needs_overflow) *overflow = (upper != 0); + if (high) + val[0] = upper; return 1; } } @@ -1302,12 +1310,28 @@ wi::mul_internal (HOST_WIDE_INT *val, co /* Handle multiplications by 1. */ if (op1 == 1) { + if (high) + { + if (sgn == SIGNED && wi::neg_p (op2)) + val[0] = -1; + else + val[0] = 0; + return 1; + } for (i = 0; i < op2len; i++) val[i] = op2val[i]; return op2len; } if (op2 == 1) { + if (high) + { + if (sgn == SIGNED && wi::neg_p (op1)) + val[0] = -1; + else + val[0] = 0; + return 1; + } for (i = 0; i < op1len; i++) val[i] = op1val[i]; return op1len; --- gcc/testsuite/gcc.c-torture/execute/pr61682.c.jj 2014-03-19 15:57:57.735114622 +0100 +++ gcc/testsuite/gcc.c-torture/execute/pr61682.c 2014-07-03 09:40:26.215520476 +0200 @@ -0,0 +1,17 @@ +/* PR tree-optimization/61682 */ + +int a, b; +static int *c = &b; + +int +main () +{ + int *d = &a; + for (a = 0; a < 12; a++) + *c |= *d / 9; + + if (b != 1) + __builtin_abort (); + + return 0; +} Jakub