/* Miscellaneous SSA utility functions.
- Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009
+ Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010
Free Software Foundation, Inc.
This file is part of GCC.
#include "tm.h"
#include "tree.h"
#include "flags.h"
-#include "rtl.h"
#include "tm_p.h"
#include "target.h"
#include "ggc.h"
#include "langhooks.h"
-#include "hard-reg-set.h"
#include "basic-block.h"
#include "output.h"
-#include "expr.h"
#include "function.h"
-#include "diagnostic.h"
+#include "tree-pretty-print.h"
+#include "gimple-pretty-print.h"
#include "bitmap.h"
#include "pointer-set.h"
#include "tree-flow.h"
#include "gimple.h"
#include "tree-inline.h"
-#include "varray.h"
#include "timevar.h"
#include "hashtab.h"
#include "tree-dump.h"
#include "tree-pass.h"
-#include "toplev.h"
+#include "diagnostic-core.h"
/* Pointer map of variable mappings, keyed by edge. */
static struct pointer_map_t *edge_var_maps;
{
struct walk_stmt_info *wi = (struct walk_stmt_info *) data_;
- if (wi->is_lhs)
+ if (wi && wi->is_lhs)
return NULL_TREE;
if (TREE_CODE (*tp) == SSA_NAME)
if (!MAY_HAVE_DEBUG_STMTS)
return;
- /* First of all, check whether there are debug stmts that reference
- this variable and, if there are, decide whether we should use a
- debug temp. */
+ /* If this name has already been registered for replacement, do nothing
+ as anything that uses this name isn't in SSA form. */
+ if (name_registered_for_update_p (var))
+ return;
+
+ /* Check whether there are debug stmts that reference this variable and,
+ if there are, decide whether we should use a debug temp. */
FOR_EACH_IMM_USE_FAST (use_p, imm_iter, var)
{
stmt = USE_STMT (use_p);
/* If we didn't get an insertion point, and the stmt has already
been removed, we won't be able to insert the debug bind stmt, so
we'll have to drop debug information. */
- if (is_gimple_assign (def_stmt))
+ if (gimple_code (def_stmt) == GIMPLE_PHI)
+ {
+ value = degenerate_phi_result (def_stmt);
+ if (value && walk_tree (&value, find_released_ssa_name, NULL, NULL))
+ value = NULL;
+ }
+ else if (is_gimple_assign (def_stmt))
{
bool no_value = false;
dead SSA NAMEs. SSA verification shall catch any
errors. */
if ((!gsi && !gimple_bb (def_stmt))
- || !walk_gimple_op (def_stmt, find_released_ssa_name,
- &wi))
+ || walk_gimple_op (def_stmt, find_released_ssa_name, &wi))
no_value = true;
}
at the expense of duplication of expressions. */
if (CONSTANT_CLASS_P (value)
+ || gimple_code (def_stmt) == GIMPLE_PHI
|| (usecount == 1
&& (!gimple_assign_single_p (def_stmt)
|| is_gimple_min_invariant (value)))
stmt = gsi_stmt (*gsi);
- FOR_EACH_SSA_DEF_OPERAND (def_p, stmt, op_iter, SSA_OP_DEF)
+ FOR_EACH_PHI_OR_STMT_DEF (def_p, stmt, op_iter, SSA_OP_DEF)
{
tree var = DEF_FROM_PTR (def_p);
if (verify_ssa_name (ssa_name, is_virtual))
goto err;
+ if (TREE_CODE (SSA_NAME_VAR (ssa_name)) == RESULT_DECL
+ && DECL_BY_REFERENCE (SSA_NAME_VAR (ssa_name)))
+ {
+ error ("RESULT_DECL should be read only when DECL_BY_REFERENCE is set.");
+ goto err;
+ }
+
if (definition_block[SSA_NAME_VERSION (ssa_name)])
{
error ("SSA_NAME created in two different blocks %i and %i",
err = true;
}
- /* Make sure the use is in an appropriate list by checking the previous
+ /* Make sure the use is in an appropriate list by checking the previous
element to make sure it's the same. */
if (use_p->prev == NULL)
{
/* Verify common invariants in the SSA web.
TODO: verify the variable annotations. */
-void
+DEBUG_FUNCTION void
verify_ssa (bool check_modified_stmt)
{
size_t i;
gimple stmt = gsi_stmt (gsi);
use_operand_p use_p;
bool has_err;
+ int count;
+ unsigned i;
if (check_modified_stmt && gimple_modified_p (stmt))
{
goto err;
}
+ count = 0;
FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_USE|SSA_OP_DEF)
{
if (verify_ssa_name (op, false))
print_gimple_stmt (stderr, stmt, 0, TDF_VOPS|TDF_MEMSYMS);
goto err;
}
+ count++;
+ }
+
+ for (i = 0; i < gimple_num_ops (stmt); i++)
+ {
+ op = gimple_op (stmt, i);
+ if (op && TREE_CODE (op) == SSA_NAME && --count < 0)
+ {
+ error ("nr of operands and imm-links don't agree");
+ error ("in statement");
+ print_gimple_stmt (stderr, stmt, 0, TDF_VOPS|TDF_MEMSYMS);
+ goto err;
+ }
}
FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE|SSA_OP_VUSE)
free_dominance_info (CDI_DOMINATORS);
else
set_dom_info_availability (CDI_DOMINATORS, orig_dom_state);
-
+
BITMAP_FREE (names_defined_in_bb);
timevar_pop (TV_TREE_SSA_VERIFY);
return;
void
init_tree_ssa (struct function *fn)
{
- fn->gimple_df = GGC_CNEW (struct gimple_df);
- fn->gimple_df->referenced_vars = htab_create_ggc (20, uid_decl_map_hash,
+ fn->gimple_df = ggc_alloc_cleared_gimple_df ();
+ fn->gimple_df->referenced_vars = htab_create_ggc (20, uid_decl_map_hash,
uid_decl_map_eq, NULL);
- fn->gimple_df->default_defs = htab_create_ggc (20, uid_ssaname_map_hash,
+ fn->gimple_df->default_defs = htab_create_ggc (20, uid_ssaname_map_hash,
uid_ssaname_map_eq, NULL);
pt_solution_reset (&fn->gimple_df->escaped);
- pt_solution_reset (&fn->gimple_df->callused);
init_ssanames (fn, 0);
init_phinodes ();
}
{
if (is_global_var (var))
continue;
- if (var->base.ann)
- ggc_free (var->base.ann);
- var->base.ann = NULL;
+ if (var_ann (var))
+ {
+ ggc_free (var_ann (var));
+ *DECL_VAR_ANN_PTR (var) = NULL;
+ }
}
htab_delete (gimple_referenced_vars (cfun));
cfun->gimple_df->referenced_vars = NULL;
htab_delete (cfun->gimple_df->default_defs);
cfun->gimple_df->default_defs = NULL;
pt_solution_reset (&cfun->gimple_df->escaped);
- pt_solution_reset (&cfun->gimple_df->callused);
if (cfun->gimple_df->decls_to_pointers != NULL)
pointer_map_destroy (cfun->gimple_df->decls_to_pointers);
cfun->gimple_df->decls_to_pointers = NULL;
if (POINTER_TYPE_P (inner_type)
&& POINTER_TYPE_P (outer_type))
{
+ /* Do not lose casts between pointers to different address spaces. */
+ if (TYPE_ADDR_SPACE (TREE_TYPE (outer_type))
+ != TYPE_ADDR_SPACE (TREE_TYPE (inner_type)))
+ return false;
+
+ /* Do not lose casts to restrict qualified pointers. */
+ if ((TYPE_RESTRICT (outer_type)
+ != TYPE_RESTRICT (inner_type))
+ && TYPE_RESTRICT (outer_type))
+ return false;
+
/* If the outer type is (void *) or a pointer to an incomplete
record type or a pointer to an unprototyped function,
then the conversion is not necessary. */
if (VOID_TYPE_P (TREE_TYPE (outer_type))
- || (AGGREGATE_TYPE_P (TREE_TYPE (outer_type))
- && TREE_CODE (TREE_TYPE (outer_type)) != ARRAY_TYPE
- && (TREE_CODE (TREE_TYPE (outer_type))
- == TREE_CODE (TREE_TYPE (inner_type)))
- && !COMPLETE_TYPE_P (TREE_TYPE (outer_type)))
|| ((TREE_CODE (TREE_TYPE (outer_type)) == FUNCTION_TYPE
|| TREE_CODE (TREE_TYPE (outer_type)) == METHOD_TYPE)
&& (TREE_CODE (TREE_TYPE (outer_type))
&& useless_type_conversion_p (TREE_TYPE (TREE_TYPE (outer_type)),
TREE_TYPE (TREE_TYPE (inner_type)))))
return true;
-
- /* Do not lose casts to restrict qualified pointers. */
- if ((TYPE_RESTRICT (outer_type)
- != TYPE_RESTRICT (inner_type))
- && TYPE_RESTRICT (outer_type))
- return false;
}
/* From now on qualifiers on value types do not matter. */
else if (POINTER_TYPE_P (inner_type)
&& POINTER_TYPE_P (outer_type))
{
- /* Don't lose casts between pointers to volatile and non-volatile
- qualified types. Doing so would result in changing the semantics
- of later accesses. For function types the volatile qualifier
- is used to indicate noreturn functions. */
- if (TREE_CODE (TREE_TYPE (outer_type)) != FUNCTION_TYPE
- && TREE_CODE (TREE_TYPE (outer_type)) != METHOD_TYPE
- && TREE_CODE (TREE_TYPE (inner_type)) != FUNCTION_TYPE
- && TREE_CODE (TREE_TYPE (inner_type)) != METHOD_TYPE
- && (TYPE_VOLATILE (TREE_TYPE (outer_type))
- != TYPE_VOLATILE (TREE_TYPE (inner_type)))
- && TYPE_VOLATILE (TREE_TYPE (outer_type)))
- return false;
-
- /* We require explicit conversions from incomplete target types. */
- if (!COMPLETE_TYPE_P (TREE_TYPE (inner_type))
- && COMPLETE_TYPE_P (TREE_TYPE (outer_type)))
- return false;
-
- /* Do not lose casts between pointers that when dereferenced access
- memory with different alias sets. */
- if (get_deref_alias_set (inner_type) != get_deref_alias_set (outer_type))
+ /* Do not lose casts to function pointer types. */
+ if ((TREE_CODE (TREE_TYPE (outer_type)) == FUNCTION_TYPE
+ || TREE_CODE (TREE_TYPE (outer_type)) == METHOD_TYPE)
+ && !useless_type_conversion_p (TREE_TYPE (outer_type),
+ TREE_TYPE (inner_type)))
return false;
/* We do not care for const qualification of the pointed-to types
as const qualification has no semantic value to the middle-end. */
- /* Otherwise pointers/references are equivalent if their pointed
- to types are effectively the same. We can strip qualifiers
- on pointed-to types for further comparison, which is done in
- the callee. Note we have to use true compatibility here
- because addresses are subject to propagation into dereferences
- and thus might get the original type exposed which is equivalent
- to a reverse conversion. */
- return types_compatible_p (TREE_TYPE (outer_type),
- TREE_TYPE (inner_type));
+ /* Otherwise pointers/references are equivalent. */
+ return true;
}
/* Recurse for complex types. */
compared types. */
else if (AGGREGATE_TYPE_P (inner_type)
&& TREE_CODE (inner_type) == TREE_CODE (outer_type))
- return false;
-
+ return (in_lto_p
+ && gimple_types_compatible_p (outer_type, inner_type, GTC_DIAG));
+
return false;
}
/* Internal helper for walk_use_def_chains. VAR, FN and DATA are as
described in walk_use_def_chains.
-
+
VISITED is a pointer set used to mark visited SSA_NAMEs to avoid
infinite loops. We used to have a bitmap for this to just mark
SSA versions we had visited. But non-sparse bitmaps are way too
if (fn (gimple_phi_arg_def (def_stmt, i), def_stmt, data))
return true;
}
-
+
return false;
}
-
+
/* Walk use-def chains starting at the SSA variable VAR. Call
arguments: VAR, its defining statement (DEF_STMT) and a generic
pointer to whatever state information that FN may want to maintain
(DATA). FN is able to stop the walk by returning true, otherwise
- in order to continue the walk, FN should return false.
+ in order to continue the walk, FN should return false.
Note, that if DEF_STMT is a PHI node, the semantics are slightly
different. The first argument to FN is no longer the original
}
\f
-/* Return true if T, an SSA_NAME, has an undefined value. */
-
-bool
-ssa_undefined_value_p (tree t)
-{
- tree var = SSA_NAME_VAR (t);
-
- /* Parameters get their initial value from the function entry. */
- if (TREE_CODE (var) == PARM_DECL)
- return false;
-
- /* Hard register variables get their initial value from the ether. */
- if (TREE_CODE (var) == VAR_DECL && DECL_HARD_REGISTER (var))
- return false;
-
- /* The value is undefined iff its definition statement is empty. */
- return gimple_nop_p (SSA_NAME_DEF_STMT (t));
-}
-
/* Emit warnings for uninitialized variables. This is done in two passes.
The first pass notices real uses of SSA names with undefined values.
/* Emit a warning for T, an SSA_NAME, being uninitialized. The exact
warning text is in MSGID and LOCUS may contain a location or be null. */
-static void
+void
warn_uninit (tree t, const char *gmsgid, void *data)
{
tree var = SSA_NAME_VAR (t);
/* Do not warn if it can be initialized outside this module. */
if (is_global_var (var))
return;
-
+
location = (context != NULL && gimple_has_location (context))
? gimple_location (context)
: DECL_SOURCE_LOCATION (var);
{
TREE_NO_WARNING (var) = 1;
+ if (location == DECL_SOURCE_LOCATION (var))
+ return;
if (xloc.file != floc.file
|| xloc.line < floc.line
|| xloc.line > LOCATION_LINE (cfun->function_end_locus))
/* We do not care about LHS. */
if (wi->is_lhs)
{
- /* Except for operands of INDIRECT_REF. */
- if (!INDIRECT_REF_P (t))
+ /* Except for operands of dereferences. */
+ if (!INDIRECT_REF_P (t)
+ && TREE_CODE (t) != MEM_REF)
return NULL_TREE;
t = TREE_OPERAND (t, 0);
}
use_operand_p vuse;
tree op;
- /* If there is not gimple stmt,
+ /* If there is not gimple stmt,
or alias information has not been computed,
then we cannot check VUSE ops. */
if (data->stmt == NULL)
return NULL_TREE;
op = USE_FROM_PTR (vuse);
- if (t != SSA_NAME_VAR (op)
+ if (t != SSA_NAME_VAR (op)
|| !SSA_NAME_IS_DEFAULT_DEF (op))
return NULL_TREE;
/* If this is a VUSE of t and it is the default definition,
return NULL_TREE;
}
-/* Look for inputs to PHI that are SSA_NAMEs that have empty definitions
- and warn about them. */
-
-static void
-warn_uninitialized_phi (gimple phi)
-{
- size_t i, n = gimple_phi_num_args (phi);
-
- /* Don't look at memory tags. */
- if (!is_gimple_reg (gimple_phi_result (phi)))
- return;
-
- for (i = 0; i < n; ++i)
- {
- tree op = gimple_phi_arg_def (phi, i);
- if (TREE_CODE (op) == SSA_NAME)
- warn_uninit (op, "%qD may be used uninitialized in this function",
- NULL);
- }
-}
-
-static unsigned int
+unsigned int
warn_uninitialized_vars (bool warn_possibly_uninitialized)
{
gimple_stmt_iterator gsi;
data.warn_possibly_uninitialized = warn_possibly_uninitialized;
- calculate_dominance_info (CDI_POST_DOMINATORS);
FOR_EACH_BB (bb)
{
}
}
- /* Post-dominator information can not be reliably updated. Free it
- after the use. */
-
- free_dominance_info (CDI_POST_DOMINATORS);
return 0;
}
as possible, thus don't do it here. However, without
optimization we need to warn here about "may be uninitialized".
*/
- warn_uninitialized_vars (/*warn_possibly_uninitialized=*/!optimize);
- return 0;
-}
-
-static unsigned int
-execute_late_warn_uninitialized (void)
-{
- basic_block bb;
- gimple_stmt_iterator gsi;
+ calculate_dominance_info (CDI_POST_DOMINATORS);
- /* Re-do the plain uninitialized variable check, as optimization may have
- straightened control flow. Do this first so that we don't accidentally
- get a "may be" warning when we'd have seen an "is" warning later. */
- warn_uninitialized_vars (/*warn_possibly_uninitialized=*/1);
+ warn_uninitialized_vars (/*warn_possibly_uninitialized=*/!optimize);
- FOR_EACH_BB (bb)
- for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
- warn_uninitialized_phi (gsi_stmt (gsi));
+ /* Post-dominator information can not be reliably updated. Free it
+ after the use. */
+ free_dominance_info (CDI_POST_DOMINATORS);
return 0;
}
{
{
GIMPLE_PASS,
- NULL, /* name */
+ "*early_warn_uninitialized", /* name */
gate_warn_uninitialized, /* gate */
execute_early_warn_uninitialized, /* execute */
NULL, /* sub */
}
};
-struct gimple_opt_pass pass_late_warn_uninitialized =
+
+/* If necessary, rewrite the base of the reference tree *TP from
+ a MEM_REF to a plain or converted symbol. */
+
+static void
+maybe_rewrite_mem_ref_base (tree *tp)
{
- {
- GIMPLE_PASS,
- NULL, /* name */
- gate_warn_uninitialized, /* gate */
- execute_late_warn_uninitialized, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_NONE, /* tv_id */
- PROP_ssa, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- 0 /* todo_flags_finish */
- }
-};
+ tree sym;
+
+ while (handled_component_p (*tp))
+ tp = &TREE_OPERAND (*tp, 0);
+ if (TREE_CODE (*tp) == MEM_REF
+ && TREE_CODE (TREE_OPERAND (*tp, 0)) == ADDR_EXPR
+ && integer_zerop (TREE_OPERAND (*tp, 1))
+ && (sym = TREE_OPERAND (TREE_OPERAND (*tp, 0), 0))
+ && DECL_P (sym)
+ && !TREE_ADDRESSABLE (sym)
+ && symbol_marked_for_renaming (sym))
+ {
+ if (!useless_type_conversion_p (TREE_TYPE (*tp),
+ TREE_TYPE (sym)))
+ *tp = build1 (VIEW_CONVERT_EXPR,
+ TREE_TYPE (*tp), sym);
+ else
+ *tp = sym;
+ }
+}
+
+/* For a tree REF return its base if it is the base of a MEM_REF
+ that cannot be rewritten into SSA form. Otherwise return NULL_TREE. */
+
+static tree
+non_rewritable_mem_ref_base (tree ref)
+{
+ tree base = ref;
+
+ /* A plain decl does not need it set. */
+ if (DECL_P (ref))
+ return NULL_TREE;
+
+ while (handled_component_p (base))
+ base = TREE_OPERAND (base, 0);
+
+ /* But watch out for MEM_REFs we cannot lower to a
+ VIEW_CONVERT_EXPR. */
+ if (TREE_CODE (base) == MEM_REF
+ && TREE_CODE (TREE_OPERAND (base, 0)) == ADDR_EXPR)
+ {
+ tree decl = TREE_OPERAND (TREE_OPERAND (base, 0), 0);
+ if (DECL_P (decl)
+ && (!integer_zerop (TREE_OPERAND (base, 1))
+ || (DECL_SIZE (decl)
+ != TYPE_SIZE (TREE_TYPE (base)))))
+ return decl;
+ }
+
+ return NULL_TREE;
+}
+
+/* When possible, clear TREE_ADDRESSABLE bit or set DECL_GIMPLE_REG_P bit and
+ mark the variable VAR for conversion into SSA. Return true when updating
+ stmts is required. */
+
+static bool
+maybe_optimize_var (tree var, bitmap addresses_taken, bitmap not_reg_needs)
+{
+ bool update_vops = false;
+
+ /* Global Variables, result decls cannot be changed. */
+ if (is_global_var (var)
+ || TREE_CODE (var) == RESULT_DECL
+ || bitmap_bit_p (addresses_taken, DECL_UID (var)))
+ return false;
+
+ /* If the variable is not in the list of referenced vars then we
+ do not need to touch it nor can we rename it. */
+ if (!referenced_var_lookup (DECL_UID (var)))
+ return false;
+
+ if (TREE_ADDRESSABLE (var)
+ /* Do not change TREE_ADDRESSABLE if we need to preserve var as
+ a non-register. Otherwise we are confused and forget to
+ add virtual operands for it. */
+ && (!is_gimple_reg_type (TREE_TYPE (var))
+ || !bitmap_bit_p (not_reg_needs, DECL_UID (var))))
+ {
+ TREE_ADDRESSABLE (var) = 0;
+ if (is_gimple_reg (var))
+ mark_sym_for_renaming (var);
+ update_vops = true;
+ if (dump_file)
+ {
+ fprintf (dump_file, "No longer having address taken: ");
+ print_generic_expr (dump_file, var, 0);
+ fprintf (dump_file, "\n");
+ }
+ }
+
+ if (!DECL_GIMPLE_REG_P (var)
+ && !bitmap_bit_p (not_reg_needs, DECL_UID (var))
+ && (TREE_CODE (TREE_TYPE (var)) == COMPLEX_TYPE
+ || TREE_CODE (TREE_TYPE (var)) == VECTOR_TYPE)
+ && !TREE_THIS_VOLATILE (var)
+ && (TREE_CODE (var) != VAR_DECL || !DECL_HARD_REGISTER (var)))
+ {
+ DECL_GIMPLE_REG_P (var) = 1;
+ mark_sym_for_renaming (var);
+ update_vops = true;
+ if (dump_file)
+ {
+ fprintf (dump_file, "Now a gimple register: ");
+ print_generic_expr (dump_file, var, 0);
+ fprintf (dump_file, "\n");
+ }
+ }
+
+ return update_vops;
+}
/* Compute TREE_ADDRESSABLE and DECL_GIMPLE_REG_P for local variables. */
void
-execute_update_addresses_taken (bool do_optimize)
+execute_update_addresses_taken (void)
{
- tree var;
- referenced_var_iterator rvi;
gimple_stmt_iterator gsi;
basic_block bb;
bitmap addresses_taken = BITMAP_ALLOC (NULL);
bitmap not_reg_needs = BITMAP_ALLOC (NULL);
bool update_vops = false;
+ tree var;
+ unsigned i;
/* Collect into ADDRESSES_TAKEN all variables whose address is taken within
the function body. */
{
gimple stmt = gsi_stmt (gsi);
enum gimple_code code = gimple_code (stmt);
+ tree decl;
/* Note all addresses taken by the stmt. */
gimple_ior_addresses_taken (addresses_taken, stmt);
if (code == GIMPLE_ASSIGN || code == GIMPLE_CALL)
{
tree lhs = gimple_get_lhs (stmt);
-
- /* We may not rewrite TMR_SYMBOL to SSA. */
- if (lhs && TREE_CODE (lhs) == TARGET_MEM_REF
- && TMR_SYMBOL (lhs))
- bitmap_set_bit (not_reg_needs, DECL_UID (TMR_SYMBOL (lhs)));
/* A plain decl does not need it set. */
- else if (lhs && handled_component_p (lhs))
- {
- var = get_base_address (lhs);
- if (DECL_P (var))
- bitmap_set_bit (not_reg_needs, DECL_UID (var));
+ if (lhs && !DECL_P (lhs))
+ {
+ if (handled_component_p (lhs))
+ lhs = get_base_address (lhs);
+
+ if (DECL_P (lhs))
+ bitmap_set_bit (not_reg_needs, DECL_UID (lhs));
+ else if (TREE_CODE (lhs) == MEM_REF
+ && TREE_CODE (TREE_OPERAND (lhs, 0)) == ADDR_EXPR)
+ {
+ decl = TREE_OPERAND (TREE_OPERAND (lhs, 0), 0);
+ if (DECL_P (decl)
+ && (!integer_zerop (TREE_OPERAND (lhs, 1))
+ || (DECL_SIZE (decl)
+ != TYPE_SIZE (TREE_TYPE (lhs)))))
+ bitmap_set_bit (not_reg_needs, DECL_UID (decl));
+ }
}
}
+
+ if (gimple_assign_single_p (stmt))
+ {
+ tree rhs = gimple_assign_rhs1 (stmt);
+ if ((decl = non_rewritable_mem_ref_base (rhs)))
+ bitmap_set_bit (not_reg_needs, DECL_UID (decl));
+ }
+
+ else if (code == GIMPLE_CALL)
+ {
+ for (i = 0; i < gimple_call_num_args (stmt); ++i)
+ {
+ tree arg = gimple_call_arg (stmt, i);
+ if ((decl = non_rewritable_mem_ref_base (arg)))
+ bitmap_set_bit (not_reg_needs, DECL_UID (decl));
+ }
+ }
+
+ else if (code == GIMPLE_ASM)
+ {
+ for (i = 0; i < gimple_asm_noutputs (stmt); ++i)
+ {
+ tree link = gimple_asm_output_op (stmt, i);
+ if ((decl = non_rewritable_mem_ref_base (TREE_VALUE (link))))
+ bitmap_set_bit (not_reg_needs, DECL_UID (decl));
+ }
+ for (i = 0; i < gimple_asm_ninputs (stmt); ++i)
+ {
+ tree link = gimple_asm_input_op (stmt, i);
+ if ((decl = non_rewritable_mem_ref_base (TREE_VALUE (link))))
+ bitmap_set_bit (not_reg_needs, DECL_UID (decl));
+ }
+ }
}
for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
}
}
- /* When possible, clear ADDRESSABLE bit or set the REGISTER bit
- and mark variable for conversion into SSA. */
- if (optimize && do_optimize)
- FOR_EACH_REFERENCED_VAR (var, rvi)
- {
- /* Global Variables, result decls cannot be changed. */
- if (is_global_var (var)
- || TREE_CODE (var) == RESULT_DECL
- || bitmap_bit_p (addresses_taken, DECL_UID (var)))
- continue;
-
- if (TREE_ADDRESSABLE (var)
- /* Do not change TREE_ADDRESSABLE if we need to preserve var as
- a non-register. Otherwise we are confused and forget to
- add virtual operands for it. */
- && (!is_gimple_reg_type (TREE_TYPE (var))
- || !bitmap_bit_p (not_reg_needs, DECL_UID (var))))
+ /* We cannot iterate over all referenced vars because that can contain
+ unused vars from BLOCK trees, which causes code generation differences
+ for -g vs. -g0. */
+ for (var = DECL_ARGUMENTS (cfun->decl); var; var = DECL_CHAIN (var))
+ update_vops |= maybe_optimize_var (var, addresses_taken, not_reg_needs);
+
+ FOR_EACH_VEC_ELT (tree, cfun->local_decls, i, var)
+ update_vops |= maybe_optimize_var (var, addresses_taken, not_reg_needs);
+
+ /* Operand caches need to be recomputed for operands referencing the updated
+ variables. */
+ if (update_vops)
+ {
+ FOR_EACH_BB (bb)
+ for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
{
- TREE_ADDRESSABLE (var) = 0;
- if (is_gimple_reg (var))
- mark_sym_for_renaming (var);
- update_vops = true;
- if (dump_file)
+ gimple stmt = gsi_stmt (gsi);
+
+ /* Re-write TARGET_MEM_REFs of symbols we want to
+ rewrite into SSA form. */
+ if (gimple_assign_single_p (stmt))
{
- fprintf (dump_file, "No longer having address taken ");
- print_generic_expr (dump_file, var, 0);
- fprintf (dump_file, "\n");
+ tree lhs = gimple_assign_lhs (stmt);
+ tree rhs, *rhsp = gimple_assign_rhs1_ptr (stmt);
+ tree sym;
+
+ /* We shouldn't have any fancy wrapping of
+ component-refs on the LHS, but look through
+ VIEW_CONVERT_EXPRs as that is easy. */
+ while (TREE_CODE (lhs) == VIEW_CONVERT_EXPR)
+ lhs = TREE_OPERAND (lhs, 0);
+ if (TREE_CODE (lhs) == MEM_REF
+ && TREE_CODE (TREE_OPERAND (lhs, 0)) == ADDR_EXPR
+ && integer_zerop (TREE_OPERAND (lhs, 1))
+ && (sym = TREE_OPERAND (TREE_OPERAND (lhs, 0), 0))
+ && DECL_P (sym)
+ && !TREE_ADDRESSABLE (sym)
+ && symbol_marked_for_renaming (sym))
+ lhs = sym;
+ else
+ lhs = gimple_assign_lhs (stmt);
+
+ /* Rewrite the RHS and make sure the resulting assignment
+ is validly typed. */
+ maybe_rewrite_mem_ref_base (rhsp);
+ rhs = gimple_assign_rhs1 (stmt);
+ if (gimple_assign_lhs (stmt) != lhs
+ && !useless_type_conversion_p (TREE_TYPE (lhs),
+ TREE_TYPE (rhs)))
+ rhs = fold_build1 (VIEW_CONVERT_EXPR,
+ TREE_TYPE (lhs), rhs);
+
+ if (gimple_assign_lhs (stmt) != lhs)
+ gimple_assign_set_lhs (stmt, lhs);
+
+ if (gimple_assign_rhs1 (stmt) != rhs)
+ {
+ gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
+ gimple_assign_set_rhs_from_tree (&gsi, rhs);
+ }
}
- }
- if (!DECL_GIMPLE_REG_P (var)
- && !bitmap_bit_p (not_reg_needs, DECL_UID (var))
- && (TREE_CODE (TREE_TYPE (var)) == COMPLEX_TYPE
- || TREE_CODE (TREE_TYPE (var)) == VECTOR_TYPE)
- && !TREE_THIS_VOLATILE (var)
- && (TREE_CODE (var) != VAR_DECL || !DECL_HARD_REGISTER (var)))
- {
- DECL_GIMPLE_REG_P (var) = 1;
- mark_sym_for_renaming (var);
- update_vops = true;
- if (dump_file)
+
+ else if (gimple_code (stmt) == GIMPLE_CALL)
{
- fprintf (dump_file, "Decl is now a gimple register ");
- print_generic_expr (dump_file, var, 0);
- fprintf (dump_file, "\n");
+ unsigned i;
+ for (i = 0; i < gimple_call_num_args (stmt); ++i)
+ {
+ tree *argp = gimple_call_arg_ptr (stmt, i);
+ maybe_rewrite_mem_ref_base (argp);
+ }
}
- }
- }
- /* Operand caches needs to be recomputed for operands referencing the updated
- variables. */
- if (update_vops)
- {
- FOR_EACH_BB (bb)
- for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
- {
- gimple stmt = gsi_stmt (gsi);
+ else if (gimple_code (stmt) == GIMPLE_ASM)
+ {
+ unsigned i;
+ for (i = 0; i < gimple_asm_noutputs (stmt); ++i)
+ {
+ tree link = gimple_asm_output_op (stmt, i);
+ maybe_rewrite_mem_ref_base (&TREE_VALUE (link));
+ }
+ for (i = 0; i < gimple_asm_ninputs (stmt); ++i)
+ {
+ tree link = gimple_asm_input_op (stmt, i);
+ maybe_rewrite_mem_ref_base (&TREE_VALUE (link));
+ }
+ }
- if (gimple_references_memory_p (stmt)
- || is_gimple_debug (stmt))
- update_stmt (stmt);
- }
+ if (gimple_references_memory_p (stmt)
+ || is_gimple_debug (stmt))
+ update_stmt (stmt);
+ }
/* Update SSA form here, we are called as non-pass as well. */
update_ssa (TODO_update_ssa);