From 45e333265b46d340a3a8070492e9d9acd97ed0ee Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Tue, 17 Jul 2018 10:49:15 -0400
Subject: [PATCH 56/56] FIXME: WIP on vect hints

---
 gcc/Makefile.in            |   1 +
 gcc/tree-vect-hints.cc     | 600 +++++++++++++++++++++++++++++++++++++++++++++
 gcc/tree-vect-loop-manip.c |   2 +
 gcc/tree-vectorizer.c      |   2 +
 gcc/tree-vectorizer.h      |   3 +
 5 files changed, 608 insertions(+)
 create mode 100644 gcc/tree-vect-hints.cc

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 50baddb..6a11d3c 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1581,6 +1581,7 @@ OBJS = \
 	tree-streamer-out.o \
 	tree-tailcall.o \
 	tree-vect-generic.o \
+	tree-vect-hints.o \
 	tree-vect-patterns.o \
 	tree-vect-data-refs.o \
 	tree-vect-stmts.o \
diff --git a/gcc/tree-vect-hints.cc b/gcc/tree-vect-hints.cc
new file mode 100644
index 0000000..b2b938d
--- /dev/null
+++ b/gcc/tree-vect-hints.cc
@@ -0,0 +1,600 @@
+/* Hints to the user about vectorization.
+   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 "predict.h"
+#include "tree-pass.h"
+#include "ssa.h"
+#include "cgraph.h"
+#include "fold-const.h"
+#include "stor-layout.h"
+#include "gimple-iterator.h"
+#include "gimple-walk.h"
+#include "tree-ssa-loop-manip.h"
+#include "tree-ssa-loop-niter.h"
+#include "tree-cfg.h"
+#include "cfgloop.h"
+#include "tree-vectorizer.h"
+#include "diagram.h"
+
+#include "diagnostic.h"
+#include "pretty-print.h"
+#include "gcc-rich-location.h"
+#include "edit-context.h"
+
+/* Classes for emitting hints to the user about how they might change their
+   code or their command-line flags to help GCC produce better code.
+
+   We want to be able to emit hints to stderr, or in machine-readable form
+   that can e.g. be exposed by an IDE, or turned into HTML reports.  */
+
+/* Forward decls; indentation shows inheritance.  */
+class opt_hint_node;
+  class opt_hint_compound;
+    class opt_hint_root;
+    class opt_hint_section;
+    class opt_hint_ol;
+  class opt_hint_para;
+  class opt_hint_gimple;
+  class opt_hint_location;
+  class opt_hint_diagram;
+
+/* FIXME.  */
+
+class opt_hint_node
+{
+public:
+  virtual ~opt_hint_node () {}
+
+  virtual void write_to_pp (pretty_printer *pp) const = 0;
+};
+
+class opt_hint_compound : public opt_hint_node
+{
+public:
+  opt_hint_compound () : m_children () {}
+  ~opt_hint_compound ();
+
+  void add_child (opt_hint_node *child);
+
+  void add_para (const char *text, ...);
+  void add_stmt (gimple *stmt);
+  void add_location (location_t loc);
+  void add_diagram (element *diagram);
+
+  void write_to_pp (pretty_printer *pp) const OVERRIDE;
+
+protected:
+  auto_vec<opt_hint_node *> m_children;
+};
+
+/* The top-level node within a user-facing hint.  */
+
+class opt_hint_root : public opt_hint_compound
+{
+public:
+  opt_hint_root (const char *hint_id);
+
+  opt_hint_section *add_problem ();
+  opt_hint_section *add_details ();
+  opt_hint_section *add_suggestion ();
+
+  /* An ID describing the hint, suitable for looking up further information
+     about the hint (e.g. "gcc.vect.unknown-iteration-count").  */
+
+  const char *get_hint_id () const { return m_hint_id; }
+
+  void emit () const;
+
+  void write_to_pp (pretty_printer *pp) const OVERRIDE;
+
+private:
+  const char *m_hint_id;
+};
+
+/* FIXME.  */
+
+enum opt_hint_section_kind
+{
+  SK_PROBLEM,
+  SK_DETAILS,
+  SK_SUGGESTION
+};
+
+class opt_hint_section : public opt_hint_compound
+{
+public:
+  opt_hint_section (enum opt_hint_section_kind kind)
+  : m_kind (kind)
+  {
+  }
+
+  void write_to_pp (pretty_printer *pp) const OVERRIDE;
+
+private:
+  enum opt_hint_section_kind m_kind;
+  auto_vec<gimple *> m_stmts;
+};
+
+class opt_hint_ol  : public opt_hint_compound
+{
+public:
+  void write_to_pp (pretty_printer *pp) const OVERRIDE;
+};
+
+class opt_hint_para : public opt_hint_node
+{
+public:
+  opt_hint_para (const char *text) : m_text (xstrdup (text))
+  {}
+  ~opt_hint_para () { free (m_text); }
+
+  void write_to_pp (pretty_printer *pp) const OVERRIDE;
+
+private:
+  char *m_text; // FIXME: i18n?
+};
+
+class opt_hint_gimple : public opt_hint_node
+{
+public:
+  opt_hint_gimple (gimple *stmt) : m_stmt (stmt)
+  {
+  }
+
+  void write_to_pp (pretty_printer *pp) const OVERRIDE;
+
+private:
+  gimple *m_stmt; // FIXME: interaction with GC?
+};
+
+class opt_hint_location : public opt_hint_node
+{
+public:
+  opt_hint_location (location_t loc) : m_loc (loc)
+  {
+  }
+
+  void write_to_pp (pretty_printer *pp) const OVERRIDE;
+
+private:
+  location_t m_loc;
+};
+
+class opt_hint_diagram : public opt_hint_node
+{
+public:
+  opt_hint_diagram (element *diagram) : m_diagram (diagram)
+  {
+  }
+  ~opt_hint_diagram ();
+
+  void write_to_pp (pretty_printer *pp) const OVERRIDE;
+
+private:
+  element *m_diagram;
+};
+
+/* FIXME.  */
+
+opt_hint_compound::~opt_hint_compound ()
+{
+  unsigned i;
+  opt_hint_node *child;
+  FOR_EACH_VEC_ELT (m_children, i, child)
+    delete child;
+}
+
+void
+opt_hint_compound::add_child (opt_hint_node *child)
+{
+  m_children.safe_push (child);
+}
+
+void
+opt_hint_compound::add_para (const char *fmt, ...)
+{
+  pretty_printer pp;
+
+  // FIXME: something of a hack:
+  pp_show_color (&pp) = pp_show_color (global_dc->printer);
+
+  text_info ti;
+  va_list ap;
+  va_start (ap, fmt);
+  ti.format_spec = fmt;
+  ti.args_ptr = &ap;
+  ti.err_no = 0;
+  ti.x_data = NULL;
+  ti.m_richloc = NULL;
+  pp_format (&pp, &ti);
+  pp_output_formatted_text (&pp);
+  va_end (ap);
+  add_child (new opt_hint_para (pp_formatted_text (&pp)));
+}
+
+void
+opt_hint_compound::add_stmt (gimple *stmt)
+{
+  add_child (new opt_hint_gimple (stmt));
+}
+
+void
+opt_hint_compound::add_location (location_t loc)
+{
+  add_child (new opt_hint_location (loc));
+}
+
+void
+opt_hint_compound::add_diagram (element *diagram)
+{
+  add_child (new opt_hint_diagram (diagram));
+}
+
+void
+opt_hint_compound::write_to_pp (pretty_printer *pp) const
+{
+  unsigned i;
+  opt_hint_node *child;
+  FOR_EACH_VEC_ELT (m_children, i, child)
+    child->write_to_pp (pp);
+}
+
+/* FIXME.  */
+
+opt_hint_root::opt_hint_root (const char *hint_id) : m_hint_id (hint_id)
+{
+}
+
+/* FIXME.  */
+
+opt_hint_section *
+opt_hint_root::add_problem ()
+{
+  opt_hint_section *section = new opt_hint_section (SK_PROBLEM);
+  add_child (section);
+  return section;
+}
+
+/* FIXME.  */
+
+opt_hint_section *
+opt_hint_root::add_details ()
+{
+  opt_hint_section *section = new opt_hint_section (SK_DETAILS);
+  add_child (section);
+  return section;
+}
+
+/* FIXME.  */
+
+opt_hint_section *
+opt_hint_root::add_suggestion ()
+{
+  opt_hint_section *section = new opt_hint_section (SK_SUGGESTION);
+  add_child (section);
+  return section;
+}
+
+/* FIXME.  */
+
+void
+opt_hint_root::emit () const
+{
+  pretty_printer pp;
+  pp_show_color (&pp) = pp_show_color (global_dc->printer);
+  write_to_pp (&pp);
+  pp_flush (&pp);
+}
+
+/* FIXME.  */
+
+void
+opt_hint_root::write_to_pp (pretty_printer *pp) const
+{
+  pp_printf (pp, "--[%r%s%R]--\n", "note", m_hint_id);
+  opt_hint_compound::write_to_pp (pp);
+  pp_newline (pp);
+}
+
+/* FIXME.  */
+
+const char *
+section_kind_as_string (enum opt_hint_section_kind kind)
+{
+  switch (kind)
+    {
+    default:
+      gcc_unreachable ();
+    case SK_PROBLEM: return "Problem";
+    case SK_DETAILS: return "Details";
+    case SK_SUGGESTION: return "Suggestion";
+  }
+}
+
+/* FIXME.  */
+
+void
+opt_hint_section::write_to_pp (pretty_printer *pp) const
+{
+  pp_printf (pp, "%r%s: %R\n", "note",
+	     section_kind_as_string (m_kind));
+  pp_indentation (pp) += 3;
+  opt_hint_compound::write_to_pp (pp);
+  pp_indentation (pp) -= 3;
+}
+
+void
+opt_hint_ol::write_to_pp (pretty_printer *pp) const
+{
+  unsigned i;
+  opt_hint_node *child;
+  FOR_EACH_VEC_ELT (m_children, i, child)
+    {
+      pp_printf (pp, "(%i) ", i + 1);
+      pp_indentation (pp) += 3;
+      child->write_to_pp (pp);
+      pp_indentation (pp) -= 3;
+    }
+}
+
+/* FIXME.  */
+
+void
+opt_hint_para::write_to_pp (pretty_printer *pp) const
+{
+  pp_printf (pp, "%s\n", m_text);
+}
+
+/* FIXME.  */
+
+static bool
+write_location_to_pp (pretty_printer *pp, location_t loc)
+{
+  if (loc == UNKNOWN_LOCATION)
+    return false;
+
+  // FIXME: also describe the source location
+  diagnostic_context dc;
+  diagnostic_initialize (&dc, 0);
+  dc.show_caret = true;
+  dc.printer = pp;
+  rich_location richloc (line_table, loc);
+  diagnostic_show_locus (&dc, &richloc, DK_ERROR);
+
+  return true;
+}
+
+/* FIXME.  */
+
+void
+opt_hint_gimple::write_to_pp (pretty_printer *pp) const
+{
+  location_t loc = gimple_location (m_stmt);
+  if (loc != UNKNOWN_LOCATION)
+    write_location_to_pp (pp, loc);
+  else
+    {
+      // FIXME: maybe print the statement?
+    }
+}
+
+/* FIXME.  */
+
+void
+opt_hint_location::write_to_pp (pretty_printer *pp) const
+{
+  write_location_to_pp (pp, m_loc);
+}
+
+/* FIXME.  */
+
+opt_hint_diagram::~opt_hint_diagram ()
+{
+  delete m_diagram;
+}
+
+/* FIXME.  */
+
+void
+opt_hint_diagram::write_to_pp (pretty_printer *pp) const
+{
+  m_diagram->print_to_pp (pp);
+}
+
+/* FIXME.  */
+
+static element *
+make_diagram (loop_vec_info loop_vinfo)
+{
+  // FIXME: conditionalize the diagram, based on presence of run-time tests
+  // and with prologue/epilogue
+  // FIXME: show iteration counts, comparing the scalar vs vectorized (e.g. N vs N/4)
+  // FIXME: show costs
+  grid_layout *grid = new grid_layout (3, 4);
+  grid->set_child (1, 0, wiring_element::make_vert ());
+  grid->set_child (0, 1, wiring_element::make_se ());
+  grid->set_child (1, 1, new box_element (new text_element ("run-time tests")));
+  grid->set_child (2, 1, wiring_element::make_sw ());
+  grid->set_child (0, 2, new box_element (new text_element ("scalar loop")));
+  grid->set_child (2, 2, new box_element (new text_element ("vectorized loop")));
+  grid->set_child (0, 3, wiring_element::make_ne ());
+  grid->set_child (1, 3, wiring_element::make_sew ());
+  grid->set_child (2, 3, wiring_element::make_nw ());
+  return grid;
+}
+
+static void
+maybe_add_restrict_fixit_hint (hash_set<tree> *vars, tree base_object)
+{
+  if (TREE_CODE (base_object) != MEM_REF)
+    return;
+  tree reffed = TREE_OPERAND (base_object, 0);
+  if (TREE_CODE (reffed) != SSA_NAME)
+    return;
+  tree var = SSA_NAME_VAR (reffed);
+  if (var == NULL_TREE)
+    return;
+  if (TREE_CODE (var) != PARM_DECL)
+    return;
+  vars->add (var);
+}
+
+/* FIXME.  */
+
+void
+emit_vect_loop_hints (loop_vec_info loop_vinfo)
+{
+  /* More details about vectorization, and how the user could help things
+     be faster.
+     Ideas:
+     "Problem: I don't know how many iterations the loop will have.  I
+      predict that vectorization will help when N > $something, but if
+      the loop is consistently shorter than that, vectorization may
+      simply bloat the binary.
+      Suggestion: use PGO."
+
+     "Problem: I couldn't prove that these data accesses were aligned to a
+      ALIGNMENT-byte boundary, so I had to add a run-time test, falling back
+      to a scalar loop.
+      Details:
+         statements in question
+      Suggestion: FIXME."
+
+      "Problem: I couldn't prove that these array accesses don't alias, so
+       I had to add a run-time test, falling back to a scalar loop.
+       Details:
+         statements in question
+
+       Suggestion: FIXME."
+  */
+
+  /* Emit a summary of information about the loop.  */
+  {
+    opt_hint_root hint ("gcc.vect.success");
+    hint.add_para ("I was able to vectorize this loop.");
+    hint.add_location (vect_location.get_location_t ());
+    hint.add_diagram (make_diagram (loop_vinfo));
+    hint.emit ();
+  }
+
+#if 0
+  {
+    unsigned i;
+    gimple *stmt;
+    FOR_EACH_VEC_ELT (LOOP_VINFO_MAY_MISALIGN_STMTS (loop_vinfo), i, stmt)
+      {
+	opt_report report;
+	report.remark (stmt, "this statement implies a runtime check for alignment");
+      }
+  }
+#endif
+
+  /* Issue a hint about aliasing.  */
+  if (LOOP_REQUIRES_VERSIONING_FOR_ALIAS (loop_vinfo))
+    {
+      opt_hint_root hint ("gcc.vect.loop-requires-versioning-for-alias");
+      opt_hint_section *problem = hint.add_problem ();
+      problem->add_para ("I couldn't prove that these data references"
+			 " don't alias, so I had to add a run-time test,"
+			 " falling back to a scalar loop for when they"
+			 " do.");
+
+      /* Details.  */
+      {
+	opt_hint_section *details = hint.add_details ();
+	unsigned i;
+	dr_with_seg_len_pair_t *dr_pair;
+	opt_hint_ol *ol = new opt_hint_ol ();
+	details->add_child (ol);
+	FOR_EACH_VEC_ELT (loop_vinfo->comp_alias_ddrs, i, dr_pair)
+	  {
+	    opt_hint_compound *li = new opt_hint_compound ();
+	    ol->add_child (li);
+	    li->add_para ("This read/write pair could alias:");
+#if 1
+	    // FIXME: it would need to be able to add a rich_location,
+	    // with both locations; but can we copy them?
+	    li->add_location (EXPR_LOCATION (dr_pair->first.dr->indices.base_object));
+	    li->add_location (EXPR_LOCATION (dr_pair->second.dr->indices.base_object));
+#else
+	    li->add_stmt (dr_pair->first.dr->stmt);
+	    li->add_stmt (dr_pair->second.dr->stmt);
+#endif
+	  }
+      }
+
+      /* Suggestions.  */
+      {
+	opt_hint_section *suggestion = hint.add_suggestion ();
+	suggestion->add_para ("If you know that the buffers cannot overlap in"
+			      " memory, marking them with %qs will"
+			      " allow me to assume it when optimizing this"
+			      " loop, and eliminate the run-time test.",
+			      "restrict");
+	hash_set<tree> vars;
+	unsigned i;
+	dr_with_seg_len_pair_t *dr_pair;
+	FOR_EACH_VEC_ELT (loop_vinfo->comp_alias_ddrs, i, dr_pair)
+	  {
+	    maybe_add_restrict_fixit_hint (&vars,
+					   dr_pair->first.dr->indices.base_object);
+	    maybe_add_restrict_fixit_hint (&vars,
+					   dr_pair->second.dr->indices.base_object);
+	  }
+	gcc_rich_location rich_loc (vect_location.get_location_t ());
+	for (hash_set<tree>::iterator it = vars.begin ();
+	     it != vars.end (); ++it)
+	  {
+	    suggestion->add_location (DECL_SOURCE_LOCATION (*it));
+
+	    // FIXME: turn this into an actual fix-it hint
+	    rich_loc.add_fixit_insert_before
+	      (get_pure_location (DECL_SOURCE_LOCATION (*it)),
+	       " restrict ");
+	  }
+	inform (&rich_loc, "FIXME"); // add this to the suggestion
+
+	{
+	  pretty_printer pp;
+	  // FIXME: something of a hack:
+	  pp_show_color (&pp) = pp_show_color (global_dc->printer);
+	  edit_context ec;
+	  ec.add_fixits (&rich_loc);
+	  ec.print_diff (&pp, true);
+	  suggestion->add_para ("%s", pp_formatted_text (&pp));
+	}
+      }
+
+      hint.emit ();
+    }
+#if 0
+      // FIXME: in my example, it's comp_alias_ddrs
+#define LOOP_REQUIRES_VERSIONING_FOR_ALIAS(L)		\
+  ((L)->comp_alias_ddrs.length () > 0 \
+   || (L)->check_unequal_addrs.length () > 0 \
+   || (L)->lower_bounds.length () > 0)
+#endif
+}
diff --git a/gcc/tree-vect-loop-manip.c b/gcc/tree-vect-loop-manip.c
index 01d1850..ca64e7d 100644
--- a/gcc/tree-vect-loop-manip.c
+++ b/gcc/tree-vect-loop-manip.c
@@ -3010,6 +3010,7 @@ vect_loop_versioning (loop_vec_info loop_vinfo,
   if (version_align)
     vect_create_cond_for_align_checks (loop_vinfo, &cond_expr,
 				       &cond_expr_stmt_list);
+  // FIXME: "I had to create a run-time check for alignment"
 
   if (version_alias)
     {
@@ -3017,6 +3018,7 @@ vect_loop_versioning (loop_vec_info loop_vinfo,
       vect_create_cond_for_lower_bounds (loop_vinfo, &cond_expr);
       vect_create_cond_for_alias_checks (loop_vinfo, &cond_expr);
     }
+  // FIXME: "I had to create a run-time check for aliasing"
 
   cond_expr = force_gimple_operand_1 (unshare_expr (cond_expr),
 				      &gimplify_stmt_list,
diff --git a/gcc/tree-vectorizer.c b/gcc/tree-vectorizer.c
index 932bfd1..fe62929 100644
--- a/gcc/tree-vectorizer.c
+++ b/gcc/tree-vectorizer.c
@@ -965,6 +965,8 @@ try_vectorize_loop_1 (hash_table<simduid_to_vf> *&simduid_to_vf_htab,
 		     "loop vectorized using variable length vectors");
     }
 
+  emit_vect_loop_hints (loop_vinfo);
+
   loop_p new_loop = vect_transform_loop (loop_vinfo);
   (*num_vectorized_loops)++;
   /* Now that the loop has been vectorized, allow it to be unrolled
diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h
index d81e476..97f280b 100644
--- a/gcc/tree-vectorizer.h
+++ b/gcc/tree-vectorizer.h
@@ -1674,4 +1674,7 @@ unsigned vectorize_loops (void);
 bool vect_stmt_in_region_p (vec_info *, gimple *);
 void vect_free_loop_info_assumptions (struct loop *);
 
+/* In tree-vect-hints.cc.  */
+extern void emit_vect_loop_hints (loop_vec_info loop_vinfo);
+
 #endif  /* GCC_TREE_VECTORIZER_H  */
-- 
1.8.5.3

