simplify-rtx.c:simplify_binary_operation_1 simplifies certain cases of IOR to constants, but fails to check when doing so that it hasn't lost side effects in the nonconstant operand. This can cause wrong code generation (when called from combine) in certain cases where the constant operand only becomes visible for optimization at RTL optimization time (otherwise an equivalent optimization will happen earlier), and the nonconstant operand is a memory operand with a pre/post-modify address; the fix, adding side_effects_p calls, is straightforward (and I didn't find such issues elsewhere in simplify-rtx.c).
The above conditions make this problem quite hard to trigger, but it shows up in pcretest on ARM with -O2 -funroll-loops, and the patch includes an artificial testcase that shows the problem (again, -O2 -funroll-loops; or -O3 -fomit-frame-pointer -funroll-loops as used by c-torture; I don't have an example that shows the issue without -funroll-loops). Tested with no regressions with cross to arm-none-linux-gnueabi (--with-mode=thumb --with-arch=armv7-a), and bootstrapped with no regressions on x86_64-unknown-linux-gnu. OK to commit? 2012-08-08 Joseph Myers <jos...@codesourcery.com> * simplify-rtx.c (simplify_binary_operation_1): Do not simplify IOR to a constant if one operand has side effects. testsuite: 2012-08-08 Joseph Myers <jos...@codesourcery.com> * gcc.c-torture/execute/20120808-1.c: New test. Index: testsuite/gcc.c-torture/execute/20120808-1.c =================================================================== --- testsuite/gcc.c-torture/execute/20120808-1.c (revision 0) +++ testsuite/gcc.c-torture/execute/20120808-1.c (revision 0) @@ -0,0 +1,37 @@ +extern void exit (int); +extern void abort (void); + +volatile int i; +unsigned char *volatile cp; +unsigned char d[32] = { 0 }; + +int +main (void) +{ + unsigned char c[32] = { 0 }; + unsigned char *p = d + i; + int j; + for (j = 0; j < 30; j++) + { + int x = 0xff; + int y = *++p; + switch (j) + { + case 1: x ^= 2; break; + case 2: x ^= 4; break; + case 25: x ^= 1; break; + default: break; + } + c[j] = y | x; + cp = p; + } + if (c[0] != 0xff + || c[1] != 0xfd + || c[2] != 0xfb + || c[3] != 0xff + || c[4] != 0xff + || c[25] != 0xfe + || cp != d + 30) + abort (); + exit (0); +} Index: simplify-rtx.c =================================================================== --- simplify-rtx.c (revision 190186) +++ simplify-rtx.c (working copy) @@ -2420,7 +2420,9 @@ simplify_binary_operation_1 (enum rtx_co case IOR: if (trueop1 == CONST0_RTX (mode)) return op0; - if (INTEGRAL_MODE_P (mode) && trueop1 == CONSTM1_RTX (mode)) + if (INTEGRAL_MODE_P (mode) + && trueop1 == CONSTM1_RTX (mode) + && !side_effects_p (op0)) return op1; if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0)) return op0; @@ -2434,7 +2436,8 @@ simplify_binary_operation_1 (enum rtx_co /* (ior A C) is C if all bits of A that might be nonzero are on in C. */ if (CONST_INT_P (op1) && HWI_COMPUTABLE_MODE_P (mode) - && (nonzero_bits (op0, mode) & ~UINTVAL (op1)) == 0) + && (nonzero_bits (op0, mode) & ~UINTVAL (op1)) == 0 + && !side_effects_p (op0)) return op1; /* Canonicalize (X & C1) | C2. */ -- Joseph S. Myers jos...@codesourcery.com