This fixes PR51042. Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to trunk.
Richard. 2011-11-10 Richard Guenther <rguent...@suse.de> PR tree-optimization/51042 * tree-ssa-pre.c (phi_translate_1): Avoid recursing on self-referential expressions. Refactor code to avoid duplication. * gcc.dg/torture/pr51042.c: New testcase. Index: gcc/tree-ssa-pre.c =================================================================== *** gcc/tree-ssa-pre.c (revision 181252) --- gcc/tree-ssa-pre.c (working copy) *************** phi_translate_1 (pre_expr expr, bitmap_s *** 1527,1533 **** tree newvuse = vuse; VEC (vn_reference_op_s, heap) *newoperands = NULL; bool changed = false, same_valid = true; ! unsigned int i, j; vn_reference_op_t operand; vn_reference_t newref; --- 1527,1533 ---- tree newvuse = vuse; VEC (vn_reference_op_s, heap) *newoperands = NULL; bool changed = false, same_valid = true; ! unsigned int i, j, n; vn_reference_op_t operand; vn_reference_t newref; *************** phi_translate_1 (pre_expr expr, bitmap_s *** 1536,1635 **** { pre_expr opresult; pre_expr leader; ! tree oldop0 = operand->op0; ! tree oldop1 = operand->op1; ! tree oldop2 = operand->op2; ! tree op0 = oldop0; ! tree op1 = oldop1; ! tree op2 = oldop2; tree type = operand->type; vn_reference_op_s newop = *operand; ! ! if (op0 && TREE_CODE (op0) == SSA_NAME) { ! unsigned int op_val_id = VN_INFO (op0)->value_id; ! leader = find_leader_in_sets (op_val_id, set1, set2); ! opresult = phi_translate (leader, set1, set2, pred, phiblock); ! if (opresult && opresult != leader) { ! tree name = get_representative_for (opresult); ! if (!name) break; ! op0 = name; } ! else if (!opresult) ! break; ! } ! changed |= op0 != oldop0; ! ! if (op1 && TREE_CODE (op1) == SSA_NAME) ! { ! unsigned int op_val_id = VN_INFO (op1)->value_id; leader = find_leader_in_sets (op_val_id, set1, set2); ! opresult = phi_translate (leader, set1, set2, pred, phiblock); ! if (opresult && opresult != leader) { ! tree name = get_representative_for (opresult); ! if (!name) break; ! op1 = name; } - else if (!opresult) - break; } ! /* We can't possibly insert these. */ ! else if (op1 && !is_gimple_min_invariant (op1)) ! break; ! changed |= op1 != oldop1; ! if (op2 && TREE_CODE (op2) == SSA_NAME) { ! unsigned int op_val_id = VN_INFO (op2)->value_id; ! leader = find_leader_in_sets (op_val_id, set1, set2); ! opresult = phi_translate (leader, set1, set2, pred, phiblock); ! if (opresult && opresult != leader) ! { ! tree name = get_representative_for (opresult); ! if (!name) ! break; ! op2 = name; ! } ! else if (!opresult) ! break; } - /* We can't possibly insert these. */ - else if (op2 && !is_gimple_min_invariant (op2)) - break; - changed |= op2 != oldop2; - if (!newoperands) newoperands = VEC_copy (vn_reference_op_s, heap, operands); /* We may have changed from an SSA_NAME to a constant */ ! if (newop.opcode == SSA_NAME && TREE_CODE (op0) != SSA_NAME) ! newop.opcode = TREE_CODE (op0); newop.type = type; ! newop.op0 = op0; ! newop.op1 = op1; ! newop.op2 = op2; /* If it transforms a non-constant ARRAY_REF into a constant one, adjust the constant offset. */ if (newop.opcode == ARRAY_REF && newop.off == -1 ! && TREE_CODE (op0) == INTEGER_CST ! && TREE_CODE (op1) == INTEGER_CST ! && TREE_CODE (op2) == INTEGER_CST) { ! double_int off = tree_to_double_int (op0); off = double_int_add (off, double_int_neg ! (tree_to_double_int (op1))); ! off = double_int_mul (off, tree_to_double_int (op2)); if (double_int_fits_in_shwi_p (off)) newop.off = off.low; } VEC_replace (vn_reference_op_s, newoperands, j, &newop); /* If it transforms from an SSA_NAME to an address, fold with a preceding indirect reference. */ ! if (j > 0 && op0 && TREE_CODE (op0) == ADDR_EXPR && VEC_index (vn_reference_op_s, newoperands, j - 1)->opcode == MEM_REF) vn_reference_fold_indirect (&newoperands, &j); --- 1536,1618 ---- { pre_expr opresult; pre_expr leader; ! tree op[3]; tree type = operand->type; vn_reference_op_s newop = *operand; ! op[0] = operand->op0; ! op[1] = operand->op1; ! op[2] = operand->op2; ! for (n = 0; n < 3; ++n) { ! unsigned int op_val_id; ! if (!op[n]) ! continue; ! if (TREE_CODE (op[n]) != SSA_NAME) { ! /* We can't possibly insert these. */ ! if (n != 0 ! && !is_gimple_min_invariant (op[n])) break; ! continue; } ! op_val_id = VN_INFO (op[n])->value_id; leader = find_leader_in_sets (op_val_id, set1, set2); ! if (!leader) ! break; ! /* Make sure we do not recursively translate ourselves ! like for translating a[n_1] with the leader for ! n_1 being a[n_1]. */ ! if (get_expression_id (leader) != get_expression_id (expr)) { ! opresult = phi_translate (leader, set1, set2, ! pred, phiblock); ! if (!opresult) break; ! if (opresult != leader) ! { ! tree name = get_representative_for (opresult); ! if (!name) ! break; ! changed |= name != op[n]; ! op[n] = name; ! } } } ! if (n != 3) { ! if (newoperands) ! VEC_free (vn_reference_op_s, heap, newoperands); ! return NULL; } if (!newoperands) newoperands = VEC_copy (vn_reference_op_s, heap, operands); /* We may have changed from an SSA_NAME to a constant */ ! if (newop.opcode == SSA_NAME && TREE_CODE (op[0]) != SSA_NAME) ! newop.opcode = TREE_CODE (op[0]); newop.type = type; ! newop.op0 = op[0]; ! newop.op1 = op[1]; ! newop.op2 = op[2]; /* If it transforms a non-constant ARRAY_REF into a constant one, adjust the constant offset. */ if (newop.opcode == ARRAY_REF && newop.off == -1 ! && TREE_CODE (op[0]) == INTEGER_CST ! && TREE_CODE (op[1]) == INTEGER_CST ! && TREE_CODE (op[2]) == INTEGER_CST) { ! double_int off = tree_to_double_int (op[0]); off = double_int_add (off, double_int_neg ! (tree_to_double_int (op[1]))); ! off = double_int_mul (off, tree_to_double_int (op[2])); if (double_int_fits_in_shwi_p (off)) newop.off = off.low; } VEC_replace (vn_reference_op_s, newoperands, j, &newop); /* If it transforms from an SSA_NAME to an address, fold with a preceding indirect reference. */ ! if (j > 0 && op[0] && TREE_CODE (op[0]) == ADDR_EXPR && VEC_index (vn_reference_op_s, newoperands, j - 1)->opcode == MEM_REF) vn_reference_fold_indirect (&newoperands, &j); Index: gcc/testsuite/gcc.dg/torture/pr51042.c =================================================================== *** gcc/testsuite/gcc.dg/torture/pr51042.c (revision 0) --- gcc/testsuite/gcc.dg/torture/pr51042.c (revision 0) *************** *** 0 **** --- 1,22 ---- + /* { dg-do compile } */ + + int a, b; + + void + foo (int x) + { + int e[2]; + int d; + while (x) + { + for (d = 0; d <= 1; d = 1) + if (e[a]) + break; + for (b = 0; b <= 0; b = 1) + { + e[a] = a; + if (a) + break; + } + } + }