--- /dev/null
+2005-04-23 Steven Bosscher <stevenb@suse.de>
+
+ PR tree-optimization/21173
+ PR tree-optimization/21167
+ * tree-ssa-pre.c (create_expression_by_pieces): Fix tcc_unary case if
+ GENOP1 is invariant. Avoid code duplication.
+
+ * gcc.c-torture/compile/20050423-2.c: New test.
+ * gcc.c-torture/execute/20050423-1.c: New test.
+
+--- gcc/tree-ssa-pre.c.jj 2005-04-23 21:55:45.000000000 +0200
++++ gcc/tree-ssa-pre.c 2005-04-23 21:57:00.000000000 +0200
+@@ -1308,125 +1308,98 @@ find_or_generate_expression (basic_block
+ static tree
+ create_expression_by_pieces (basic_block block, tree expr, tree stmts)
+ {
+- tree name = NULL_TREE;
+- tree newexpr = NULL_TREE;
++ tree temp, name;
++ tree folded, forced_stmts, newexpr;
+ tree v;
+-
++ tree_stmt_iterator tsi;
++
+ switch (TREE_CODE_CLASS (TREE_CODE (expr)))
+ {
+ case tcc_binary:
+ {
+- tree_stmt_iterator tsi;
+- tree forced_stmts;
+- tree genop1, genop2;
+- tree temp;
+- tree folded;
+ tree op1 = TREE_OPERAND (expr, 0);
+ tree op2 = TREE_OPERAND (expr, 1);
+- genop1 = find_or_generate_expression (block, op1, stmts);
+- genop2 = find_or_generate_expression (block, op2, stmts);
+- temp = create_tmp_var (TREE_TYPE (expr), "pretmp");
+- add_referenced_tmp_var (temp);
+-
++ tree genop1 = find_or_generate_expression (block, op1, stmts);
++ tree genop2 = find_or_generate_expression (block, op2, stmts);
+ folded = fold (build (TREE_CODE (expr), TREE_TYPE (expr),
+ genop1, genop2));
+- newexpr = force_gimple_operand (folded, &forced_stmts, false, NULL);
+- if (forced_stmts)
+- {
+- tsi = tsi_start (forced_stmts);
+- for (; !tsi_end_p (tsi); tsi_next (&tsi))
+- {
+- tree stmt = tsi_stmt (tsi);
+- tree forcedname = TREE_OPERAND (stmt, 0);
+- tree forcedexpr = TREE_OPERAND (stmt, 1);
+- tree val = vn_lookup_or_add (forcedexpr, NULL);
+- vn_add (forcedname, val, NULL);
+- bitmap_value_replace_in_set (NEW_SETS (block), forcedname);
+- bitmap_value_replace_in_set (AVAIL_OUT (block), forcedname);
+- }
+-
+- tsi = tsi_last (stmts);
+- tsi_link_after (&tsi, forced_stmts, TSI_CONTINUE_LINKING);
+- }
+- newexpr = build (MODIFY_EXPR, TREE_TYPE (expr),
+- temp, newexpr);
+- NECESSARY (newexpr) = 0;
+- name = make_ssa_name (temp, newexpr);
+- TREE_OPERAND (newexpr, 0) = name;
+- tsi = tsi_last (stmts);
+- tsi_link_after (&tsi, newexpr, TSI_CONTINUE_LINKING);
+- VEC_safe_push (tree_on_heap, inserted_exprs, newexpr);
+- pre_stats.insertions++;
+ break;
+ }
++
+ case tcc_unary:
+ {
+- tree_stmt_iterator tsi;
+- tree forced_stmts = NULL;
+- tree genop1;
+- tree temp;
+- tree folded;
+ tree op1 = TREE_OPERAND (expr, 0);
+- genop1 = find_or_generate_expression (block, op1, stmts);
+- temp = create_tmp_var (TREE_TYPE (expr), "pretmp");
+- add_referenced_tmp_var (temp);
++ tree genop1 = find_or_generate_expression (block, op1, stmts);
+ folded = fold (build (TREE_CODE (expr), TREE_TYPE (expr),
+ genop1));
+- /* If the generated operand is already GIMPLE min_invariant
+- just use it instead of calling force_gimple_operand on it,
+- since that may make it not invariant by copying it into an
+- assignment. */
+- if (!is_gimple_min_invariant (genop1))
+- newexpr = force_gimple_operand (folded, &forced_stmts, false, NULL);
+- else
+- newexpr = genop1;
+- if (forced_stmts)
+- {
+- tsi = tsi_start (forced_stmts);
+- for (; !tsi_end_p (tsi); tsi_next (&tsi))
+- {
+- tree stmt = tsi_stmt (tsi);
+- tree forcedname = TREE_OPERAND (stmt, 0);
+- tree forcedexpr = TREE_OPERAND (stmt, 1);
+- tree val = vn_lookup_or_add (forcedexpr, NULL);
+- vn_add (forcedname, val, NULL);
+- bitmap_value_replace_in_set (NEW_SETS (block), forcedname);
+- bitmap_value_replace_in_set (AVAIL_OUT (block), forcedname);
+- }
+- tsi = tsi_last (stmts);
+- tsi_link_after (&tsi, forced_stmts, TSI_CONTINUE_LINKING);
+- }
+- newexpr = build (MODIFY_EXPR, TREE_TYPE (expr),
+- temp, newexpr);
+- name = make_ssa_name (temp, newexpr);
+- TREE_OPERAND (newexpr, 0) = name;
+- NECESSARY (newexpr) = 0;
+- tsi = tsi_last (stmts);
+- tsi_link_after (&tsi, newexpr, TSI_CONTINUE_LINKING);
+- VEC_safe_push (tree_on_heap, inserted_exprs, newexpr);
+- pre_stats.insertions++;
+-
+ break;
+ }
++
+ default:
+ gcc_unreachable ();
+-
+ }
+- v = get_value_handle (expr);
+- vn_add (name, v, NULL);
+
+- /* The value may already exist in either NEW_SETS, or AVAIL_OUT, because
++ /* If the generated expression is already a valid GIMPLE rhs that can
++ be assigned to TEMP. just use it as-is. Otherwise, we will have to
++ call force_gimple_operand on it, and add intermediate expressions
++ to the value sets as well. */
++ if (is_gimple_reg_rhs (folded))
++ newexpr = folded;
++ else
++ {
++ newexpr = force_gimple_operand (folded, &forced_stmts, false, NULL);
++
++ /* If we have any intermediate expressions to the value sets,
++ add them to the value sets and chain them on in the instruction
++ stream. */
++ if (forced_stmts)
++ {
++ tsi = tsi_start (forced_stmts);
++ for (; !tsi_end_p (tsi); tsi_next (&tsi))
++ {
++ tree stmt = tsi_stmt (tsi);
++ tree forcedname = TREE_OPERAND (stmt, 0);
++ tree forcedexpr = TREE_OPERAND (stmt, 1);
++ tree val = vn_lookup_or_add (forcedexpr, NULL);
++ vn_add (forcedname, val, NULL);
++ bitmap_value_replace_in_set (NEW_SETS (block), forcedname);
++ bitmap_value_replace_in_set (AVAIL_OUT (block), forcedname);
++ }
++ tsi = tsi_last (stmts);
++ tsi_link_after (&tsi, forced_stmts, TSI_CONTINUE_LINKING);
++ }
++ }
++
++ /* Build and insert the assignment of the end result to the temporary
++ that we will return. */
++ temp = create_tmp_var (TREE_TYPE (expr), "pretmp");
++ add_referenced_tmp_var (temp);
++ newexpr = build (MODIFY_EXPR, TREE_TYPE (expr), temp, newexpr);
++ name = make_ssa_name (temp, newexpr);
++ TREE_OPERAND (newexpr, 0) = name;
++ NECESSARY (newexpr) = 0;
++ tsi = tsi_last (stmts);
++ tsi_link_after (&tsi, newexpr, TSI_CONTINUE_LINKING);
++ VEC_safe_push (tree_on_heap, inserted_exprs, newexpr);
++
++ /* Add a value handle to the temprorary.
++ The value may already exist in either NEW_SETS, or AVAIL_OUT, because
+ we are creating the expression by pieces, and this particular piece of
+ the expression may have been represented. There is no harm in replacing
+ here. */
++ v = get_value_handle (expr);
++ vn_add (name, v, NULL);
+ bitmap_value_replace_in_set (NEW_SETS (block), name);
+ bitmap_value_replace_in_set (AVAIL_OUT (block), name);
++
++ pre_stats.insertions++;
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Inserted ");
+ print_generic_expr (dump_file, newexpr, 0);
+ fprintf (dump_file, " in predecessor %d\n", block->index);
+ }
++
+ return name;
+ }
+
+--- gcc/testsuite/gcc.c-torture/compile/20050423-2.c 2005-04-07 15:51:53.775361896 +0200
++++ gcc/testsuite/gcc.c-torture/compile/20050423-2.c 2005-04-23 19:47:22.000000000 +0200
+@@ -0,0 +1,21 @@
++/* PR tree-optimization/21167 */
++
++extern const char *f_extensions[];
++const char *f_extensions[] = { ".cnf", 0 };
++void f (void);
++
++int
++g (int ij)
++{
++ char **tmp_ext;
++ unsigned i;
++
++ for (i = 0; i < (unsigned) ij; i++)
++ {
++ f ();
++ tmp_ext = (char **) &f_extensions[0];
++ if (*tmp_ext)
++ return 0;
++ }
++ return 1;
++}
+--- gcc/testsuite/gcc.c-torture/execute/20050423-1.c 2005-04-07 15:51:53.775361896 +0200
++++ gcc/testsuite/gcc.c-torture/execute/20050423-1.c 2005-04-23 19:48:05.000000000 +0200
+@@ -0,0 +1,24 @@
++/* PR tree-optimization/21173 */
++void abort (void);
++
++char q;
++void *a[2];
++
++void
++foo (char *p)
++{
++ int i;
++ for (i = 0; i < 2; i++)
++ a[i] += p - &q;
++}
++
++int
++main (void)
++{
++ int i;
++ foo (&q);
++ for (i = 0; i < 2; i++)
++ if (a[i])
++ abort ();
++ return 0;
++}