/* Rewrite a program in Normal form into SSA.
- Copyright (C) 2001-2017 Free Software Foundation, Inc.
+ Copyright (C) 2001-2021 Free Software Foundation, Inc.
Contributed by Diego Novillo <dnovillo@redhat.com>
This file is part of GCC.
#include "tree-ssa.h"
#include "domwalk.h"
#include "statistics.h"
+#include "stringpool.h"
+#include "attribs.h"
+#include "asan.h"
+#include "attr-fnspec.h"
#define PERCENT(x,y) ((float)(x) * 100.0 / (float)(y))
/* Re-allocate the vector at most once per update/into-SSA. */
if (ver >= len)
- info_for_ssa_name.safe_grow_cleared (num_ssa_names);
+ info_for_ssa_name.safe_grow_cleared (num_ssa_names, true);
/* But allocate infos lazily. */
info = info_for_ssa_name[ver];
if (!blocks_with_phis_to_rewrite)
return;
- bitmap_set_bit (blocks_with_phis_to_rewrite, idx);
-
- n = (unsigned) last_basic_block_for_fn (cfun) + 1;
- if (phis_to_rewrite.length () < n)
- phis_to_rewrite.safe_grow_cleared (n);
+ if (bitmap_set_bit (blocks_with_phis_to_rewrite, idx))
+ {
+ n = (unsigned) last_basic_block_for_fn (cfun) + 1;
+ if (phis_to_rewrite.length () < n)
+ phis_to_rewrite.safe_grow_cleared (n, true);
- phis = phis_to_rewrite[idx];
- phis.reserve (10);
+ phis = phis_to_rewrite[idx];
+ gcc_assert (!phis.exists ());
+ phis.create (10);
+ }
+ else
+ phis = phis_to_rewrite[idx];
phis.safe_push (phi);
phis_to_rewrite[idx] = phis;
unsigned i;
var_info *info;
- timevar_push (TV_TREE_INSERT_PHI_NODES);
+ /* When the gimplifier introduces SSA names it cannot easily avoid
+ situations where abnormal edges added by CFG construction break
+ the use-def dominance requirement. For this case rewrite SSA
+ names with broken use-def dominance out-of-SSA and register them
+ for PHI insertion. We only need to do this if abnormal edges
+ can appear in the function. */
+ tree name;
+ if (cfun->calls_setjmp
+ || cfun->has_nonlocal_label)
+ FOR_EACH_SSA_NAME (i, name, cfun)
+ {
+ gimple *def_stmt = SSA_NAME_DEF_STMT (name);
+ if (SSA_NAME_IS_DEFAULT_DEF (name))
+ continue;
+
+ basic_block def_bb = gimple_bb (def_stmt);
+ imm_use_iterator it;
+ gimple *use_stmt;
+ bool need_phis = false;
+ FOR_EACH_IMM_USE_STMT (use_stmt, it, name)
+ {
+ basic_block use_bb = gimple_bb (use_stmt);
+ if (use_bb != def_bb
+ && ! dominated_by_p (CDI_DOMINATORS, use_bb, def_bb))
+ need_phis = true;
+ }
+ if (need_phis)
+ {
+ tree var = create_tmp_reg (TREE_TYPE (name));
+ use_operand_p use_p;
+ FOR_EACH_IMM_USE_STMT (use_stmt, it, name)
+ {
+ basic_block use_bb = gimple_bb (use_stmt);
+ FOR_EACH_IMM_USE_ON_STMT (use_p, it)
+ SET_USE (use_p, var);
+ update_stmt (use_stmt);
+ set_livein_block (var, use_bb);
+ set_rewrite_uses (use_stmt, true);
+ bitmap_set_bit (interesting_blocks, use_bb->index);
+ }
+ def_operand_p def_p;
+ ssa_op_iter dit;
+ FOR_EACH_SSA_DEF_OPERAND (def_p, def_stmt, dit, SSA_OP_DEF)
+ if (DEF_FROM_PTR (def_p) == name)
+ SET_DEF (def_p, var);
+ update_stmt (def_stmt);
+ set_def_block (var, def_bb, false);
+ set_register_defs (def_stmt, true);
+ bitmap_set_bit (interesting_blocks, def_bb->index);
+ release_ssa_name (name);
+ }
+ }
auto_vec<var_info *> vars (var_infos->elements ());
FOR_EACH_HASH_TABLE_ELEMENT (*var_infos, info, var_info_p, hi)
insert_phi_nodes_for (info->var, idf, false);
BITMAP_FREE (idf);
}
-
- timevar_pop (TV_TREE_INSERT_PHI_NODES);
}
if (currdef == NULL_TREE)
{
tree sym = DECL_P (var) ? var : SSA_NAME_VAR (var);
+ if (! sym)
+ sym = create_tmp_reg (TREE_TYPE (var));
currdef = get_or_create_ssa_default_def (cfun, sym);
}
SET_DEF (def_p, name);
register_new_def (DEF_FROM_PTR (def_p), var);
+ /* Do not insert debug stmts if the stmt ends the BB. */
+ if (stmt_ends_bb_p (stmt))
+ continue;
+
tracked_var = target_for_debug_bind (var);
if (tracked_var)
{
for (gsi = gsi_start_phis (e->dest); !gsi_end_p (gsi);
gsi_next (&gsi))
{
- tree currdef, res, argvar;
+ tree currdef, res;
location_t loc;
phi = gsi.phi ();
res = gimple_phi_result (phi);
- /* If we have pre-existing PHI (via the GIMPLE FE) its args may
- be different vars than existing vars and they may be constants
- as well. Note the following supports partial SSA for PHI args. */
- argvar = gimple_phi_arg_def (phi, e->dest_idx);
- if (argvar && ! DECL_P (argvar))
- continue;
- if (!argvar)
- argvar = SSA_NAME_VAR (res);
- currdef = get_reaching_def (argvar);
+ currdef = get_reaching_def (SSA_NAME_VAR (res));
/* Virtual operand PHI args do not need a location. */
if (virtual_operand_p (res))
loc = UNKNOWN_LOCATION;
class rewrite_dom_walker : public dom_walker
{
public:
- rewrite_dom_walker (cdi_direction direction) : dom_walker (direction) {}
+ rewrite_dom_walker (cdi_direction direction)
+ : dom_walker (direction, ALL_BLOCKS, NULL) {}
virtual edge before_dom_children (basic_block);
virtual void after_dom_children (basic_block);
}
fprintf (file, " Previous CURRDEF (");
- print_generic_expr (file, var, 0);
+ print_generic_expr (file, var);
fprintf (file, ") = ");
if (name)
- print_generic_expr (file, name, 0);
+ print_generic_expr (file, name);
else
fprintf (file, "<NIL>");
fprintf (file, "\n");
void
dump_currdefs (FILE *file)
{
- unsigned i;
- tree var;
-
if (symbols_to_rename.is_empty ())
return;
fprintf (file, "\n\nCurrent reaching definitions\n\n");
- FOR_EACH_VEC_ELT (symbols_to_rename, i, var)
+ for (tree var : symbols_to_rename)
{
common_info *info = get_common_info (var);
fprintf (file, "CURRDEF (");
- print_generic_expr (file, var, 0);
+ print_generic_expr (file, var);
fprintf (file, ") = ");
if (info->current_def)
- print_generic_expr (file, info->current_def, 0);
+ print_generic_expr (file, info->current_def);
else
fprintf (file, "<NIL>");
fprintf (file, "\n");
}
+/* If DEF has x_5 = ASAN_POISON () as its current def, add
+ ASAN_POISON_USE (x_5) stmt before GSI to denote the stmt writes into
+ a poisoned (out of scope) variable. */
+
+static void
+maybe_add_asan_poison_write (tree def, gimple_stmt_iterator *gsi)
+{
+ tree cdef = get_current_def (def);
+ if (cdef != NULL
+ && TREE_CODE (cdef) == SSA_NAME
+ && gimple_call_internal_p (SSA_NAME_DEF_STMT (cdef), IFN_ASAN_POISON))
+ {
+ gcall *call
+ = gimple_build_call_internal (IFN_ASAN_POISON_USE, 1, cdef);
+ gimple_set_location (call, gimple_location (gsi_stmt (*gsi)));
+ gsi_insert_before (gsi, call, GSI_SAME_STMT);
+ }
+}
+
+
/* If the operand pointed to by DEF_P is an SSA name in NEW_SSA_NAMES
or OLD_SSA_NAMES, or if it is a symbol marked for renaming,
register it as the current definition for the names replaced by
def = get_or_create_ssa_default_def (cfun, sym);
}
else
- def = make_ssa_name (def, stmt);
+ {
+ if (asan_sanitize_use_after_scope ())
+ maybe_add_asan_poison_write (def, &gsi);
+ def = make_ssa_name (def, stmt);
+ }
SET_DEF (def_p, def);
tree tracked_var = target_for_debug_bind (sym);
{
edge e;
edge_iterator ei;
- unsigned i;
FOR_EACH_EDGE (e, ei, bb->succs)
{
- gphi *phi;
vec<gphi *> phis;
if (!bitmap_bit_p (blocks_with_phis_to_rewrite, e->dest->index))
continue;
phis = phis_to_rewrite[e->dest->index];
- FOR_EACH_VEC_ELT (phis, i, phi)
+ for (gphi *phi : phis)
{
tree arg, lhs_sym, reaching_def = NULL;
use_operand_p arg_p;
/* Update the argument if there is a reaching def. */
if (reaching_def)
{
- source_location locus;
+ location_t locus;
int arg_i = PHI_ARG_INDEX_FROM_USE (arg_p);
SET_USE (arg_p, reaching_def);
class rewrite_update_dom_walker : public dom_walker
{
public:
- rewrite_update_dom_walker (cdi_direction direction) : dom_walker (direction) {}
+ rewrite_update_dom_walker (cdi_direction direction)
+ : dom_walker (direction, ALL_BLOCKS, NULL) {}
virtual edge before_dom_children (basic_block);
virtual void after_dom_children (basic_block);
static void
rewrite_blocks (basic_block entry, enum rewrite_mode what)
{
- /* Rewrite all the basic blocks in the program. */
- timevar_push (TV_TREE_SSA_REWRITE_BLOCKS);
-
block_defs_stack.create (10);
/* Recursively walk the dominator tree rewriting each statement in
}
block_defs_stack.release ();
-
- timevar_pop (TV_TREE_SSA_REWRITE_BLOCKS);
}
class mark_def_dom_walker : public dom_walker
};
mark_def_dom_walker::mark_def_dom_walker (cdi_direction direction)
- : dom_walker (direction), m_kills (BITMAP_ALLOC (NULL))
+ : dom_walker (direction, ALL_BLOCKS, NULL), m_kills (BITMAP_ALLOC (NULL))
{
}
GIMPLE_PASS, /* type */
"ssa", /* name */
OPTGROUP_NONE, /* optinfo_flags */
- TV_TREE_SSA_OTHER, /* tv_id */
+ TV_TREE_INTO_SSA, /* tv_id */
PROP_cfg, /* properties_required */
PROP_ssa, /* properties_provided */
0, /* properties_destroyed */
bitmap_head *dfs;
basic_block bb;
+ /* Increase the set of variables we can rewrite into SSA form
+ by clearing TREE_ADDRESSABLE and transform the IL to support this. */
+ if (optimize)
+ execute_update_addresses_taken ();
+
/* Initialize operand data structures. */
init_ssa_operands (fun);
SET_SSA_NAME_VAR_OR_IDENTIFIER (name, DECL_NAME (decl));
}
+ /* Initialize SSA_NAME_POINTS_TO_READONLY_MEMORY. */
+ tree fnspec_tree
+ = lookup_attribute ("fn spec",
+ TYPE_ATTRIBUTES (TREE_TYPE (fun->decl)));
+ if (fnspec_tree)
+ {
+ attr_fnspec fnspec (TREE_VALUE (TREE_VALUE (fnspec_tree)));
+ unsigned i = 0;
+ for (tree arg = DECL_ARGUMENTS (cfun->decl);
+ arg; arg = DECL_CHAIN (arg), ++i)
+ {
+ if (!fnspec.arg_specified_p (i))
+ break;
+ if (fnspec.arg_readonly_p (i))
+ {
+ tree name = ssa_default_def (fun, arg);
+ if (name)
+ SSA_NAME_POINTS_TO_READONLY_MEMORY (name) = 1;
+ }
+ }
+ }
+
return 0;
}
}
}
-
-/* Do a dominator walk starting at BB processing statements that
- reference symbols in SSA operands. This is very similar to
- mark_def_sites, but the scan handles statements whose operands may
- already be SSA names.
+/* Processing statements in BB that reference symbols in SSA operands.
+ This is very similar to mark_def_sites, but the scan handles
+ statements whose operands may already be SSA names.
If INSERT_PHI_P is true, mark those uses as live in the
corresponding block. This is later used by the PHI placement
that. */
static void
-prepare_block_for_update (basic_block bb, bool insert_phi_p)
+prepare_block_for_update_1 (basic_block bb, bool insert_phi_p)
{
- basic_block son;
edge e;
edge_iterator ei;
}
}
- /* Now visit all the blocks dominated by BB. */
- for (son = first_dom_son (CDI_DOMINATORS, bb);
- son;
- son = next_dom_son (CDI_DOMINATORS, son))
- prepare_block_for_update (son, insert_phi_p);
}
+/* Do a dominator walk starting at BB processing statements that
+ reference symbols in SSA operands. This is very similar to
+ mark_def_sites, but the scan handles statements whose operands may
+ already be SSA names.
+
+ If INSERT_PHI_P is true, mark those uses as live in the
+ corresponding block. This is later used by the PHI placement
+ algorithm to make PHI pruning decisions.
+
+ FIXME. Most of this would be unnecessary if we could associate a
+ symbol to all the SSA names that reference it. But that
+ sounds like it would be expensive to maintain. Still, it
+ would be interesting to see if it makes better sense to do
+ that. */
+static void
+prepare_block_for_update (basic_block bb, bool insert_phi_p)
+{
+ size_t sp = 0;
+ basic_block *worklist;
+
+ /* Allocate the worklist. */
+ worklist = XNEWVEC (basic_block, n_basic_blocks_for_fn (cfun));
+ /* Add the BB to the worklist. */
+ worklist[sp++] = bb;
+
+ while (sp)
+ {
+ basic_block bb;
+ basic_block son;
+
+ /* Pick a block from the worklist. */
+ bb = worklist[--sp];
+
+ prepare_block_for_update_1 (bb, insert_phi_p);
+
+ /* Now add all the blocks dominated by BB to the worklist. */
+ for (son = first_dom_son (CDI_DOMINATORS, bb);
+ son;
+ son = next_dom_son (CDI_DOMINATORS, son))
+ worklist[sp++] = son;
+ }
+ free (worklist);
+}
/* Helper for prepare_names_to_update. Mark all the use sites for
NAME as interesting. BLOCKS and INSERT_PHI_P are as in
bitmap old_set;
bitmap_iterator bi;
- print_generic_expr (file, name, 0);
+ print_generic_expr (file, name);
fprintf (file, " -> { ");
old_set = names_replaced_by (name);
EXECUTE_IF_SET_IN_BITMAP (old_set, 0, i, bi)
{
- print_generic_expr (file, ssa_name (i), 0);
+ print_generic_expr (file, ssa_name (i));
fprintf (file, " ");
}
fprintf (file, "\nSSA names to release after updating the SSA web\n\n");
EXECUTE_IF_SET_IN_BITMAP (names_to_release, 0, i, bi)
{
- print_generic_expr (file, ssa_name (i), 0);
+ print_generic_expr (file, ssa_name (i));
fprintf (file, " ");
}
fprintf (file, "\n");
if (blocks_with_phis_to_rewrite)
EXECUTE_IF_SET_IN_BITMAP (blocks_with_phis_to_rewrite, 0, i, bi)
- {
- vec<gphi *> phis = phis_to_rewrite[i];
- phis.release ();
- phis_to_rewrite[i].create (0);
- }
+ phis_to_rewrite[i].release ();
BITMAP_FREE (blocks_with_phis_to_rewrite);
BITMAP_FREE (blocks_to_update);
if (SSA_NAME_IN_FREE_LIST (use))
{
- error ("statement uses released SSA name:");
+ error ("statement uses released SSA name");
debug_gimple_stmt (stmt);
fprintf (stderr, "The use of ");
- print_generic_expr (stderr, use, 0);
+ print_generic_expr (stderr, use);
fprintf (stderr," should have been replaced\n");
err = true;
}