From 156d7d8dbc8d65d3958486bc4112a7279935e47d Mon Sep 17 00:00:00 2001 From: Andrew MacLeod Date: Tue, 24 May 2022 11:32:42 -0400 Subject: Use infer instead of side-effect for ranges. Rename the files and classes to reflect the term infer rather than side-effect. * Makefile.in (OBJS): Use gimple-range-infer.o. * gimple-range-cache.cc (ranger_cache::fill_block_cache): Change msg. (ranger_cache::range_from_dom): Rename var side_effect to infer. (ranger_cache::apply_inferred_ranges): Rename from apply_side_effects. * gimple-range-cache.h: Include gimple-range-infer.h. (class ranger_cache): Adjust prototypes, use infer_range_manager. * gimple-range-infer.cc: Rename from gimple-range-side-effects.cc. (gimple_infer_range::*): Rename from stmt_side_effects. (infer_range_manager::*): Rename from side_effect_manager. * gimple-range-side-effect.cc: Rename. * gimple-range-side-effect.h: Rename. * gimple-range-infer.h: Rename from gimple-range-side-effects.h. (class gimple_infer_range): Rename from stmt_side_effects. (class infer_range_manager): Rename from side_effect_manager. * gimple-range.cc (gimple_ranger::register_inferred_ranges): Rename from register_side_effects. * gimple-range.h (register_inferred_ranges): Adjust prototype. * range-op.h: Adjust comment. * tree-vrp.cc (rvrp_folder::pre_fold_bb): Use register_inferred_ranges. (rvrp_folder::post_fold_bb): Use register_inferred_ranges. --- gcc/Makefile.in | 2 +- gcc/gimple-range-cache.cc | 32 ++--- gcc/gimple-range-cache.h | 6 +- gcc/gimple-range-infer.cc | 310 ++++++++++++++++++++++++++++++++++++++++ gcc/gimple-range-infer.h | 84 +++++++++++ gcc/gimple-range-side-effect.cc | 310 ---------------------------------------- gcc/gimple-range-side-effect.h | 82 ----------- gcc/gimple-range.cc | 9 +- gcc/gimple-range.h | 2 +- gcc/range-op.h | 2 +- gcc/tree-vrp.cc | 4 +- 11 files changed, 422 insertions(+), 421 deletions(-) create mode 100644 gcc/gimple-range-infer.cc create mode 100644 gcc/gimple-range-infer.h delete mode 100644 gcc/gimple-range-side-effect.cc delete mode 100644 gcc/gimple-range-side-effect.h (limited to 'gcc') diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 97e5450..731d8dd 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1410,7 +1410,7 @@ OBJS = \ gimple-range-edge.o \ gimple-range-fold.o \ gimple-range-gori.o \ - gimple-range-side-effect.o \ + gimple-range-infer.o \ gimple-range-trace.o \ gimple-ssa-backprop.o \ gimple-ssa-evrp.o \ diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc index c726393..5d5e2bf 100644 --- a/gcc/gimple-range-cache.cc +++ b/gcc/gimple-range-cache.cc @@ -944,7 +944,7 @@ bool ranger_cache::edge_range (irange &r, edge e, tree name, enum rfd_mode mode) { exit_range (r, name, e->src, mode); - // If this is not an abnormal edge, check for side effects on exit. + // If this is not an abnormal edge, check for inferred ranges on exit. if ((e->flags & (EDGE_EH | EDGE_ABNORMAL)) == 0) m_exit.maybe_adjust_range (r, name, e->src); int_range_max er; @@ -1251,12 +1251,12 @@ ranger_cache::fill_block_cache (tree name, basic_block bb, basic_block def_bb) } // Regardless of whether we have visited pred or not, if the - // pred has side_effects, revisit this block. + // pred has inferred ranges, revisit this block. // Don't search the DOM tree. if (m_exit.has_range_p (name, pred)) { if (DEBUG_RANGE_CACHE) - fprintf (dump_file, "side effect: update "); + fprintf (dump_file, "Inferred range: update "); m_update->add (node); } @@ -1317,8 +1317,8 @@ ranger_cache::range_from_dom (irange &r, tree name, basic_block start_bb, basic_block bb; basic_block prev_bb = start_bb; - // Track any side effects seen - int_range_max side_effect (TREE_TYPE (name)); + // Track any inferred ranges seen. + int_range_max infer (TREE_TYPE (name)); // Range on entry to the DEF block should not be queried. gcc_checking_assert (start_bb != def_bb); @@ -1332,8 +1332,8 @@ ranger_cache::range_from_dom (irange &r, tree name, basic_block start_bb, bb; prev_bb = bb, bb = get_immediate_dominator (CDI_DOMINATORS, bb)) { - // Accumulate any block exit side effects. - m_exit.maybe_adjust_range (side_effect, name, bb); + // Accumulate any block exit inferred ranges. + m_exit.maybe_adjust_range (infer, name, bb); // This block has an outgoing range. if (m_gori.has_edge_range_p (name, bb)) @@ -1399,7 +1399,7 @@ ranger_cache::range_from_dom (irange &r, tree name, basic_block start_bb, if (m_gori.outgoing_edge_range_p (er, e, name, *this)) { r.intersect (er); - // If this is a normal edge, apply any side effects. + // If this is a normal edge, apply any inferred ranges. if ((e->flags & (EDGE_EH | EDGE_ABNORMAL)) == 0) m_exit.maybe_adjust_range (r, name, bb); @@ -1415,7 +1415,7 @@ ranger_cache::range_from_dom (irange &r, tree name, basic_block start_bb, // Apply non-null if appropriate. if (!has_abnormal_call_or_eh_pred_edge_p (start_bb)) - r.intersect (side_effect); + r.intersect (infer); if (DEBUG_RANGE_CACHE) { @@ -1430,14 +1430,14 @@ ranger_cache::range_from_dom (irange &r, tree name, basic_block start_bb, // any operands on stmt S to nonnull. void -ranger_cache::apply_side_effects (gimple *s) +ranger_cache::apply_inferred_ranges (gimple *s) { int_range_max r; bool update = true; basic_block bb = gimple_bb (s); - stmt_side_effects se(s); - if (se.num () == 0) + gimple_infer_range infer(s); + if (infer.num () == 0) return; // Do not update the on-netry cache for block ending stmts. @@ -1452,15 +1452,15 @@ ranger_cache::apply_side_effects (gimple *s) update = false; } - for (unsigned x = 0; x < se.num (); x++) + for (unsigned x = 0; x < infer.num (); x++) { - tree name = se.name (x); - m_exit.add_range (name, bb, se.range (x)); + tree name = infer.name (x); + m_exit.add_range (name, bb, infer.range (x)); if (update) { if (!m_on_entry.get_bb_range (r, name, bb)) exit_range (r, name, bb, RFD_READ_ONLY); - if (r.intersect (se.range (x))) + if (r.intersect (infer.range (x))) m_on_entry.set_bb_range (name, bb, r); } } diff --git a/gcc/gimple-range-cache.h b/gcc/gimple-range-cache.h index 555fe32..d56e56c 100644 --- a/gcc/gimple-range-cache.h +++ b/gcc/gimple-range-cache.h @@ -22,7 +22,7 @@ along with GCC; see the file COPYING3. If not see #define GCC_SSA_RANGE_CACHE_H #include "gimple-range-gori.h" -#include "gimple-range-side-effect.h" +#include "gimple-range-infer.h" // This class manages a vector of pointers to ssa_block ranges. It // provides the basis for the "range on entry" cache for all @@ -87,9 +87,9 @@ public: void propagate_updated_value (tree name, basic_block bb); - void apply_side_effects (gimple *s); + void apply_inferred_ranges (gimple *s); gori_compute m_gori; - side_effect_manager m_exit; + infer_range_manager m_exit; void dump_bb (FILE *f, basic_block bb); virtual void dump (FILE *f) override; diff --git a/gcc/gimple-range-infer.cc b/gcc/gimple-range-infer.cc new file mode 100644 index 0000000..8e25830 --- /dev/null +++ b/gcc/gimple-range-infer.cc @@ -0,0 +1,310 @@ +/* Gimple range inference implementation. + Copyright (C) 2022 Free Software Foundation, Inc. + Contributed by Andrew MacLeod . + +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 3, 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 COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "backend.h" +#include "insn-codes.h" +#include "tree.h" +#include "gimple.h" +#include "ssa.h" +#include "gimple-pretty-print.h" +#include "gimple-range.h" +#include "tree-cfg.h" +#include "target.h" +#include "attribs.h" +#include "gimple-iterator.h" +#include "gimple-walk.h" +#include "cfganal.h" + +// Adapted from infer_nonnull_range_by_dereference and check_loadstore +// to process nonnull ssa_name OP in S. DATA contains a pointer to a +// stmt range inference instance. + +static bool +non_null_loadstore (gimple *, tree op, tree, void *data) +{ + if (TREE_CODE (op) == MEM_REF || TREE_CODE (op) == TARGET_MEM_REF) + { + /* Some address spaces may legitimately dereference zero. */ + addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (op)); + if (!targetm.addr_space.zero_address_valid (as)) + { + tree ssa = TREE_OPERAND (op, 0); + ((gimple_infer_range *)data)->add_nonzero (ssa); + } + } + return false; +} + +// Add NAME and RANGE to the the range inference summary. + +void +gimple_infer_range::add_range (tree name, irange &range) +{ + m_names[num_args] = name; + m_ranges[num_args] = range; + if (num_args < size_limit - 1) + num_args++; +} + +// Add a nonzero range for NAME to the range inference summary. + +void +gimple_infer_range::add_nonzero (tree name) +{ + if (!gimple_range_ssa_p (name)) + return; + int_range<2> nz; + nz.set_nonzero (TREE_TYPE (name)); + add_range (name, nz); +} + +// Process S for range inference and fill in the summary list. +// This is the routine where new inferred ranges should be added. + +gimple_infer_range::gimple_infer_range (gimple *s) +{ + num_args = 0; + + if (is_a (s)) + return; + + if (is_a (s) && flag_delete_null_pointer_checks) + { + tree fntype = gimple_call_fntype (s); + bitmap nonnullargs = get_nonnull_args (fntype); + // Process any non-null arguments + if (nonnullargs) + { + for (unsigned i = 0; i < gimple_call_num_args (s); i++) + { + if (bitmap_empty_p (nonnullargs) + || bitmap_bit_p (nonnullargs, i)) + { + tree op = gimple_call_arg (s, i); + if (POINTER_TYPE_P (TREE_TYPE (op))) + add_nonzero (op); + } + } + BITMAP_FREE (nonnullargs); + } + // Fallthru and walk load/store ops now. + } + + // Look for possible non-null values. + if (flag_delete_null_pointer_checks && gimple_code (s) != GIMPLE_ASM + && !gimple_clobber_p (s)) + walk_stmt_load_store_ops (s, (void *)this, non_null_loadstore, + non_null_loadstore); + +} + +// ------------------------------------------------------------------------- + +// This class is an element in list of infered ranges. + +class exit_range +{ +public: + tree name; + irange *range; + exit_range *next; +}; + +// If there is an element which matches SSA, return a pointer to the element. +// Otherwise return NULL. + +exit_range * +infer_range_manager::exit_range_head::find_ptr (tree ssa) +{ + // Return NULL if SSA is not in this list. + if (!m_names || !bitmap_bit_p (m_names, SSA_NAME_VERSION (ssa))) + return NULL; + for (exit_range *ptr = head; ptr != NULL; ptr = ptr->next) + if (ptr->name == ssa) + return ptr; + // Should be unreachable. + gcc_unreachable (); + return NULL; +} + +// Construct a range infer manager. DO_SEARCH indicates whether an immediate +// use scan should be made the first time a name is processed. This is for +// on-demand clients who may not visit every statement and may miss uses. + +infer_range_manager::infer_range_manager (bool do_search) +{ + bitmap_obstack_initialize (&m_bitmaps); + m_on_exit.create (0); + m_on_exit.safe_grow_cleared (last_basic_block_for_fn (cfun) + 1); + // m_seen == NULL indicates no scanning. Otherwise the bit indicates a + // scan has been performed on NAME. + if (do_search) + m_seen = BITMAP_ALLOC (&m_bitmaps); + else + m_seen = NULL; + obstack_init (&m_list_obstack); + // Non-zero elements are very common, so cache them for each ssa-name. + m_nonzero.create (0); + m_nonzero.safe_grow_cleared (num_ssa_names + 1); +} + +// Destruct a range infer manager. + +infer_range_manager::~infer_range_manager () +{ + m_nonzero.release (); + obstack_free (&m_list_obstack, NULL); + m_on_exit.release (); + bitmap_obstack_release (&m_bitmaps); +} + +// Return a non-zero range value of the appropriate type for NAME from +// the cache, creating it if necessary. + +const irange& +infer_range_manager::get_nonzero (tree name) +{ + unsigned v = SSA_NAME_VERSION (name); + if (v >= m_nonzero.length ()) + m_nonzero.safe_grow_cleared (num_ssa_names + 20); + if (!m_nonzero[v]) + { + m_nonzero[v] = m_range_allocator.allocate (2); + m_nonzero[v]->set_nonzero (TREE_TYPE (name)); + } + return *(m_nonzero[v]); +} + +// Return TRUE if NAME has a range inference in block BB. + +bool +infer_range_manager::has_range_p (tree name, basic_block bb) +{ + // Check if this is an immediate use search model. + if (m_seen && !bitmap_bit_p (m_seen, SSA_NAME_VERSION (name))) + register_all_uses (name); + + if (bb->index >= (int)m_on_exit.length ()) + return false; + if (!m_on_exit[bb->index].m_names) + return false; + if (!bitmap_bit_p (m_on_exit[bb->index].m_names, SSA_NAME_VERSION (name))) + return false; + return true; +} + +// Return TRUE if NAME has a range inference in block BB, and adjust range R +// to include it. + +bool +infer_range_manager::maybe_adjust_range (irange &r, tree name, basic_block bb) +{ + if (!has_range_p (name, bb)) + return false; + exit_range *ptr = m_on_exit[bb->index].find_ptr (name); + gcc_checking_assert (ptr); + // Return true if this exit range changes R, otherwise false. + return r.intersect (*(ptr->range)); +} + +// Add range R as an inferred range for NAME in block BB. + +void +infer_range_manager::add_range (tree name, basic_block bb, const irange &r) +{ + if (bb->index >= (int)m_on_exit.length ()) + m_on_exit.safe_grow_cleared (last_basic_block_for_fn (cfun) + 1); + + // Create the summary list bitmap if it doesn't exist. + if (!m_on_exit[bb->index].m_names) + m_on_exit[bb->index].m_names = BITMAP_ALLOC (&m_bitmaps); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, " on-exit update "); + print_generic_expr (dump_file, name, TDF_SLIM); + fprintf (dump_file, " in BB%d : ",bb->index); + r.dump (dump_file); + fprintf (dump_file, "\n"); + } + + // If NAME already has a range, intersect them and done. + exit_range *ptr = m_on_exit[bb->index].find_ptr (name); + if (ptr) + { + int_range_max cur = r; + // If no new info is added, just return. + if (!cur.intersect (*(ptr->range))) + return; + if (ptr->range->fits_p (cur)) + *(ptr->range) = cur; + else + ptr->range = m_range_allocator.allocate (cur); + return; + } + + // Otherwise create a record. + bitmap_set_bit (m_on_exit[bb->index].m_names, SSA_NAME_VERSION (name)); + ptr = (exit_range *)obstack_alloc (&m_list_obstack, sizeof (exit_range)); + ptr->range = m_range_allocator.allocate (r); + ptr->name = name; + ptr->next = m_on_exit[bb->index].head; + m_on_exit[bb->index].head = ptr; +} + +// Add a non-zero inferred range for NAME in block BB. + +void +infer_range_manager::add_nonzero (tree name, basic_block bb) +{ + add_range (name, bb, get_nonzero (name)); +} + +// Follow immediate use chains and find all inferred ranges for NAME. + +void +infer_range_manager::register_all_uses (tree name) +{ + gcc_checking_assert (m_seen); + + // Check if we've already processed this name. + unsigned v = SSA_NAME_VERSION (name); + if (bitmap_bit_p (m_seen, v)) + return; + bitmap_set_bit (m_seen, v); + + use_operand_p use_p; + imm_use_iterator iter; + + // Loop over each immediate use and see if it has an inferred range. + FOR_EACH_IMM_USE_FAST (use_p, iter, name) + { + gimple *s = USE_STMT (use_p); + gimple_infer_range infer (s); + for (unsigned x = 0; x < infer.num (); x++) + { + if (name == infer.name (x)) + add_range (name, gimple_bb (s), infer.range (x)); + } + } +} diff --git a/gcc/gimple-range-infer.h b/gcc/gimple-range-infer.h new file mode 100644 index 0000000..6294367 --- /dev/null +++ b/gcc/gimple-range-infer.h @@ -0,0 +1,84 @@ +/* Header file for gimple range inference. + Copyright (C) 2022 Free Software Foundation, Inc. + Contributed by Andrew MacLeod . + +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 3, 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 COPYING3. If not see +. */ + +#ifndef GCC_GIMPLE_RANGE_SIDE_H +#define GCC_GIMPLE_RANGE_SIDE_H + +// Inferred ranges are ranges which are applied to use operands as a by product +// of executing an operation. + +// This class manages an on-demand summary of inferred ranges for a statement. +// It can be instantiated as required and provides a list of inferred ranges. +// New inferred ranges should added in the constructor of this class. + +class gimple_infer_range +{ +public: + gimple_infer_range (gimple *s); + inline unsigned num () const { return num_args; } + inline tree name (unsigned index) const + { gcc_checking_assert (index < num_args); return m_names[index]; } + inline const irange& range (unsigned index) const + { gcc_checking_assert (index < num_args); return m_ranges[index]; } + void add_range (tree name, irange &range); + void add_nonzero (tree name); +private: + unsigned num_args; + static const int size_limit = 10; + tree m_names[size_limit]; + int_range<3> m_ranges[size_limit]; + inline void bump_index () { if (num_args < size_limit - 1) num_args++; } +}; + +// This class manages a list of inferred ranges for each basic block. +// As inferences are made, they can be registered to a block and later +// queried. WHen constructed with a TRUE flag, immediate uses chains are +// followed the first time a name is referenced and block populated if +// there are any inferred ranges. + +class infer_range_manager +{ +public: + infer_range_manager (bool do_search); + ~infer_range_manager (); + void add_range (tree name, basic_block bb, const irange &r); + void add_nonzero (tree name, basic_block bb); + bool has_range_p (tree name, basic_block bb); + bool maybe_adjust_range (irange &r, tree name, basic_block bb); +private: + class exit_range_head + { + public: + bitmap m_names; // list of names with an outgoing range. + class exit_range *head; + int m_num_ranges; + exit_range *find_ptr (tree name); + }; + void register_all_uses (tree name); + vec m_on_exit; + const irange &get_nonzero (tree name); + vec m_nonzero; + bitmap m_seen; + bitmap_obstack m_bitmaps; + struct obstack m_list_obstack; + irange_allocator m_range_allocator; +}; + +#endif // GCC_GIMPLE_RANGE_SIDE_H diff --git a/gcc/gimple-range-side-effect.cc b/gcc/gimple-range-side-effect.cc deleted file mode 100644 index 2c8c77d..0000000 --- a/gcc/gimple-range-side-effect.cc +++ /dev/null @@ -1,310 +0,0 @@ -/* Gimple range side effect implementation. - Copyright (C) 2022 Free Software Foundation, Inc. - Contributed by Andrew MacLeod . - -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 3, 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 COPYING3. If not see -. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "backend.h" -#include "insn-codes.h" -#include "tree.h" -#include "gimple.h" -#include "ssa.h" -#include "gimple-pretty-print.h" -#include "gimple-range.h" -#include "tree-cfg.h" -#include "target.h" -#include "attribs.h" -#include "gimple-iterator.h" -#include "gimple-walk.h" -#include "cfganal.h" - -// Adapted from infer_nonnull_range_by_dereference and check_loadstore -// to process nonnull ssa_name OP in S. DATA contains a pointer to a -// stmt side effects instance. - -static bool -non_null_loadstore (gimple *, tree op, tree, void *data) -{ - if (TREE_CODE (op) == MEM_REF || TREE_CODE (op) == TARGET_MEM_REF) - { - /* Some address spaces may legitimately dereference zero. */ - addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (op)); - if (!targetm.addr_space.zero_address_valid (as)) - { - tree ssa = TREE_OPERAND (op, 0); - ((stmt_side_effects *)data)->add_nonzero (ssa); - } - } - return false; -} - -// Add NAME and RANGE to the the side effect summary. - -void -stmt_side_effects::add_range (tree name, irange &range) -{ - m_names[num_args] = name; - m_ranges[num_args] = range; - if (num_args < size_limit - 1) - num_args++; -} - -// Add a nonzero range for NAME to the side effect summary. - -void -stmt_side_effects::add_nonzero (tree name) -{ - if (!gimple_range_ssa_p (name)) - return; - int_range<2> nz; - nz.set_nonzero (TREE_TYPE (name)); - add_range (name, nz); -} - -// Process S for side effects and fill in the summary list. -// This is the routine where new side effects should be added. - -stmt_side_effects::stmt_side_effects (gimple *s) -{ - num_args = 0; - - if (is_a (s)) - return; - - if (is_a (s) && flag_delete_null_pointer_checks) - { - tree fntype = gimple_call_fntype (s); - bitmap nonnullargs = get_nonnull_args (fntype); - // Process any non-null arguments - if (nonnullargs) - { - for (unsigned i = 0; i < gimple_call_num_args (s); i++) - { - if (bitmap_empty_p (nonnullargs) - || bitmap_bit_p (nonnullargs, i)) - { - tree op = gimple_call_arg (s, i); - if (POINTER_TYPE_P (TREE_TYPE (op))) - add_nonzero (op); - } - } - BITMAP_FREE (nonnullargs); - } - // Fallthru and walk load/store ops now. - } - - // Look for possible non-null values. - if (flag_delete_null_pointer_checks && gimple_code (s) != GIMPLE_ASM - && !gimple_clobber_p (s)) - walk_stmt_load_store_ops (s, (void *)this, non_null_loadstore, - non_null_loadstore); - -} - -// ------------------------------------------------------------------------- - -// This class is an element in list of side effect ranges. - -class exit_range -{ -public: - tree name; - irange *range; - exit_range *next; -}; - -// If there is an element which matches SSA, return a pointer to the element. -// Otherwise return NULL. - -exit_range * -side_effect_manager::exit_range_head::find_ptr (tree ssa) -{ - // Return NULL if SSA is not in this list. - if (!m_names || !bitmap_bit_p (m_names, SSA_NAME_VERSION (ssa))) - return NULL; - for (exit_range *ptr = head; ptr != NULL; ptr = ptr->next) - if (ptr->name == ssa) - return ptr; - // Should be unreachable. - gcc_unreachable (); - return NULL; -} - -// Construct a side effects manager. DO_SEARCH indicates whether an immediate -// use scan should be made the first time a name is processed. This is for -// on-demand clients who may not visit every statement and may miss uses. - -side_effect_manager::side_effect_manager (bool do_search) -{ - bitmap_obstack_initialize (&m_bitmaps); - m_on_exit.create (0); - m_on_exit.safe_grow_cleared (last_basic_block_for_fn (cfun) + 1); - // m_seen == NULL indicates no scanning. Otherwise the bit indicates a - // scan has been performed on NAME. - if (do_search) - m_seen = BITMAP_ALLOC (&m_bitmaps); - else - m_seen = NULL; - obstack_init (&m_list_obstack); - // Non-zero elements are very common, so cache them for each ssa-name. - m_nonzero.create (0); - m_nonzero.safe_grow_cleared (num_ssa_names + 1); -} - -// Destruct a side effects manager. - -side_effect_manager::~side_effect_manager () -{ - m_nonzero.release (); - obstack_free (&m_list_obstack, NULL); - m_on_exit.release (); - bitmap_obstack_release (&m_bitmaps); -} - -// Return a non-zero range value of the appropriate type for NAME from -// the cache, creating it if necessary. - -const irange& -side_effect_manager::get_nonzero (tree name) -{ - unsigned v = SSA_NAME_VERSION (name); - if (v >= m_nonzero.length ()) - m_nonzero.safe_grow_cleared (num_ssa_names + 20); - if (!m_nonzero[v]) - { - m_nonzero[v] = m_range_allocator.allocate (2); - m_nonzero[v]->set_nonzero (TREE_TYPE (name)); - } - return *(m_nonzero[v]); -} - -// Return TRUE if NAME has a side effect range in block BB. - -bool -side_effect_manager::has_range_p (tree name, basic_block bb) -{ - // Check if this is an immediate use search model. - if (m_seen && !bitmap_bit_p (m_seen, SSA_NAME_VERSION (name))) - register_all_uses (name); - - if (bb->index >= (int)m_on_exit.length ()) - return false; - if (!m_on_exit[bb->index].m_names) - return false; - if (!bitmap_bit_p (m_on_exit[bb->index].m_names, SSA_NAME_VERSION (name))) - return false; - return true; -} - -// Return TRUE if NAME has a side effect range in block BB, and adjust range R -// to include it. - -bool -side_effect_manager::maybe_adjust_range (irange &r, tree name, basic_block bb) -{ - if (!has_range_p (name, bb)) - return false; - exit_range *ptr = m_on_exit[bb->index].find_ptr (name); - gcc_checking_assert (ptr); - // Return true if this exit range changes R, otherwise false. - return r.intersect (*(ptr->range)); -} - -// Add range R as a side effect for NAME in block BB. - -void -side_effect_manager::add_range (tree name, basic_block bb, const irange &r) -{ - if (bb->index >= (int)m_on_exit.length ()) - m_on_exit.safe_grow_cleared (last_basic_block_for_fn (cfun) + 1); - - // Create the summary list bitmap if it doesn't exist. - if (!m_on_exit[bb->index].m_names) - m_on_exit[bb->index].m_names = BITMAP_ALLOC (&m_bitmaps); - - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, " on-exit update "); - print_generic_expr (dump_file, name, TDF_SLIM); - fprintf (dump_file, " in BB%d : ",bb->index); - r.dump (dump_file); - fprintf (dump_file, "\n"); - } - - // If NAME already has a range, intersect them and done. - exit_range *ptr = m_on_exit[bb->index].find_ptr (name); - if (ptr) - { - int_range_max cur = r; - // If no new info is added, just return. - if (!cur.intersect (*(ptr->range))) - return; - if (ptr->range->fits_p (cur)) - *(ptr->range) = cur; - else - ptr->range = m_range_allocator.allocate (cur); - return; - } - - // Otherwise create a record. - bitmap_set_bit (m_on_exit[bb->index].m_names, SSA_NAME_VERSION (name)); - ptr = (exit_range *)obstack_alloc (&m_list_obstack, sizeof (exit_range)); - ptr->range = m_range_allocator.allocate (r); - ptr->name = name; - ptr->next = m_on_exit[bb->index].head; - m_on_exit[bb->index].head = ptr; -} - -// Add a non-zero side effect for NAME in block BB. - -void -side_effect_manager::add_nonzero (tree name, basic_block bb) -{ - add_range (name, bb, get_nonzero (name)); -} - -// Follow immediate use chains and find all side effects for NAME. - -void -side_effect_manager::register_all_uses (tree name) -{ - gcc_checking_assert (m_seen); - - // Check if we've already processed this name. - unsigned v = SSA_NAME_VERSION (name); - if (bitmap_bit_p (m_seen, v)) - return; - bitmap_set_bit (m_seen, v); - - use_operand_p use_p; - imm_use_iterator iter; - - // Loop over each immediate use and see if it has a side effect. - FOR_EACH_IMM_USE_FAST (use_p, iter, name) - { - gimple *s = USE_STMT (use_p); - stmt_side_effects se (s); - for (unsigned x = 0; x < se.num (); x++) - { - if (name == se.name (x)) - add_range (name, gimple_bb (s), se.range (x)); - } - } -} diff --git a/gcc/gimple-range-side-effect.h b/gcc/gimple-range-side-effect.h deleted file mode 100644 index 848d94b..0000000 --- a/gcc/gimple-range-side-effect.h +++ /dev/null @@ -1,82 +0,0 @@ -/* Header file for gimple range side effects. - Copyright (C) 2022 Free Software Foundation, Inc. - Contributed by Andrew MacLeod . - -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 3, 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 COPYING3. If not see -. */ - -#ifndef GCC_GIMPLE_RANGE_SIDE_H -#define GCC_GIMPLE_RANGE_SIDE_H - -// This class manages an on-demand summary of side effects for a statement. -// It can be instantiated as required and provides a list of side effects. - -// New side effects should added in the constructor of this class. - -class stmt_side_effects -{ -public: - stmt_side_effects (gimple *s); - inline unsigned num () const { return num_args; } - inline tree name (unsigned index) const - { gcc_checking_assert (index < num_args); return m_names[index]; } - inline const irange& range (unsigned index) const - { gcc_checking_assert (index < num_args); return m_ranges[index]; } - void add_range (tree name, irange &range); - void add_nonzero (tree name); -private: - unsigned num_args; - static const int size_limit = 10; - tree m_names[size_limit]; - int_range<3> m_ranges[size_limit]; - inline void bump_index () { if (num_args < size_limit - 1) num_args++; } -}; - -// This class manages a list of side effect ranges for each basic block. -// As side effects are seen, they can be registered to a block and later -// queried. WHen constructed with a TRUE flag, immediate uses chains are -// followed the first time a name is referenced and block populated if -// thre are any side effects. - -class side_effect_manager -{ -public: - side_effect_manager (bool do_search); - ~side_effect_manager (); - void add_range (tree name, basic_block bb, const irange &r); - void add_nonzero (tree name, basic_block bb); - bool has_range_p (tree name, basic_block bb); - bool maybe_adjust_range (irange &r, tree name, basic_block bb); -private: - class exit_range_head - { - public: - bitmap m_names; // list of names with an outgoing range. - class exit_range *head; - int m_num_ranges; - exit_range *find_ptr (tree name); - }; - void register_all_uses (tree name); - vec m_on_exit; - const irange &get_nonzero (tree name); - vec m_nonzero; - bitmap m_seen; - bitmap_obstack m_bitmaps; - struct obstack m_list_obstack; - irange_allocator m_range_allocator; -}; - -#endif // GCC_GIMPLE_RANGE_SIDE_H diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc index f5e9e77..08a9c01 100644 --- a/gcc/gimple-range.cc +++ b/gcc/gimple-range.cc @@ -446,12 +446,11 @@ gimple_ranger::fold_stmt (gimple_stmt_iterator *gsi, tree (*valueize) (tree)) return ret; } -// Called during dominator walks to register any side effects that take effect -// from this point forward. Current release is only for tracking non-null -// within a block. +// Called during dominator walks to register any inferred ranges that take +// effect from this point forward. void -gimple_ranger::register_side_effects (gimple *s) +gimple_ranger::register_inferred_ranges (gimple *s) { // First, export the LHS if it is a new global range. tree lhs = gimple_get_lhs (s); @@ -475,7 +474,7 @@ gimple_ranger::register_side_effects (gimple *s) fputc ('\n', dump_file); } } - m_cache.apply_side_effects (s); + m_cache.apply_inferred_ranges (s); } // This routine will export whatever global ranges are known to GCC diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h index 13d4c77..c67280d 100644 --- a/gcc/gimple-range.h +++ b/gcc/gimple-range.h @@ -60,7 +60,7 @@ public: void dump_bb (FILE *f, basic_block bb); auto_edge_flag non_executable_edge_flag; bool fold_stmt (gimple_stmt_iterator *gsi, tree (*) (tree)); - void register_side_effects (gimple *s); + void register_inferred_ranges (gimple *s); protected: bool fold_range_internal (irange &r, gimple *s, tree name); void prefill_name (irange &r, tree name); diff --git a/gcc/range-op.h b/gcc/range-op.h index 5fdda32..300974fb 100644 --- a/gcc/range-op.h +++ b/gcc/range-op.h @@ -95,7 +95,7 @@ protected: const wide_int &lh_ub, const wide_int &rh_lb, const wide_int &rh_ub) const; - // Side effect of relation for generic fold_range clients. + // Effect of relation for generic fold_range clients. virtual bool op1_op2_relation_effect (irange &lhs_range, tree type, const irange &op1_range, const irange &op2_range, diff --git a/gcc/tree-vrp.cc b/gcc/tree-vrp.cc index 0784d65..62ae5a9 100644 --- a/gcc/tree-vrp.cc +++ b/gcc/tree-vrp.cc @@ -4304,7 +4304,7 @@ public: m_pta->enter (bb); for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi)) - m_ranger->register_side_effects (gsi.phi ()); + m_ranger->register_inferred_ranges (gsi.phi ()); } void post_fold_bb (basic_block bb) override @@ -4322,7 +4322,7 @@ public: bool ret = m_simplifier.simplify (gsi); if (!ret) ret = m_ranger->fold_stmt (gsi, follow_single_use_edges); - m_ranger->register_side_effects (gsi_stmt (*gsi)); + m_ranger->register_inferred_ranges (gsi_stmt (*gsi)); return ret; } -- cgit v1.1