+/* Return a copy of NODE that is stored in the temporary alloc_pool's.
+ This is made recursively true, so that the operands are stored in
+ the pool as well. */
+
+static tree
+poolify_tree (tree node)
+{
+ switch (TREE_CODE (node))
+ {
+ case INDIRECT_REF:
+ {
+ tree temp = (tree) pool_alloc (reference_node_pool);
+ memcpy (temp, node, tree_size (node));
+ TREE_OPERAND (temp, 0) = poolify_tree (TREE_OPERAND (temp, 0));
+ return temp;
+ }
+ break;
+ case GIMPLE_MODIFY_STMT:
+ {
+ tree temp = (tree) pool_alloc (modify_expr_node_pool);
+ memcpy (temp, node, tree_size (node));
+ GIMPLE_STMT_OPERAND (temp, 0) =
+ poolify_tree (GIMPLE_STMT_OPERAND (temp, 0));
+ GIMPLE_STMT_OPERAND (temp, 1) =
+ poolify_tree (GIMPLE_STMT_OPERAND (temp, 1));
+ return temp;
+ }
+ break;
+ case SSA_NAME:
+ case INTEGER_CST:
+ case STRING_CST:
+ case REAL_CST:
+ case FIXED_CST:
+ case PARM_DECL:
+ case VAR_DECL:
+ case RESULT_DECL:
+ return node;
+ default:
+ gcc_unreachable ();
+ }
+}
+
+static tree modify_expr_template;
+
+/* Allocate a GIMPLE_MODIFY_STMT with TYPE, and operands OP1, OP2 in the
+ alloc pools and return it. */
+static tree
+poolify_modify_stmt (tree op1, tree op2)
+{
+ if (modify_expr_template == NULL)
+ modify_expr_template = build_gimple_modify_stmt (op1, op2);
+
+ GIMPLE_STMT_OPERAND (modify_expr_template, 0) = op1;
+ GIMPLE_STMT_OPERAND (modify_expr_template, 1) = op2;
+
+ return poolify_tree (modify_expr_template);
+}
+
+
+/* For each real store operation of the form
+ *a = <value> that we see, create a corresponding fake store of the
+ form storetmp_<version> = *a.
+
+ This enables AVAIL computation to mark the results of stores as
+ available. Without this, you'd need to do some computation to
+ mark the result of stores as ANTIC and AVAIL at all the right
+ points.
+ To save memory, we keep the store
+ statements pool allocated until we decide whether they are
+ necessary or not. */
+
+static void
+insert_fake_stores (void)
+{
+ basic_block block;
+
+ FOR_ALL_BB (block)
+ {
+ block_stmt_iterator bsi;
+ for (bsi = bsi_start (block); !bsi_end_p (bsi); bsi_next (&bsi))
+ {
+ tree stmt = bsi_stmt (bsi);
+
+ /* We can't generate SSA names for stores that are complex
+ or aggregate. We also want to ignore things whose
+ virtual uses occur in abnormal phis. */
+
+ if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT
+ && TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 0)) == INDIRECT_REF
+ && !AGGREGATE_TYPE_P (TREE_TYPE (GIMPLE_STMT_OPERAND (stmt, 0)))
+ && TREE_CODE (TREE_TYPE (GIMPLE_STMT_OPERAND
+ (stmt, 0))) != COMPLEX_TYPE)
+ {
+ ssa_op_iter iter;
+ def_operand_p defp;
+ tree lhs = GIMPLE_STMT_OPERAND (stmt, 0);
+ tree rhs = GIMPLE_STMT_OPERAND (stmt, 1);
+ tree new_tree;
+ bool notokay = false;
+
+ FOR_EACH_SSA_DEF_OPERAND (defp, stmt, iter, SSA_OP_VIRTUAL_DEFS)
+ {
+ tree defvar = DEF_FROM_PTR (defp);
+ if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (defvar))
+ {
+ notokay = true;
+ break;
+ }
+ }
+
+ if (notokay)
+ continue;
+
+ if (!storetemp || TREE_TYPE (rhs) != TREE_TYPE (storetemp))
+ {
+ storetemp = create_tmp_var (TREE_TYPE (rhs), "storetmp");
+ if (TREE_CODE (TREE_TYPE (storetemp)) == VECTOR_TYPE)
+ DECL_GIMPLE_REG_P (storetemp) = 1;
+ get_var_ann (storetemp);
+ }
+
+ new_tree = poolify_modify_stmt (storetemp, lhs);
+
+ lhs = make_ssa_name (storetemp, new_tree);
+ GIMPLE_STMT_OPERAND (new_tree, 0) = lhs;
+ create_ssa_artificial_load_stmt (new_tree, stmt);
+
+ NECESSARY (new_tree) = 0;
+ VEC_safe_push (tree, heap, inserted_exprs, new_tree);
+ VEC_safe_push (tree, heap, need_creation, new_tree);
+ bsi_insert_after (&bsi, new_tree, BSI_NEW_STMT);
+ }
+ }
+ }
+}
+
+/* Turn the pool allocated fake stores that we created back into real
+ GC allocated ones if they turned out to be necessary to PRE some
+ expressions. */
+
+static void
+realify_fake_stores (void)
+{
+ unsigned int i;
+ tree stmt;
+
+ for (i = 0; VEC_iterate (tree, need_creation, i, stmt); i++)
+ {
+ if (NECESSARY (stmt))
+ {
+ block_stmt_iterator bsi;
+ tree newstmt, tmp;
+
+ /* Mark the temp variable as referenced */
+ add_referenced_var (SSA_NAME_VAR (GIMPLE_STMT_OPERAND (stmt, 0)));
+
+ /* Put the new statement in GC memory, fix up the
+ SSA_NAME_DEF_STMT on it, and then put it in place of
+ the old statement before the store in the IR stream
+ as a plain ssa name copy. */
+ bsi = bsi_for_stmt (stmt);
+ bsi_prev (&bsi);
+ tmp = GIMPLE_STMT_OPERAND (bsi_stmt (bsi), 1);
+ newstmt = build_gimple_modify_stmt (GIMPLE_STMT_OPERAND (stmt, 0),
+ tmp);
+ SSA_NAME_DEF_STMT (GIMPLE_STMT_OPERAND (newstmt, 0)) = newstmt;
+ bsi_insert_before (&bsi, newstmt, BSI_SAME_STMT);
+ bsi = bsi_for_stmt (stmt);
+ bsi_remove (&bsi, true);
+ }
+ else
+ release_defs (stmt);
+ }
+}
+
+/* Given an SSA_NAME, see if SCCVN has a value number for it, and if
+ so, return the value handle for this value number, creating it if
+ necessary.
+ Return NULL if SCCVN has no info for us. */
+
+static tree
+get_sccvn_value (tree name)
+{
+ if (TREE_CODE (name) == SSA_NAME
+ && VN_INFO (name)->valnum != name
+ && VN_INFO (name)->valnum != VN_TOP)
+ {
+ tree val = VN_INFO (name)->valnum;
+ bool is_invariant = is_gimple_min_invariant (val);
+ tree valvh = !is_invariant ? get_value_handle (val) : NULL_TREE;
+
+ /* We may end up with situations where SCCVN has chosen a
+ representative for the equivalence set that we have not
+ visited yet. In this case, just create the value handle for
+ it. */
+ if (!valvh && !is_invariant)
+ {
+ tree defstmt = SSA_NAME_DEF_STMT (val);
+
+ gcc_assert (VN_INFO (val)->valnum == val);
+ /* PHI nodes can't have vuses and attempts to iterate over
+ their VUSE operands will crash. */
+ if (TREE_CODE (defstmt) == PHI_NODE || IS_EMPTY_STMT (defstmt))
+ defstmt = NULL;
+ {
+ tree defstmt2 = SSA_NAME_DEF_STMT (name);
+ if (TREE_CODE (defstmt2) != PHI_NODE &&
+ !ZERO_SSA_OPERANDS (defstmt2, SSA_OP_ALL_VIRTUALS))
+ gcc_assert (defstmt);
+ }
+ valvh = vn_lookup_or_add_with_stmt (val, defstmt);
+ }
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "SCCVN says ");
+ print_generic_expr (dump_file, name, 0);
+ fprintf (dump_file, " value numbers to ");
+ if (valvh && !is_invariant)
+ {
+ print_generic_expr (dump_file, val, 0);
+ fprintf (dump_file, " (");
+ print_generic_expr (dump_file, valvh, 0);
+ fprintf (dump_file, ")\n");
+ }
+ else
+ print_generic_stmt (dump_file, val, 0);
+ }
+ if (valvh)
+ return valvh;
+ else
+ return val;
+ }
+ return NULL_TREE;
+}
+
+/* Create value handles for PHI in BLOCK. */
+
+static void
+make_values_for_phi (tree phi, basic_block block)
+{
+ tree result = PHI_RESULT (phi);
+ /* We have no need for virtual phis, as they don't represent
+ actual computations. */
+ if (is_gimple_reg (result))
+ {
+ tree sccvnval = get_sccvn_value (result);
+ if (sccvnval)
+ {
+ vn_add (result, sccvnval);
+ bitmap_insert_into_set (PHI_GEN (block), result);
+ bitmap_value_insert_into_set (AVAIL_OUT (block), result);
+ }
+ else
+ add_to_sets (result, result, NULL,
+ PHI_GEN (block), AVAIL_OUT (block));
+ }
+}
+
+/* Create value handles for STMT in BLOCK. Return true if we handled
+ the statement. */
+
+static bool
+make_values_for_stmt (tree stmt, basic_block block)
+{
+
+ tree lhs = GIMPLE_STMT_OPERAND (stmt, 0);
+ tree rhs = GIMPLE_STMT_OPERAND (stmt, 1);
+ tree valvh = NULL_TREE;
+ tree lhsval;
+ VEC (tree, gc) *vuses = NULL;
+
+ valvh = get_sccvn_value (lhs);
+
+ if (valvh)
+ {
+ vn_add (lhs, valvh);
+ bitmap_value_insert_into_set (AVAIL_OUT (block), lhs);
+ /* Shortcut for FRE. We have no need to create value expressions,
+ just want to know what values are available where. */
+ if (in_fre)
+ return true;
+
+ }
+ else if (in_fre)
+ {
+ /* For FRE, if SCCVN didn't find anything, we aren't going to
+ either, so just make up a new value number if necessary and
+ call it a day */
+ if (get_value_handle (lhs) == NULL)
+ vn_lookup_or_add (lhs);
+ bitmap_value_insert_into_set (AVAIL_OUT (block), lhs);
+ return true;
+ }
+
+ lhsval = valvh ? valvh : get_value_handle (lhs);
+ vuses = copy_vuses_from_stmt (stmt);
+ STRIP_USELESS_TYPE_CONVERSION (rhs);
+ if (can_value_number_operation (rhs)
+ && (!lhsval || !is_gimple_min_invariant (lhsval)))
+ {
+ /* For value numberable operation, create a
+ duplicate expression with the operands replaced
+ with the value handles of the original RHS. */
+ tree newt = create_value_expr_from (rhs, block, vuses);
+ if (newt)
+ {
+ set_expression_vuses (newt, vuses);
+ /* If we already have a value number for the LHS, reuse
+ it rather than creating a new one. */
+ if (lhsval)
+ {
+ set_value_handle (newt, lhsval);
+ if (!is_gimple_min_invariant (lhsval))
+ add_to_value (lhsval, newt);
+ }
+ else
+ {
+ tree val = vn_lookup_or_add_with_vuses (newt, vuses);
+ vn_add (lhs, val);
+ }
+
+ add_to_exp_gen (block, newt);
+ }
+
+ bitmap_insert_into_set (TMP_GEN (block), lhs);
+ bitmap_value_insert_into_set (AVAIL_OUT (block), lhs);
+ return true;
+ }
+ else if ((TREE_CODE (rhs) == SSA_NAME
+ && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (rhs))
+ || is_gimple_min_invariant (rhs)
+ || TREE_CODE (rhs) == ADDR_EXPR
+ || TREE_INVARIANT (rhs)
+ || DECL_P (rhs))
+ {
+
+ if (lhsval)
+ {
+ set_expression_vuses (rhs, vuses);
+ set_value_handle (rhs, lhsval);
+ if (!is_gimple_min_invariant (lhsval))
+ add_to_value (lhsval, rhs);
+ bitmap_insert_into_set (TMP_GEN (block), lhs);
+ bitmap_value_insert_into_set (AVAIL_OUT (block), lhs);
+ }
+ else
+ {
+ /* Compute a value number for the RHS of the statement
+ and add its value to the AVAIL_OUT set for the block.
+ Add the LHS to TMP_GEN. */
+ set_expression_vuses (rhs, vuses);
+ add_to_sets (lhs, rhs, vuses, TMP_GEN (block),
+ AVAIL_OUT (block));
+ }
+ /* None of the rest of these can be PRE'd. */
+ if (TREE_CODE (rhs) == SSA_NAME && !ssa_undefined_value_p (rhs))
+ add_to_exp_gen (block, rhs);
+ return true;
+ }
+ return false;
+
+}