Merge from tree-cleanup-branch: VRP, store CCP, store copy-prop, incremental SSA updating of FUD chains and newly exposed symbols. * Makefile.in (tree-ssa-copy.o): Depend on tree-ssa-propagate.h. (OBJS-common): Add tree-vrp.o. (tree-vrp.o): New rule. * basic-block.h (nearest_common_dominator_for_set): Declare. * common.opt (ftree-store-ccp): New flag. (ftree-copy-prop): New flag. (ftree-vrp): New flag. (ftree-store-copy-prop): New flag. * dominance.c (nearest_common_dominator_for_set): New. * domwalk.c (walk_dominator_tree): Only traverse statements in blocks marked in walk_data->interesting_blocks. * domwalk.h (struct dom_walk_data): Add field interesting_blocks. * fold-const.c (fold): Handle ASSERT_EXPR. * opts.c (decode_options): Set flag_tree_copy_prop at -O1. Set flag_tree_store_ccp, flag_tree_store_copy_prop and flag_tree_vrp at -O2. * timevar.def (TV_TREE_VRP): Define. (TV_TREE_COPY_PROP): Define. (TV_TREE_STORE_COPY_PROP): Define. (TV_TREE_SSA_INCREMENTAL): Define. (TV_TREE_STORE_CCP): Define. * tree-cfg.c (tree_can_merge_blocks_p): Remove reference to kill_redundant_phi_nodes from comment. (verify_expr): Handle ASSERT_EXPR. * tree-dfa.c (mark_new_vars_to_rename): Remove second argument. Update all users. (mark_call_clobbered_vars_to_rename): Remove. Update all users. * tree-flow-inline.h (unmodifiable_var_p): New. * tree-flow.h (enum value_range_type): Declare. (struct value_range_def): Declare. (value_range): Declare. (remove_all_phi_nodes_for): Remove. Update all users. (find_phi_node_for): Declare. (add_type_alias): Declare. (count_uses_and_derefs): Declare. (kill_redundant_phi_nodes): Remove. (rewrite_into_ssa): Remove. (rewrite_def_def_chains): Remove. (update_ssa, register_new_name_mapping, create_new_def_for, need_ssa_update_p, name_registered_for_update_p, release_ssa_name_after_update_ssa, dump_repl_tbl, debug_repl_tbl, dump_names_replaced_by, debug_names_replaced_by, mark_sym_for_renaming, mark_set_for_renaming, get_current_def, set_current_def, get_value_range, dump_value_range, debug_value_range, dump_all_value_ranges, debug_all_value_ranges, expr_computes_nonzero, loop_depth_of_name, unmodifiable_var_p): Declare. * tree-gimple.c (is_gimple_formal_tmp_rhs): Handle ASSERT_EXPR. * tree-into-ssa.c (block_defs_stack): Update comment. (old_ssa_names, new_ssa_names, old_virtual_ssa_names, syms_to_rename, names_to_release, repl_tbl, need_to_initialize_update_ssa_p, need_to_update_vops_p, need_to_replace_names_p): New locals. (NAME_SETS_GROWTH_FACTOR): Define. (struct repl_map_d): Declare. (struct mark_def_sites_global_data): Add field interesting_blocks. (enum rewrite_mode): Declare. (REGISTER_DEFS_IN_THIS_STMT): Define. (compute_global_livein): Use last_basic_block instead of n_basic_blocks. (set_def_block): Remove last argument. Update all callers. (prepare_use_operand_for_rename): Remove. Update all callers. (prepare_def_operand_for_rename): Remove. Update all callers. (symbol_marked_for_renaming): New. (is_old_name): New. (is_new_name): New. (repl_map_hash): New. (repl_map_eq): New. (repl_map_free): New. (names_replaced_by): New. (add_to_repl_tbl): New. (add_new_name_mapping): New. (mark_def_sites): Assume that all the operands in the statement are in normal form. (find_idf): Assert that the block in the stack is valid. (get_default_def_for): New. (insert_phi_nodes_for): Add new argument 'update_p'. Add documentation. If update_p is true, add a new mapping between the LHS of each new PHI and the name that it replaces. (insert_phi_nodes_1): Only call find_idf if needed. (get_reaching_def): Call get_default_def_for. (rewrite_operand): Remove. (rewrite_stmt): Do nothing if REGISTER_DEFS_IN_THIS_STMT and REWRITE_THIS_STMT are false. Assume that all the operands in the statement are in normal form. (rewrite_add_phi_arguments): Don't use PHI_REWRITTEN. (rewrite_virtual_phi_arguments): Remove. (invalidate_name_tags): Remove. (register_new_update_single, register_new_update_set, rewrite_update_init_block, replace_use, rewrite_update_fini_block, rewrite_update_stmt, rewrite_update_phi_arguments): New. rewrite_blocks): Remove argument 'fix_virtual_phis'. Add arguments 'entry', 'what' and 'blocks'. Initialize the dominator walker according to 'what' and 'blocks'. Start the dominator walk at 'entry'. (mark_def_site_blocks): Add argument 'interesting_blocks'. Use it to configure the dominator walker. (rewrite_into_ssa): Remove argument 'all'. Make internal. (rewrite_all_into_ssa): Remove. (rewrite_def_def_chains): Remove. (mark_def_interesting, mark_use_interesting, prepare_phi_args_for_update, prepare_block_for_update, prepare_def_site_for, prepare_def_sites, dump_names_replaced_by, debug_names_replaced_by, dump_repl_tbl, debug_repl_tbl, init_update_ssa, delete_update_ssa, create_new_def_for, register_new_name_mapping, mark_sym_for_renaming, mark_set_for_renaming, need_ssa_update_p, name_registered_for_update_p, ssa_names_to_replace, release_ssa_name_after_update_ssa, insert_updated_phi_nodes_for, update_ssa): New. * tree-loop-linear.c (linear_transform_loops): Call update_ssa instead of rewrite_into_ssa. * tree-optimize.c (vars_to_rename): Remove. Update all users. (init_tree_optimization_passes): Replace pass_redundant_phi with pass_copy_prop. Add pass_vrp. Replace pass_ccp with pass_store_ccp. Add pass_store_copy_prop after pass_store_ccp. (execute_todo): If the TODO_ flags don't include updating the SSA form, assert that it does not need to be updated. Call update_ssa instead of rewrite_into_ssa and rewrite_def_def_chains. If TODO_verify_loops is set, call verify_loop_closed_ssa. (tree_rest_of_compilation): * tree-pass.h (TODO_dump_func, TODO_ggc_collect, TODO_verify_ssa, TODO_verify_flow, TODO_verify_stmts, TODO_cleanup_cfg): Renumber. (TODO_verify_loops, TODO_update_ssa, TODO_update_ssa_no_phi, TODO_update_ssa_full_phi, TODO_update_ssa_only_virtuals): Define. (pass_copy_prop, pass_store_ccp, pass_store_copy_prop, pass_vrp): Declare. * tree-phinodes.c (make_phi_node): Update documentation. (remove_all_phi_nodes_for): Remove. (find_phi_node_for): New. * tree-pretty-print.c (dump_generic_node): Handle ASSERT_EXPR. * tree-scalar-evolution.c (follow_ssa_edge_in_rhs): Likewise. (interpret_rhs_modify_expr): Likewise. * tree-sra.c (decide_instantiations): Mark all symbols in SRA_CANDIDATES for renaming. (mark_all_v_defs_1): Rename from mark_all_v_defs. (mark_all_v_defs): New function. Update all users to call it with the whole list of scalarized statements, not just the first one. * tree-ssa-alias.c (count_ptr_derefs): Make extern. (compute_flow_insensitive_aliasing): If the tag is unmodifiable and the variable isn't or vice-versa, don't make them alias of each other. (setup_pointers_and_addressables): If the type tag for VAR is about to change, mark the old one for renaming. (add_type_alias): New. * tree-ssa-ccp.c: Document SSA-CCP and STORE-CCP. (ccp_lattice_t): Rename from latticevalue. (value): Remove. Update all users. (const_val): New local variable. (do_store_ccp): New local variable. (dump_lattice_value): Handle UNINITIALIZED. (debug_lattice_value): New. (get_default_value): Re-write. (set_lattice_value): Re-write. (def_to_varying): Remove. Update all users. (likely_value): Return VARYING for statements that make stores when STORE_CCP is false. Return VARYING for any statement other than MODIFY_EXPR, COND_EXPR and SWITCH_EXPR. (ccp_initialize): Re-write. (replace_uses_in, replace_vuse_in, substitute_and_fold): Move to tree-ssa-propagate.c. (ccp_lattice_meet): Handle memory stores when DO_STORE_CCP is true. (ccp_visit_phi_node): Likewise. (ccp_fold): Likewise. (evaluate_stmt): Likewise. (visit_assignment): Likewise. (ccp_visit_stmt): Likewise. (execute_ssa_ccp): Add argument 'store_ccp'. Copy it into DO_STORE_CCP. (do_ssa_ccp): New. (pass_ccp): Use it. (do_ssa_store_ccp): New. (gate_store_ccp): New. (pass_store_ccp): Declare. * tree-ssa-copy.c: Include tree-ssa-propagate.h. (may_propagate_copy): Reformat. Don't abort if ORIG is a virtual and DEST isn't. If NEW does not have alias information but DEST does, copy it. (copy_of, cached_last_copy_of, do_store_copy_prop, enum copy_prop_kind, which_copy_prop): Declare. (stmt_may_generate_copy, get_copy_of_val, get_last_copy_of, set_copy_of_val, dump_copy_of, copy_prop_visit_assignment, copy_prop_visit_cond_stmt, copy_prop_visit_stmt, copy_prop_visit_phi_node, init_copy_prop, fini_copy_prop, execute_copy_prop, gate_copy_prop, do_copy_prop, gate_store_copy_prop, store_copy_prop): New. (pass_copy_prop, pass_store_copy_prop): Declare. * tree-ssa-dom.c (struct opt_stats_d): Add fields 'num_const_prop' and 'num_copy_prop'. (cprop_operand): Update them. (dump_dominator_optimization_stats): Dump them. (tree_ssa_dominator_optimize): Call update_ssa instead of rewrite_into_ssa. (loop_depth_of_name): Declare extern. (simplify_cond_and_lookup_avail_expr): Guard against NULL values for LOW or HIGH. (cprop_into_successor_phis): Only propagate if NEW != ORIG. (record_equivalences_from_stmt): Call expr_computes_nonzero. (cprop_operand): Only propagate if VAL != OP. * tree-ssa-dse.c (dse_optimize_stmt): Mark symbols in removed statement for renaming. * tree-ssa-loop-im.c (move_computations): Call update_ssa. * tree-ssa-loop-ivopts.c (rewrite_address_base): Call add_type_alias if necessary. Call mark_new_vars_to_rename. (tree_ssa_iv_optimize): If new symbols need to be renamed, mark every statement updated, call update_ssa and rewrite_into_loop_closed_ssa. * tree-ssa-loop-manip.c (add_exit_phis): Do not remove DEF_BB from LIVEIN if VAR is a virtual. * tree-ssa-loop.c (tree_loop_optimizer_init): Call update_ssa. * tree-ssa-operands.c (get_expr_operands): Handle ASSERT_EXPR. (get_call_expr_operands): Reformat statement. (add_stmt_operand): Don't create V_MAY_DEFs for read-only symbols. * tree-ssa-propagate.c (ssa_prop_init): Initialize SSA_NAME_VALUE for every name. (first_vdef, stmt_makes_single_load, stmt_makes_single_store, get_value_loaded_by): New. (replace_uses_in, replace_vuses_in, replace_phi_args_in, substitute_and_fold): Move from tree-ssa-ccp.c. * tree-ssa-propagate.h (struct prop_value_d, prop_value_t, first_vdef, stmt_makes_single_load, stmt_makes_single_store, get_value_loaded_by, replace_uses_in, substitute_and_fold): Declare. * tree-ssa.c (verify_use): Fix error message. (propagate_into_addr, replace_immediate_uses, get_eq_name, check_phi_redundancy, kill_redundant_phi_nodes, pass_redundant_phi): Remove. Update all users. * tree-vect-transform.c (vect_create_data_ref_ptr): Call add_type_alias, if necessary. * tree-vectorizer.h (struct _stmt_vect_info): Update documentation for field 'memtag'. * tree-vrp.c: New file. * tree.def (ASSERT_EXPR): Define. * tree.h (ASSERT_EXPR_VAR): Define. (ASSERT_EXPR_COND): Define. (SSA_NAME_VALUE_RANGE): Define. (struct tree_ssa_name): Add field 'value_range'. (PHI_REWRITTEN): Remove. (struct tree_phi_node): Remove field 'rewritten'. * doc/invoke.texi (-fdump-tree-storeccp, -ftree-copy-prop, -ftree-store-copy-prop): Document. * doc/tree-ssa.texi: Remove broken link to McCAT's compiler. Document usage of update_ssa. testsuite/ChangeLog * g++.dg/tree-ssa/pr18178.C: New test. * gcc.c-torture/execute/20030216-1.x: Ignore at -O1. * gcc.c-torture/execute/20041019-1.c: New test. * gcc.dg/tree-ssa/20041008-1.c: New test. * gcc.dg/tree-ssa/ssa-ccp-12.c: New test. * gcc.dg/tree-ssa/20030731-2.c: Update to use -fdump-tree-store_ccp. * gcc.dg/tree-ssa/20030917-1.c: Likewise. * gcc.dg/tree-ssa/20030917-3.c: Likewise. * gcc.dg/tree-ssa/20040721-1.c: Likewise. * gcc.dg/tree-ssa/ssa-ccp-1.c: Likewise. * gcc.dg/tree-ssa/ssa-ccp-2.c: Likewise. * gcc.dg/tree-ssa/ssa-ccp-3.c: Likewise. * gcc.dg/tree-ssa/ssa-ccp-7.c: Likewise. * gcc.dg/tree-ssa/ssa-ccp-9.c: Likewise. From-SVN: r97884
493 lines
12 KiB
C
493 lines
12 KiB
C
/* Functions to analyze and validate GIMPLE trees.
|
|
Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
|
|
Contributed by Diego Novillo <dnovillo@redhat.com>
|
|
Rewritten by Jason Merrill <jason@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, 59 Temple Place - Suite 330,
|
|
Boston, MA 02111-1307, USA. */
|
|
|
|
#include "config.h"
|
|
#include "system.h"
|
|
#include "coretypes.h"
|
|
#include "ggc.h"
|
|
#include "tm.h"
|
|
#include "tree.h"
|
|
#include "tree-gimple.h"
|
|
#include "tree-flow.h"
|
|
#include "output.h"
|
|
#include "rtl.h"
|
|
#include "expr.h"
|
|
#include "bitmap.h"
|
|
|
|
/* For the definitive definition of GIMPLE, see doc/tree-ssa.texi. */
|
|
|
|
static inline bool is_gimple_id (tree);
|
|
|
|
/* Validation of GIMPLE expressions. */
|
|
|
|
/* Return true if T is a GIMPLE RHS for an assignment to a temporary. */
|
|
|
|
bool
|
|
is_gimple_formal_tmp_rhs (tree t)
|
|
{
|
|
enum tree_code code = TREE_CODE (t);
|
|
|
|
switch (TREE_CODE_CLASS (code))
|
|
{
|
|
case tcc_unary:
|
|
case tcc_binary:
|
|
case tcc_comparison:
|
|
return true;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch (code)
|
|
{
|
|
case TRUTH_NOT_EXPR:
|
|
case TRUTH_AND_EXPR:
|
|
case TRUTH_OR_EXPR:
|
|
case TRUTH_XOR_EXPR:
|
|
case ADDR_EXPR:
|
|
case CALL_EXPR:
|
|
case CONSTRUCTOR:
|
|
case COMPLEX_EXPR:
|
|
case INTEGER_CST:
|
|
case REAL_CST:
|
|
case STRING_CST:
|
|
case COMPLEX_CST:
|
|
case VECTOR_CST:
|
|
case OBJ_TYPE_REF:
|
|
case ASSERT_EXPR:
|
|
return true;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return is_gimple_lvalue (t) || is_gimple_val (t);
|
|
}
|
|
|
|
/* Returns true iff T is a valid RHS for an assignment to a renamed
|
|
user -- or front-end generated artificial -- variable. */
|
|
|
|
bool
|
|
is_gimple_reg_rhs (tree t)
|
|
{
|
|
/* If the RHS of the MODIFY_EXPR may throw or make a nonlocal goto
|
|
and the LHS is a user variable, then we need to introduce a formal
|
|
temporary. This way the optimizers can determine that the user
|
|
variable is only modified if evaluation of the RHS does not throw.
|
|
|
|
Don't force a temp of a non-renamable type; the copy could be
|
|
arbitrarily expensive. Instead we will generate a V_MAY_DEF for
|
|
the assignment. */
|
|
|
|
if (is_gimple_reg_type (TREE_TYPE (t))
|
|
&& ((TREE_CODE (t) == CALL_EXPR && TREE_SIDE_EFFECTS (t))
|
|
|| tree_could_throw_p (t)))
|
|
return false;
|
|
|
|
return is_gimple_formal_tmp_rhs (t);
|
|
}
|
|
|
|
/* Returns true iff T is a valid RHS for an assignment to an un-renamed
|
|
LHS, or for a call argument. */
|
|
|
|
bool
|
|
is_gimple_mem_rhs (tree t)
|
|
{
|
|
/* If we're dealing with a renamable type, either source or dest must be
|
|
a renamed variable. Also force a temporary if the type doesn't need
|
|
to be stored in memory, since it's cheap and prevents erroneous
|
|
tailcalls (PR 17526). */
|
|
if (is_gimple_reg_type (TREE_TYPE (t))
|
|
|| TYPE_MODE (TREE_TYPE (t)) != BLKmode)
|
|
return is_gimple_val (t);
|
|
else
|
|
return is_gimple_formal_tmp_rhs (t);
|
|
}
|
|
|
|
/* Returns the appropriate RHS predicate for this LHS. */
|
|
|
|
gimple_predicate
|
|
rhs_predicate_for (tree lhs)
|
|
{
|
|
if (is_gimple_formal_tmp_var (lhs))
|
|
return is_gimple_formal_tmp_rhs;
|
|
else if (is_gimple_reg (lhs))
|
|
return is_gimple_reg_rhs;
|
|
else
|
|
return is_gimple_mem_rhs;
|
|
}
|
|
|
|
/* Return true if T is a valid LHS for a GIMPLE assignment expression. */
|
|
|
|
bool
|
|
is_gimple_lvalue (tree t)
|
|
{
|
|
return (is_gimple_addressable (t)
|
|
|| TREE_CODE (t) == WITH_SIZE_EXPR
|
|
/* These are complex lvalues, but don't have addresses, so they
|
|
go here. */
|
|
|| TREE_CODE (t) == BIT_FIELD_REF);
|
|
}
|
|
|
|
/* Return true if T is a GIMPLE condition. */
|
|
|
|
bool
|
|
is_gimple_condexpr (tree t)
|
|
{
|
|
return (is_gimple_val (t) || COMPARISON_CLASS_P (t));
|
|
}
|
|
|
|
/* Return true if T is something whose address can be taken. */
|
|
|
|
bool
|
|
is_gimple_addressable (tree t)
|
|
{
|
|
return (is_gimple_id (t) || handled_component_p (t)
|
|
|| INDIRECT_REF_P (t));
|
|
}
|
|
|
|
/* Return true if T is function invariant. Or rather a restricted
|
|
form of function invariant. */
|
|
|
|
bool
|
|
is_gimple_min_invariant (tree t)
|
|
{
|
|
switch (TREE_CODE (t))
|
|
{
|
|
case ADDR_EXPR:
|
|
return TREE_INVARIANT (t);
|
|
|
|
case INTEGER_CST:
|
|
case REAL_CST:
|
|
case STRING_CST:
|
|
case COMPLEX_CST:
|
|
case VECTOR_CST:
|
|
return true;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/* Return true if T looks like a valid GIMPLE statement. */
|
|
|
|
bool
|
|
is_gimple_stmt (tree t)
|
|
{
|
|
enum tree_code code = TREE_CODE (t);
|
|
|
|
if (IS_EMPTY_STMT (t))
|
|
return 1;
|
|
|
|
switch (code)
|
|
{
|
|
case BIND_EXPR:
|
|
case COND_EXPR:
|
|
/* These are only valid if they're void. */
|
|
return TREE_TYPE (t) == NULL || VOID_TYPE_P (TREE_TYPE (t));
|
|
|
|
case SWITCH_EXPR:
|
|
case GOTO_EXPR:
|
|
case RETURN_EXPR:
|
|
case LABEL_EXPR:
|
|
case CASE_LABEL_EXPR:
|
|
case TRY_CATCH_EXPR:
|
|
case TRY_FINALLY_EXPR:
|
|
case EH_FILTER_EXPR:
|
|
case CATCH_EXPR:
|
|
case ASM_EXPR:
|
|
case RESX_EXPR:
|
|
case PHI_NODE:
|
|
case STATEMENT_LIST:
|
|
/* These are always void. */
|
|
return true;
|
|
|
|
case CALL_EXPR:
|
|
case MODIFY_EXPR:
|
|
/* These are valid regardless of their type. */
|
|
return true;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/* Return true if T is a variable. */
|
|
|
|
bool
|
|
is_gimple_variable (tree t)
|
|
{
|
|
return (TREE_CODE (t) == VAR_DECL
|
|
|| TREE_CODE (t) == PARM_DECL
|
|
|| TREE_CODE (t) == RESULT_DECL
|
|
|| TREE_CODE (t) == SSA_NAME);
|
|
}
|
|
|
|
/* Return true if T is a GIMPLE identifier (something with an address). */
|
|
|
|
static inline bool
|
|
is_gimple_id (tree t)
|
|
{
|
|
return (is_gimple_variable (t)
|
|
|| TREE_CODE (t) == FUNCTION_DECL
|
|
|| TREE_CODE (t) == LABEL_DECL
|
|
|| TREE_CODE (t) == CONST_DECL
|
|
/* Allow string constants, since they are addressable. */
|
|
|| TREE_CODE (t) == STRING_CST);
|
|
}
|
|
|
|
/* Return true if TYPE is a suitable type for a scalar register variable. */
|
|
|
|
bool
|
|
is_gimple_reg_type (tree type)
|
|
{
|
|
return (!AGGREGATE_TYPE_P (type)
|
|
&& TREE_CODE (type) != COMPLEX_TYPE);
|
|
}
|
|
|
|
|
|
/* Return true if T is a scalar register variable. */
|
|
|
|
bool
|
|
is_gimple_reg (tree t)
|
|
{
|
|
if (TREE_CODE (t) == SSA_NAME)
|
|
t = SSA_NAME_VAR (t);
|
|
|
|
if (!is_gimple_variable (t))
|
|
return false;
|
|
if (!is_gimple_reg_type (TREE_TYPE (t)))
|
|
return false;
|
|
|
|
/* A volatile decl is not acceptable because we can't reuse it as
|
|
needed. We need to copy it into a temp first. */
|
|
if (TREE_THIS_VOLATILE (t))
|
|
return false;
|
|
|
|
/* We define "registers" as things that can be renamed as needed,
|
|
which with our infrastructure does not apply to memory. */
|
|
if (needs_to_live_in_memory (t))
|
|
return false;
|
|
|
|
/* Hard register variables are an interesting case. For those that
|
|
are call-clobbered, we don't know where all the calls are, since
|
|
we don't (want to) take into account which operations will turn
|
|
into libcalls at the rtl level. For those that are call-saved,
|
|
we don't currently model the fact that calls may in fact change
|
|
global hard registers, nor do we examine ASM_CLOBBERS at the tree
|
|
level, and so miss variable changes that might imply. All around,
|
|
it seems safest to not do too much optimization with these at the
|
|
tree level at all. We'll have to rely on the rtl optimizers to
|
|
clean this up, as there we've got all the appropriate bits exposed. */
|
|
if (TREE_CODE (t) == VAR_DECL && DECL_HARD_REGISTER (t))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
/* Returns true if T is a GIMPLE formal temporary variable. */
|
|
|
|
bool
|
|
is_gimple_formal_tmp_var (tree t)
|
|
{
|
|
if (TREE_CODE (t) == SSA_NAME)
|
|
return true;
|
|
|
|
return TREE_CODE (t) == VAR_DECL && DECL_GIMPLE_FORMAL_TEMP_P (t);
|
|
}
|
|
|
|
/* Returns true if T is a GIMPLE formal temporary register variable. */
|
|
|
|
bool
|
|
is_gimple_formal_tmp_reg (tree t)
|
|
{
|
|
/* The intent of this is to get hold of a value that won't change.
|
|
An SSA_NAME qualifies no matter if its of a user variable or not. */
|
|
if (TREE_CODE (t) == SSA_NAME)
|
|
return true;
|
|
|
|
/* We don't know the lifetime characteristics of user variables. */
|
|
if (!is_gimple_formal_tmp_var (t))
|
|
return false;
|
|
|
|
/* Finally, it must be capable of being placed in a register. */
|
|
return is_gimple_reg (t);
|
|
}
|
|
|
|
/* Return true if T is a GIMPLE variable whose address is not needed. */
|
|
|
|
bool
|
|
is_gimple_non_addressable (tree t)
|
|
{
|
|
if (TREE_CODE (t) == SSA_NAME)
|
|
t = SSA_NAME_VAR (t);
|
|
|
|
return (is_gimple_variable (t) && ! needs_to_live_in_memory (t));
|
|
}
|
|
|
|
/* Return true if T is a GIMPLE rvalue, i.e. an identifier or a constant. */
|
|
|
|
bool
|
|
is_gimple_val (tree t)
|
|
{
|
|
/* Make loads from volatiles and memory vars explicit. */
|
|
if (is_gimple_variable (t)
|
|
&& is_gimple_reg_type (TREE_TYPE (t))
|
|
&& !is_gimple_reg (t))
|
|
return false;
|
|
|
|
/* FIXME make these decls. That can happen only when we expose the
|
|
entire landing-pad construct at the tree level. */
|
|
if (TREE_CODE (t) == EXC_PTR_EXPR || TREE_CODE (t) == FILTER_EXPR)
|
|
return 1;
|
|
|
|
return (is_gimple_variable (t) || is_gimple_min_invariant (t));
|
|
}
|
|
|
|
/* Similarly, but accept hard registers as inputs to asm statements. */
|
|
|
|
bool
|
|
is_gimple_asm_val (tree t)
|
|
{
|
|
if (TREE_CODE (t) == VAR_DECL && DECL_HARD_REGISTER (t))
|
|
return true;
|
|
|
|
return is_gimple_val (t);
|
|
}
|
|
|
|
/* Return true if T is a GIMPLE minimal lvalue. */
|
|
|
|
bool
|
|
is_gimple_min_lval (tree t)
|
|
{
|
|
return (is_gimple_id (t)
|
|
|| TREE_CODE (t) == INDIRECT_REF);
|
|
}
|
|
|
|
/* Return true if T is a typecast operation. */
|
|
|
|
bool
|
|
is_gimple_cast (tree t)
|
|
{
|
|
return (TREE_CODE (t) == NOP_EXPR
|
|
|| TREE_CODE (t) == CONVERT_EXPR
|
|
|| TREE_CODE (t) == FIX_TRUNC_EXPR
|
|
|| TREE_CODE (t) == FIX_CEIL_EXPR
|
|
|| TREE_CODE (t) == FIX_FLOOR_EXPR
|
|
|| TREE_CODE (t) == FIX_ROUND_EXPR);
|
|
}
|
|
|
|
/* Return true if T is a valid op0 of a CALL_EXPR. */
|
|
|
|
bool
|
|
is_gimple_call_addr (tree t)
|
|
{
|
|
return (TREE_CODE (t) == OBJ_TYPE_REF
|
|
|| is_gimple_val (t));
|
|
}
|
|
|
|
/* If T makes a function call, return the corresponding CALL_EXPR operand.
|
|
Otherwise, return NULL_TREE. */
|
|
|
|
tree
|
|
get_call_expr_in (tree t)
|
|
{
|
|
if (TREE_CODE (t) == MODIFY_EXPR)
|
|
t = TREE_OPERAND (t, 1);
|
|
if (TREE_CODE (t) == WITH_SIZE_EXPR)
|
|
t = TREE_OPERAND (t, 0);
|
|
if (TREE_CODE (t) == CALL_EXPR)
|
|
return t;
|
|
return NULL_TREE;
|
|
}
|
|
|
|
/* Given a memory reference expression T, return its base address.
|
|
The base address of a memory reference expression is the main
|
|
object being referenced. For instance, the base address for
|
|
'array[i].fld[j]' is 'array'. You can think of this as stripping
|
|
away the offset part from a memory address.
|
|
|
|
This function calls handled_component_p to strip away all the inner
|
|
parts of the memory reference until it reaches the base object. */
|
|
|
|
tree
|
|
get_base_address (tree t)
|
|
{
|
|
while (handled_component_p (t))
|
|
t = TREE_OPERAND (t, 0);
|
|
|
|
if (SSA_VAR_P (t)
|
|
|| TREE_CODE (t) == STRING_CST
|
|
|| TREE_CODE (t) == CONSTRUCTOR
|
|
|| INDIRECT_REF_P (t))
|
|
return t;
|
|
else
|
|
return NULL_TREE;
|
|
}
|
|
|
|
void
|
|
recalculate_side_effects (tree t)
|
|
{
|
|
enum tree_code code = TREE_CODE (t);
|
|
int len = TREE_CODE_LENGTH (code);
|
|
int i;
|
|
|
|
switch (TREE_CODE_CLASS (code))
|
|
{
|
|
case tcc_expression:
|
|
switch (code)
|
|
{
|
|
case INIT_EXPR:
|
|
case MODIFY_EXPR:
|
|
case VA_ARG_EXPR:
|
|
case PREDECREMENT_EXPR:
|
|
case PREINCREMENT_EXPR:
|
|
case POSTDECREMENT_EXPR:
|
|
case POSTINCREMENT_EXPR:
|
|
/* All of these have side-effects, no matter what their
|
|
operands are. */
|
|
return;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
/* Fall through. */
|
|
|
|
case tcc_comparison: /* a comparison expression */
|
|
case tcc_unary: /* a unary arithmetic expression */
|
|
case tcc_binary: /* a binary arithmetic expression */
|
|
case tcc_reference: /* a reference */
|
|
TREE_SIDE_EFFECTS (t) = TREE_THIS_VOLATILE (t);
|
|
for (i = 0; i < len; ++i)
|
|
{
|
|
tree op = TREE_OPERAND (t, i);
|
|
if (op && TREE_SIDE_EFFECTS (op))
|
|
TREE_SIDE_EFFECTS (t) = 1;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
/* Can never be used with non-expressions. */
|
|
gcc_unreachable ();
|
|
}
|
|
}
|