Hi! Apparently, for iv->extend == IV_UNKNOWN_EXTEND if iv->mode != iv->extend_mode get_iv_value returns a value in iv->mode mode, while otherwise in iv->extend_mode. This makes some sense, because with IV_UNKNOWN_EXTEND the upper bits are unknown, so there is nothing reasonable to return in the extended mode. But e.g. iv_subreg when it calls assumed unconditionally the value would be in iv->extend_mode (the reason for the ICE on the attached testcase). Furthermore, for iv_extend, IMHO if iv->extend isn't IV_UNKNOWN_EXTEND, but is different from the new extend, the middle bits might be incorrect. And, lastly, I think may_unswitch_on assumes the returned values will be in the expected mode (iv->mode), but they can be wider and that can result in invalid RTL (say comparing of SImode with DImode rtl), or wrong code.
Fixed thusly, bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk and for 4.8 later? 2013-11-05 Jakub Jelinek <ja...@redhat.com> PR rtl-optimization/58997 * loop-iv.c (iv_subreg): For IV_UNKNOWN_EXTEND, expect get_iv_value to be in iv->mode rather than iv->extend_mode. (iv_extend): Likewise. Otherwise, if iv->extend != extend, use lowpart_subreg on get_iv_value before calling simplify_gen_unary. * loop-unswitch.c (may_unswitch_on): Make sure op[i] is in the right mode. * gcc.c-torture/compile/pr58997.c: New test. --- gcc/loop-iv.c.jj 2013-10-17 22:30:56.000000000 +0200 +++ gcc/loop-iv.c 2013-11-05 10:10:31.685719102 +0100 @@ -436,7 +436,9 @@ iv_subreg (struct rtx_iv *iv, enum machi && !iv->first_special) { rtx val = get_iv_value (iv, const0_rtx); - val = lowpart_subreg (mode, val, iv->extend_mode); + val = lowpart_subreg (mode, val, + iv->extend == IV_UNKNOWN_EXTEND + ? iv->mode : iv->extend_mode); iv->base = val; iv->extend = IV_UNKNOWN_EXTEND; @@ -476,8 +478,14 @@ iv_extend (struct rtx_iv *iv, enum iv_ex && !iv->first_special) { rtx val = get_iv_value (iv, const0_rtx); + if (iv->extend_mode != iv->mode + && iv->extend != IV_UNKNOWN_EXTEND + && iv->extend != extend) + val = lowpart_subreg (iv->mode, val, iv->extend_mode); val = simplify_gen_unary (iv_extend_to_rtx_code (extend), mode, - val, iv->extend_mode); + val, + iv->extend == extend + ? iv->extend_mode : iv->mode); iv->base = val; iv->extend = IV_UNKNOWN_EXTEND; iv->mode = iv->extend_mode = mode; --- gcc/loop-unswitch.c.jj 2013-10-17 22:30:41.780251692 +0200 +++ gcc/loop-unswitch.c 2013-11-05 10:28:57.172719881 +0100 @@ -191,6 +191,7 @@ may_unswitch_on (basic_block bb, struct if (!test) return NULL_RTX; + mode = VOIDmode; for (i = 0; i < 2; i++) { op[i] = XEXP (test, i); @@ -205,11 +206,15 @@ may_unswitch_on (basic_block bb, struct return NULL_RTX; op[i] = get_iv_value (&iv, const0_rtx); + if (iv.extend != IV_UNKNOWN_EXTEND + && iv.mode != iv.extend_mode) + op[i] = lowpart_subreg (iv.mode, op[i], iv.extend_mode); + if (mode == VOIDmode) + mode = iv.mode; + else + gcc_assert (mode == iv.mode); } - mode = GET_MODE (op[0]); - if (mode == VOIDmode) - mode = GET_MODE (op[1]); if (GET_MODE_CLASS (mode) == MODE_CC) { if (at != BB_END (bb)) --- gcc/testsuite/gcc.c-torture/compile/pr58997.c.jj 2013-11-05 10:26:30.802517924 +0100 +++ gcc/testsuite/gcc.c-torture/compile/pr58997.c 2013-11-05 10:26:15.000000000 +0100 @@ -0,0 +1,19 @@ +/* PR rtl-optimization/58997 */ + +int a, b, c, e; +short d; +char h; + +void +foo () +{ + while (b) + { + d = a ? c : 1 % a; + c = d; + h = d; + if (!h) + while (e) + ; + } +} Jakub