Hi! As discussed in the PR, this testcase ICEs on arm, because ifcvt is relying on active instruction counts from various routines (count_bb_insns, flow_find_cross_jump and flow_find_head_matching_sequence), but each of those routines have different view of what counts as active insns.
Fixed thusly, bootstrapped/regtested on x86_64-linux and i686-linux and tested on the testcase using cross to arm. Ok for trunk? 2013-12-18 Jakub Jelinek <ja...@redhat.com> PR rtl-optimization/58668 * cfgcleanup.c (flow_find_cross_jump): Don't count any jumps if dir_p is NULL. Remove p1 variable and make USE/CLOBBER check consistent with other places. (flow_find_head_matching_sequence): Don't count USE or CLOBBER insns. (try_head_merge_bb): Adjust for the flow_find_head_matching_sequence counting change. * ifcvt.c (count_bb_insns): Don't count USE or CLOBBER insns. * gcc.dg/pr58668.c: New test. --- gcc/cfgcleanup.c.jj 2013-12-10 08:52:13.000000000 +0100 +++ gcc/cfgcleanup.c 2013-12-18 12:23:11.695684615 +0100 @@ -1295,7 +1295,6 @@ flow_find_cross_jump (basic_block bb1, b { rtx i1, i2, last1, last2, afterlast1, afterlast2; int ninsns = 0; - rtx p1; enum replace_direction dir, last_dir, afterlast_dir; bool follow_fallthru, did_fallthru; @@ -1323,8 +1322,9 @@ flow_find_cross_jump (basic_block bb1, b || (returnjump_p (i2) && !side_effects_p (PATTERN (i2)))) { last2 = i2; - /* Count everything except for unconditional jump as insn. */ - if (!simplejump_p (i2) && !returnjump_p (i2) && last1) + /* Count everything except for unconditional jump as insn. + Don't count any jumps if dir_p is NULL. */ + if (!simplejump_p (i2) && !returnjump_p (i2) && last1 && dir_p) ninsns++; i2 = PREV_INSN (i2); } @@ -1375,8 +1375,8 @@ flow_find_cross_jump (basic_block bb1, b last1 = i1, last2 = i2; afterlast_dir = last_dir; last_dir = dir; - p1 = PATTERN (i1); - if (!(GET_CODE (p1) == USE || GET_CODE (p1) == CLOBBER)) + if (GET_CODE (PATTERN (i1)) != USE + && GET_CODE (PATTERN (i1)) != CLOBBER) ninsns++; } @@ -1494,7 +1494,9 @@ flow_find_head_matching_sequence (basic_ beforelast1 = last1, beforelast2 = last2; last1 = i1, last2 = i2; - ninsns++; + if (GET_CODE (PATTERN (i1)) != USE + && GET_CODE (PATTERN (i1)) != CLOBBER) + ninsns++; } if (i1 == BB_END (bb1) || i2 == BB_END (bb2) @@ -2410,7 +2412,9 @@ try_head_merge_bb (basic_block bb) return false; do e0_last_head = prev_real_insn (e0_last_head); - while (DEBUG_INSN_P (e0_last_head)); + while (DEBUG_INSN_P (e0_last_head) + || GET_CODE (PATTERN (e0_last_head)) == USE + || GET_CODE (PATTERN (e0_last_head)) == CLOBBER); } if (max_match == 0) @@ -2430,7 +2434,9 @@ try_head_merge_bb (basic_block bb) basic_block merge_bb = EDGE_SUCC (bb, ix)->dest; rtx head = BB_HEAD (merge_bb); - while (!NONDEBUG_INSN_P (head)) + while (!NONDEBUG_INSN_P (head) + || GET_CODE (PATTERN (head)) == USE + || GET_CODE (PATTERN (head)) == CLOBBER) head = NEXT_INSN (head); headptr[ix] = head; currptr[ix] = head; @@ -2439,7 +2445,9 @@ try_head_merge_bb (basic_block bb) for (j = 1; j < max_match; j++) do head = NEXT_INSN (head); - while (!NONDEBUG_INSN_P (head)); + while (!NONDEBUG_INSN_P (head) + || GET_CODE (PATTERN (head)) == USE + || GET_CODE (PATTERN (head)) == CLOBBER); simulate_backwards_to_point (merge_bb, live, head); IOR_REG_SET (live_union, live); } --- gcc/ifcvt.c.jj 2013-12-11 10:11:04.000000000 +0100 +++ gcc/ifcvt.c 2013-12-18 11:37:31.924056330 +0100 @@ -118,7 +118,11 @@ count_bb_insns (const_basic_block bb) while (1) { - if (CALL_P (insn) || NONJUMP_INSN_P (insn)) + if ((CALL_P (insn) || NONJUMP_INSN_P (insn)) + /* Don't count USE/CLOBBER insns, flow_find_cross_jump etc. + don't count them either and we need consistency. */ + && GET_CODE (PATTERN (insn)) != USE + && GET_CODE (PATTERN (insn)) != CLOBBER) count++; if (insn == BB_END (bb)) --- gcc/testsuite/gcc.dg/pr58668.c.jj 2013-12-18 11:43:05.729311888 +0100 +++ gcc/testsuite/gcc.dg/pr58668.c 2013-12-18 11:42:54.000000000 +0100 @@ -0,0 +1,25 @@ +/* PR rtl-optimization/58668 */ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-additional-options "-mthumb" { target { { arm*-*-* } && arm_thumb2_ok } } } */ + +void *fn1 (void *); +void *fn2 (void *, const char *); +void fn3 (void *); +void fn4 (void *, int); + +void * +test (void *x) +{ + void *a, *b; + if (!(a = fn1 (x))) + return (void *) 0; + if (!(b = fn2 (a, "w"))) + { + fn3 (a); + return (void *) 0; + } + fn3 (a); + fn4 (b, 1); + return b; +} Jakub