aboutsummaryrefslogtreecommitdiff
path: root/gcc/gimple-range-edge.cc
diff options
context:
space:
mode:
authorAndrew MacLeod <amacleod@redhat.com>2020-10-06 12:12:53 -0400
committerAndrew MacLeod <amacleod@redhat.com>2020-10-06 12:47:59 -0400
commit90e88fd376bb9ad6223a1f5ccd803d1bd9539b05 (patch)
tree7272e9d5642fd7ae4c15cefc98dea5b5a1b71db0 /gcc/gimple-range-edge.cc
parent1644d7f4c1c4f99231d7de5e35fa7ce2d2e2c4c6 (diff)
downloadgcc-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.cc197
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;
+}