- /* At this point we have a statement which assigns an RHS to an
- SSA_VAR on the LHS. We want to try and simplify this statement
- to expose more context sensitive equivalences which in turn may
- allow us to simplify the condition at the end of the loop. */
- if (TREE_CODE (TREE_OPERAND (stmt, 1)) == SSA_NAME)
- cached_lhs = TREE_OPERAND (stmt, 1);
- else
- {
- /* Copy the operands. */
- tree *copy, pre_fold_expr;
- ssa_op_iter iter;
- use_operand_p use_p;
- unsigned int num, i = 0;
-
- num = NUM_SSA_OPERANDS (stmt, (SSA_OP_USE | SSA_OP_VUSE));
- copy = XCNEWVEC (tree, num);
-
- /* Make a copy of the uses & vuses into USES_COPY, then cprop into
- the operands. */
- FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE | SSA_OP_VUSE)
- {
- tree tmp = NULL;
- tree use = USE_FROM_PTR (use_p);
-
- copy[i++] = use;
- if (TREE_CODE (use) == SSA_NAME)
- tmp = SSA_NAME_VALUE (use);
- if (tmp && TREE_CODE (tmp) != VALUE_HANDLE)
- SET_USE (use_p, tmp);
- }
-
- /* Try to fold/lookup the new expression. Inserting the
- expression into the hash table is unlikely to help
- 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;
- FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE | SSA_OP_VUSE)
- SET_USE (use_p, copy[i++]);
-
- free (copy);
- }
-
- /* Record the context sensitive equivalence if we were able
- to simplify this statement. */
- if (cached_lhs
- && (TREE_CODE (cached_lhs) == SSA_NAME
- || is_gimple_min_invariant (cached_lhs)))
- record_const_or_copy (TREE_OPERAND (stmt, 0), cached_lhs);
- }
-
- /* If we stopped at a COND_EXPR or SWITCH_EXPR, see if we know which arm
- will be taken. */
- if (stmt
- && (TREE_CODE (stmt) == COND_EXPR
- || TREE_CODE (stmt) == GOTO_EXPR
- || TREE_CODE (stmt) == SWITCH_EXPR))
- {
- tree cond, cached_lhs;
-
- /* Now temporarily cprop the operands and try to find the resulting
- expression in the hash tables. */
- if (TREE_CODE (stmt) == COND_EXPR)
- {
- canonicalize_comparison (stmt);
- cond = COND_EXPR_COND (stmt);
- }
- else if (TREE_CODE (stmt) == GOTO_EXPR)
- cond = GOTO_DESTINATION (stmt);
- else
- cond = SWITCH_COND (stmt);
-
- if (COMPARISON_CLASS_P (cond))
- {
- tree dummy_cond, op0, op1;
- enum tree_code cond_code;
-
- op0 = TREE_OPERAND (cond, 0);
- op1 = TREE_OPERAND (cond, 1);
- cond_code = TREE_CODE (cond);
-
- /* Get the current value of both operands. */
- if (TREE_CODE (op0) == SSA_NAME)
- {
- tree tmp = SSA_NAME_VALUE (op0);
- if (tmp && TREE_CODE (tmp) != VALUE_HANDLE)
- op0 = tmp;
- }
-
- if (TREE_CODE (op1) == SSA_NAME)
- {
- tree tmp = SSA_NAME_VALUE (op1);
- if (tmp && TREE_CODE (tmp) != VALUE_HANDLE)
- op1 = tmp;
- }
-
- /* Stuff the operator and operands into our dummy conditional
- expression, creating the dummy conditional if necessary. */
- dummy_cond = (tree) walk_data->global_data;
- if (! dummy_cond)
- {
- dummy_cond = build2 (cond_code, boolean_type_node, op0, op1);
- dummy_cond = build3 (COND_EXPR, void_type_node,
- dummy_cond, NULL_TREE, NULL_TREE);
- walk_data->global_data = dummy_cond;
- }
- else
- {
- TREE_SET_CODE (COND_EXPR_COND (dummy_cond), cond_code);
- TREE_OPERAND (COND_EXPR_COND (dummy_cond), 0) = op0;
- TREE_OPERAND (COND_EXPR_COND (dummy_cond), 1) = op1;
- }
-
- /* We absolutely do not care about any type conversions
- we only care about a zero/nonzero value. */
- cached_lhs = fold (COND_EXPR_COND (dummy_cond));
- while (TREE_CODE (cached_lhs) == NOP_EXPR
- || TREE_CODE (cached_lhs) == CONVERT_EXPR
- || TREE_CODE (cached_lhs) == NON_LVALUE_EXPR)
- cached_lhs = TREE_OPERAND (cached_lhs, 0);
-
- if (! is_gimple_min_invariant (cached_lhs))
- {
- 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);
- }
- }
- /* We can have conditionals which just test the state of a
- variable rather than use a relational operator. These are
- simpler to handle. */
- else if (TREE_CODE (cond) == SSA_NAME)
- {
- cached_lhs = cond;
- cached_lhs = SSA_NAME_VALUE (cached_lhs);
- if (cached_lhs && ! is_gimple_min_invariant (cached_lhs))
- cached_lhs = NULL;
- }
- else
- cached_lhs = lookup_avail_expr (stmt, false);
-
- if (cached_lhs)
- {
- edge taken_edge = find_taken_edge (e->dest, cached_lhs);
- basic_block dest = (taken_edge ? taken_edge->dest : NULL);
-
- if (dest == e->dest)
- return;
-
- /* If we have a known destination for the conditional, then
- we can perform this optimization, which saves at least one
- conditional jump each time it applies since we get to
- bypass the conditional at our original destination. */
- if (dest)
- {
- struct edge_info *edge_info;
-
- if (e->aux)
- edge_info = (struct edge_info *) e->aux;
- else
- edge_info = allocate_edge_info (e);
- edge_info->redirection_target = taken_edge;
- bitmap_set_bit (threaded_blocks, e->dest->index);
- }
- }
- }
-}
-
-
-/* Initialize local stacks for this optimizer and record equivalences
- upon entry to BB. Equivalences can come from the edge traversed to
- reach BB or they may come from PHI nodes at the start of BB. */
-
-static void
-dom_opt_initialize_block (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
- basic_block bb)
-{
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, "\n\nOptimizing block #%d\n\n", bb->index);
-
- /* Push a marker on the stacks of local information so that we know how
- far to unwind when we finalize this block. */
- VEC_safe_push (tree, heap, avail_exprs_stack, NULL_TREE);
- VEC_safe_push (tree, heap, const_and_copies_stack, NULL_TREE);
- VEC_safe_push (tree, heap, nonzero_vars_stack, NULL_TREE);
- VEC_safe_push (tree, heap, vrp_variables_stack, NULL_TREE);
-
- record_equivalences_from_incoming_edge (bb);
-
- /* PHI nodes can create equivalences too. */
- record_equivalences_from_phis (bb);
-}
-
-/* Given an expression EXPR (a relational expression or a statement),
- initialize the hash table element pointed to by ELEMENT. */
-
-static void
-initialize_hash_element (tree expr, tree lhs, struct expr_hash_elt *element)
-{
- /* Hash table elements may be based on conditional expressions or statements.
-
- For the former case, we have no annotation and we want to hash the
- conditional expression. In the latter case we have an annotation and
- we want to record the expression the statement evaluates. */
- if (COMPARISON_CLASS_P (expr) || TREE_CODE (expr) == TRUTH_NOT_EXPR)
- {
- element->stmt = NULL;
- element->rhs = expr;
- }
- else if (TREE_CODE (expr) == COND_EXPR)
- {
- element->stmt = expr;
- element->rhs = COND_EXPR_COND (expr);
- }
- else if (TREE_CODE (expr) == SWITCH_EXPR)
- {
- element->stmt = expr;
- element->rhs = SWITCH_COND (expr);
- }
- else if (TREE_CODE (expr) == RETURN_EXPR && TREE_OPERAND (expr, 0))
- {
- element->stmt = expr;
- element->rhs = TREE_OPERAND (TREE_OPERAND (expr, 0), 1);
- }
- else if (TREE_CODE (expr) == GOTO_EXPR)
- {
- element->stmt = expr;
- element->rhs = GOTO_DESTINATION (expr);
- }
- else
- {
- element->stmt = expr;
- element->rhs = TREE_OPERAND (expr, 1);
- }
-
- element->lhs = lhs;
- element->hash = avail_expr_hash (element);
-}
-
-/* Remove all the expressions in LOCALS from TABLE, stopping when there are
- LIMIT entries left in LOCALs. */
-
-static void
-remove_local_expressions_from_table (void)
-{
- /* Remove all the expressions made available in this block. */
- while (VEC_length (tree, avail_exprs_stack) > 0)
- {
- struct expr_hash_elt element;
- tree expr = VEC_pop (tree, avail_exprs_stack);
-
- if (expr == NULL_TREE)
- break;
-
- initialize_hash_element (expr, NULL, &element);
- htab_remove_elt_with_hash (avail_exprs, &element, element.hash);
- }
-}
-
-/* Use the SSA_NAMES in LOCALS to restore TABLE to its original
- state, stopping when there are LIMIT entries left in LOCALs. */
-
-static void
-restore_nonzero_vars_to_original_value (void)
-{
- while (VEC_length (tree, nonzero_vars_stack) > 0)
- {
- tree name = VEC_pop (tree, nonzero_vars_stack);
-
- if (name == NULL)
- break;
-
- bitmap_clear_bit (nonzero_vars, SSA_NAME_VERSION (name));
- }
-}
-
-/* Use the source/dest pairs in CONST_AND_COPIES_STACK to restore
- CONST_AND_COPIES to its original state, stopping when we hit a
- NULL marker. */
-
-static void
-restore_vars_to_original_value (void)
-{
- while (VEC_length (tree, const_and_copies_stack) > 0)
- {
- tree prev_value, dest;
-
- dest = VEC_pop (tree, const_and_copies_stack);
-
- if (dest == NULL)
- break;
-
- prev_value = VEC_pop (tree, const_and_copies_stack);
- SSA_NAME_VALUE (dest) = prev_value;
- }
-}
-
-/* We have finished processing the dominator children of BB, perform
- any finalization actions in preparation for leaving this node in
- the dominator tree. */
-
-static void
-dom_opt_finalize_block (struct dom_walk_data *walk_data, basic_block bb)
-{
- tree last;
-
- /* 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
- && !single_pred_p (single_succ (bb))
- && !single_succ_p (single_succ (bb)))
-
- {
- thread_across_edge (walk_data, single_succ_edge (bb));
- }
- else if ((last = last_stmt (bb))
- && TREE_CODE (last) == COND_EXPR
- && (COMPARISON_CLASS_P (COND_EXPR_COND (last))
- || TREE_CODE (COND_EXPR_COND (last)) == SSA_NAME)
- && EDGE_COUNT (bb->succs) == 2
- && (EDGE_SUCC (bb, 0)->flags & EDGE_ABNORMAL) == 0
- && (EDGE_SUCC (bb, 1)->flags & EDGE_ABNORMAL) == 0)
- {
- edge true_edge, false_edge;
-
- extract_true_false_edges_from_block (bb, &true_edge, &false_edge);
-
- /* 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;
-
- /* Push a marker onto the available expression stack so that we
- unwind any expressions related to the TRUE arm before processing
- the false arm below. */
- VEC_safe_push (tree, heap, avail_exprs_stack, NULL_TREE);
- VEC_safe_push (tree, heap, const_and_copies_stack, NULL_TREE);
-
- edge_info = (struct edge_info *) true_edge->aux;
-
- /* If we have info associated with this edge, record it into
- our equivalency tables. */
- if (edge_info)
- {
- tree *cond_equivalences = edge_info->cond_equivalences;
- tree lhs = edge_info->lhs;
- tree rhs = edge_info->rhs;
-
- /* If we have a simple NAME = VALUE equivalency record it. */
- if (lhs && TREE_CODE (lhs) == SSA_NAME)
- record_const_or_copy (lhs, rhs);
-
- /* If we have 0 = COND or 1 = COND equivalences, record them
- into our expression hash tables. */
- if (cond_equivalences)
- for (i = 0; i < edge_info->max_cond_equivalences; i += 2)
- {
- tree expr = cond_equivalences[i];
- tree value = cond_equivalences[i + 1];
-
- record_cond (expr, value);
- }
- }
-
- /* Now thread the edge. */
- thread_across_edge (walk_data, true_edge);
-
- /* And restore the various tables to their state before
- we threaded this edge. */
- remove_local_expressions_from_table ();
- restore_vars_to_original_value ();
- }
-
- /* Similarly for the ELSE arm. */
- if (!single_pred_p (false_edge->dest) && !single_succ_p (false_edge->dest))
- {
- struct edge_info *edge_info;
- unsigned int i;
-
- edge_info = (struct edge_info *) false_edge->aux;
-
- /* If we have info associated with this edge, record it into
- our equivalency tables. */
- if (edge_info)
- {
- tree *cond_equivalences = edge_info->cond_equivalences;
- tree lhs = edge_info->lhs;
- tree rhs = edge_info->rhs;
-
- /* If we have a simple NAME = VALUE equivalency record it. */
- if (lhs && TREE_CODE (lhs) == SSA_NAME)
- record_const_or_copy (lhs, rhs);
-
- /* If we have 0 = COND or 1 = COND equivalences, record them
- into our expression hash tables. */
- if (cond_equivalences)
- for (i = 0; i < edge_info->max_cond_equivalences; i += 2)
- {
- tree expr = cond_equivalences[i];
- tree value = cond_equivalences[i + 1];
-
- record_cond (expr, value);
- }
- }
-
- thread_across_edge (walk_data, false_edge);
-
- /* No need to remove local expressions from our tables
- or restore vars to their original value as that will
- be done immediately below. */
- }
- }
-
- remove_local_expressions_from_table ();
- restore_nonzero_vars_to_original_value ();
- restore_vars_to_original_value ();
-
- /* Remove VRP records associated with this basic block. They are no
- longer valid.
-
- To be efficient, we note which variables have had their values
- constrained in this block. So walk over each variable in the
- VRP_VARIABLEs array. */
- while (VEC_length (tree, vrp_variables_stack) > 0)
- {
- tree var = VEC_pop (tree, vrp_variables_stack);
- struct vrp_hash_elt vrp_hash_elt, *vrp_hash_elt_p;
- void **slot;
-
- /* Each variable has a stack of value range records. We want to
- invalidate those associated with our basic block. So we walk
- the array backwards popping off records associated with our
- block. Once we hit a record not associated with our block
- we are done. */
- VEC(vrp_element_p,heap) **var_vrp_records;
-
- if (var == NULL)
- break;
-
- vrp_hash_elt.var = var;
- vrp_hash_elt.records = NULL;
-
- slot = htab_find_slot (vrp_data, &vrp_hash_elt, NO_INSERT);
-
- vrp_hash_elt_p = (struct vrp_hash_elt *) *slot;
- var_vrp_records = &vrp_hash_elt_p->records;
-
- while (VEC_length (vrp_element_p, *var_vrp_records) > 0)
- {
- struct vrp_element *element
- = VEC_last (vrp_element_p, *var_vrp_records);
-
- if (element->bb != bb)
- break;
-
- VEC_pop (vrp_element_p, *var_vrp_records);
- }
- }
-
- /* If we queued any statements to rescan in this block, then
- go ahead and rescan them now. */
- while (VEC_length (tree, stmts_to_rescan) > 0)
- {
- tree stmt = VEC_last (tree, stmts_to_rescan);
- basic_block stmt_bb = bb_for_stmt (stmt);
-
- if (stmt_bb != bb)
- break;
-
- VEC_pop (tree, stmts_to_rescan);
- mark_new_vars_to_rename (stmt);
- }
-}