} pre_stats;
static bool do_partial_partial;
-static tree bitmap_find_leader (bitmap_set_t, tree);
+static tree bitmap_find_leader (bitmap_set_t, tree, tree);
static void bitmap_value_insert_into_set (bitmap_set_t, tree);
static void bitmap_value_replace_in_set (bitmap_set_t, tree);
static void bitmap_set_copy (bitmap_set_t, bitmap_set_t);
static bool bitmap_set_contains_value (bitmap_set_t, tree);
static void bitmap_insert_into_set (bitmap_set_t, tree);
static bitmap_set_t bitmap_set_new (void);
-static tree create_expression_by_pieces (basic_block, tree, tree);
-static tree find_or_generate_expression (basic_block, tree, tree);
+static tree create_expression_by_pieces (basic_block, tree, tree, tree);
+static tree find_or_generate_expression (basic_block, tree, tree, tree);
/* We can add and remove elements and entries to and from sets
and hash tables, so we use alloc pools for them. */
{
tree result;
- result = bitmap_find_leader (set1, expr);
+ result = bitmap_find_leader (set1, expr, NULL_TREE);
if (!result && set2)
- result = bitmap_find_leader (set2, expr);
+ result = bitmap_find_leader (set2, expr, NULL_TREE);
return result;
}
}
/* Find the leader for a value (i.e., the name representing that
- value) in a given set, and return it. Return NULL if no leader is
- found. */
+ value) in a given set, and return it. If STMT is non-NULL it
+ makes sure the defining statement for the leader dominates it.
+ Return NULL if no leader is found. */
static tree
-bitmap_find_leader (bitmap_set_t set, tree val)
+bitmap_find_leader (bitmap_set_t set, tree val, tree stmt)
{
if (val == NULL)
return NULL;
EXECUTE_IF_AND_IN_BITMAP (exprset->expressions,
set->expressions, 0, i, bi)
- return expression_for_id (i);
+ {
+ tree val = expression_for_id (i);
+ if (stmt)
+ {
+ tree def_stmt = SSA_NAME_DEF_STMT (val);
+ if (bb_for_stmt (def_stmt) == bb_for_stmt (stmt)
+ && stmt_ann (def_stmt)->uid >= stmt_ann (stmt)->uid)
+ continue;
+ }
+ return val;
+ }
}
return NULL;
}
|| COMPARISON_CLASS_P (op)
|| TREE_CODE (op) == INDIRECT_REF
|| TREE_CODE (op) == COMPONENT_REF
+ || TREE_CODE (op) == VIEW_CONVERT_EXPR
|| TREE_CODE (op) == CALL_EXPR
|| TREE_CODE (op) == ARRAY_REF;
}
are doing.
*/
static tree
-create_component_ref_by_pieces (basic_block block, tree expr, tree stmts)
+create_component_ref_by_pieces (basic_block block, tree expr, tree stmts,
+ tree domstmt)
{
tree genop = expr;
tree folded;
if (TREE_CODE (genop) == VALUE_HANDLE)
{
- tree found = bitmap_find_leader (AVAIL_OUT (block), expr);
+ tree found = bitmap_find_leader (AVAIL_OUT (block), expr, domstmt);
if (found)
return found;
}
tree op1, op2, op3;
op0 = create_component_ref_by_pieces (block,
TREE_OPERAND (genop, 0),
- stmts);
+ stmts, domstmt);
op1 = TREE_OPERAND (genop, 1);
if (TREE_CODE (op1) == VALUE_HANDLE)
- op1 = find_or_generate_expression (block, op1, stmts);
+ op1 = find_or_generate_expression (block, op1, stmts, domstmt);
op2 = TREE_OPERAND (genop, 2);
if (op2 && TREE_CODE (op2) == VALUE_HANDLE)
- op2 = find_or_generate_expression (block, op2, stmts);
+ op2 = find_or_generate_expression (block, op2, stmts, domstmt);
op3 = TREE_OPERAND (genop, 3);
if (op3 && TREE_CODE (op3) == VALUE_HANDLE)
- op3 = find_or_generate_expression (block, op3, stmts);
+ op3 = find_or_generate_expression (block, op3, stmts, domstmt);
+ if (!op0 || !op1)
+ return NULL_TREE;
folded = build4 (ARRAY_REF, TREE_TYPE (genop), op0, op1,
op2, op3);
return folded;
tree op1;
op0 = create_component_ref_by_pieces (block,
TREE_OPERAND (genop, 0),
- stmts);
+ stmts, domstmt);
+ if (!op0)
+ return NULL_TREE;
/* op1 should be a FIELD_DECL, which are represented by
themselves. */
op1 = TREE_OPERAND (genop, 1);
case INDIRECT_REF:
{
tree op1 = TREE_OPERAND (genop, 0);
- tree genop1 = find_or_generate_expression (block, op1, stmts);
+ tree genop1 = find_or_generate_expression (block, op1, stmts, domstmt);
+ if (!genop1)
+ return NULL_TREE;
folded = fold_build1 (TREE_CODE (genop), TREE_TYPE (genop),
genop1);
EXPR is the expression to find a leader or generate for.
STMTS is the statement list to put the inserted expressions on.
Returns the SSA_NAME of the LHS of the generated expression or the
- leader. */
+ leader.
+ DOMSTMT if non-NULL is a statement that should be dominated by
+ all uses in the generated expression. If DOMSTMT is non-NULL this
+ routine can fail and return NULL_TREE. Otherwise it will assert
+ on failure. */
static tree
-find_or_generate_expression (basic_block block, tree expr, tree stmts)
+find_or_generate_expression (basic_block block, tree expr, tree stmts,
+ tree domstmt)
{
- tree genop = bitmap_find_leader (AVAIL_OUT (block), expr);
+ tree genop = bitmap_find_leader (AVAIL_OUT (block), expr, domstmt);
/* If it's still NULL, it must be a complex expression, so generate
it recursively. */
if (can_PRE_operation (genop))
{
handled = true;
- genop = create_expression_by_pieces (block, genop, stmts);
+ genop = create_expression_by_pieces (block, genop, stmts,
+ domstmt);
break;
}
}
+ if (!handled && domstmt)
+ return NULL_TREE;
+
gcc_assert (handled);
}
return genop;
partially or fully redundant. Those that are will be either made
fully redundant during the next iteration of insert (for partially
redundant ones), or eliminated by eliminate (for fully redundant
- ones). */
+ ones).
+
+ If DOMSTMT is non-NULL then we make sure that all uses in the
+ expressions dominate that statement. In this case the function
+ can return NULL_TREE to signal failure. */
static tree
-create_expression_by_pieces (basic_block block, tree expr, tree stmts)
+create_expression_by_pieces (basic_block block, tree expr, tree stmts,
+ tree domstmt)
{
tree temp, name;
tree folded, forced_stmts, newexpr;
fn = CALL_EXPR_FN (expr);
sc = CALL_EXPR_STATIC_CHAIN (expr);
- genfn = find_or_generate_expression (block, fn, stmts);
+ genfn = find_or_generate_expression (block, fn, stmts, domstmt);
+ if (!genfn)
+ return NULL_TREE;
nargs = call_expr_nargs (expr);
buffer = (tree*) alloca (nargs * sizeof (tree));
for (i = 0; i < nargs; i++)
{
tree arg = CALL_EXPR_ARG (expr, i);
- buffer[i] = find_or_generate_expression (block, arg, stmts);
+ buffer[i] = find_or_generate_expression (block, arg, stmts,
+ domstmt);
+ if (!buffer[i])
+ return NULL_TREE;
}
folded = build_call_array (TREE_TYPE (expr), genfn, nargs, buffer);
if (sc)
- CALL_EXPR_STATIC_CHAIN (folded) =
- find_or_generate_expression (block, sc, stmts);
+ {
+ CALL_EXPR_STATIC_CHAIN (folded) =
+ find_or_generate_expression (block, sc, stmts, domstmt);
+ if (!CALL_EXPR_STATIC_CHAIN (folded))
+ return NULL_TREE;
+ }
folded = fold (folded);
break;
}
if (TREE_CODE (expr) == COMPONENT_REF
|| TREE_CODE (expr) == ARRAY_REF)
{
- folded = create_component_ref_by_pieces (block, expr, stmts);
+ folded = create_component_ref_by_pieces (block, expr, stmts,
+ domstmt);
+ if (!folded)
+ return NULL_TREE;
}
else
{
tree op1 = TREE_OPERAND (expr, 0);
- tree genop1 = find_or_generate_expression (block, op1, stmts);
+ tree genop1 = find_or_generate_expression (block, op1, stmts,
+ domstmt);
+ if (!genop1)
+ return NULL_TREE;
folded = fold_build1 (TREE_CODE (expr), TREE_TYPE (expr),
genop1);
{
tree op1 = TREE_OPERAND (expr, 0);
tree op2 = TREE_OPERAND (expr, 1);
- tree genop1 = find_or_generate_expression (block, op1, stmts);
- tree genop2 = find_or_generate_expression (block, op2, stmts);
+ tree genop1 = find_or_generate_expression (block, op1, stmts, domstmt);
+ tree genop2 = find_or_generate_expression (block, op2, stmts, domstmt);
+ if (!genop1 || !genop2)
+ return NULL_TREE;
folded = fold_build2 (TREE_CODE (expr), TREE_TYPE (expr),
genop1, genop2);
break;
case tcc_unary:
{
tree op1 = TREE_OPERAND (expr, 0);
- tree genop1 = find_or_generate_expression (block, op1, stmts);
+ tree genop1 = find_or_generate_expression (block, op1, stmts, domstmt);
+ if (!genop1)
+ return NULL_TREE;
folded = fold_build1 (TREE_CODE (expr), TREE_TYPE (expr),
genop1);
break;
vn_add (name, v);
VN_INFO_GET (name)->valnum = name;
get_or_alloc_expression_id (name);
- bitmap_value_replace_in_set (NEW_SETS (block), name);
+ if (!in_fre)
+ bitmap_value_replace_in_set (NEW_SETS (block), name);
bitmap_value_replace_in_set (AVAIL_OUT (block), name);
pre_stats.insertions++;
{
builtexpr = create_expression_by_pieces (bprime,
eprime,
- stmts);
+ stmts, NULL_TREE);
gcc_assert (!(pred->flags & EDGE_ABNORMAL));
bsi_insert_on_edge (pred, stmts);
avail[bprime->index] = builtexpr;
vprime = get_value_handle (eprime);
gcc_assert (vprime);
edoubleprime = bitmap_find_leader (AVAIL_OUT (bprime),
- vprime);
+ vprime, NULL_TREE);
if (edoubleprime == NULL)
{
avail[bprime->index] = eprime;
vprime = get_value_handle (eprime);
gcc_assert (vprime);
edoubleprime = bitmap_find_leader (AVAIL_OUT (bprime),
- vprime);
+ vprime, NULL_TREE);
if (edoubleprime == NULL)
{
by_all = false;
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. */
+ any). Insert EXPR's operands into the EXP_GEN set for BLOCK.
+
+ If CHECK_AVAIL is true, checks availability of each operand in
+ BLOCKs AVAIL_OUT set. */
static inline tree
-create_value_expr_from (tree expr, basic_block block, VEC (tree, gc) *vuses)
+create_value_expr_from (tree expr, basic_block block, VEC (tree, gc) *vuses,
+ bool check_avail)
{
int i;
enum tree_code code = TREE_CODE (expr);
/* Recursively value-numberize reference ops and tree lists. */
if (REFERENCE_CLASS_P (op))
{
- tree tempop = create_value_expr_from (op, block, vuses);
+ tree tempop = create_value_expr_from (op, block, vuses, check_avail);
op = tempop ? tempop : op;
val = vn_lookup_or_add_with_vuses (op, vuses);
set_expression_vuses (op, vuses);
TREE_TYPE (val) = TREE_TYPE (TREE_OPERAND (vexpr, i));
TREE_OPERAND (vexpr, i) = val;
+
+ if (check_avail
+ && TREE_CODE (val) == VALUE_HANDLE
+ && !bitmap_set_contains_value (AVAIL_OUT (block), val))
+ return NULL_TREE;
}
efi = find_existing_value_expr (vexpr, vuses);
if (efi)
vuses = copy_vuses_from_stmt (stmt);
STRIP_USELESS_TYPE_CONVERSION (rhs);
if (can_value_number_operation (rhs)
- && (!lhsval || !is_gimple_min_invariant (lhsval)))
+ && (!lhsval || !is_gimple_min_invariant (lhsval))
+ && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
{
/* 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);
+ tree newt = create_value_expr_from (rhs, block, vuses, false);
if (newt)
{
set_expression_vuses (newt, vuses);
else if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT
&& !ann->has_volatile_ops
&& TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 0)) == SSA_NAME
- && (!SSA_NAME_OCCURS_IN_ABNORMAL_PHI
- (GIMPLE_STMT_OPERAND (stmt, 0)))
&& !tree_could_throw_p (stmt))
{
if (make_values_for_stmt (stmt, block))
free (worklist);
}
+/* Insert the expression for SSA_VN that SCCVN thought would be simpler
+ than the available expressions for it. The insertion point is
+ right before the first use in STMT. Returns the SSA_NAME that should
+ be used for replacement. */
+
+static tree
+do_SCCVN_insertion (tree stmt, tree ssa_vn)
+{
+ basic_block bb = bb_for_stmt (stmt);
+ block_stmt_iterator bsi;
+ tree expr, stmts;
+
+ /* First create a value expression from the expression we want
+ to insert and associate it with the value handle for SSA_VN. */
+ expr = create_value_expr_from (VN_INFO (ssa_vn)->expr, bb, NULL, true);
+ if (expr == NULL_TREE)
+ return NULL_TREE;
+ set_value_handle (expr, get_value_handle (ssa_vn));
+
+ /* Then use create_expression_by_pieces to generate a valid
+ expression to insert at this point of the IL stream. */
+ stmts = alloc_stmt_list ();
+ expr = create_expression_by_pieces (bb, expr, stmts, stmt);
+ if (expr == NULL_TREE)
+ return NULL_TREE;
+ bsi = bsi_for_stmt (stmt);
+ bsi_insert_before (&bsi, stmts, BSI_SAME_STMT);
+
+ return expr;
+}
/* Eliminate fully redundant computations. */
tree sprime;
sprime = bitmap_find_leader (AVAIL_OUT (b),
- get_value_handle (lhs));
+ get_value_handle (lhs), NULL_TREE);
+
+ /* If there is no existing usable leader but SCCVN thinks
+ it has an expression it wants to use as replacement,
+ insert that. */
+ if (!sprime
+ || sprime == lhs)
+ {
+ tree val = VN_INFO (lhs)->valnum;
+ if (val != VN_TOP
+ && VN_INFO (val)->needs_insertion
+ && can_PRE_operation (VN_INFO (val)->expr))
+ sprime = do_SCCVN_insertion (stmt, val);
+ }
if (sprime
&& sprime != lhs
insert_fake_stores ();
/* Collect and value number expressions computed in each basic block. */
- if (!run_scc_vn ())
+ if (!run_scc_vn (do_fre))
{
if (!do_fre)
remove_dead_inserted_code ();
}
bsi_commit_edge_inserts ();
- free_scc_vn ();
clear_expression_ids ();
+ free_scc_vn ();
if (!do_fre)
{
remove_dead_inserted_code ();
static unsigned int next_dfs_num;
static VEC (tree, heap) *sccstack;
+static bool may_insert;
+
+
DEF_VEC_P(vn_ssa_aux_t);
DEF_VEC_ALLOC_P(vn_ssa_aux_t, heap);
temp.op1 = TREE_OPERAND (ref, 2);
break;
case COMPONENT_REF:
- /* Record field as operand. */
- temp.op0 = TREE_OPERAND (ref, 1);
+ /* If this is a reference to a union member, record the union
+ member size as operand. Do so only if we are doing
+ expression insertion (during FRE), as PRE currently gets
+ confused with this. */
+ if (may_insert
+ && TREE_CODE (DECL_CONTEXT (TREE_OPERAND (ref, 1))) == UNION_TYPE
+ && integer_zerop (DECL_FIELD_OFFSET (TREE_OPERAND (ref, 1)))
+ && integer_zerop (DECL_FIELD_BIT_OFFSET (TREE_OPERAND (ref, 1))))
+ {
+ temp.type = NULL_TREE;
+ temp.op0 = TYPE_SIZE (TREE_TYPE (TREE_OPERAND (ref, 1)));
+ }
+ else
+ /* Record field as operand. */
+ temp.op0 = TREE_OPERAND (ref, 1);
break;
case ARRAY_RANGE_REF:
case ARRAY_REF:
return changed;
}
+static tree
+try_to_simplify (tree stmt, tree rhs);
+
/* Visit a copy between LHS and RHS, return true if the value number
changed. */
bool changed = false;
tree result = vn_reference_lookup (op, shared_vuses_from_stmt (stmt));
+ /* We handle type-punning through unions by value-numbering based
+ on offset and size of the access. Be prepared to handle a
+ type-mismatch here via creating a VIEW_CONVERT_EXPR. */
+ if (result
+ && !useless_type_conversion_p (TREE_TYPE (result), TREE_TYPE (op)))
+ {
+ /* We will be setting the value number of lhs to the value number
+ of VIEW_CONVERT_EXPR <TREE_TYPE (result)> (result).
+ So first simplify and lookup this expression to see if it
+ is already available. */
+ tree val = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (op), result);
+ if (stmt
+ && !is_gimple_min_invariant (val)
+ && TREE_CODE (val) != SSA_NAME)
+ {
+ tree tem = try_to_simplify (stmt, val);
+ if (tem)
+ val = tem;
+ }
+ result = val;
+ if (!is_gimple_min_invariant (val)
+ && TREE_CODE (val) != SSA_NAME)
+ result = vn_nary_op_lookup (val);
+ /* If the expression is not yet available, value-number lhs to
+ a new SSA_NAME we create. */
+ if (!result && may_insert)
+ {
+ result = make_ssa_name (SSA_NAME_VAR (lhs), NULL_TREE);
+ /* Initialize value-number information properly. */
+ VN_INFO_GET (result)->valnum = result;
+ VN_INFO (result)->expr = val;
+ VN_INFO (result)->needs_insertion = true;
+ /* As all "inserted" statements are singleton SCCs, insert
+ to the valid table. This is strictly needed to
+ avoid re-generating new value SSA_NAMEs for the same
+ expression during SCC iteration over and over (the
+ optimistic table gets cleared after each iteration).
+ We do not need to insert into the optimistic table, as
+ lookups there will fall back to the valid table. */
+ if (current_info == optimistic_info)
+ {
+ current_info = valid_info;
+ vn_nary_op_insert (val, result);
+ current_info = optimistic_info;
+ }
+ else
+ vn_nary_op_insert (val, result);
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Inserting name ");
+ print_generic_expr (dump_file, result, 0);
+ fprintf (dump_file, " for expression ");
+ print_generic_expr (dump_file, val, 0);
+ fprintf (dump_file, "\n");
+ }
+ }
+ }
+
if (result)
{
changed = set_ssa_val_to (lhs, result);
VN_INFO (use)->use_processed = true;
gcc_assert (!SSA_NAME_IN_FREE_LIST (use));
- if (dump_file && (dump_flags & TDF_DETAILS))
+ if (dump_file && (dump_flags & TDF_DETAILS)
+ && !IS_EMPTY_STMT (stmt))
{
fprintf (dump_file, "Value numbering ");
print_generic_expr (dump_file, use, 0);
}
if (TREE_CODE (lhs) == SSA_NAME
+ /* We can substitute SSA_NAMEs that are live over
+ abnormal edges with their constant value. */
+ && !is_gimple_min_invariant (rhs)
&& SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
changed = defs_to_varying (stmt);
else if (REFERENCE_CLASS_P (lhs) || DECL_P (lhs))
&& SSA_NAME_VALUE (name)
&& TREE_CODE (SSA_NAME_VALUE (name)) == VALUE_HANDLE)
SSA_NAME_VALUE (name) = NULL;
+ if (name
+ && VN_INFO (name)->needs_insertion)
+ release_ssa_name (name);
}
obstack_free (&vn_ssa_aux_obstack, NULL);
VEC_free (vn_ssa_aux_t, heap, vn_ssa_aux_table);
due to ressource constraints. */
bool
-run_scc_vn (void)
+run_scc_vn (bool may_insert_arg)
{
size_t i;
tree param;
+ may_insert = may_insert_arg;
+
init_scc_vn ();
current_info = valid_info;
}
}
- for (i = num_ssa_names - 1; i > 0; i--)
+ for (i = 1; i < num_ssa_names; ++i)
{
tree name = ssa_name (i);
if (name
if (!DFS (name))
{
free_scc_vn ();
+ may_insert = false;
return false;
}
}
}
}
+ may_insert = false;
return true;
}