From 00c8d0a1eb1cc3ce75c26f091b8535db5caa188b Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Wed, 16 May 2018 13:46:06 -0400
Subject: [PATCH 60/83] Split up the optinfo backends into separate files and
 headers

---
 gcc/Makefile.in                 |   4 +-
 gcc/optimization-records.cc     | 285 ----------------------------------------
 gcc/optimization-records.h      |  39 ------
 gcc/optinfo-emit-diagnostics.cc | 101 ++++++++++++++
 gcc/optinfo-emit-diagnostics.h  |  26 ++++
 gcc/optinfo-emit-fopt-info.cc   |  88 +++++++++++++
 gcc/optinfo-emit-fopt-info.h    |  26 ++++
 gcc/optinfo-emit-json.cc        | 273 ++++++++++++++++++++++++++++++++++++++
 gcc/optinfo-emit-json.h         |  38 ++++++
 gcc/optinfo.cc                  | 161 ++---------------------
 gcc/optinfo.h                   |   4 -
 gcc/toplev.c                    |   2 +-
 gcc/tree-vect-loop.c            |   6 -
 gcc/tree-vect-slp.c             |   2 +-
 gcc/tree-vectorizer.c           |   2 +-
 gcc/tree-vectorizer.h           |   1 -
 16 files changed, 571 insertions(+), 487 deletions(-)
 delete mode 100644 gcc/optimization-records.cc
 delete mode 100644 gcc/optimization-records.h
 create mode 100644 gcc/optinfo-emit-diagnostics.cc
 create mode 100644 gcc/optinfo-emit-diagnostics.h
 create mode 100644 gcc/optinfo-emit-fopt-info.cc
 create mode 100644 gcc/optinfo-emit-fopt-info.h
 create mode 100644 gcc/optinfo-emit-json.cc
 create mode 100644 gcc/optinfo-emit-json.h

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 40722b2..04da12d 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1423,11 +1423,13 @@ OBJS = \
 	omp-low.o \
 	omp-simd-clone.o \
 	optinfo.o \
+	optinfo-emit-diagnostics.o \
+	optinfo-emit-fopt-info.o \
+	optinfo-emit-json.o \
 	optabs.o \
 	optabs-libfuncs.o \
 	optabs-query.o \
 	optabs-tree.o \
-	optimization-records.o \
 	options-save.o \
 	opts-global.o \
 	passes.o \
