diff options
author | Dan Albert <danalbert@google.com> | 2015-06-17 11:09:54 -0700 |
---|---|---|
committer | Dan Albert <danalbert@google.com> | 2015-06-17 14:15:22 -0700 |
commit | f378ebf14df0952eae870c9865bab8326aa8f137 (patch) | |
tree | 31794503eb2a8c64ea5f313b93100f1163afcffb /gcc-4.2.1/gcc/tree-ssa-propagate.c | |
parent | 2c58169824949d3a597d9fa81931e001ef9b1bd0 (diff) | |
download | toolchain_gcc-f378ebf14df0952eae870c9865bab8326aa8f137.tar.gz toolchain_gcc-f378ebf14df0952eae870c9865bab8326aa8f137.tar.bz2 toolchain_gcc-f378ebf14df0952eae870c9865bab8326aa8f137.zip |
Delete old versions of GCC.
Change-Id: I710f125d905290e1024cbd67f48299861790c66c
Diffstat (limited to 'gcc-4.2.1/gcc/tree-ssa-propagate.c')
-rw-r--r-- | gcc-4.2.1/gcc/tree-ssa-propagate.c | 1207 |
1 files changed, 0 insertions, 1207 deletions
diff --git a/gcc-4.2.1/gcc/tree-ssa-propagate.c b/gcc-4.2.1/gcc/tree-ssa-propagate.c deleted file mode 100644 index e08591106..000000000 --- a/gcc-4.2.1/gcc/tree-ssa-propagate.c +++ /dev/null @@ -1,1207 +0,0 @@ -/* Generic SSA value propagation engine. - Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. - Contributed by Diego Novillo <dnovillo@redhat.com> - - This file is part of GCC. - - GCC is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2, or (at your option) any - later version. - - GCC is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License - along with GCC; see the file COPYING. If not, write to the Free - Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tm.h" -#include "tree.h" -#include "flags.h" -#include "rtl.h" -#include "tm_p.h" -#include "ggc.h" -#include "basic-block.h" -#include "output.h" -#include "expr.h" -#include "function.h" -#include "diagnostic.h" -#include "timevar.h" -#include "tree-dump.h" -#include "tree-flow.h" -#include "tree-pass.h" -#include "tree-ssa-propagate.h" -#include "langhooks.h" -#include "varray.h" -#include "vec.h" - -/* This file implements a generic value propagation engine based on - the same propagation used by the SSA-CCP algorithm [1]. - - Propagation is performed by simulating the execution of every - statement that produces the value being propagated. Simulation - proceeds as follows: - - 1- Initially, all edges of the CFG are marked not executable and - the CFG worklist is seeded with all the statements in the entry - basic block (block 0). - - 2- Every statement S is simulated with a call to the call-back - function SSA_PROP_VISIT_STMT. This evaluation may produce 3 - results: - - SSA_PROP_NOT_INTERESTING: Statement S produces nothing of - interest and does not affect any of the work lists. - - SSA_PROP_VARYING: The value produced by S cannot be determined - at compile time. Further simulation of S is not required. - If S is a conditional jump, all the outgoing edges for the - block are considered executable and added to the work - list. - - SSA_PROP_INTERESTING: S produces a value that can be computed - at compile time. Its result can be propagated into the - statements that feed from S. Furthermore, if S is a - conditional jump, only the edge known to be taken is added - to the work list. Edges that are known not to execute are - never simulated. - - 3- PHI nodes are simulated with a call to SSA_PROP_VISIT_PHI. The - return value from SSA_PROP_VISIT_PHI has the same semantics as - described in #2. - - 4- Three work lists are kept. Statements are only added to these - lists if they produce one of SSA_PROP_INTERESTING or - SSA_PROP_VARYING. - - CFG_BLOCKS contains the list of blocks to be simulated. - Blocks are added to this list if their incoming edges are - found executable. - - VARYING_SSA_EDGES contains the list of statements that feed - from statements that produce an SSA_PROP_VARYING result. - These are simulated first to speed up processing. - - INTERESTING_SSA_EDGES contains the list of statements that - feed from statements that produce an SSA_PROP_INTERESTING - result. - - 5- Simulation terminates when all three work lists are drained. - - Before calling ssa_propagate, it is important to clear - DONT_SIMULATE_AGAIN for all the statements in the program that - should be simulated. This initialization allows an implementation - to specify which statements should never be simulated. - - It is also important to compute def-use information before calling - ssa_propagate. - - References: - - [1] Constant propagation with conditional branches, - Wegman and Zadeck, ACM TOPLAS 13(2):181-210. - - [2] Building an Optimizing Compiler, - Robert Morgan, Butterworth-Heinemann, 1998, Section 8.9. - - [3] Advanced Compiler Design and Implementation, - Steven Muchnick, Morgan Kaufmann, 1997, Section 12.6 */ - -/* Function pointers used to parameterize the propagation engine. */ -static ssa_prop_visit_stmt_fn ssa_prop_visit_stmt; -static ssa_prop_visit_phi_fn ssa_prop_visit_phi; - -/* Use the TREE_DEPRECATED bitflag to mark statements that have been - added to one of the SSA edges worklists. This flag is used to - avoid visiting statements unnecessarily when draining an SSA edge - worklist. If while simulating a basic block, we find a statement with - STMT_IN_SSA_EDGE_WORKLIST set, we clear it to prevent SSA edge - processing from visiting it again. */ -#define STMT_IN_SSA_EDGE_WORKLIST(T) TREE_DEPRECATED (T) - -/* A bitmap to keep track of executable blocks in the CFG. */ -static sbitmap executable_blocks; - -/* Array of control flow edges on the worklist. */ -static VEC(basic_block,heap) *cfg_blocks; - -static unsigned int cfg_blocks_num = 0; -static int cfg_blocks_tail; -static int cfg_blocks_head; - -static sbitmap bb_in_list; - -/* Worklist of SSA edges which will need reexamination as their - definition has changed. SSA edges are def-use edges in the SSA - web. For each D-U edge, we store the target statement or PHI node - U. */ -static GTY(()) VEC(tree,gc) *interesting_ssa_edges; - -/* Identical to INTERESTING_SSA_EDGES. For performance reasons, the - list of SSA edges is split into two. One contains all SSA edges - who need to be reexamined because their lattice value changed to - varying (this worklist), and the other contains all other SSA edges - to be reexamined (INTERESTING_SSA_EDGES). - - Since most values in the program are VARYING, the ideal situation - is to move them to that lattice value as quickly as possible. - Thus, it doesn't make sense to process any other type of lattice - value until all VARYING values are propagated fully, which is one - thing using the VARYING worklist achieves. In addition, if we - don't use a separate worklist for VARYING edges, we end up with - situations where lattice values move from - UNDEFINED->INTERESTING->VARYING instead of UNDEFINED->VARYING. */ -static GTY(()) VEC(tree,gc) *varying_ssa_edges; - - -/* Return true if the block worklist empty. */ - -static inline bool -cfg_blocks_empty_p (void) -{ - return (cfg_blocks_num == 0); -} - - -/* Add a basic block to the worklist. The block must not be already - in the worklist, and it must not be the ENTRY or EXIT block. */ - -static void -cfg_blocks_add (basic_block bb) -{ - gcc_assert (bb != ENTRY_BLOCK_PTR && bb != EXIT_BLOCK_PTR); - gcc_assert (!TEST_BIT (bb_in_list, bb->index)); - - if (cfg_blocks_empty_p ()) - { - cfg_blocks_tail = cfg_blocks_head = 0; - cfg_blocks_num = 1; - } - else - { - cfg_blocks_num++; - if (cfg_blocks_num > VEC_length (basic_block, cfg_blocks)) - { - /* We have to grow the array now. Adjust to queue to occupy - the full space of the original array. We do not need to - initialize the newly allocated portion of the array - because we keep track of CFG_BLOCKS_HEAD and - CFG_BLOCKS_HEAD. */ - cfg_blocks_tail = VEC_length (basic_block, cfg_blocks); - cfg_blocks_head = 0; - VEC_safe_grow (basic_block, heap, cfg_blocks, 2 * cfg_blocks_tail); - } - else - cfg_blocks_tail = ((cfg_blocks_tail + 1) - % VEC_length (basic_block, cfg_blocks)); - } - - VEC_replace (basic_block, cfg_blocks, cfg_blocks_tail, bb); - SET_BIT (bb_in_list, bb->index); -} - - -/* Remove a block from the worklist. */ - -static basic_block -cfg_blocks_get (void) -{ - basic_block bb; - - bb = VEC_index (basic_block, cfg_blocks, cfg_blocks_head); - - gcc_assert (!cfg_blocks_empty_p ()); - gcc_assert (bb); - - cfg_blocks_head = ((cfg_blocks_head + 1) - % VEC_length (basic_block, cfg_blocks)); - --cfg_blocks_num; - RESET_BIT (bb_in_list, bb->index); - - return bb; -} - - -/* We have just defined a new value for VAR. If IS_VARYING is true, - add all immediate uses of VAR to VARYING_SSA_EDGES, otherwise add - them to INTERESTING_SSA_EDGES. */ - -static void -add_ssa_edge (tree var, bool is_varying) -{ - imm_use_iterator iter; - use_operand_p use_p; - - FOR_EACH_IMM_USE_FAST (use_p, iter, var) - { - tree use_stmt = USE_STMT (use_p); - - if (!DONT_SIMULATE_AGAIN (use_stmt) - && !STMT_IN_SSA_EDGE_WORKLIST (use_stmt)) - { - STMT_IN_SSA_EDGE_WORKLIST (use_stmt) = 1; - if (is_varying) - VEC_safe_push (tree, gc, varying_ssa_edges, use_stmt); - else - VEC_safe_push (tree, gc, interesting_ssa_edges, use_stmt); - } - } -} - - -/* Add edge E to the control flow worklist. */ - -static void -add_control_edge (edge e) -{ - basic_block bb = e->dest; - if (bb == EXIT_BLOCK_PTR) - return; - - /* If the edge had already been executed, skip it. */ - if (e->flags & EDGE_EXECUTABLE) - return; - - e->flags |= EDGE_EXECUTABLE; - - /* If the block is already in the list, we're done. */ - if (TEST_BIT (bb_in_list, bb->index)) - return; - - cfg_blocks_add (bb); - - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "Adding Destination of edge (%d -> %d) to worklist\n\n", - e->src->index, e->dest->index); -} - - -/* Simulate the execution of STMT and update the work lists accordingly. */ - -static void -simulate_stmt (tree stmt) -{ - enum ssa_prop_result val = SSA_PROP_NOT_INTERESTING; - edge taken_edge = NULL; - tree output_name = NULL_TREE; - - /* Don't bother visiting statements that are already - considered varying by the propagator. */ - if (DONT_SIMULATE_AGAIN (stmt)) - return; - - if (TREE_CODE (stmt) == PHI_NODE) - { - val = ssa_prop_visit_phi (stmt); - output_name = PHI_RESULT (stmt); - } - else - val = ssa_prop_visit_stmt (stmt, &taken_edge, &output_name); - - if (val == SSA_PROP_VARYING) - { - DONT_SIMULATE_AGAIN (stmt) = 1; - - /* If the statement produced a new varying value, add the SSA - edges coming out of OUTPUT_NAME. */ - if (output_name) - add_ssa_edge (output_name, true); - - /* If STMT transfers control out of its basic block, add - all outgoing edges to the work list. */ - if (stmt_ends_bb_p (stmt)) - { - edge e; - edge_iterator ei; - basic_block bb = bb_for_stmt (stmt); - FOR_EACH_EDGE (e, ei, bb->succs) - add_control_edge (e); - } - } - else if (val == SSA_PROP_INTERESTING) - { - /* If the statement produced new value, add the SSA edges coming - out of OUTPUT_NAME. */ - if (output_name) - add_ssa_edge (output_name, false); - - /* If we know which edge is going to be taken out of this block, - add it to the CFG work list. */ - if (taken_edge) - add_control_edge (taken_edge); - } -} - -/* Process an SSA edge worklist. WORKLIST is the SSA edge worklist to - drain. This pops statements off the given WORKLIST and processes - them until there are no more statements on WORKLIST. - We take a pointer to WORKLIST because it may be reallocated when an - SSA edge is added to it in simulate_stmt. */ - -static void -process_ssa_edge_worklist (VEC(tree,gc) **worklist) -{ - /* Drain the entire worklist. */ - while (VEC_length (tree, *worklist) > 0) - { - basic_block bb; - - /* Pull the statement to simulate off the worklist. */ - tree stmt = VEC_pop (tree, *worklist); - - /* If this statement was already visited by simulate_block, then - we don't need to visit it again here. */ - if (!STMT_IN_SSA_EDGE_WORKLIST (stmt)) - continue; - - /* STMT is no longer in a worklist. */ - STMT_IN_SSA_EDGE_WORKLIST (stmt) = 0; - - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "\nSimulating statement (from ssa_edges): "); - print_generic_stmt (dump_file, stmt, dump_flags); - } - - bb = bb_for_stmt (stmt); - - /* PHI nodes are always visited, regardless of whether or not - the destination block is executable. Otherwise, visit the - statement only if its block is marked executable. */ - if (TREE_CODE (stmt) == PHI_NODE - || TEST_BIT (executable_blocks, bb->index)) - simulate_stmt (stmt); - } -} - - -/* Simulate the execution of BLOCK. Evaluate the statement associated - with each variable reference inside the block. */ - -static void -simulate_block (basic_block block) -{ - tree phi; - - /* There is nothing to do for the exit block. */ - if (block == EXIT_BLOCK_PTR) - return; - - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "\nSimulating block %d\n", block->index); - - /* Always simulate PHI nodes, even if we have simulated this block - before. */ - for (phi = phi_nodes (block); phi; phi = PHI_CHAIN (phi)) - simulate_stmt (phi); - - /* If this is the first time we've simulated this block, then we - must simulate each of its statements. */ - if (!TEST_BIT (executable_blocks, block->index)) - { - block_stmt_iterator j; - unsigned int normal_edge_count; - edge e, normal_edge; - edge_iterator ei; - - /* Note that we have simulated this block. */ - SET_BIT (executable_blocks, block->index); - - for (j = bsi_start (block); !bsi_end_p (j); bsi_next (&j)) - { - tree stmt = bsi_stmt (j); - - /* If this statement is already in the worklist then - "cancel" it. The reevaluation implied by the worklist - entry will produce the same value we generate here and - thus reevaluating it again from the worklist is - pointless. */ - if (STMT_IN_SSA_EDGE_WORKLIST (stmt)) - STMT_IN_SSA_EDGE_WORKLIST (stmt) = 0; - - simulate_stmt (stmt); - } - - /* We can not predict when abnormal edges will be executed, so - once a block is considered executable, we consider any - outgoing abnormal edges as executable. - - At the same time, if this block has only one successor that is - reached by non-abnormal edges, then add that successor to the - worklist. */ - normal_edge_count = 0; - normal_edge = NULL; - FOR_EACH_EDGE (e, ei, block->succs) - { - if (e->flags & EDGE_ABNORMAL) - add_control_edge (e); - else - { - normal_edge_count++; - normal_edge = e; - } - } - - if (normal_edge_count == 1) - add_control_edge (normal_edge); - } -} - - -/* Initialize local data structures and work lists. */ - -static void -ssa_prop_init (void) -{ - edge e; - edge_iterator ei; - basic_block bb; - size_t i; - - /* Worklists of SSA edges. */ - interesting_ssa_edges = VEC_alloc (tree, gc, 20); - varying_ssa_edges = VEC_alloc (tree, gc, 20); - - executable_blocks = sbitmap_alloc (last_basic_block); - sbitmap_zero (executable_blocks); - - bb_in_list = sbitmap_alloc (last_basic_block); - sbitmap_zero (bb_in_list); - - if (dump_file && (dump_flags & TDF_DETAILS)) - dump_immediate_uses (dump_file); - - cfg_blocks = VEC_alloc (basic_block, heap, 20); - VEC_safe_grow (basic_block, heap, cfg_blocks, 20); - - /* Initialize the values for every SSA_NAME. */ - for (i = 1; i < num_ssa_names; i++) - if (ssa_name (i)) - SSA_NAME_VALUE (ssa_name (i)) = NULL_TREE; - - /* Initially assume that every edge in the CFG is not executable. - (including the edges coming out of ENTRY_BLOCK_PTR). */ - FOR_ALL_BB (bb) - { - block_stmt_iterator si; - - for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si)) - STMT_IN_SSA_EDGE_WORKLIST (bsi_stmt (si)) = 0; - - FOR_EACH_EDGE (e, ei, bb->succs) - e->flags &= ~EDGE_EXECUTABLE; - } - - /* Seed the algorithm by adding the successors of the entry block to the - edge worklist. */ - FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR->succs) - add_control_edge (e); -} - - -/* Free allocated storage. */ - -static void -ssa_prop_fini (void) -{ - VEC_free (tree, gc, interesting_ssa_edges); - VEC_free (tree, gc, varying_ssa_edges); - VEC_free (basic_block, heap, cfg_blocks); - cfg_blocks = NULL; - sbitmap_free (bb_in_list); - sbitmap_free (executable_blocks); -} - - -/* Get the main expression from statement STMT. */ - -tree -get_rhs (tree stmt) -{ - enum tree_code code = TREE_CODE (stmt); - - switch (code) - { - case RETURN_EXPR: - stmt = TREE_OPERAND (stmt, 0); - if (!stmt || TREE_CODE (stmt) != MODIFY_EXPR) - return stmt; - /* FALLTHRU */ - - case MODIFY_EXPR: - stmt = TREE_OPERAND (stmt, 1); - if (TREE_CODE (stmt) == WITH_SIZE_EXPR) - return TREE_OPERAND (stmt, 0); - else - return stmt; - - case COND_EXPR: - return COND_EXPR_COND (stmt); - case SWITCH_EXPR: - return SWITCH_COND (stmt); - case GOTO_EXPR: - return GOTO_DESTINATION (stmt); - case LABEL_EXPR: - return LABEL_EXPR_LABEL (stmt); - - default: - return stmt; - } -} - - -/* Set the main expression of *STMT_P to EXPR. If EXPR is not a valid - GIMPLE expression no changes are done and the function returns - false. */ - -bool -set_rhs (tree *stmt_p, tree expr) -{ - tree stmt = *stmt_p, op; - enum tree_code code = TREE_CODE (expr); - stmt_ann_t ann; - tree var; - ssa_op_iter iter; - - /* Verify the constant folded result is valid gimple. */ - if (TREE_CODE_CLASS (code) == tcc_binary) - { - if (!is_gimple_val (TREE_OPERAND (expr, 0)) - || !is_gimple_val (TREE_OPERAND (expr, 1))) - return false; - } - else if (TREE_CODE_CLASS (code) == tcc_unary) - { - if (!is_gimple_val (TREE_OPERAND (expr, 0))) - return false; - } - else if (code == ADDR_EXPR) - { - if (TREE_CODE (TREE_OPERAND (expr, 0)) == ARRAY_REF - && !is_gimple_val (TREE_OPERAND (TREE_OPERAND (expr, 0), 1))) - return false; - } - else if (code == COMPOUND_EXPR - || code == MODIFY_EXPR) - return false; - - if (EXPR_HAS_LOCATION (stmt) - && EXPR_P (expr) - && ! EXPR_HAS_LOCATION (expr) - && TREE_SIDE_EFFECTS (expr) - && TREE_CODE (expr) != LABEL_EXPR) - SET_EXPR_LOCATION (expr, EXPR_LOCATION (stmt)); - - switch (TREE_CODE (stmt)) - { - case RETURN_EXPR: - op = TREE_OPERAND (stmt, 0); - if (TREE_CODE (op) != MODIFY_EXPR) - { - TREE_OPERAND (stmt, 0) = expr; - break; - } - stmt = op; - /* FALLTHRU */ - - case MODIFY_EXPR: - op = TREE_OPERAND (stmt, 1); - if (TREE_CODE (op) == WITH_SIZE_EXPR) - stmt = op; - TREE_OPERAND (stmt, 1) = expr; - break; - - case COND_EXPR: - if (!is_gimple_condexpr (expr)) - return false; - COND_EXPR_COND (stmt) = expr; - break; - case SWITCH_EXPR: - SWITCH_COND (stmt) = expr; - break; - case GOTO_EXPR: - GOTO_DESTINATION (stmt) = expr; - break; - case LABEL_EXPR: - LABEL_EXPR_LABEL (stmt) = expr; - break; - - default: - /* Replace the whole statement with EXPR. If EXPR has no side - effects, then replace *STMT_P with an empty statement. */ - ann = stmt_ann (stmt); - *stmt_p = TREE_SIDE_EFFECTS (expr) ? expr : build_empty_stmt (); - (*stmt_p)->common.ann = (tree_ann_t) ann; - - if (in_ssa_p - && TREE_SIDE_EFFECTS (expr)) - { - /* Fix all the SSA_NAMEs created by *STMT_P to point to its new - replacement. */ - FOR_EACH_SSA_TREE_OPERAND (var, stmt, iter, SSA_OP_ALL_DEFS) - { - if (TREE_CODE (var) == SSA_NAME) - SSA_NAME_DEF_STMT (var) = *stmt_p; - } - } - break; - } - - return true; -} - - -/* Entry point to the propagation engine. - - VISIT_STMT is called for every statement visited. - VISIT_PHI is called for every PHI node visited. */ - -void -ssa_propagate (ssa_prop_visit_stmt_fn visit_stmt, - ssa_prop_visit_phi_fn visit_phi) -{ - ssa_prop_visit_stmt = visit_stmt; - ssa_prop_visit_phi = visit_phi; - - ssa_prop_init (); - - /* Iterate until the worklists are empty. */ - while (!cfg_blocks_empty_p () - || VEC_length (tree, interesting_ssa_edges) > 0 - || VEC_length (tree, varying_ssa_edges) > 0) - { - if (!cfg_blocks_empty_p ()) - { - /* Pull the next block to simulate off the worklist. */ - basic_block dest_block = cfg_blocks_get (); - simulate_block (dest_block); - } - - /* In order to move things to varying as quickly as - possible,process the VARYING_SSA_EDGES worklist first. */ - process_ssa_edge_worklist (&varying_ssa_edges); - - /* Now process the INTERESTING_SSA_EDGES worklist. */ - process_ssa_edge_worklist (&interesting_ssa_edges); - } - - ssa_prop_fini (); -} - - -/* Return the first V_MAY_DEF or V_MUST_DEF operand for STMT. */ - -tree -first_vdef (tree stmt) -{ - ssa_op_iter iter; - tree op; - - /* Simply return the first operand we arrive at. */ - FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_VIRTUAL_DEFS) - return (op); - - gcc_unreachable (); -} - - -/* Return true if STMT is of the form 'LHS = mem_ref', where 'mem_ref' - is a non-volatile pointer dereference, a structure reference or a - reference to a single _DECL. Ignore volatile memory references - because they are not interesting for the optimizers. */ - -bool -stmt_makes_single_load (tree stmt) -{ - tree rhs; - - if (TREE_CODE (stmt) != MODIFY_EXPR) - return false; - - if (ZERO_SSA_OPERANDS (stmt, SSA_OP_VMAYDEF|SSA_OP_VUSE)) - return false; - - rhs = TREE_OPERAND (stmt, 1); - STRIP_NOPS (rhs); - - return (!TREE_THIS_VOLATILE (rhs) - && (DECL_P (rhs) - || REFERENCE_CLASS_P (rhs))); -} - - -/* Return true if STMT is of the form 'mem_ref = RHS', where 'mem_ref' - is a non-volatile pointer dereference, a structure reference or a - reference to a single _DECL. Ignore volatile memory references - because they are not interesting for the optimizers. */ - -bool -stmt_makes_single_store (tree stmt) -{ - tree lhs; - - if (TREE_CODE (stmt) != MODIFY_EXPR) - return false; - - if (ZERO_SSA_OPERANDS (stmt, SSA_OP_VMAYDEF|SSA_OP_VMUSTDEF)) - return false; - - lhs = TREE_OPERAND (stmt, 0); - STRIP_NOPS (lhs); - - return (!TREE_THIS_VOLATILE (lhs) - && (DECL_P (lhs) - || REFERENCE_CLASS_P (lhs))); -} - - -/* If STMT makes a single memory load and all the virtual use operands - have the same value in array VALUES, return it. Otherwise, return - NULL. */ - -prop_value_t * -get_value_loaded_by (tree stmt, prop_value_t *values) -{ - ssa_op_iter i; - tree vuse; - prop_value_t *prev_val = NULL; - prop_value_t *val = NULL; - - FOR_EACH_SSA_TREE_OPERAND (vuse, stmt, i, SSA_OP_VIRTUAL_USES) - { - val = &values[SSA_NAME_VERSION (vuse)]; - if (prev_val && prev_val->value != val->value) - return NULL; - prev_val = val; - } - - return val; -} - - -/* Propagation statistics. */ -struct prop_stats_d -{ - long num_const_prop; - long num_copy_prop; - long num_pred_folded; -}; - -static struct prop_stats_d prop_stats; - -/* Replace USE references in statement STMT with the values stored in - PROP_VALUE. Return true if at least one reference was replaced. If - REPLACED_ADDRESSES_P is given, it will be set to true if an address - constant was replaced. */ - -bool -replace_uses_in (tree stmt, bool *replaced_addresses_p, - prop_value_t *prop_value) -{ - bool replaced = false; - use_operand_p use; - ssa_op_iter iter; - - FOR_EACH_SSA_USE_OPERAND (use, stmt, iter, SSA_OP_USE) - { - tree tuse = USE_FROM_PTR (use); - tree val = prop_value[SSA_NAME_VERSION (tuse)].value; - - if (val == tuse || val == NULL_TREE) - continue; - - if (TREE_CODE (stmt) == ASM_EXPR - && !may_propagate_copy_into_asm (tuse)) - continue; - - if (!may_propagate_copy (tuse, val)) - continue; - - if (TREE_CODE (val) != SSA_NAME) - prop_stats.num_const_prop++; - else - prop_stats.num_copy_prop++; - - propagate_value (use, val); - - replaced = true; - if (POINTER_TYPE_P (TREE_TYPE (tuse)) && replaced_addresses_p) - *replaced_addresses_p = true; - } - - return replaced; -} - - -/* Replace the VUSE references in statement STMT with the values - stored in PROP_VALUE. Return true if a reference was replaced. If - REPLACED_ADDRESSES_P is given, it will be set to true if an address - constant was replaced. - - Replacing VUSE operands is slightly more complex than replacing - regular USEs. We are only interested in two types of replacements - here: - - 1- If the value to be replaced is a constant or an SSA name for a - GIMPLE register, then we are making a copy/constant propagation - from a memory store. For instance, - - # a_3 = V_MAY_DEF <a_2> - a.b = x_1; - ... - # VUSE <a_3> - y_4 = a.b; - - This replacement is only possible iff STMT is an assignment - whose RHS is identical to the LHS of the statement that created - the VUSE(s) that we are replacing. Otherwise, we may do the - wrong replacement: - - # a_3 = V_MAY_DEF <a_2> - # b_5 = V_MAY_DEF <b_4> - *p = 10; - ... - # VUSE <b_5> - x_8 = b; - - Even though 'b_5' acquires the value '10' during propagation, - there is no way for the propagator to tell whether the - replacement is correct in every reached use, because values are - computed at definition sites. Therefore, when doing final - substitution of propagated values, we have to check each use - site. Since the RHS of STMT ('b') is different from the LHS of - the originating statement ('*p'), we cannot replace 'b' with - '10'. - - Similarly, when merging values from PHI node arguments, - propagators need to take care not to merge the same values - stored in different locations: - - if (...) - # a_3 = V_MAY_DEF <a_2> - a.b = 3; - else - # a_4 = V_MAY_DEF <a_2> - a.c = 3; - # a_5 = PHI <a_3, a_4> - - It would be wrong to propagate '3' into 'a_5' because that - operation merges two stores to different memory locations. - - - 2- If the value to be replaced is an SSA name for a virtual - register, then we simply replace each VUSE operand with its - value from PROP_VALUE. This is the same replacement done by - replace_uses_in. */ - -static bool -replace_vuses_in (tree stmt, bool *replaced_addresses_p, - prop_value_t *prop_value) -{ - bool replaced = false; - ssa_op_iter iter; - use_operand_p vuse; - - if (stmt_makes_single_load (stmt)) - { - /* If STMT is an assignment whose RHS is a single memory load, - see if we are trying to propagate a constant or a GIMPLE - register (case #1 above). */ - prop_value_t *val = get_value_loaded_by (stmt, prop_value); - tree rhs = TREE_OPERAND (stmt, 1); - - if (val - && val->value - && (is_gimple_reg (val->value) - || is_gimple_min_invariant (val->value)) - && simple_cst_equal (rhs, val->mem_ref) == 1) - - { - /* If we are replacing a constant address, inform our - caller. */ - if (TREE_CODE (val->value) != SSA_NAME - && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (stmt, 1))) - && replaced_addresses_p) - *replaced_addresses_p = true; - - /* We can only perform the substitution if the load is done - from the same memory location as the original store. - Since we already know that there are no intervening - stores between DEF_STMT and STMT, we only need to check - that the RHS of STMT is the same as the memory reference - propagated together with the value. */ - TREE_OPERAND (stmt, 1) = val->value; - - if (TREE_CODE (val->value) != SSA_NAME) - prop_stats.num_const_prop++; - else - prop_stats.num_copy_prop++; - - /* Since we have replaced the whole RHS of STMT, there - is no point in checking the other VUSEs, as they will - all have the same value. */ - return true; - } - } - - /* Otherwise, the values for every VUSE operand must be other - SSA_NAMEs that can be propagated into STMT. */ - FOR_EACH_SSA_USE_OPERAND (vuse, stmt, iter, SSA_OP_VIRTUAL_USES) - { - tree var = USE_FROM_PTR (vuse); - tree val = prop_value[SSA_NAME_VERSION (var)].value; - - if (val == NULL_TREE || var == val) - continue; - - /* Constants and copies propagated between real and virtual - operands are only possible in the cases handled above. They - should be ignored in any other context. */ - if (is_gimple_min_invariant (val) || is_gimple_reg (val)) - continue; - - propagate_value (vuse, val); - prop_stats.num_copy_prop++; - replaced = true; - } - - return replaced; -} - - -/* Replace propagated values into all the arguments for PHI using the - values from PROP_VALUE. */ - -static void -replace_phi_args_in (tree phi, prop_value_t *prop_value) -{ - int i; - bool replaced = false; - tree prev_phi = NULL; - - if (dump_file && (dump_flags & TDF_DETAILS)) - prev_phi = unshare_expr (phi); - - for (i = 0; i < PHI_NUM_ARGS (phi); i++) - { - tree arg = PHI_ARG_DEF (phi, i); - - if (TREE_CODE (arg) == SSA_NAME) - { - tree val = prop_value[SSA_NAME_VERSION (arg)].value; - - if (val && val != arg && may_propagate_copy (arg, val)) - { - if (TREE_CODE (val) != SSA_NAME) - prop_stats.num_const_prop++; - else - prop_stats.num_copy_prop++; - - propagate_value (PHI_ARG_DEF_PTR (phi, i), val); - replaced = true; - - /* If we propagated a copy and this argument flows - through an abnormal edge, update the replacement - accordingly. */ - if (TREE_CODE (val) == SSA_NAME - && PHI_ARG_EDGE (phi, i)->flags & EDGE_ABNORMAL) - SSA_NAME_OCCURS_IN_ABNORMAL_PHI (val) = 1; - } - } - } - - if (replaced && dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "Folded PHI node: "); - print_generic_stmt (dump_file, prev_phi, TDF_SLIM); - fprintf (dump_file, " into: "); - print_generic_stmt (dump_file, phi, TDF_SLIM); - fprintf (dump_file, "\n"); - } -} - - -/* If STMT has a predicate whose value can be computed using the value - range information computed by VRP, compute its value and return true. - Otherwise, return false. */ - -static bool -fold_predicate_in (tree stmt) -{ - tree *pred_p = NULL; - bool modify_expr_p = false; - tree val; - - if (TREE_CODE (stmt) == MODIFY_EXPR - && COMPARISON_CLASS_P (TREE_OPERAND (stmt, 1))) - { - modify_expr_p = true; - pred_p = &TREE_OPERAND (stmt, 1); - } - else if (TREE_CODE (stmt) == COND_EXPR) - pred_p = &COND_EXPR_COND (stmt); - else - return false; - - val = vrp_evaluate_conditional (*pred_p, stmt); - if (val) - { - if (modify_expr_p) - val = fold_convert (TREE_TYPE (*pred_p), val); - - if (dump_file) - { - fprintf (dump_file, "Folding predicate "); - print_generic_expr (dump_file, *pred_p, 0); - fprintf (dump_file, " to "); - print_generic_expr (dump_file, val, 0); - fprintf (dump_file, "\n"); - } - - prop_stats.num_pred_folded++; - *pred_p = val; - return true; - } - - return false; -} - - -/* Perform final substitution and folding of propagated values. - - PROP_VALUE[I] contains the single value that should be substituted - at every use of SSA name N_I. If PROP_VALUE is NULL, no values are - substituted. - - If USE_RANGES_P is true, statements that contain predicate - expressions are evaluated with a call to vrp_evaluate_conditional. - This will only give meaningful results when called from tree-vrp.c - (the information used by vrp_evaluate_conditional is built by the - VRP pass). */ - -void -substitute_and_fold (prop_value_t *prop_value, bool use_ranges_p) -{ - basic_block bb; - - if (prop_value == NULL && !use_ranges_p) - return; - - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "\nSubstituing values and folding statements\n\n"); - - memset (&prop_stats, 0, sizeof (prop_stats)); - - /* Substitute values in every statement of every basic block. */ - FOR_EACH_BB (bb) - { - block_stmt_iterator i; - tree phi; - - /* Propagate known values into PHI nodes. */ - if (prop_value) - for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi)) - replace_phi_args_in (phi, prop_value); - - for (i = bsi_start (bb); !bsi_end_p (i); bsi_next (&i)) - { - bool replaced_address, did_replace; - tree prev_stmt = NULL; - tree stmt = bsi_stmt (i); - - /* Ignore ASSERT_EXPRs. They are used by VRP to generate - range information for names and they are discarded - afterwards. */ - if (TREE_CODE (stmt) == MODIFY_EXPR - && TREE_CODE (TREE_OPERAND (stmt, 1)) == ASSERT_EXPR) - continue; - - /* Replace the statement with its folded version and mark it - folded. */ - did_replace = false; - replaced_address = false; - if (dump_file && (dump_flags & TDF_DETAILS)) - prev_stmt = unshare_expr (stmt); - - /* If we have range information, see if we can fold - predicate expressions. */ - if (use_ranges_p) - did_replace = fold_predicate_in (stmt); - - if (prop_value) - { - /* Only replace real uses if we couldn't fold the - statement using value range information (value range - information is not collected on virtuals, so we only - need to check this for real uses). */ - if (!did_replace) - did_replace |= replace_uses_in (stmt, &replaced_address, - prop_value); - - did_replace |= replace_vuses_in (stmt, &replaced_address, - prop_value); - } - - /* If we made a replacement, fold and cleanup the statement. */ - if (did_replace) - { - tree old_stmt = stmt; - tree rhs; - - fold_stmt (bsi_stmt_ptr (i)); - stmt = bsi_stmt (i); - - /* If we folded a builtin function, we'll likely - need to rename VDEFs. */ - mark_new_vars_to_rename (stmt); - - /* If we cleaned up EH information from the statement, - remove EH edges. */ - if (maybe_clean_or_replace_eh_stmt (old_stmt, stmt)) - tree_purge_dead_eh_edges (bb); - - rhs = get_rhs (stmt); - if (TREE_CODE (rhs) == ADDR_EXPR) - recompute_tree_invariant_for_addr_expr (rhs); - - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "Folded statement: "); - print_generic_stmt (dump_file, prev_stmt, TDF_SLIM); - fprintf (dump_file, " into: "); - print_generic_stmt (dump_file, stmt, TDF_SLIM); - fprintf (dump_file, "\n"); - } - } - - /* Some statements may be simplified using ranges. For - example, division may be replaced by shifts, modulo - replaced with bitwise and, etc. Do this after - substituting constants, folding, etc so that we're - presented with a fully propagated, canonicalized - statement. */ - if (use_ranges_p) - simplify_stmt_using_ranges (stmt); - - } - } - - if (dump_file && (dump_flags & TDF_STATS)) - { - fprintf (dump_file, "Constants propagated: %6ld\n", - prop_stats.num_const_prop); - fprintf (dump_file, "Copies propagated: %6ld\n", - prop_stats.num_copy_prop); - fprintf (dump_file, "Predicates folded: %6ld\n", - prop_stats.num_pred_folded); - } -} - -#include "gt-tree-ssa-propagate.h" |