#include "tree-pass.h"
#include "tree-ssa-propagate.h"
#include "langhooks.h"
+#include "params.h"
/* This file implements optimizations on the dominator tree. */
block_stmt_iterator bsi;
tree stmt = NULL;
tree phi;
+ int stmt_count = 0;
+ int max_stmt_count;
+
/* If E->dest does not end with a conditional, then there is
nothing to do. */
tree src = PHI_ARG_DEF_FROM_EDGE (phi, e);
tree dst = PHI_RESULT (phi);
+ /* Do not include virtual PHIs in our statement count as
+ they never generate code. */
+ if (is_gimple_reg (dst))
+ stmt_count++;
+
/* If the desired argument is not the same as this PHI's result
and it is set by a PHI in E->dest, then we can not thread
through E->dest. */
Failure to simplify into the form above merely means that the
statement provides no equivalences to help simplify later
statements. This does not prevent threading through E->dest. */
+ max_stmt_count = PARAM_VALUE (PARAM_MAX_JUMP_THREAD_DUPLICATION_STMTS);
for (bsi = bsi_start (e->dest); ! bsi_end_p (bsi); bsi_next (&bsi))
{
- tree cached_lhs;
+ tree cached_lhs = NULL;
stmt = bsi_stmt (bsi);
if (IS_EMPTY_STMT (stmt) || TREE_CODE (stmt) == LABEL_EXPR)
continue;
+ /* If duplicating this block is going to cause too much code
+ expansion, then do not thread through this block. */
+ stmt_count++;
+ if (stmt_count > max_stmt_count)
+ return;
+
/* Safely handle threading across loop backedges. This is
over conservative, but still allows us to capture the
majority of the cases where we can thread across a loop
else
{
/* Copy the operands. */
- tree *copy;
+ tree *copy, pre_fold_expr;
ssa_op_iter iter;
use_operand_p use_p;
unsigned int num, i = 0;
/* Try to fold/lookup the new expression. Inserting the
expression into the hash table is unlikely to help
- simplify anything later, so just query the hashtable. */
- cached_lhs = fold (TREE_OPERAND (stmt, 1));
- if (TREE_CODE (cached_lhs) != SSA_NAME
- && !is_gimple_min_invariant (cached_lhs))
- cached_lhs = lookup_avail_expr (stmt, false);
+ Sadly, we have to handle conditional assignments specially
+ here, because fold expects all the operands of an expression
+ to be folded before the expression itself is folded, but we
+ can't just substitute the folded condition here. */
+ if (TREE_CODE (TREE_OPERAND (stmt, 1)) == COND_EXPR)
+ {
+ tree cond = COND_EXPR_COND (TREE_OPERAND (stmt, 1));
+ cond = fold (cond);
+ if (cond == boolean_true_node)
+ pre_fold_expr = COND_EXPR_THEN (TREE_OPERAND (stmt, 1));
+ else if (cond == boolean_false_node)
+ pre_fold_expr = COND_EXPR_ELSE (TREE_OPERAND (stmt, 1));
+ else
+ pre_fold_expr = TREE_OPERAND (stmt, 1);
+ }
+ else
+ pre_fold_expr = TREE_OPERAND (stmt, 1);
+ if (pre_fold_expr)
+ {
+ cached_lhs = fold (pre_fold_expr);
+ if (TREE_CODE (cached_lhs) != SSA_NAME
+ && !is_gimple_min_invariant (cached_lhs))
+ cached_lhs = lookup_avail_expr (stmt, false);
+ }
/* Restore the statement's original uses/defs. */
i = 0;
{
tree last;
- /* If we are at a leaf node in the dominator tree, see if we can thread
- the edge from BB through its successor.
-
- Do this before we remove entries from our equivalence tables. */
+ /* If we have an outgoing edge to a block with multiple incoming and
+ outgoing edges, then we may be able to thread the edge. ie, we
+ may be able to statically determine which of the outgoing edges
+ will be traversed when the incoming edge from BB is traversed. */
if (single_succ_p (bb)
&& (single_succ_edge (bb)->flags & EDGE_ABNORMAL) == 0
- && (get_immediate_dominator (CDI_DOMINATORS, single_succ (bb)) != bb
- || phi_nodes (single_succ (bb))))
+ && !single_pred_p (single_succ (bb))
+ && !single_succ_p (single_succ (bb)))
{
thread_across_edge (walk_data, single_succ_edge (bb));
extract_true_false_edges_from_block (bb, &true_edge, &false_edge);
- /* If the THEN arm is the end of a dominator tree or has PHI nodes,
- then try to thread through its edge. */
- if (get_immediate_dominator (CDI_DOMINATORS, true_edge->dest) != bb
- || phi_nodes (true_edge->dest))
+ /* Only try to thread the edge if it reaches a target block with
+ more than one predecessor and more than one successor. */
+ if (!single_pred_p (true_edge->dest) && !single_succ_p (true_edge->dest))
{
struct edge_info *edge_info;
unsigned int i;
}
/* Similarly for the ELSE arm. */
- if (get_immediate_dominator (CDI_DOMINATORS, false_edge->dest) != bb
- || phi_nodes (false_edge->dest))
+ if (!single_pred_p (false_edge->dest) && !single_succ_p (false_edge->dest))
{
struct edge_info *edge_info;
unsigned int i;
assignment. Add minus to this, as we handle it specially below. */
if ((associative_tree_code (rhs_code) || rhs_code == MINUS_EXPR)
&& TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME
+ && num_imm_uses (TREE_OPERAND (rhs, 0)) == 1
&& is_gimple_min_invariant (TREE_OPERAND (rhs, 1)))
{
tree rhs_def_stmt = SSA_NAME_DEF_STMT (TREE_OPERAND (rhs, 0));
record ranges for enumerations. Presumably this is due to
the fact that they're rarely used directly. They are typically
cast into an integer type and used that way. */
- if (TREE_CODE (type) != INTEGER_TYPE
- /* We don't know how to deal with types with variable bounds. */
- || TREE_CODE (TYPE_MIN_VALUE (type)) != INTEGER_CST
- || TREE_CODE (TYPE_MAX_VALUE (type)) != INTEGER_CST)
+ if (TREE_CODE (type) != INTEGER_TYPE)
return 0;
switch (TREE_CODE (cond))
case GE_EXPR:
low = op1;
+
+ /* Get the highest value of the type. If not a constant, use that
+ of its base type, if it has one. */
high = TYPE_MAX_VALUE (type);
+ if (TREE_CODE (high) != INTEGER_CST && TREE_TYPE (type))
+ high = TYPE_MAX_VALUE (TREE_TYPE (type));
inverted = 0;
break;
case GT_EXPR:
high = TYPE_MAX_VALUE (type);
+ if (TREE_CODE (high) != INTEGER_CST && TREE_TYPE (type))
+ high = TYPE_MAX_VALUE (TREE_TYPE (type));
if (!tree_int_cst_lt (op1, high))
return 0;
low = int_const_binop (PLUS_EXPR, op1, integer_one_node, 1);
case LE_EXPR:
high = op1;
low = TYPE_MIN_VALUE (type);
+ if (TREE_CODE (low) != INTEGER_CST && TREE_TYPE (type))
+ low = TYPE_MIN_VALUE (TREE_TYPE (type));
inverted = 0;
break;
case LT_EXPR:
low = TYPE_MIN_VALUE (type);
+ if (TREE_CODE (low) != INTEGER_CST && TREE_TYPE (type))
+ low = TYPE_MIN_VALUE (TREE_TYPE (type));
if (!tree_int_cst_lt (low, op1))
return 0;
high = int_const_binop (MINUS_EXPR, op1, integer_one_node, 1);