static void record_cond (tree, tree);
static void record_const_or_copy (tree, tree);
static void record_equality (tree, tree);
-static tree simplify_cond_and_lookup_avail_expr (tree, stmt_ann_t, int);
-static tree find_equivalent_equality_comparison (tree);
+static tree simplify_cond_and_lookup_avail_expr (tree);
static void record_range (tree, basic_block);
static bool extract_range_from_cond (tree, tree *, tree *, int *);
static void record_equivalences_from_phis (basic_block);
static void record_equivalences_from_incoming_edge (basic_block);
-static bool eliminate_redundant_computations (tree, stmt_ann_t);
+static bool eliminate_redundant_computations (tree);
static void record_equivalences_from_stmt (tree, int, stmt_ann_t);
static void thread_across_edge (struct dom_walk_data *, edge);
static void dom_opt_finalize_block (struct dom_walk_data *, basic_block);
static inline bool unsafe_associative_fp_binop (tree);
-/* Local version of fold that doesn't introduce cruft. */
-
-static tree
-local_fold (tree t)
-{
- t = fold (t);
-
- /* Strip away useless type conversions. Both the NON_LVALUE_EXPR that
- may have been added by fold, and "useless" type conversions that might
- now be apparent due to propagation. */
- STRIP_USELESS_TYPE_CONVERSION (t);
-
- return t;
-}
-
/* Allocate an EDGE_INFO for edge E and attach it to E.
Return the new EDGE_INFO structure. */
{
cached_lhs = lookup_avail_expr (dummy_cond, false);
if (!cached_lhs || ! is_gimple_min_invariant (cached_lhs))
- cached_lhs = simplify_cond_and_lookup_avail_expr (dummy_cond,
- NULL,
- false);
+ cached_lhs = simplify_cond_and_lookup_avail_expr (dummy_cond);
}
}
/* We can have conditionals which just test the state of a
return false;
}
-/* COND is a condition of the form:
-
- x == const or x != const
-
- Look back to x's defining statement and see if x is defined as
-
- x = (type) y;
-
- If const is unchanged if we convert it to type, then we can build
- the equivalent expression:
-
-
- y == const or y != const
-
- Which may allow further optimizations.
-
- Return the equivalent comparison or NULL if no such equivalent comparison
- was found. */
-
-static tree
-find_equivalent_equality_comparison (tree cond)
-{
- tree op0 = TREE_OPERAND (cond, 0);
- tree op1 = TREE_OPERAND (cond, 1);
- tree def_stmt = SSA_NAME_DEF_STMT (op0);
-
- /* OP0 might have been a parameter, so first make sure it
- was defined by a MODIFY_EXPR. */
- if (def_stmt && TREE_CODE (def_stmt) == MODIFY_EXPR)
- {
- tree def_rhs = TREE_OPERAND (def_stmt, 1);
-
-
- /* If either operand to the comparison is a pointer to
- a function, then we can not apply this optimization
- as some targets require function pointers to be
- canonicalized and in this case this optimization would
- eliminate a necessary canonicalization. */
- if ((POINTER_TYPE_P (TREE_TYPE (op0))
- && TREE_CODE (TREE_TYPE (TREE_TYPE (op0))) == FUNCTION_TYPE)
- || (POINTER_TYPE_P (TREE_TYPE (op1))
- && TREE_CODE (TREE_TYPE (TREE_TYPE (op1))) == FUNCTION_TYPE))
- return NULL;
-
- /* Now make sure the RHS of the MODIFY_EXPR is a typecast. */
- if ((TREE_CODE (def_rhs) == NOP_EXPR
- || TREE_CODE (def_rhs) == CONVERT_EXPR)
- && TREE_CODE (TREE_OPERAND (def_rhs, 0)) == SSA_NAME)
- {
- tree def_rhs_inner = TREE_OPERAND (def_rhs, 0);
- tree def_rhs_inner_type = TREE_TYPE (def_rhs_inner);
- tree new;
-
- if (TYPE_PRECISION (def_rhs_inner_type)
- > TYPE_PRECISION (TREE_TYPE (def_rhs)))
- return NULL;
-
- /* If the inner type of the conversion is a pointer to
- a function, then we can not apply this optimization
- as some targets require function pointers to be
- canonicalized. This optimization would result in
- canonicalization of the pointer when it was not originally
- needed/intended. */
- if (POINTER_TYPE_P (def_rhs_inner_type)
- && TREE_CODE (TREE_TYPE (def_rhs_inner_type)) == FUNCTION_TYPE)
- return NULL;
-
- /* What we want to prove is that if we convert OP1 to
- the type of the object inside the NOP_EXPR that the
- result is still equivalent to SRC.
-
- If that is true, the build and return new equivalent
- condition which uses the source of the typecast and the
- new constant (which has only changed its type). */
- new = build1 (TREE_CODE (def_rhs), def_rhs_inner_type, op1);
- new = local_fold (new);
- if (is_gimple_val (new) && tree_int_cst_equal (new, op1))
- return build2 (TREE_CODE (cond), TREE_TYPE (cond),
- def_rhs_inner, new);
- }
- }
- return NULL;
-}
-
/* STMT is a COND_EXPR for which we could not trivially determine its
result. This routine attempts to find equivalent forms of the
condition which we may be able to optimize better. It also
uses simple value range propagation to optimize conditionals. */
static tree
-simplify_cond_and_lookup_avail_expr (tree stmt,
- stmt_ann_t ann,
- int insert)
+simplify_cond_and_lookup_avail_expr (tree stmt)
{
tree cond = COND_EXPR_COND (stmt);
struct vrp_hash_elt vrp_hash_elt, *vrp_hash_elt_p;
void **slot;
- /* First see if we have test of an SSA_NAME against a constant
- where the SSA_NAME is defined by an earlier typecast which
- is irrelevant when performing tests against the given
- constant. */
- if (TREE_CODE (cond) == EQ_EXPR || TREE_CODE (cond) == NE_EXPR)
- {
- tree new_cond = find_equivalent_equality_comparison (cond);
-
- if (new_cond)
- {
- /* Update the statement to use the new equivalent
- condition. */
- COND_EXPR_COND (stmt) = new_cond;
-
- /* If this is not a real stmt, ann will be NULL and we
- avoid processing the operands. */
- if (ann)
- mark_stmt_modified (stmt);
-
- /* Lookup the condition and return its known value if it
- exists. */
- new_cond = lookup_avail_expr (stmt, insert);
- if (new_cond)
- return new_cond;
-
- /* The operands have changed, so update op0 and op1. */
- op0 = TREE_OPERAND (cond, 0);
- op1 = TREE_OPERAND (cond, 1);
- }
- }
-
/* Consult the value range records for this variable (if they exist)
to see if we can eliminate or simplify this conditional.
table. */
static bool
-eliminate_redundant_computations (tree stmt, stmt_ann_t ann)
+eliminate_redundant_computations (tree stmt)
{
tree *expr_p, def = NULL_TREE;
bool insert = true;
/* If this is a COND_EXPR and we did not find its expression in
the hash table, simplify the condition and try again. */
if (! cached_lhs && TREE_CODE (stmt) == COND_EXPR)
- cached_lhs = simplify_cond_and_lookup_avail_expr (stmt, ann, insert);
+ cached_lhs = simplify_cond_and_lookup_avail_expr (stmt);
opt_stats.num_exprs_considered++;
|| TREE_CODE (stmt) == SWITCH_EXPR));
if (may_optimize_p)
- may_have_exposed_new_symbols
- |= eliminate_redundant_computations (stmt, ann);
+ may_have_exposed_new_symbols |= eliminate_redundant_computations (stmt);
/* Record any additional equivalences created by this statement. */
if (TREE_CODE (stmt) == MODIFY_EXPR)
/* This pass propagates the RHS of assignment statements into use
sites of the LHS of the assignment. It's basically a specialized
- form of tree combination.
+ form of tree combination. It is hoped all of this can disappear
+ when we have a generalized tree combiner.
Note carefully that after propagation the resulting statement
must still be a proper gimple statement. Right now we simply
ptr2 = &x[index];
+ We also propagate casts into SWITCH_EXPR and COND_EXPR conditions to
+ allow us to remove the cast and {NOT_EXPR,NEG_EXPR} into a subsequent
+ {NOT_EXPR,NEG_EXPR}.
This will (of course) be extended as other needs arise. */
return new_cond;
}
+/* COND is a condition of the form:
+
+ x == const or x != const
+
+ Look back to x's defining statement and see if x is defined as
+
+ x = (type) y;
+
+ If const is unchanged if we convert it to type, then we can build
+ the equivalent expression:
+
+
+ y == const or y != const
+
+ Which may allow further optimizations.
+
+ Return the equivalent comparison or NULL if no such equivalent comparison
+ was found. */
+
+static tree
+find_equivalent_equality_comparison (tree cond)
+{
+ tree op0 = TREE_OPERAND (cond, 0);
+ tree op1 = TREE_OPERAND (cond, 1);
+ tree def_stmt = SSA_NAME_DEF_STMT (op0);
+
+ while (def_stmt
+ && TREE_CODE (def_stmt) == MODIFY_EXPR
+ && TREE_CODE (TREE_OPERAND (def_stmt, 1)) == SSA_NAME)
+ def_stmt = SSA_NAME_DEF_STMT (TREE_OPERAND (def_stmt, 1));
+
+ /* OP0 might have been a parameter, so first make sure it
+ was defined by a MODIFY_EXPR. */
+ if (def_stmt && TREE_CODE (def_stmt) == MODIFY_EXPR)
+ {
+ tree def_rhs = TREE_OPERAND (def_stmt, 1);
+
+ /* If either operand to the comparison is a pointer to
+ a function, then we can not apply this optimization
+ as some targets require function pointers to be
+ canonicalized and in this case this optimization would
+ eliminate a necessary canonicalization. */
+ if ((POINTER_TYPE_P (TREE_TYPE (op0))
+ && TREE_CODE (TREE_TYPE (TREE_TYPE (op0))) == FUNCTION_TYPE)
+ || (POINTER_TYPE_P (TREE_TYPE (op1))
+ && TREE_CODE (TREE_TYPE (TREE_TYPE (op1))) == FUNCTION_TYPE))
+ return NULL;
+
+ /* Now make sure the RHS of the MODIFY_EXPR is a typecast. */
+ if ((TREE_CODE (def_rhs) == NOP_EXPR
+ || TREE_CODE (def_rhs) == CONVERT_EXPR)
+ && TREE_CODE (TREE_OPERAND (def_rhs, 0)) == SSA_NAME)
+ {
+ tree def_rhs_inner = TREE_OPERAND (def_rhs, 0);
+ tree def_rhs_inner_type = TREE_TYPE (def_rhs_inner);
+ tree new;
+
+ if (TYPE_PRECISION (def_rhs_inner_type)
+ > TYPE_PRECISION (TREE_TYPE (def_rhs)))
+ return NULL;
+
+ /* If the inner type of the conversion is a pointer to
+ a function, then we can not apply this optimization
+ as some targets require function pointers to be
+ canonicalized. This optimization would result in
+ canonicalization of the pointer when it was not originally
+ needed/intended. */
+ if (POINTER_TYPE_P (def_rhs_inner_type)
+ && TREE_CODE (TREE_TYPE (def_rhs_inner_type)) == FUNCTION_TYPE)
+ return NULL;
+
+ /* What we want to prove is that if we convert OP1 to
+ the type of the object inside the NOP_EXPR that the
+ result is still equivalent to SRC.
+
+ If that is true, the build and return new equivalent
+ condition which uses the source of the typecast and the
+ new constant (which has only changed its type). */
+ new = fold_build1 (TREE_CODE (def_rhs), def_rhs_inner_type, op1);
+ STRIP_USELESS_TYPE_CONVERSION (new);
+ if (is_gimple_val (new) && tree_int_cst_equal (new, op1))
+ return build2 (TREE_CODE (cond), TREE_TYPE (cond),
+ def_rhs_inner, new);
+ }
+ }
+ return NULL;
+}
+
+/* STMT is a COND_EXPR
+
+ This routine attempts to find equivalent forms of the condition
+ which we may be able to optimize better. */
+
+static void
+simplify_cond (tree stmt)
+{
+ tree cond = COND_EXPR_COND (stmt);
+
+ if (COMPARISON_CLASS_P (cond))
+ {
+ tree op0 = TREE_OPERAND (cond, 0);
+ tree op1 = TREE_OPERAND (cond, 1);
+
+ if (TREE_CODE (op0) == SSA_NAME && is_gimple_min_invariant (op1))
+ {
+ /* First see if we have test of an SSA_NAME against a constant
+ where the SSA_NAME is defined by an earlier typecast which
+ is irrelevant when performing tests against the given
+ constant. */
+ if (TREE_CODE (cond) == EQ_EXPR || TREE_CODE (cond) == NE_EXPR)
+ {
+ tree new_cond = find_equivalent_equality_comparison (cond);
+
+ if (new_cond)
+ {
+ COND_EXPR_COND (stmt) = new_cond;
+ update_stmt (stmt);
+ }
+ }
+ }
+ }
+}
+
/* Forward propagate a single-use variable into COND_EXPR as many
times as possible. */
bsi_remove (&bsi, true);
}
}
+
+ /* There are further simplifications that can be performed
+ on COND_EXPRs. Specifically, when comparing an SSA_NAME
+ against a constant where the SSA_NAME is the result of a
+ conversion. Perhaps this should be folded into the rest
+ of the COND_EXPR simplification code. */
+ simplify_cond (cond_expr);
}
/* We've just substituted an ADDR_EXPR into stmt. Update all the