From c21644704160710a17d1ea6c1cd212e079cd5e36 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacleod@redhat.com>
Date: Tue, 25 May 2021 14:15:50 -0400
Subject: [PATCH 3/8] Add imports and strengthen the export definition in
 range_def and gori_map.

All add up to 2 direct dependencies for each ssa-name.
Add gori import/export iterators.

	* gimple-range-gori.cc (range_def_chain::range_def_chain): init
	bitmap obstack.
	(range_def_chain::~range_def_chain): Dispose of obstack rather than
	each individual bitmap.
	(range_def_chain::set_import): New.
	(range_def_chain::get_imports): New.
	(range_def_chain::chain_import_p): New.
	(range_def_chain::register_dependency): Rename from build_def_chain
	and set imports.
	(range_def_chain::def_chain_in_bitmap_p): New.
	(range_def_chain::add_def_chain_to_bitmap): New.
	(range_def_chain::has_def_chain): Just check first depenedence.
	(range_def_chain::get_def_chain): Process imports, use generic
	register_dependency routine.
	(range_def_chain::dump): New.
	(gori_map::gori_map): Allocate import list.
	(gori_map::~gori_map): Release imports.
	(gori_map::exports): Check for past allocated block size.
	(gori_map::imports): New.
	(gori_map::def_chain_in_export_p): Delete.
	(gori_map::is_import_p): New.
	(gori_map::maybe_add_gori): Handle imports.
	(gori_map::dump): Adjust output, add imports.
	(gori_compute::has_edge_range_p): Remove def_chain_in_export call.
	(gori_export_iterator::gori_export_iterator): New.
	(gori_export_iterator::next): New.
	(gori_export_iterator::get_name): New.
	* gimple-range-gori.h (range_def_chain): Add imports and direct
	dependecies via struct rdc.
	(range_def_chain::depend1): New.
	(range_def_chain::depend2): New.
	(class gori_map): Adjust.
	(FOR_EACH_GORI_IMPORT_NAME): New.
	(FOR_EACH_GORI_EXPORT_NAME): New.
	(class gori_export_iterator): New.
---
 gcc/gimple-range-gori.cc | 356 ++++++++++++++++++++++++++++-----------
 gcc/gimple-range-gori.h  |  77 ++++++++-
 2 files changed, 327 insertions(+), 106 deletions(-)

diff --git a/gcc/gimple-range-gori.cc b/gcc/gimple-range-gori.cc
index e30049edfbd..94640adc041 100644
--- a/gcc/gimple-range-gori.cc
+++ b/gcc/gimple-range-gori.cc
@@ -56,7 +56,7 @@ is_gimple_logical_p (const gimple *gs)
   return false;
 }
 
