diff options
author | Andrew MacLeod <amacleod@redhat.com> | 2020-10-06 12:12:53 -0400 |
---|---|---|
committer | Andrew MacLeod <amacleod@redhat.com> | 2020-10-06 12:47:59 -0400 |
commit | 90e88fd376bb9ad6223a1f5ccd803d1bd9539b05 (patch) | |
tree | 7272e9d5642fd7ae4c15cefc98dea5b5a1b71db0 /gcc/gimple-range-edge.cc | |
parent | 1644d7f4c1c4f99231d7de5e35fa7ce2d2e2c4c6 (diff) | |
download | gcc-90e88fd376bb9ad6223a1f5ccd803d1bd9539b05.zip gcc-90e88fd376bb9ad6223a1f5ccd803d1bd9539b05.tar.gz gcc-90e88fd376bb9ad6223a1f5ccd803d1bd9539b05.tar.bz2 |
Ranger classes.
Add the 8 ranger files and the Makefile changes to build it.
2020-10-06 Andrew MacLeod <amacleod@redhat.com>
* Makefile.in (OBJS): Add gimple-range*.o.
* gimple-range.h: New file.
* gimple-range.cc: New file.
* gimple-range-cache.h: New file.
* gimple-range-cache.cc: New file.
* gimple-range-edge.h: New file.
* gimple-range-edge.cc: New file.
* gimple-range-gori.h: New file.
* gimple-range-gori.cc: New file.
Diffstat (limited to 'gcc/gimple-range-edge.cc')
-rw-r--r-- | gcc/gimple-range-edge.cc | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/gcc/gimple-range-edge.cc b/gcc/gimple-range-edge.cc new file mode 100644 index 0000000..c5ee54f --- /dev/null +++ b/gcc/gimple-range-edge.cc @@ -0,0 +1,197 @@ +/* Gimple range edge functionaluity. + Copyright (C) 2020 Free Software Foundation, Inc. + Contributed by Andrew MacLeod <amacleod@redhat.com> + and Aldy Hernandez <aldyh@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 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 +<http://www.gnu.org/licenses/>. */ + + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "backend.h" +#include "tree.h" +#include "gimple.h" +#include "ssa.h" +#include "gimple-pretty-print.h" +#include "gimple-iterator.h" +#include "tree-cfg.h" +#include "gimple-range.h" + +// If there is a range control statment at the end of block BB, return it. +// Otherwise return NULL. + +gimple * +gimple_outgoing_range_stmt_p (basic_block bb) +{ + gimple_stmt_iterator gsi = gsi_last_nondebug_bb (bb); + if (!gsi_end_p (gsi)) + { + gimple *s = gsi_stmt (gsi); + if (is_a<gcond *> (s) && gimple_range_handler (s)) + return gsi_stmt (gsi); + gswitch *sw = dyn_cast<gswitch *> (s); + if (sw && irange::supports_type_p (TREE_TYPE (gimple_switch_index (sw)))) + return gsi_stmt (gsi); + } + return NULL; +} + + +outgoing_range::outgoing_range () +{ + m_edge_table = NULL; +} + +outgoing_range::~outgoing_range () +{ + if (m_edge_table) + delete m_edge_table; +} + + +// Get a range for a switch edge E from statement S and return it in R. +// Use a cached value if it exists, or calculate it if not. + +bool +outgoing_range::get_edge_range (irange &r, gimple *s, edge e) +{ + gcc_checking_assert (is_a<gswitch *> (s)); + gswitch *sw = as_a<gswitch *> (s); + + // ADA currently has cases where the index is 64 bits and the case + // arguments are 32 bit, causing a trap when we create a case_range. + // Until this is resolved (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87798) + // punt on switches where the labels dont match the argument. + if (gimple_switch_num_labels (sw) > 1 && + TYPE_PRECISION (TREE_TYPE (CASE_LOW (gimple_switch_label (sw, 1)))) != + TYPE_PRECISION (TREE_TYPE (gimple_switch_index (sw)))) + return false; + + if (!m_edge_table) + m_edge_table = new hash_map<edge, irange *> (n_edges_for_fn (cfun)); + + irange **val = m_edge_table->get (e); + if (!val) + { + calc_switch_ranges (sw); + val = m_edge_table->get (e); + gcc_checking_assert (val); + } + r = **val; + return true; +} + + +// Calculate all switch edges from SW and cache them in the hash table. + +void +outgoing_range::calc_switch_ranges (gswitch *sw) +{ + bool existed; + unsigned x, lim; + lim = gimple_switch_num_labels (sw); + tree type = TREE_TYPE (gimple_switch_index (sw)); + + edge default_edge = gimple_switch_default_edge (cfun, sw); + irange *&default_slot = m_edge_table->get_or_insert (default_edge, &existed); + + // This should be the first call into this switch. For the default + // range case, start with varying and intersect each other case from + // it. + + gcc_checking_assert (!existed); + + // Allocate an int_range_max for default case. + default_slot = m_range_allocator.allocate (255); + default_slot->set_varying (type); + + for (x = 1; x < lim; x++) + { + edge e = gimple_switch_edge (cfun, sw, x); + + // If this edge is the same as the default edge, do nothing else. + if (e == default_edge) + continue; + + tree low = CASE_LOW (gimple_switch_label (sw, x)); + tree high = CASE_HIGH (gimple_switch_label (sw, x)); + if (!high) + high = low; + + // Remove the case range from the default case. + int_range_max def_range (low, high); + range_cast (def_range, type); + def_range.invert (); + default_slot->intersect (def_range); + + // Create/union this case with anything on else on the edge. + int_range_max case_range (low, high); + range_cast (case_range, type); + irange *&slot = m_edge_table->get_or_insert (e, &existed); + if (existed) + { + case_range.union_ (*slot); + if (slot->fits_p (case_range)) + { + *slot = case_range; + continue; + } + } + // If there was an existing range and it doesn't fit, we lose the memory. + // It'll get reclaimed when the obstack is freed. This seems less + // intrusive than allocating max ranges for each case. + slot = m_range_allocator.allocate (case_range); + } +} + + +// Calculate the range forced on on edge E by control flow, return it +// in R. Return the statment which defines the range, otherwise +// return NULL + +gimple * +outgoing_range::edge_range_p (irange &r, edge e) +{ + // Determine if there is an outgoing edge. + gimple *s = gimple_outgoing_range_stmt_p (e->src); + if (!s) + return NULL; + + if (is_a<gcond *> (s)) + { + if (e->flags & EDGE_TRUE_VALUE) + r = int_range<2> (boolean_true_node, boolean_true_node); + else if (e->flags & EDGE_FALSE_VALUE) + r = int_range<2> (boolean_false_node, boolean_false_node); + else + gcc_unreachable (); + return s; + } + + gcc_checking_assert (is_a<gswitch *> (s)); + gswitch *sw = as_a<gswitch *> (s); + tree type = TREE_TYPE (gimple_switch_index (sw)); + + if (!irange::supports_type_p (type)) + return NULL; + + if (get_edge_range (r, sw, e)) + return s; + + return NULL; +} |