+/* Make SSA names defined by OLD_STMT point to NEW_STMT
+ as their defining statement. */
+
+void
+move_ssa_defining_stmt_for_defs (gimple new_stmt, gimple old_stmt)
+{
+ tree var;
+ ssa_op_iter iter;
+
+ if (gimple_in_ssa_p (cfun))
+ {
+ /* Make defined SSA_NAMEs point to the new
+ statement as their definition. */
+ FOR_EACH_SSA_TREE_OPERAND (var, old_stmt, iter, SSA_OP_ALL_DEFS)
+ {
+ if (TREE_CODE (var) == SSA_NAME)
+ SSA_NAME_DEF_STMT (var) = new_stmt;
+ }
+ }
+}
+
+
+/* Update a GIMPLE_CALL statement at iterator *SI_P to reflect the
+ value of EXPR, which is expected to be the result of folding the
+ call. This can only be done if EXPR is a CALL_EXPR with valid
+ GIMPLE operands as arguments, or if it is a suitable RHS expression
+ for a GIMPLE_ASSIGN. More complex expressions will require
+ gimplification, which will introduce addtional statements. In this
+ event, no update is performed, and the function returns false.
+ Note that we cannot mutate a GIMPLE_CALL in-place, so we always
+ replace the statement at *SI_P with an entirely new statement.
+ The new statement need not be a call, e.g., if the original call
+ folded to a constant. */
+
+bool
+update_call_from_tree (gimple_stmt_iterator *si_p, tree expr)
+{
+ tree lhs;
+
+ gimple stmt = gsi_stmt (*si_p);
+
+ gcc_assert (is_gimple_call (stmt));
+
+ lhs = gimple_call_lhs (stmt);
+
+ if (valid_gimple_call_p (expr))
+ {
+ /* The call has simplified to another call. */
+ tree fn = CALL_EXPR_FN (expr);
+ unsigned i;
+ unsigned nargs = call_expr_nargs (expr);
+ VEC(tree, heap) *args = NULL;
+ gimple new_stmt;
+
+ if (nargs > 0)
+ {
+ args = VEC_alloc (tree, heap, nargs);
+ VEC_safe_grow (tree, heap, args, nargs);
+
+ for (i = 0; i < nargs; i++)
+ VEC_replace (tree, args, i, CALL_EXPR_ARG (expr, i));
+ }
+
+ new_stmt = gimple_build_call_vec (fn, args);
+ gimple_call_set_lhs (new_stmt, lhs);
+ move_ssa_defining_stmt_for_defs (new_stmt, stmt);
+ gimple_set_vuse (new_stmt, gimple_vuse (stmt));
+ gimple_set_vdef (new_stmt, gimple_vdef (stmt));
+ gimple_set_location (new_stmt, gimple_location (stmt));
+ gsi_replace (si_p, new_stmt, false);
+ VEC_free (tree, heap, args);
+
+ return true;
+ }
+ else if (valid_gimple_rhs_p (expr))
+ {
+ gimple new_stmt;
+
+ /* The call has simplified to an expression
+ that cannot be represented as a GIMPLE_CALL. */
+ if (lhs)
+ {
+ /* A value is expected.
+ Introduce a new GIMPLE_ASSIGN statement. */
+ STRIP_USELESS_TYPE_CONVERSION (expr);
+ new_stmt = gimple_build_assign (lhs, expr);
+ move_ssa_defining_stmt_for_defs (new_stmt, stmt);
+ gimple_set_vuse (new_stmt, gimple_vuse (stmt));
+ gimple_set_vdef (new_stmt, gimple_vdef (stmt));
+ }
+ else if (!TREE_SIDE_EFFECTS (expr))
+ {
+ /* No value is expected, and EXPR has no effect.
+ Replace it with an empty statement. */
+ new_stmt = gimple_build_nop ();
+ if (gimple_in_ssa_p (cfun))
+ {
+ unlink_stmt_vdef (stmt);
+ release_defs (stmt);
+ }
+ }
+ else
+ {
+ /* No value is expected, but EXPR has an effect,
+ e.g., it could be a reference to a volatile
+ variable. Create an assignment statement
+ with a dummy (unused) lhs variable. */
+ STRIP_USELESS_TYPE_CONVERSION (expr);
+ lhs = create_tmp_var (TREE_TYPE (expr), NULL);
+ new_stmt = gimple_build_assign (lhs, expr);
+ add_referenced_var (lhs);
+ if (gimple_in_ssa_p (cfun))
+ lhs = make_ssa_name (lhs, new_stmt);
+ gimple_assign_set_lhs (new_stmt, lhs);
+ gimple_set_vuse (new_stmt, gimple_vuse (stmt));
+ gimple_set_vdef (new_stmt, gimple_vdef (stmt));
+ move_ssa_defining_stmt_for_defs (new_stmt, stmt);
+ }
+ gimple_set_location (new_stmt, gimple_location (stmt));
+ gsi_replace (si_p, new_stmt, false);
+ return true;
+ }
+ else
+ /* The call simplified to an expression that is
+ not a valid GIMPLE RHS. */
+ return false;
+}
+
+