diff --git a/gcc/optimization-records.cc b/gcc/optimization-records.cc
deleted file mode 100644
index 11cc065..0000000
--- a/gcc/optimization-records.cc
+++ /dev/null
@@ -1,285 +0,0 @@
-/* Support for recording information about optimizations.
-   Copyright (C) 2018 Free Software Foundation, Inc.
-   Contributed by David Malcolm <dmalcolm@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"
-
-/* FIXME: trim these.  */
-#include "backend.h"
-#include "rtl.h"
-#include "tree.h"
-#include "gimple.h"
-#include "cfghooks.h"
-#include "cgraph.h"
-#include "coverage.h"
-#include "diagnostic-core.h"
-#include "cfganal.h"
-#include "value-prof.h"
-#include "gimple-iterator.h"
-#include "tree-cfg.h"
-#include "dumpfile.h"
-#include "cfgloop.h"
-
-#include "profile.h"
-#include "output.h"
-#include "tree-pass.h"
-
-#include "optinfo.h"
-#include "optimization-records.h"
-#include "json.h"
-#include "tree-scalar-evolution.h"
-#include "pretty-print.h"
-#include "tree-pretty-print.h"
-#include "gimple-pretty-print.h"
-
-/* FIXME.  */
-
-static json::object *
-impl_location_to_json (location loc)
-{
-  json::object *obj = new json::object ();
-  obj->set ("file", new json::string (loc.m_file));
-  obj->set ("line", new json::number (loc.m_line));
-  obj->set ("function", new json::string (loc.m_function));
-  return obj;
-}
-
-/* FIXME.  */
-
-static json::object *
-location_to_json (location_t loc)
-{
-  json::object *obj = new json::object ();
-  obj->set ("file", new json::string (LOCATION_FILE (loc)));
-  obj->set ("line", new json::number (LOCATION_LINE (loc)));
-  obj->set ("column", new json::number (LOCATION_COLUMN (loc)));
-  return obj;
-}
-
-/* FIXME.  */
-static json::object *
-profile_count_to_json (profile_count count)
-{
-  json::object *obj = new json::object ();
-  obj->set ("value", new json::number (count.to_gcov_type ()));
-  obj->set ("quality",
-	    new json::string (profile_quality_as_string (count.quality ())));
-  return obj;
-}
-
-/* FIXME.  */
-
-static json::array *records;
-
-/* FIXME.  */
-
-static vec<json::array *> scopes;
-
-/* FIXME.  */
-
-void
-optimization_records_start ()
-{
-  /* Bail immediately if recording not enabled.  */
-  if (!flag_save_optimization_record)
-    return;
-
-  records = new json::array ();
-
-  scopes.safe_push (records);
-}
-
-/* FIXME.  */
-
-void
-optimization_records_finish ()
-{
-  /* Bail immediately if recording not enabled.  */
-  if (!records)
-    return;
-
-  char *filename = concat (dump_base_name, ".opt-record.json", NULL);
-  FILE *outfile = fopen (filename, "w");
-  if (outfile)
-    {
-      records->dump (outfile);
-      fclose (outfile);
-    }
-  else
-    error_at (UNKNOWN_LOCATION, "unable to write optimization records to %qs",
-	      filename); // FIXME: more info?
-  free (filename);
-
-  delete records;
-  records = NULL;
-}
-
-/* FIXME.  */
-
-bool
-optimization_records_enabled_p ()
-{
-  return records != NULL;
-}
-
-/* FIXME.  */
-
-void
-optimization_records_maybe_record_optinfo (const optinfo *optinfo)
-{
-  /* Bail immediately if recording not enabled.  */
-  if (!records)
-    return;
-
-  gimple *stmt = optinfo->get_location ().m_stmt;//get_best_stmt ();
-
-  json::object *obj = new json::object ();
-
-  obj->set ("impl_location",
-	    impl_location_to_json (optinfo->get_impl_location ()));
-
-  const char *kind_str = optinfo_kind_to_string (optinfo->get_kind ());
-  obj->set ("kind", new json::string (kind_str));
-  json::array *message = new json::array ();
-  obj->set ("message", message);
-  for (unsigned i = 0; i < optinfo->num_items (); i++)
-    {
-      const optinfo_item *item = optinfo->get_item (i);
-      switch (item->get_kind ())
-	{
-	default:
-	  gcc_unreachable ();
-	case OPTINFO_ITEM_KIND_TEXT:
-	  {
-	    const optinfo_item_text *as_text = (const optinfo_item_text *)item;
-	    message->append (new json::string (as_text->get_text ()));
-	  }
-	  break;
-	case OPTINFO_ITEM_KIND_TREE:
-	  {
-	    const optinfo_item_tree *as_tree = (const optinfo_item_tree *)item;
-	    tree node = as_tree->get_node ();
-	    json::object *item = new json::object ();
-	    /* Capture output of:
-	         dump_generic_expr (MSG_NOTE, flags, node);
-	       into a text buffer, and add it as a attribute of ITEM.
-	       This is:
-	         print_generic_expr (alt_dump_file, node, dump_flags | extra_dump_flags);
-	       which is:
-		 maybe_init_pretty_print (file);
-		 dump_generic_node (tree_pp, node, 0, flags, false);
-		 pp_flush (tree_pp);
-	    */
-	    pretty_printer pp;
-	    pp_needs_newline (&pp) = true;
-	    pp_translate_identifiers (&pp) = false;
-
-	    dump_generic_node (&pp, node, 0, as_tree->get_flags (), false);
-
-	    item->set ("expr", new json::string (pp_formatted_text (&pp)));
-
-	    /* Capture any location for the node.  */
-	    if (EXPR_HAS_LOCATION (node))
-	      item->set ("location", location_to_json (EXPR_LOCATION (node)));
-
-	    message->append (item);
-	  }
-	  break;
-	case OPTINFO_ITEM_KIND_GIMPLE:
-	  {
-	    const optinfo_item_gimple *as_gimple = (const optinfo_item_gimple *)item;
-	    gimple *stmt = as_gimple->get_stmt ();
-	    json::object *item = new json::object ();
-	    /* Capture output of:
-		 dump_gimple_stmt (MSG_NOTE, TDF_SLIM, stmt, 0);
-	       into a text buffer, and add it as a attribute of ITEM.
-	       This is:
-		 print_gimple_stmt (dump_file, gs, spc, dump_flags | extra_dump_flags);
-	       which is:
-		 pp_needs_newline (&buffer) = true;
-		 buffer.buffer->stream = file;
-		 pp_gimple_stmt_1 (&buffer, g, spc, flags);
-		 pp_newline_and_flush (&buffer);
-	    */
-	    pretty_printer pp;
-	    pp_needs_newline (&pp) = true;
-	    pp_gimple_stmt_1 (&pp, stmt, 0, TDF_SLIM);
-	    item->set ("stmt", new json::string (pp_formatted_text (&pp)));
-
-	    /* Capture any location for the stmt.  */
-	    if (gimple_location (stmt))
-	      item->set ("location", location_to_json (gimple_location (stmt)));
-
-	    message->append (item);
-	  }
-	  break;
-	}
-   }
-
-  if (current_pass)
-    obj->set ("pass", new json::string (current_pass->name));
-
-  location_t loc = UNKNOWN_LOCATION;
-  if (stmt)
-    {
-      loc = gimple_location (stmt);
-      if (stmt->bb)
-	if (stmt->bb->count.initialized_p ())
-	  obj->set ("count", profile_count_to_json (stmt->bb->count));
-    }
-
-  if (loc != UNKNOWN_LOCATION)
-    {
-      // TOOD: record the location (just caret for now)
-      // TODO: start/finish also?
-      obj->set ("location", location_to_json (loc));
-    }
-
-  if (current_function_decl)
-    {
-      const char *fnname = get_fnname_from_decl (current_function_decl);
-      obj->set ("function", new json::string (fnname));
-    }
-
-  /* Add to innermost scope.  */
-  gcc_assert (scopes.length () > 0);
-  scopes[scopes.length () - 1]->append (obj);
-
-  /* Potentially push the scope.  */
-  if (optinfo->get_kind () == OPTINFO_KIND_SCOPE)
-    {
-      json::array *children = new json::array ();
-      obj->set ("children", children);
-      scopes.safe_push (children);
-    }
-}
-
-/* FIXME.  */
-
-void
-optimization_records_maybe_pop_optinfo_scope ()
-{
-  /* Bail immediately if recording not enabled.  */
-  if (!records)
-    return;
-
-  scopes.pop ();
-}
diff --git a/gcc/optimization-records.h b/gcc/optimization-records.h
deleted file mode 100644
index 18c67d5..0000000
--- a/gcc/optimization-records.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Support for recording information about optimizations.
-   Copyright (C) 2018 Free Software Foundation, Inc.
-   Contributed by David Malcolm <dmalcolm@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/>.  */
-
-#ifndef GCC_OPTIMIZATION_RECORDS_H
-#define GCC_OPTIMIZATION_RECORDS_H
-
-struct loop;
-class optinfo;
-
-/* FIXME.  */
-
-extern void optimization_records_start ();
-extern void optimization_records_finish ();
-
-// FIXME: maybe make this inline?
-extern bool optimization_records_enabled_p ();
-
-extern void optimization_records_maybe_record_optinfo (const optinfo *);
-extern void optimization_records_maybe_pop_optinfo_scope ();
-
-
-#endif /* #ifndef GCC_OPTIMIZATION_RECORDS_H */
diff --git a/gcc/optinfo-emit-diagnostics.cc b/gcc/optinfo-emit-diagnostics.cc
new file mode 100644
index 0000000..e245a76
--- /dev/null
+++ b/gcc/optinfo-emit-diagnostics.cc
@@ -0,0 +1,101 @@
+/* Emit optimization information as "remark" diagnostics.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalcolm@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 "tree.h"
+#include "tree-pass.h"
+#include "pretty-print.h"
+#include "tree-pretty-print.h"
+#include "gimple-pretty-print.h"
+#include "diagnostic.h"
+#include "diagnostic-color.h"
+
+#include "optinfo.h"
+#include "optinfo-emit-diagnostics.h"
+
+/* FIXME.  */
+
+void
+emit_optinfo_as_diagnostic_remark (const optinfo *optinfo)
+{
+  pretty_printer pp;
+  pp_needs_newline (&pp) = true;
+  pp_translate_identifiers (&pp) = false;
+
+  bool show_color = pp_show_color (global_dc->printer);
+
+  /* Start with scope-based indentation.  */
+  for (unsigned i = get_optinfo_scope_depth (); i > 0; i--)
+    pp_space (&pp);
+
+  /* Print the items into PP.  */
+  for (unsigned i = 0; i < optinfo->num_items (); i++)
+    {
+      const optinfo_item *item = optinfo->get_item (i);
+      switch (item->get_kind ())
+	{
+	default:
+	  gcc_unreachable ();
+	case OPTINFO_ITEM_KIND_TEXT:
+	  {
+	    const optinfo_item_text *as_text
+	      = (const optinfo_item_text *)item;
+	    pp_string (&pp, as_text->get_text ());
+	  }
+	  break;
+	case OPTINFO_ITEM_KIND_TREE:
+	  {
+	    const optinfo_item_tree *as_tree
+	      = (const optinfo_item_tree *)item;
+	    pp_begin_quote (&pp, show_color);
+	    dump_generic_node (&pp, as_tree->get_node (), 0, TDF_DETAILS,
+			       false);
+	    pp_end_quote (&pp, show_color);
+	  }
+	  break;
+	case OPTINFO_ITEM_KIND_GIMPLE:
+	  {
+	    const optinfo_item_gimple *as_gimple
+	      = (const optinfo_item_gimple *)item;
+	    gimple *stmt = as_gimple->get_stmt ();
+	    pp_begin_quote (&pp, show_color);
+	    pp_gimple_stmt_1 (&pp, stmt, 0, TDF_SLIM);
+	    pp_end_quote (&pp, show_color);
+	  }
+	  break;
+	}
+    }
+
+  const char *msg = pp_formatted_text (&pp);
+
+  location_t loc = optinfo->get_location_t ();
+  if (current_pass)
+    remark (loc, 0, "%s [%spass=%s%s]",
+	    msg,
+	    colorize_start (show_color,
+			    diagnostic_get_color_for_kind (DK_REMARK)),
+	    current_pass->name,
+	    colorize_stop (show_color));
+  else
+    remark (loc, 0, "%s", msg);
+}
diff --git a/gcc/optinfo-emit-diagnostics.h b/gcc/optinfo-emit-diagnostics.h
new file mode 100644
index 0000000..820cefd
--- /dev/null
+++ b/gcc/optinfo-emit-diagnostics.h
@@ -0,0 +1,26 @@
+/* Emit optimization information as "remark" diagnostics.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalcolm@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/>.  */
+
+#ifndef GCC_OPTINFO_EMIT_DIAGNOSTICS_H
+#define GCC_OPTINFO_EMIT_DIAGNOSTICS_H
+
+extern void emit_optinfo_as_diagnostic_remark (const optinfo *);
+
+#endif /* #ifndef GCC_OPTINFO_EMIT_DIAGNOSTICS_H */
diff --git a/gcc/optinfo-emit-fopt-info.cc b/gcc/optinfo-emit-fopt-info.cc
new file mode 100644
index 0000000..1c6ec56
--- /dev/null
+++ b/gcc/optinfo-emit-fopt-info.cc
@@ -0,0 +1,88 @@
+/* Emit optimization information via -fopt-info.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalcolm@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 "tree.h"
+#include "tree-pass.h"
+#include "pretty-print.h"
+#include "tree-pretty-print.h"
+#include "gimple-pretty-print.h"
+
+#include "optinfo.h"
+#include "optinfo-emit-fopt-info.h"
+
+/* Emit OPTINFO via -fopt-info.  */
+
+void
+emit_optinfo_via_fopt_info (const optinfo *optinfo)
+{
+  dump_flags_t flags = 0;
+  switch (optinfo->get_kind ())
+    {
+    default:
+      gcc_unreachable ();
+    case OPTINFO_KIND_SUCCESS:
+      flags = MSG_OPTIMIZED_LOCATIONS;
+      break;
+    case OPTINFO_KIND_FAILURE:
+      flags = MSG_MISSED_OPTIMIZATION;
+      break;
+    case OPTINFO_KIND_NOTE:
+    case OPTINFO_KIND_SCOPE:
+      flags = MSG_NOTE;
+      break;
+    }
+
+  // FIXME: location!
+  dump_printf_loc (MSG_NOTE, UNKNOWN_LOCATION, "");
+  for (unsigned i = 0; i < optinfo->num_items (); i++)
+    {
+      const optinfo_item *item = optinfo->get_item (i);
+      switch (item->get_kind ())
+	{
+	default:
+	  gcc_unreachable ();
+	case OPTINFO_ITEM_KIND_TEXT:
+	  {
+	    const optinfo_item_text *text = (const optinfo_item_text *)item;
+	    dump_printf (flags, "%s", text->get_text ());
+	  }
+	  break;
+	case OPTINFO_ITEM_KIND_TREE:
+	  {
+	    const optinfo_item_tree *tree = (const optinfo_item_tree *)item;
+	    dump_generic_expr (flags, TDF_DETAILS, tree->get_node ());
+	  }
+	  break;
+	case OPTINFO_ITEM_KIND_GIMPLE:
+	  {
+	    const optinfo_item_gimple *as_gimple
+	      = (const optinfo_item_gimple *)item;
+	    gimple *stmt = as_gimple->get_stmt ();
+	    dump_gimple_stmt (flags, TDF_SLIM, stmt, 0);
+	  }
+	  break;
+	}
+    }
+  dump_printf (flags, "\n");
+}
diff --git a/gcc/optinfo-emit-fopt-info.h b/gcc/optinfo-emit-fopt-info.h
new file mode 100644
index 0000000..35868ab
--- /dev/null
+++ b/gcc/optinfo-emit-fopt-info.h
@@ -0,0 +1,26 @@
+/* Emit optimization information via -fopt-info.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalcolm@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/>.  */
+
+#ifndef GCC_OPTINFO_EMIT_FOPT_INFO_H
+#define GCC_OPTINFO_EMIT_FOPT_INFO_H
+
+extern void emit_optinfo_via_fopt_info (const optinfo *);
+
+#endif /* #ifndef GCC_OPTINFO_EMIT_FOPT_INFO_H */
diff --git a/gcc/optinfo-emit-json.cc b/gcc/optinfo-emit-json.cc
new file mode 100644
index 0000000..b1dcdf8
--- /dev/null
+++ b/gcc/optinfo-emit-json.cc
@@ -0,0 +1,273 @@
+/* Emit optimization information as JSON files.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalcolm@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 "diagnostic-core.h"
+
+#include "profile.h"
+#include "output.h"
+#include "tree-pass.h"
+
+#include "optinfo.h"
+#include "optinfo-emit-json.h"
+#include "json.h"
+#include "pretty-print.h"
+#include "tree-pretty-print.h"
+#include "gimple-pretty-print.h"
+
+/* FIXME.  */
+
+static json::object *
+impl_location_to_json (location loc)
+{
+  json::object *obj = new json::object ();
+  obj->set ("file", new json::string (loc.m_file));
+  obj->set ("line", new json::number (loc.m_line));
+  obj->set ("function", new json::string (loc.m_function));
+  return obj;
+}
+
+/* FIXME.  */
+
+static json::object *
+location_to_json (location_t loc)
+{
+  json::object *obj = new json::object ();
+  obj->set ("file", new json::string (LOCATION_FILE (loc)));
+  obj->set ("line", new json::number (LOCATION_LINE (loc)));
+  obj->set ("column", new json::number (LOCATION_COLUMN (loc)));
+  return obj;
+}
+
+/* FIXME.  */
+static json::object *
+profile_count_to_json (profile_count count)
+{
+  json::object *obj = new json::object ();
+  obj->set ("value", new json::number (count.to_gcov_type ()));
+  obj->set ("quality",
+	    new json::string (profile_quality_as_string (count.quality ())));
+  return obj;
+}
+
+/* FIXME.  */
+
+static json::array *records;
+
+/* FIXME.  */
+
+static vec<json::array *> scopes;
+
+/* FIXME.  */
+
+void
+optimization_records_start ()
+{
+  /* Bail immediately if recording not enabled.  */
+  if (!flag_save_optimization_record)
+    return;
+
+  records = new json::array ();
+
+  scopes.safe_push (records);
+}
+
+/* FIXME.  */
+
+void
+optimization_records_finish ()
+{
+  /* Bail immediately if recording not enabled.  */
+  if (!records)
+    return;
+
+  char *filename = concat (dump_base_name, ".opt-record.json", NULL);
+  FILE *outfile = fopen (filename, "w");
+  if (outfile)
+    {
+      records->dump (outfile);
+      fclose (outfile);
+    }
+  else
+    error_at (UNKNOWN_LOCATION, "unable to write optimization records to %qs",
+	      filename); // FIXME: more info?
+  free (filename);
+
+  delete records;
+  records = NULL;
+}
+
+/* FIXME.  */
+
+bool
+optimization_records_enabled_p ()
+{
+  return records != NULL;
+}
+
+/* FIXME.  */
+
+void
+optimization_records_maybe_record_optinfo (const optinfo *optinfo)
+{
+  /* Bail immediately if recording not enabled.  */
+  if (!records)
+    return;
+
+  gimple *stmt = optinfo->get_location ().m_stmt;//get_best_stmt ();
+
+  json::object *obj = new json::object ();
+
+  obj->set ("impl_location",
+	    impl_location_to_json (optinfo->get_impl_location ()));
+
+  const char *kind_str = optinfo_kind_to_string (optinfo->get_kind ());
+  obj->set ("kind", new json::string (kind_str));
+  json::array *message = new json::array ();
+  obj->set ("message", message);
+  for (unsigned i = 0; i < optinfo->num_items (); i++)
+    {
+      const optinfo_item *item = optinfo->get_item (i);
+      switch (item->get_kind ())
+	{
+	default:
+	  gcc_unreachable ();
+	case OPTINFO_ITEM_KIND_TEXT:
+	  {
+	    const optinfo_item_text *as_text = (const optinfo_item_text *)item;
+	    message->append (new json::string (as_text->get_text ()));
+	  }
+	  break;
+	case OPTINFO_ITEM_KIND_TREE:
+	  {
+	    const optinfo_item_tree *as_tree = (const optinfo_item_tree *)item;
+	    tree node = as_tree->get_node ();
+	    json::object *item = new json::object ();
+	    /* Capture output of:
+	         dump_generic_expr (MSG_NOTE, flags, node);
+	       into a text buffer, and add it as a attribute of ITEM.
+	       This is:
+	         print_generic_expr (alt_dump_file, node, dump_flags | extra_dump_flags);
+	       which is:
+		 maybe_init_pretty_print (file);
+		 dump_generic_node (tree_pp, node, 0, flags, false);
+		 pp_flush (tree_pp);
+	    */
+	    pretty_printer pp;
+	    pp_needs_newline (&pp) = true;
+	    pp_translate_identifiers (&pp) = false;
+
+	    dump_generic_node (&pp, node, 0, as_tree->get_flags (), false);
+
+	    item->set ("expr", new json::string (pp_formatted_text (&pp)));
+
+	    /* Capture any location for the node.  */
+	    if (EXPR_HAS_LOCATION (node))
+	      item->set ("location", location_to_json (EXPR_LOCATION (node)));
+
+	    message->append (item);
+	  }
+	  break;
+	case OPTINFO_ITEM_KIND_GIMPLE:
+	  {
+	    const optinfo_item_gimple *as_gimple = (const optinfo_item_gimple *)item;
+	    gimple *stmt = as_gimple->get_stmt ();
+	    json::object *item = new json::object ();
+	    /* Capture output of:
+		 dump_gimple_stmt (MSG_NOTE, TDF_SLIM, stmt, 0);
+	       into a text buffer, and add it as a attribute of ITEM.
+	       This is:
+		 print_gimple_stmt (dump_file, gs, spc, dump_flags | extra_dump_flags);
+	       which is:
+		 pp_needs_newline (&buffer) = true;
+		 buffer.buffer->stream = file;
+		 pp_gimple_stmt_1 (&buffer, g, spc, flags);
+		 pp_newline_and_flush (&buffer);
+	    */
+	    pretty_printer pp;
+	    pp_needs_newline (&pp) = true;
+	    pp_gimple_stmt_1 (&pp, stmt, 0, TDF_SLIM);
+	    item->set ("stmt", new json::string (pp_formatted_text (&pp)));
+
+	    /* Capture any location for the stmt.  */
+	    if (gimple_location (stmt))
+	      item->set ("location", location_to_json (gimple_location (stmt)));
+
+	    message->append (item);
+	  }
+	  break;
+	}
+   }
+
+  if (current_pass)
+    obj->set ("pass", new json::string (current_pass->name));
+
+  location_t loc = UNKNOWN_LOCATION;
+  if (stmt)
+    {
+      loc = gimple_location (stmt);
+      if (stmt->bb)
+	if (stmt->bb->count.initialized_p ())
+	  obj->set ("count", profile_count_to_json (stmt->bb->count));
+    }
+
+  if (loc != UNKNOWN_LOCATION)
+    {
+      // TOOD: record the location (just caret for now)
+      // TODO: start/finish also?
+      obj->set ("location", location_to_json (loc));
+    }
+
+  if (current_function_decl)
+    {
+      const char *fnname = get_fnname_from_decl (current_function_decl);
+      obj->set ("function", new json::string (fnname));
+    }
+
+  /* Add to innermost scope.  */
+  gcc_assert (scopes.length () > 0);
+  scopes[scopes.length () - 1]->append (obj);
+
+  /* Potentially push the scope.  */
+  if (optinfo->get_kind () == OPTINFO_KIND_SCOPE)
+    {
+      json::array *children = new json::array ();
+      obj->set ("children", children);
+      scopes.safe_push (children);
+    }
+}
+
+/* FIXME.  */
+
+void
+optimization_records_maybe_pop_optinfo_scope ()
+{
+  /* Bail immediately if recording not enabled.  */
+  if (!records)
+    return;
+
+  scopes.pop ();
+}
diff --git a/gcc/optinfo-emit-json.h b/gcc/optinfo-emit-json.h
new file mode 100644
index 0000000..7d8f69f
--- /dev/null
+++ b/gcc/optinfo-emit-json.h
@@ -0,0 +1,38 @@
+/* Emit optimization information as JSON files.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalcolm@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/>.  */
+
+#ifndef GCC_OPTINFO_EMIT_JSON_H
+#define GCC_OPTINFO_EMIT_JSON_H
+
+class optinfo;
+
+/* FIXME.  */
+
+extern void optimization_records_start ();
+extern void optimization_records_finish ();
+
+// FIXME: maybe make this inline?
+extern bool optimization_records_enabled_p ();
+
+extern void optimization_records_maybe_record_optinfo (const optinfo *);
+extern void optimization_records_maybe_pop_optinfo_scope ();
+
+
+#endif /* #ifndef GCC_OPTINFO_EMIT_JSON_H */
diff --git a/gcc/optinfo.cc b/gcc/optinfo.cc
index d39ad66..f6b51f3 100644
--- a/gcc/optinfo.cc
+++ b/gcc/optinfo.cc
@@ -22,35 +22,17 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 
-/* FIXME: trim these.  */
 #include "backend.h"