-/* RANGE_DEF_CHAIN is used to determine what SSA names in a block can
+/* RANGE_DEF_CHAIN is used to determine which SSA names in a block can
    have range information calculated for them, and what the
    dependencies on each other are.
 
@@ -95,6 +95,7 @@ is_gimple_logical_p (const gimple *gs)
 
 range_def_chain::range_def_chain ()
 {
+  bitmap_obstack_initialize (&m_bitmaps);
   m_def_chain.create (0);
   m_def_chain.safe_grow_cleared (num_ssa_names);
   m_logical_depth = 0;
@@ -104,11 +105,8 @@ range_def_chain::range_def_chain ()
 
 range_def_chain::~range_def_chain ()
 {
-  unsigned x;
-  for (x = 0; x < m_def_chain.length (); ++x)
-    if (m_def_chain[x])
-      BITMAP_FREE (m_def_chain[x]);
   m_def_chain.release ();
+  bitmap_obstack_release (&m_bitmaps);
 }
 
 // Return true if NAME is in the def chain of DEF.  If BB is provided,
@@ -128,26 +126,112 @@ range_def_chain::in_chain_p (tree name, tree def)
   return bitmap_bit_p (chain, SSA_NAME_VERSION (name));
 }
 
+// Add either IMP or the import list B to the import set of DATA.
+
+void
+range_def_chain::set_import (struct rdc &data, tree imp, bitmap b)
+{
+  // If there are no imports, just return
+  if (imp == NULL_TREE && !b)
+    return;
+  if (!data.m_import)
+    data.m_import = BITMAP_ALLOC (&m_bitmaps);
+  if (imp != NULL_TREE)
+    bitmap_set_bit (data.m_import, SSA_NAME_VERSION (imp));
+  else
+    bitmap_ior_into (data.m_import, b);
+}
+
+// Return the import list for NAME.
+
+bitmap
+range_def_chain::get_imports (tree name)
+{
+  if (!has_def_chain (name))
+    get_def_chain (name);
+  bitmap i = m_def_chain[SSA_NAME_VERSION (name)].m_import;
+  // Either this is a default def,  OR imports must be a subset of exports.
+  gcc_checking_assert (!get_def_chain (name) || !i
+		       || !bitmap_intersect_compl_p (i, get_def_chain (name)));
+  return i;
+}
+
+// Return true if IMPORT is an import to NAMEs def chain.
+
+bool
+range_def_chain::chain_import_p (tree name, tree import)
+{
+  bitmap b = get_imports (name);
+  if (b)
+    return bitmap_bit_p (b, SSA_NAME_VERSION (import));
+  return false;
+}
+
 // Build def_chains for NAME if it is in BB.  Copy the def chain into RESULT.
 
 void
-range_def_chain::build_def_chain (tree name, bitmap result, basic_block bb)
+range_def_chain::register_dependency (tree name, tree dep, basic_block bb)
 {
+  if (!gimple_range_ssa_p (dep))
+    return;
+
+  unsigned v = SSA_NAME_VERSION (name);
+  struct rdc &src = m_def_chain[v];
+  gimple *def_stmt = SSA_NAME_DEF_STMT (dep);
+  unsigned dep_v = SSA_NAME_VERSION (dep);
   bitmap b;
-  gimple *def_stmt = SSA_NAME_DEF_STMT (name);
+
+  // Set the direct dependency cache entries.
+  if (!src.ssa1)
+    src.ssa1 = dep;
+  else if (!src.ssa2 && src.ssa1 != dep)
+    src.ssa2 = dep;
+
+  // Don't calculate imports or export/dep chains if BB is not provided.
+  // This is usually the case for when the temporal cache wants the direct
+  // dependencies of a stmt.
+  if (!bb)
+    return;
+
+  if (!src.bm)
+    src.bm = BITMAP_ALLOC (&m_bitmaps);
+
   // Add this operand into the result.
-  bitmap_set_bit (result, SSA_NAME_VERSION (name));
+  bitmap_set_bit (src.bm, dep_v);
 
   if (gimple_bb (def_stmt) == bb && !is_a<gphi *>(def_stmt))
     {
       // Get the def chain for the operand.
-      b = get_def_chain (name);
+      b = get_def_chain (dep);
       // If there was one, copy it into result.
       if (b)
-	bitmap_ior_into (result, b);
+	bitmap_ior_into (src.bm, b);
+      // And copy the import list.
+      set_import (src, NULL_TREE, get_imports (dep));
     }
+  else
+    // Originated outside the block, so it is an import.
+    set_import (src, dep, NULL);
+}
+
+bool
+range_def_chain::def_chain_in_bitmap_p (tree name, bitmap b)
+{
+  bitmap a = get_def_chain (name);
+  if (a && b)
+    return bitmap_intersect_p (a, b);
+  return false;
 }
 
+void
+range_def_chain::add_def_chain_to_bitmap (bitmap b, tree name)
+{
+  bitmap r = get_def_chain (name);
+  if (r)
+    bitmap_ior_into (b, r);
+}
+
+
 // Return TRUE if NAME has been processed for a def_chain.
 
 inline bool
@@ -157,9 +241,11 @@ range_def_chain::has_def_chain (tree name)
   unsigned v = SSA_NAME_VERSION (name);
   if (v >= m_def_chain.length ())
     m_def_chain.safe_grow_cleared (num_ssa_names + 1);
-  return (m_def_chain[v] != NULL);
+  return (m_def_chain[v].ssa1 != 0);
 }
 
+
+
 // Calculate the def chain for NAME and all of its dependent
 // operands. Only using names in the same BB.  Return the bitmap of
 // all names in the m_def_chain.  This only works for supported range
@@ -174,11 +260,15 @@ range_def_chain::get_def_chain (tree name)
 
   // If it has already been processed, just return the cached value.
   if (has_def_chain (name))
-    return m_def_chain[v];
+    return m_def_chain[v].bm;
 
   // No definition chain for default defs.
   if (SSA_NAME_IS_DEFAULT_DEF (name))
-    return NULL;
+    {
+      // A Default def is always an import.
+      set_import (m_def_chain[v], name, NULL);
+      return NULL;
+    }
 
   gimple *stmt = SSA_NAME_DEF_STMT (name);
   if (gimple_range_handler (stmt))
@@ -205,30 +295,63 @@ range_def_chain::get_def_chain (tree name)
       ssa3 = gimple_range_ssa_p (gimple_assign_rhs3 (st));
     }
   else
-    return NULL;
-
-  basic_block bb = gimple_bb (stmt);
-
-  m_def_chain[v] = BITMAP_ALLOC (NULL);
+    {
+      // Stmts not understood are always imports.
+      set_import (m_def_chain[v], name, NULL);
+      return NULL;
+    }
 
-  if (ssa1)
-    build_def_chain (ssa1, m_def_chain[v], bb);
-  if (ssa2)
-    build_def_chain (ssa2, m_def_chain[v], bb);
-  if (ssa3)
-    build_def_chain (ssa3, m_def_chain[v], bb);
+  register_dependency (name, ssa1, gimple_bb (stmt));
+  register_dependency (name, ssa2, gimple_bb (stmt));
+  register_dependency (name, ssa3, gimple_bb (stmt));
+  // Stmts with no understandable operands are also imports.
+  if (!ssa1 && !ssa2 & !ssa3)
+    set_import (m_def_chain[v], name, NULL);
 
   if (is_logical)
     m_logical_depth--;
 
-  // If we run into pathological cases where the defintion chains are
-  // huge (ie  huge basic block fully unrolled) we might be able to limit
-  // this by deciding here that if some criteria is satisfied, we change the
-  // def_chain back to be just the ssa-names.  That will help prevent chains
-  // of a_2 = b_6 + a_8 from creating a pathological case.
-  return m_def_chain[v];
+  return m_def_chain[v].bm;
+}
+
+// Dump what we know for basic block BB to file F.
+
+void
+range_def_chain::dump (FILE *f, basic_block bb, const char *prefix)
+{
+  unsigned x, y;
+  bitmap_iterator bi;
+
+  // Dump the def chain for each SSA_NAME defined in BB.
+  for (x = 1; x < num_ssa_names; x++)
+    {
+      tree name = ssa_name (x);
+      if (!name)
+	continue;
+      gimple *stmt = SSA_NAME_DEF_STMT (name);
+      if (!stmt || (bb && gimple_bb (stmt) != bb))
+	continue;
+      bitmap chain = (has_def_chain (name) ? get_def_chain (name) : NULL);
+      if (chain && !bitmap_empty_p (chain))
+	{
+	  fprintf (f, prefix);
+	  print_generic_expr (f, name, TDF_SLIM);
+	  fprintf (f, " : ");
+
+	  bitmap imports = get_imports (name);
+	  EXECUTE_IF_SET_IN_BITMAP (chain, 0, y, bi)
+	    {
+	      print_generic_expr (f, ssa_name (y), TDF_SLIM);
+	      if (imports && bitmap_bit_p (imports, y))
+		fprintf (f, "(I)");
+	      fprintf (f, "  ");
+	    }
+	  fprintf (f, "\n");
+	}
+    }
 }
 
+
 // -------------------------------------------------------------------
 
 /* GORI_MAP is used to accumulate what SSA names in a block can
@@ -256,7 +379,8 @@ gori_map::gori_map ()
 {
   m_outgoing.create (0);
   m_outgoing.safe_grow_cleared (last_basic_block_for_fn (cfun));
-  bitmap_obstack_initialize (&m_bitmaps);
+  m_incoming.create (0);
+  m_incoming.safe_grow_cleared (last_basic_block_for_fn (cfun));
   m_maybe_variant = BITMAP_ALLOC (&m_bitmaps);
 }
 
@@ -264,7 +388,7 @@ gori_map::gori_map ()
 
 gori_map::~gori_map ()
 {
-  bitmap_obstack_release (&m_bitmaps);
+  m_incoming.release ();
   m_outgoing.release ();
 }
 
@@ -273,11 +397,21 @@ gori_map::~gori_map ()
 bitmap
 gori_map::exports (basic_block bb)
 {
-  if (!m_outgoing[bb->index])
+  if (bb->index >= (signed int)m_outgoing.length () || !m_outgoing[bb->index])
     calculate_gori (bb);
   return m_outgoing[bb->index];
 }
 
+// Return the bitmap vector of all imports to BB.  Calculate if necessary.
+
+bitmap
+gori_map::imports (basic_block bb)
+{
+  if (bb->index >= (signed int)m_outgoing.length () || !m_outgoing[bb->index])
+    calculate_gori (bb);
+  return m_incoming[bb->index];
+}
+
 // Return true if NAME is can have ranges generated for it from basic
 // block BB.
 
@@ -298,17 +432,13 @@ gori_map::set_range_invariant (tree name)
   bitmap_clear_bit (m_maybe_variant, SSA_NAME_VERSION (name));
 }
 
-// Return true if any element in the def chain of NAME is in the
-// export list for BB.
+// Return true if NAME is an import to block BB.
 
 bool
-gori_map::def_chain_in_export_p (tree name, basic_block bb)
+gori_map::is_import_p (tree name, basic_block bb)
 {
-  bitmap a = exports (bb);
-  bitmap b = get_def_chain (name);
-  if (a && b)
-    return bitmap_intersect_p (a, b);
-  return false;
+  // If no BB is specified, test if it is exported anywhere in the IL.
+  return bitmap_bit_p (imports (bb), SSA_NAME_VERSION (name));
 }
 
 // If NAME is non-NULL and defined in block BB, calculate the def
@@ -319,11 +449,17 @@ gori_map::maybe_add_gori (tree name, basic_block bb)
 {
   if (name)
     {
-      gimple *s = SSA_NAME_DEF_STMT (name);
-      bitmap r = get_def_chain (name);
-      // Check if there is a def chain, and it is in this block.
-      if (r && gimple_bb (s) == bb)
-	bitmap_copy (m_outgoing[bb->index], r);
+      // Check if there is a def chain, regardless of the block.
+      add_def_chain_to_bitmap (m_outgoing[bb->index], name);
+      // Check for any imports.
+      bitmap imp = get_imports (name);
+      // If there were imports, add them so we can recompute
+      if (imp)
+	bitmap_ior_into (m_incoming[bb->index], imp);
+      // This name is always an import.
+      if (gimple_bb (SSA_NAME_DEF_STMT (name)) != bb)
+	bitmap_set_bit (m_incoming[bb->index], SSA_NAME_VERSION (name));
+
       // Def chain doesn't include itself, and even if there isn't a
       // def chain, this name should be added to exports.
       bitmap_set_bit (m_outgoing[bb->index], SSA_NAME_VERSION (name));
@@ -337,9 +473,13 @@ gori_map::calculate_gori (basic_block bb)
 {
   tree name;
   if (bb->index >= (signed int)m_outgoing.length ())
-    m_outgoing.safe_grow_cleared (last_basic_block_for_fn (cfun));
+    {
+      m_outgoing.safe_grow_cleared (last_basic_block_for_fn (cfun));
+      m_incoming.safe_grow_cleared (last_basic_block_for_fn (cfun));
+    }
   gcc_checking_assert (m_outgoing[bb->index] == NULL);
   m_outgoing[bb->index] = BITMAP_ALLOC (&m_bitmaps);
+  m_incoming[bb->index] = BITMAP_ALLOC (&m_bitmaps);
 
   // If this block's last statement may generate range informaiton, go
   // calculate it.
@@ -368,65 +508,42 @@ gori_map::calculate_gori (basic_block bb)
 // Dump the table information for BB to file F.
 
 void
-gori_map::dump (FILE *f, basic_block bb)
+gori_map::dump (FILE *f, basic_block bb, bool verbose)
 {
-  bool header = false;
-  const char *header_string = "bb%-4d ";
-  const char *header2 = "       ";
-  bool printed_something = false;;
-  unsigned x, y;
-  bitmap_iterator bi;
-
   // BB was not processed.
-  if (!m_outgoing[bb->index])
+  if (!m_outgoing[bb->index] || bitmap_empty_p (m_outgoing[bb->index]))
     return;
 
-  // Dump the def chain for each SSA_NAME defined in BB.
-  for (x = 1; x < num_ssa_names; x++)
+  tree name;
+
+  bitmap imp = imports (bb);
+  if (!bitmap_empty_p (imp))
     {
-      tree name = ssa_name (x);
-      if (!name)
-	continue;
-      gimple *stmt = SSA_NAME_DEF_STMT (name);
-      bitmap chain = (has_def_chain (name) ? get_def_chain (name) : NULL);
-      if (stmt && gimple_bb (stmt) == bb && chain && !bitmap_empty_p (chain))
-        {
-	  fprintf (f, header_string, bb->index);
-	  header_string = header2;
-	  header = true;
+      if (verbose)
+	fprintf (f, "bb<%u> Imports: ",bb->index);
+      else
+	fprintf (f, "Imports: ");
+      FOR_EACH_GORI_IMPORT_NAME (*this, bb, name)
+	{
 	  print_generic_expr (f, name, TDF_SLIM);
-	  fprintf (f, " : ");
-	  EXECUTE_IF_SET_IN_BITMAP (chain, 0, y, bi)
-	    {
-	      print_generic_expr (f, ssa_name (y), TDF_SLIM);
-	      fprintf (f, "  ");
-	    }
-	  fprintf (f, "\n");
+	  fprintf (f, "  ");
 	}
+      fputc ('\n', f);
     }
 
-  printed_something |= header;
-
-  // Now dump the export vector.
-  header = false;
-  EXECUTE_IF_SET_IN_BITMAP (m_outgoing[bb->index], 0, y, bi)
+  if (verbose)
+    fprintf (f, "bb<%u> Exports: ",bb->index);
+  else
+    fprintf (f, "Exports: ");
+  // Dump the export vector.
+  FOR_EACH_GORI_EXPORT_NAME (*this, bb, name)
     {
-      if (!header)
-        {
-	  fprintf (f, header_string, bb->index);
-	  fprintf (f, "exports: ");
-	  header_string = header2;
-	  header = true;
-	}
-      print_generic_expr (f, ssa_name (y), TDF_SLIM);
+      print_generic_expr (f, name, TDF_SLIM);
       fprintf (f, "  ");
     }
-  if (header)
-    fputc ('\n', f);
+  fputc ('\n', f);
 
-  printed_something |= header;
-  if (printed_something)
-    fprintf (f, "\n");
+  range_def_chain::dump (f, bb, "         ");
 }
 
 // Dump the entire GORI map structure to file F.
@@ -436,11 +553,7 @@ gori_map::dump (FILE *f)
 {
   basic_block bb;
   FOR_EACH_BB_FN (bb, cfun)
-    {
-      dump (f, bb);
-      if (m_outgoing[bb->index])
-	fprintf (f, "\n");
-    }
+    dump (f, bb);
 }
 
 DEBUG_FUNCTION void
@@ -960,8 +1073,7 @@ gori_compute::has_edge_range_p (tree name, edge e)
   if (!e)
     return is_export_p (name);
 
-  return (is_export_p (name, e->src)
-	  || def_chain_in_export_p (name, e->src));
+  return is_export_p (name, e->src);
 }
 
 // Dump what is known to GORI computes to listing file F.
@@ -1006,6 +1118,50 @@ gori_compute::outgoing_edge_range_p (irange &r, edge e, tree name)
   return false;
 }
 
+
+// ------------------------------------------------------------------------
+//  GORI iterator.  Although we have bitmap iterators, don't expose that it
+//  is currently a bitmap.  Use an export iterator to hide future changes.
+
+// Construct a basic iterator over an export bitmap.
+
+gori_export_iterator::gori_export_iterator (bitmap b)
+{
+  bm = b;
+  if (b)
+    bmp_iter_set_init (&bi, b, 1, &y);
+}
+
+
+// Move to the next export bitmap spot.
+
+void
+gori_export_iterator::next ()
+{
+  bmp_iter_next (&bi, &y);
+}
+
+
+// Fetch the name of the next export in the export list.  Return NULL if
+// iteration is done.
+
+tree
+gori_export_iterator::get_name ()
+{
+  if (!bm)
+    return NULL_TREE;
+
+  while (bmp_iter_set (&bi, &y))
+    {
+      tree t = ssa_name (y);
+      if (t)
+	return t;
+      next ();
+    }
+  return NULL_TREE;
+}
+
+
 // --------------------------------------------------------------------------
 
 // Cache for SSAs that appear on the RHS of a boolean assignment.
diff --git a/gcc/gimple-range-gori.h b/gcc/gimple-range-gori.h
index 6208931a0d8..8f44216cfcd 100644
--- a/gcc/gimple-range-gori.h
+++ b/gcc/gimple-range-gori.h
@@ -31,15 +31,55 @@ class range_def_chain
 public:
   range_def_chain ();
   ~range_def_chain ();
+  tree depend1 (tree name) const;
+  tree depend2 (tree name) const;
+  bool in_chain_p (tree name, tree def);
+  bool chain_import_p (tree name, tree import);
+  void register_dependency (tree name, tree ssa1, basic_block bb = NULL);
+  void dump (FILE *f, basic_block bb, const char *prefix = NULL);
+protected:
   bool has_def_chain (tree name);
+  bool def_chain_in_bitmap_p (tree name, bitmap b);
+  void add_def_chain_to_bitmap (bitmap b, tree name);
   bitmap get_def_chain (tree name);
-  bool in_chain_p (tree name, tree def);
+  bitmap get_imports (tree name);
+  bitmap_obstack m_bitmaps;
 private:
-  vec<bitmap> m_def_chain;	// SSA_NAME : def chain components.
-  void build_def_chain (tree name, bitmap result, basic_block bb);
+  struct rdc {
+   tree ssa1;		// First direct dependency
+   tree ssa2;		// Second direct dependency
+   bitmap bm;		// All dependencies
+   bitmap m_import;
+  };
+  vec<rdc> m_def_chain;	// SSA_NAME : def chain components.
+  void set_import (struct rdc &data, tree imp, bitmap b);
   int m_logical_depth;
 };
 
+// Return the first direct dependency for NAME, if there is one.
+// Direct dependencies are those which occur on the defintion statement.
+// Only the first 2 such names are cached.
+
+inline tree
+range_def_chain::depend1 (tree name) const
+{
+  unsigned v = SSA_NAME_VERSION (name);
+  if (v >= m_def_chain.length ())
+    return NULL_TREE;
+  return m_def_chain[v].ssa1;
+}
+
+// Return the second direct dependency for NAME, if there is one.
+
+inline tree
+range_def_chain::depend2 (tree name) const
+{
+  unsigned v = SSA_NAME_VERSION (name);
+  if (v >= m_def_chain.length ())
+    return NULL_TREE;
+  return m_def_chain[v].ssa2;
+}
+
 // GORI_MAP is used to accumulate what SSA names in a block can
 // generate range information, and provides tools for the block ranger
 // to enable it to efficiently calculate these ranges.
@@ -51,15 +91,16 @@ public:
   ~gori_map ();
 
   bool is_export_p (tree name, basic_block bb = NULL);
-  bool def_chain_in_export_p (tree name, basic_block bb);
+  bool is_import_p (tree name, basic_block bb);
   bitmap exports (basic_block bb);
+  bitmap imports (basic_block bb);
   void set_range_invariant (tree name);
 
   void dump (FILE *f);
-  void dump (FILE *f, basic_block bb);
+  void dump (FILE *f, basic_block bb, bool verbose = true);
 private:
-  bitmap_obstack m_bitmaps;
   vec<bitmap> m_outgoing;	// BB: Outgoing ranges calculatable on edges
+  vec<bitmap> m_incoming;	// BB: Incoming ranges which can affect exports.
   bitmap m_maybe_variant;	// Names which might have outgoing ranges.
   void maybe_add_gori (tree name, basic_block bb);
   void calculate_gori (basic_block bb);
@@ -152,6 +193,30 @@ private:
 };
 
 
+// For each name that is an import into BB's exports..
+#define FOR_EACH_GORI_IMPORT_NAME(gori, bb, name)			\
+  for (gori_export_iterator iter ((gori).imports ((bb)));	\
+       ((name) = iter.get_name ());				\
+       iter.next ())
+
+// For each name possibly exported from block BB.
+#define FOR_EACH_GORI_EXPORT_NAME(gori, bb, name)		\
+  for (gori_export_iterator iter ((gori).exports ((bb)));	\
+       ((name) = iter.get_name ());				\
+       iter.next ())
+
+// Used to assist with iterating over the GORI export list in various ways
+class gori_export_iterator {
+public:
+  gori_export_iterator (bitmap b);
+  void next ();
+  tree get_name ();
+protected:
+  bitmap bm;
+  bitmap_iterator bi;
+  unsigned y;
+};
+
 // This class adds a cache to gori_computes for logical expressions.
 //       bool result = x && y
 // requires calcuation of both X and Y for both true and false results.
-- 
2.17.2

