Hi! As described in the PR, the problem here is that during combine i2 pattern is substituted into more than one place in i3 pattern, unique_copy is 0 (but, even if it would be non-zero, it could happen if the comparison was processed first before the normal set inside of the parallel) and thus the same RTL is (temporarily) shared between two locations. force_to_mode is first called with mask 0xdc36 (that is actually find for both occurrences in the andhi_2 pattern) and later on inside of the comparison again with mask 0x8000, and as it modifies the IF_THEN_ELSE in place, it modifies also the other location (it is fine if the comparison uses 0x8000 mask, but not in the other spot). As in the end we fold it to a constant, we don't undo it and use incorrect constant.
Fixed by making sure force_to_mode doesn't modify x in place. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk/4.8? 2013-12-03 Jakub Jelinek <ja...@redhat.com> PR rtl-optimization/58726 * combine.c (force_to_mode): Fix comment typo. Don't destructively modify x for ROTATE, ROTATERT and IF_THEN_ELSE. * gcc.c-torture/execute/pr58726.c: New test. --- gcc/combine.c.jj 2013-12-02 14:33:34.000000000 +0100 +++ gcc/combine.c 2013-12-03 20:37:25.140274452 +0100 @@ -8029,7 +8029,7 @@ force_to_mode (rtx x, enum machine_mode if (code == CALL || code == ASM_OPERANDS || code == CLOBBER) return x; - /* We want to perform the operation is its present mode unless we know + /* We want to perform the operation in its present mode unless we know that the operation is valid in MODE, in which case we do the operation in MODE. */ op_mode = ((GET_MODE_CLASS (mode) == GET_MODE_CLASS (GET_MODE (x)) @@ -8460,9 +8460,10 @@ force_to_mode (rtx x, enum machine_mode gen_int_mode (mask, GET_MODE (x)), XEXP (x, 1)); if (temp && CONST_INT_P (temp)) - SUBST (XEXP (x, 0), - force_to_mode (XEXP (x, 0), GET_MODE (x), - INTVAL (temp), next_select)); + x = simplify_gen_binary (code, GET_MODE (x), + force_to_mode (XEXP (x, 0), GET_MODE (x), + INTVAL (temp), next_select), + XEXP (x, 1)); } break; @@ -8530,14 +8531,16 @@ force_to_mode (rtx x, enum machine_mode /* We have no way of knowing if the IF_THEN_ELSE can itself be written in a narrower mode. We play it safe and do not do so. */ - SUBST (XEXP (x, 1), - gen_lowpart_or_truncate (GET_MODE (x), - force_to_mode (XEXP (x, 1), mode, - mask, next_select))); - SUBST (XEXP (x, 2), - gen_lowpart_or_truncate (GET_MODE (x), - force_to_mode (XEXP (x, 2), mode, - mask, next_select))); + op0 = gen_lowpart_or_truncate (GET_MODE (x), + force_to_mode (XEXP (x, 1), mode, + mask, next_select)); + op1 = gen_lowpart_or_truncate (GET_MODE (x), + force_to_mode (XEXP (x, 2), mode, + mask, next_select)); + if (op0 != XEXP (x, 1) || op1 != XEXP (x, 2)) + x = simplify_gen_ternary (IF_THEN_ELSE, GET_MODE (x), + GET_MODE (XEXP (x, 0)), XEXP (x, 0), + op0, op1); break; default: --- gcc/testsuite/gcc.c-torture/execute/pr58726.c.jj 2013-12-03 20:47:41.024094847 +0100 +++ gcc/testsuite/gcc.c-torture/execute/pr58726.c 2013-12-03 20:47:24.000000000 +0100 @@ -0,0 +1,26 @@ +/* PR rtl-optimization/58726 */ + +int a, c; +union { int f1; int f2 : 1; } b; + +short +foo (short p) +{ + return p < 0 ? p : a; +} + +int +main () +{ + if (sizeof (short) * __CHAR_BIT__ != 16 + || sizeof (int) * __CHAR_BIT__ != 32) + return 0; + b.f1 = 56374; + unsigned short d; + int e = b.f2; + d = e == 0 ? b.f1 : 0; + c = foo (d); + if (c != (short) 56374) + __builtin_abort (); + return 0; +} Jakub