-#include "rtl.h"
 #include "tree.h"
 #include "gimple.h"
-#include "cfghooks.h"
-#include "cgraph.h"
-#include "coverage.h"
-#include "diagnostic-core.h"
-#include "cfganal.h"
-#include "value-prof.h"
 #include "gimple-iterator.h"
-#include "tree-cfg.h"
-#include "dumpfile.h"
-#include "cfgloop.h"
-
-#include "profile.h"
-#include "output.h"
-#include "tree-pass.h"
+#include "cfgloop.h" // for struct loop and loop_p, etc
+#include "tree-scalar-evolution.h" // for get_loop_exit_condition
 
 #include "optinfo.h"
-#include "optimization-records.h"
-#include "json.h"
-#include "tree-scalar-evolution.h"
-#include "pretty-print.h"
-#include "tree-pretty-print.h"
-#include "gimple-pretty-print.h"
-#include "diagnostic.h"
-#include "diagnostic-color.h"
+#include "optinfo-emit-diagnostics.h"
+#include "optinfo-emit-json.h"
+#include "optinfo-emit-fopt-info.h"
 
 /* Constructing an optinfo_location from a loop.  */
 
@@ -133,131 +115,7 @@ optinfo::emit () const
   emit_optinfo_as_diagnostic_remark (this);
 
   /* -fopt-info.  */
