From 22b75a53ae8d1d7a0df12977555b294915a30502 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Thu, 14 Apr 2016 15:39:12 -0400
Subject: [PATCH 091/117] FIXME: create edges in CFG

---
 gcc/rtl/rtl-frontend.c | 126 +++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 121 insertions(+), 5 deletions(-)

diff --git a/gcc/rtl/rtl-frontend.c b/gcc/rtl/rtl-frontend.c
index d536319..0fb65c4 100644
--- a/gcc/rtl/rtl-frontend.c
+++ b/gcc/rtl/rtl-frontend.c
@@ -335,6 +335,7 @@ class function_reader : public rtx_reader
 
   void create_function ();
   void apply_fixups ();
+  void create_cfg_edges ();
 
   rtx_insn **get_insn_by_uid (int uid);
 
@@ -343,7 +344,7 @@ class function_reader : public rtx_reader
   tree parse_mem_expr (const char *desc);
 
  private:
-  void create_cfg ();
+  void create_cfg_and_basic_blocks ();
 
  private:
   struct uid_hash : int_hash <int, -1, -2> {};
@@ -610,7 +611,7 @@ function_reader::create_function ()
   //struct function *fn = ; // DECL_STRUCT_FUNCTION (node->decl);
   //push_cfun (fn);
 
-  create_cfg ();
+  create_cfg_and_basic_blocks ();
   cfun->curr_properties = (PROP_cfg | PROP_rtl);
 
   //pop_cfun ();
@@ -669,9 +670,11 @@ function_reader::get_insn_by_uid (int uid)
   return m_insns_by_uid.get (uid);
 }
 
-/* Create cfun's CFG and populate with blocks (TODO: and edges), a helper
+/* Create cfun's CFG and populate with blocks, a helper
    function for function_reader::create_function ().
 
+   The edges are created later on, after fixups are applied.
+
    We can't call create_basic_block and use the regular RTL block-creation
    hooks, since this creates NOTE_INSN_BASIC_BLOCK instances.  We don't
    want to do that; we want to use the notes we were provided with.
@@ -690,7 +693,7 @@ function_reader::get_insn_by_uid (int uid)
    blocks (next_bb/prev_bb) skips over these "holes".  */
 
 void
-function_reader::create_cfg ()
+function_reader::create_cfg_and_basic_blocks ()
 {
   /* Create bare-bones cfg.  This creates the entry and exit blocks.  */
 #if 1
@@ -733,9 +736,121 @@ function_reader::create_cfg ()
 
       after = bb;
     }
+}
+
+/* FIXME.  */
+
+static void
+for_each_label_ref (rtx_jump_insn *jump_insn,
+		    void (*cb) (rtx_jump_insn *jump_insn,
+				rtx label_ref,
+				void *user_data),
+		    void *user_data)
+{
+  /* TODO: edges for jump.  */
+  /* FIXME: how to do this?  there could be multiple labels
+     e.g. computed jump.  */
+
+  if (any_condjump_p (jump_insn))
+    {
+      rtx label_ref = condjump_label (jump_insn);
+      cb (jump_insn, label_ref, user_data);
+      return;
+    }
+
+  if (simplejump_p (jump_insn))
+    {
+      rtx label_ref = SET_SRC (PATTERN (jump_insn));
+      cb (jump_insn, label_ref, user_data);
+      return;
+    }
+
+  rtx_jump_table_data *tablep;
+  if (tablejump_p (jump_insn, NULL, &tablep))
+    {
+      gcc_assert (tablep);
+      rtvec labels = tablep->get_labels ();
+      int i, veclen = GET_NUM_ELEM (labels);
+      for (i = 0; i < veclen; ++i)
+	{
+	  rtx label_ref = RTVEC_ELT (labels, i);
+	  cb (jump_insn, label_ref, user_data);
+	}
+      return;
+    }
+
+  /* TODO: something else?  */
+  gcc_unreachable ();
+}
 
-  /* TODO: create edges.  */
+/* FIXME.  */
 
+static void
+add_edge (basic_block src, basic_block dst, int flags)
+{
+  if (0)
+    fprintf (stderr, "making edge %i->%i\n",
+	     src->index, dst->index);
+  unchecked_make_edge (src, dst, flags);
+}
+
+/* FIXME.  */
+
+static void
+add_edge_cb (rtx_jump_insn *jump_insn, rtx label_ref, void *user_data)
+{
+  gcc_assert (jump_insn);
+  gcc_assert (label_ref);
+  rtx_insn *label_insn = as_a <rtx_insn *> (LABEL_REF_LABEL (label_ref));
+  add_edge (BLOCK_FOR_INSN (jump_insn), BLOCK_FOR_INSN (label_insn), 0);
+}
+
+/* Create edges within cfun's CFG, by examining instructions in the
+   basic blocks and reconstructing the edges accordingly.
+   This is done after fixups are applied, since the latter is responsible
+   for setting up BB_HEAD and BB_END within each basic block.  */
+
+void
+function_reader::create_cfg_edges ()
+{
+  /* Create edge from ENTRY_BLOCK to block of first insn.  */
+  basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (cfun);
+  add_edge (entry, entry->next_bb, EDGE_FALLTHRU);
+
+  /* Create other edges.
+
+     The edge from the block of last insn to EXIT_BLOCK is created
+     below, by fall-through from the end of its block.  */
+  basic_block bb;
+  FOR_ALL_BB_FN (bb, cfun)
+    {
+      if (!BB_HEAD (bb))
+	continue;
+      rtx_insn *end_insn = BB_END (bb);
+      if (rtx_jump_insn *jump_insn = dyn_cast <rtx_jump_insn *> (end_insn))
+	{
+	  if (0)
+	    fprintf (stderr, "bb %i ends in jump\n", bb->index);
+	  if (!any_uncondjump_p (end_insn))
+	    {
+	      /* Add fallthrough edge first.  */
+	      gcc_assert (bb->next_bb);
+	      add_edge (bb, bb->next_bb, EDGE_FALLTHRU);
+	    }
+	  for_each_label_ref (jump_insn, add_edge_cb, NULL);
+	}
+      else
+	{
+	  if (0)
+	    fprintf (stderr, "bb %i ends in non-jump\n", bb->index);
+	  if (bb->next_bb != NULL)
+	    {
+	      /* Add fallthrough edge.  */
+	      gcc_assert (bb->next_bb);
+	      add_edge (bb, bb->next_bb, EDGE_FALLTHRU);
+	    }
+	}
+    }
 }
 
 /*  Locate and run PASS_NAME on cfun.  */
@@ -774,6 +889,7 @@ rtl_langhook_parse_file (void)
 
   reader.create_function ();
   reader.apply_fixups ();
+  reader.create_cfg_edges ();
 
   /* If -froundtrip=FILENAME was provided, immediately dump the
      result, so that the testsuite can compare it against the
-- 
1.8.5.3

