-/* Given a unary or binary expression EXPR, create and return a new
- expression with the same structure as EXPR but with its operands
- replaced with the value handles of each of the operands of EXPR.
-
- VUSES represent the virtual use operands associated with EXPR (if
- any). Insert EXPR's operands into the EXP_GEN set for BLOCK. */
-
-static inline tree
-create_value_expr_from (tree expr, basic_block block, VEC (tree, gc) *vuses)
-{
- int i;
- enum tree_code code = TREE_CODE (expr);
- tree vexpr;
- alloc_pool pool = NULL;
- tree efi;
-
- gcc_assert (TREE_CODE_CLASS (code) == tcc_unary
- || TREE_CODE_CLASS (code) == tcc_binary
- || TREE_CODE_CLASS (code) == tcc_comparison
- || TREE_CODE_CLASS (code) == tcc_reference
- || TREE_CODE_CLASS (code) == tcc_expression
- || TREE_CODE_CLASS (code) == tcc_vl_exp
- || TREE_CODE_CLASS (code) == tcc_exceptional
- || TREE_CODE_CLASS (code) == tcc_declaration);
-
- if (TREE_CODE_CLASS (code) == tcc_unary)
- pool = unary_node_pool;
- else if (TREE_CODE_CLASS (code) == tcc_reference)
- pool = reference_node_pool;
- else if (TREE_CODE_CLASS (code) == tcc_binary)
- pool = binary_node_pool;
- else if (TREE_CODE_CLASS (code) == tcc_comparison)
- pool = comparison_node_pool;
- else
- gcc_assert (code == CALL_EXPR);
-
- if (code == CALL_EXPR)
- vexpr = temp_copy_call_expr (expr);
- else
- {
- vexpr = (tree) pool_alloc (pool);
- memcpy (vexpr, expr, tree_size (expr));
- }
-
- for (i = 0; i < TREE_OPERAND_LENGTH (expr); i++)
- {
- tree val = NULL_TREE;
- tree op;
-
- op = TREE_OPERAND (expr, i);
- if (op == NULL_TREE)
- continue;
-
- /* Recursively value-numberize reference ops and tree lists. */
- if (REFERENCE_CLASS_P (op))
- {
- tree tempop = create_value_expr_from (op, block, vuses);
- op = tempop ? tempop : op;
- val = vn_lookup_or_add_with_vuses (op, vuses);
- set_expression_vuses (op, vuses);
- }
- else
- {
- val = vn_lookup_or_add (op);
- }
- if (TREE_CODE (op) != TREE_LIST)
- add_to_exp_gen (block, op);
-
- if (TREE_CODE (val) == VALUE_HANDLE)
- TREE_TYPE (val) = TREE_TYPE (TREE_OPERAND (vexpr, i));
-
- TREE_OPERAND (vexpr, i) = val;
- }
- efi = find_existing_value_expr (vexpr, vuses);
- if (efi)
- return efi;
- get_or_alloc_expression_id (vexpr);
- return vexpr;
-}
-
-/* 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, false);
-
- 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. */