-  emit_via_fopt_info ();
-}
-
-/* FIXME.  */
-
-void
-emit_optinfo_as_diagnostic_remark (const optinfo *optinfo)
-{
-  pretty_printer pp;
-  pp_needs_newline (&pp) = true;
-  pp_translate_identifiers (&pp) = false;
-
-  bool show_color = pp_show_color (global_dc->printer);
-
-  /* Start with scope-based indentation.  */
-  for (unsigned i = get_optinfo_scope_depth (); i > 0; i--)
-    pp_space (&pp);
-
-  /* Print the items into PP.  */
-  for (unsigned i = 0; i < optinfo->num_items (); i++)
-    {
-      const optinfo_item *item = optinfo->get_item (i);
-      switch (item->get_kind ())
-	{
-	default:
-	  gcc_unreachable ();
-	case OPTINFO_ITEM_KIND_TEXT:
-	  {
-	    const optinfo_item_text *as_text
-	      = (const optinfo_item_text *)item;
-	    pp_string (&pp, as_text->get_text ());
-	  }
-	  break;
-	case OPTINFO_ITEM_KIND_TREE:
-	  {
-	    const optinfo_item_tree *as_tree
-	      = (const optinfo_item_tree *)item;
-	    pp_begin_quote (&pp, show_color);
-	    dump_generic_node (&pp, as_tree->get_node (), 0, TDF_DETAILS,
-			       false);
-	    pp_end_quote (&pp, show_color);
-	  }
-	  break;
-	case OPTINFO_ITEM_KIND_GIMPLE:
-	  {
-	    const optinfo_item_gimple *as_gimple
-	      = (const optinfo_item_gimple *)item;
-	    gimple *stmt = as_gimple->get_stmt ();
-	    pp_begin_quote (&pp, show_color);
-	    pp_gimple_stmt_1 (&pp, stmt, 0, TDF_SLIM);
-	    pp_end_quote (&pp, show_color);
-	  }
-	  break;
-	}
-    }
-
-  const char *msg = pp_formatted_text (&pp);
-
-  location_t loc = optinfo->get_location_t ();
-  if (current_pass)
-    remark (loc, 0, "%s [%spass=%s%s]",
-	    msg,
-	    colorize_start (show_color,
-			    diagnostic_get_color_for_kind (DK_REMARK)),
-	    current_pass->name,
-	    colorize_stop (show_color));
-  else
-    remark (loc, 0, "%s", msg);
-}
-
-/* FIXME.  */
-/* -fopt-info.  */
-
-void
-optinfo::emit_via_fopt_info () const
-{
-  dump_flags_t flags = 0;
-  switch (m_kind)
-    {
-    default:
-      gcc_unreachable ();
-    case OPTINFO_KIND_SUCCESS:
-      flags = MSG_OPTIMIZED_LOCATIONS;
-      break;
-    case OPTINFO_KIND_FAILURE:
-      flags = MSG_MISSED_OPTIMIZATION;
-      break;
-    case OPTINFO_KIND_NOTE:
-    case OPTINFO_KIND_SCOPE:
-      flags = MSG_NOTE;
-      break;
-    }
-
-  // FIXME: location!
-  dump_printf_loc (MSG_NOTE, UNKNOWN_LOCATION, "");
-  for (unsigned i = 0; i < num_items (); i++)
-    {
-      const optinfo_item *item = get_item (i);
-      switch (item->get_kind ())
-	{
-	default:
-	  gcc_unreachable ();
-	case OPTINFO_ITEM_KIND_TEXT:
-	  {
-	    const optinfo_item_text *text = (const optinfo_item_text *)item;
-	    dump_printf (flags, "%s", text->get_text ());
-	  }
-	  break;
-	case OPTINFO_ITEM_KIND_TREE:
-	  {
-	    const optinfo_item_tree *tree = (const optinfo_item_tree *)item;
-	    dump_generic_expr (flags, TDF_DETAILS, tree->get_node ());
-	  }
-	  break;
-	case OPTINFO_ITEM_KIND_GIMPLE:
-	  {
-	    const optinfo_item_gimple *as_gimple
-	      = (const optinfo_item_gimple *)item;
-	    gimple *stmt = as_gimple->get_stmt ();
-	    dump_gimple_stmt (flags, TDF_SLIM, stmt, 0);
-	  }
-	  break;
-	}
-    }
-  dump_printf (flags, "\n");
+  emit_optinfo_via_fopt_info (this);
 }
 
 /* pending_optinfo's ctor.  */
@@ -338,3 +196,10 @@ get_optinfo_scope_depth ()
 {
   return scope_depth;
 }
+
+/* FIXME.  */
+
+bool optinfo_enabled_p ()
+{
+  return dump_enabled_p () || optimization_records_enabled_p ();
+}
diff --git a/gcc/optinfo.h b/gcc/optinfo.h
index e5c2eda..ca0f0c7 100644
--- a/gcc/optinfo.h
+++ b/gcc/optinfo.h
@@ -388,8 +388,4 @@ class optinfo_scope
 #define OPTINFO_SCOPE(NAME, LOC) \
   optinfo_scope scope (NAME, LOC, (OPTINFO_IMPL_LOCATION))
 
-/* Implementation detail.  */
-
-extern void emit_optinfo_as_diagnostic_remark (const optinfo *);
-
 #endif /* #ifndef GCC_OPTINFO_H */
diff --git a/gcc/toplev.c b/gcc/toplev.c
index ceabc42..eb35b98 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -84,7 +84,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-pass.h"
 #include "dumpfile.h"
 #include "ipa-fnsummary.h"
-#include "optimization-records.h"
+#include "optinfo-emit-json.h"
 
 #if defined(DBX_DEBUGGING_INFO) || defined(XCOFF_DEBUGGING_INFO)
 #include "dbxout.h"
diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c
index ae33161..b25024ac 100644
--- a/gcc/tree-vect-loop.c
+++ b/gcc/tree-vect-loop.c
@@ -54,7 +54,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-vector-builder.h"
 #include "vec-perm-indices.h"
 #include "tree-eh.h"
-#include "optimization-records.h"
 #include "optinfo.h"
 
 /* Loop Vectorization Pass.
@@ -157,11 +156,6 @@ along with GCC; see the file COPYING3.  If not see
 
 static void vect_estimate_min_profitable_iters (loop_vec_info, int *, int *);
 
-bool optinfo_enabled_p ()
-{
-  return dump_enabled_p () || optimization_records_enabled_p ();
-}
-
 /* FIXME.  */
 
 pending_optinfo
diff --git a/gcc/tree-vect-slp.c b/gcc/tree-vect-slp.c
index c40f5d1..c502945 100644
--- a/gcc/tree-vect-slp.c
+++ b/gcc/tree-vect-slp.c
@@ -45,7 +45,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "vec-perm-indices.h"
 #include "gimple-fold.h"
 #include "internal-fn.h"
-#include "optimization-records.h"
+#include "optinfo.h"
 
 
 /* Recursively free the memory allocated for the SLP tree rooted at NODE.  */
diff --git a/gcc/tree-vectorizer.c b/gcc/tree-vectorizer.c
index 9464665..3e09a9b 100644
--- a/gcc/tree-vectorizer.c
+++ b/gcc/tree-vectorizer.c
@@ -78,7 +78,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-scalar-evolution.h"
 #include "stringpool.h"
 #include "attribs.h"
-#include "optimization-records.h"
+#include "optinfo.h"
 
 
 /* Loop or bb location.  */
diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h
index 9f4278a7..9854e23 100644
--- a/gcc/tree-vectorizer.h
+++ b/gcc/tree-vectorizer.h
@@ -24,7 +24,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-data-ref.h"
 #include "tree-hash-traits.h"
 #include "target.h"
-#include "optimization-records.h"
 #include "optinfo.h"
 
 /* Used for naming of new temporaries.  */
-- 
1.8.5.3

