From 04d0c1661577950866e2ae4942369a00e32bc485 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Fri, 22 Jun 2018 16:03:29 -0400
Subject: [PATCH 35/58] [RFC] Higher-level reporting of vectorization problems
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

NightStrike and I were chatting on IRC last week about
issues with trying to vectorize the following code:

std::size_t f(std::vector<std::vector<float>> const & v) {
	std::size_t ret = 0;
	for (auto const & w: v)
		ret += w.size();
	return ret;
}

icc could vectorize it, but gcc couldn't, but neither of us could
immediately figure out what the problem was.

Using -fopt-info leads to a wall of text.

I tried using my patch here:

 "[PATCH] v3 of optinfo, remarks and optimization records"
  https://gcc.gnu.org/ml/gcc-patches/2018-06/msg01267.html

It improved things somewhat, by showing:
(a) the nesting structure via indentation, and
(b) the GCC line at which each message is emitted (by using the
    "remark" output)

but it's still a wall of text:

  https://dmalcolm.fedorapeople.org/gcc/2018-06-18/test.cc.remarks.html
  https://dmalcolm.fedorapeople.org/gcc/2018-06-18/test.cc.d/..%7C..%7Csrc%7Ctest.cc.html#line-4

It doesn't yet provide a simple high-level message to a
tech-savvy user on what they need to do to get GCC to
vectorize their loop.

The pertinent dump messages are:

test.cc:4:23: remark: === try_vectorize_loop_1 === [../../src/gcc/tree-vectorizer.c:674:try_vectorize_loop_1]
cc1plus: remark:
Analyzing loop at test.cc:4 [../../src/gcc/dumpfile.c:735:ensure_pending_optinfo]
test.cc:4:23: remark:  === analyze_loop_nest === [../../src/gcc/tree-vect-loop.c:2299:vect_analyze_loop]
[...snip...]
test.cc:4:23: remark:   === vect_analyze_loop_operations === [../../src/gcc/tree-vect-loop.c:1520:vect_analyze_loop_operations]
[...snip...]
test.cc:4:23: remark:    ==> examining statement: ‘_15 = _14 /[ex] 4;’ [../../src/gcc/tree-vect-stmts.c:9382:vect_analyze_stmt]
test.cc:4:23: remark:    vect_is_simple_use: operand ‘_14’ [../../src/gcc/tree-vect-stmts.c:10064:vect_is_simple_use]
test.cc:4:23: remark:    def_stmt: ‘_14 = _8 - _7;’ [../../src/gcc/tree-vect-stmts.c:10098:vect_is_simple_use]
test.cc:4:23: remark:    type of def: internal [../../src/gcc/tree-vect-stmts.c:10112:vect_is_simple_use]
test.cc:4:23: remark:    vect_is_simple_use: operand ‘4’ [../../src/gcc/tree-vect-stmts.c:10064:vect_is_simple_use]
test.cc:4:23: remark:    op not supported by target. [../../src/gcc/tree-vect-stmts.c:5932:vectorizable_operation]
test.cc:4:23: remark:    not vectorized: relevant stmt not supported: ‘_15 = _14 /[ex] 4;’ [../../src/gcc/tree-vect-stmts.c:9565:vect_analyze_stmt]
test.cc:4:23: remark:   bad operation or unsupported loop bound. [../../src/gcc/tree-vect-loop.c:2043:vect_analyze_loop_2]
cc1plus: remark: vectorized 0 loops in function. [../../src/gcc/tree-vectorizer.c:904:vectorize_loops]

In particular, that complaint from
  [../../src/gcc/tree-vect-stmts.c:9565:vect_analyze_stmt]
is coming from:

  if (!ok)
    {
      if (dump_enabled_p ())
        {
          dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
                           "not vectorized: relevant stmt not ");
          dump_printf (MSG_MISSED_OPTIMIZATION, "supported: ");
          dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM, stmt, 0);
        }

      return false;
    }

This got me thinking: the user presumably wants to know several
things:

* the location of the loop that can't be vectorized (vect_location
  captures this)
* location of the problematic statement
* why it's problematic
* the problematic statement itself.

The following is an experiment at capturing that information, by
recording an "opt_problem" instance describing what the optimization
problem is, created deep in the callstack when it occurs, for use
later on back at the top of the vectorization callstack.

This extra work is only done if dump_enabled_p.

It feels vaguely analogous to an exception object (in terms of
packaging up a problem that occurs deep in the stack for reporting
back at a higher level).

With this patch, we emit:

../../src/test.cc: In function ‘std::size_t f(const std::vector<std::vector<float> >&)’:
../../src/test.cc:4:23: remark: couldn't vectorize loop
  for (auto const & w: v)
                       ^
In file included from ../x86_64-pc-linux-gnu/libstdc++-v3/include/vector:64,
                 from ../../src/test.cc:1:
../x86_64-pc-linux-gnu/libstdc++-v3/include/bits/stl_vector.h:806:50:
note: relevant stmt not supported: ‘_15 = _14 /[ex] 4;’
       { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); }
                          ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~

which reports both the location of the loop and the statement that's
problematic (if I'm reading it right, the pointer arithmetic leads to a
division by 4, and presumably we're not able to handle that).

(not bootstrapped or anything, just experimenting at this stage)

Thoughts?

gcc/ChangeLog:
	* Makefile.in (OBJS): Add opt-problem.o.
	* opt-problem.cc: New file.
	* opt-problem.h: New file.
	* tree-vect-stmts.c (vect_analyze_stmt): Replace "not vectorized"
	dumps with calls to push_vect_problem.
	* tree-vectorizer.c: Include "diagnostic-core.h" and
	"opt-problem.h".
	(try_vectorize_loop_1): If the_vect_problem has been set by
	vect_analyze_loop, issue a "couldn't vectorize loop" remark and
	the reason, clearing it.
	(the_vect_problem): New global.
	(push_vect_problem): New function.
	* tree-vectorizer.h (the_vect_problem): New decl.
	(push_vect_problem): New decl.
---
 gcc/Makefile.in       |  1 +
 gcc/opt-problem.cc    | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
 gcc/opt-problem.h     | 45 +++++++++++++++++++++++++++++++++++++++++++++
 gcc/tree-vect-stmts.c | 16 ++--------------
 gcc/tree-vectorizer.c | 33 +++++++++++++++++++++++++++++++++
 gcc/tree-vectorizer.h |  7 +++++++
 6 files changed, 137 insertions(+), 14 deletions(-)
 create mode 100644 gcc/opt-problem.cc
 create mode 100644 gcc/opt-problem.h

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index c5c3d3c..fb262da 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1425,6 +1425,7 @@ OBJS = \
 	omp-grid.o \
 	omp-low.o \
 	omp-simd-clone.o \
+	opt-problem.o \
 	optabs.o \
 	optabs-libfuncs.o \
 	optabs-query.o \
diff --git a/gcc/opt-problem.cc b/gcc/opt-problem.cc
new file mode 100644
index 0000000..78d5200
--- /dev/null
+++ b/gcc/opt-problem.cc
@@ -0,0 +1,49 @@
+/* Rich information on why an optimization wasn't possible.
+   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 "diagnostic.h"
+#include "tree.h"
+#include "gimple.h"
+#include "pretty-print.h"
+#include "gimple-pretty-print.h"
+#include "opt-problem.h"
+
+/* Emit a diagnostic note describing why an optimization wasn't possible.  */
+
+void
+opt_problem::report_reason ()
+{
+  bool show_color = pp_show_color (global_dc->printer);
+
+  pretty_printer pp;
+  pp_string (&pp, m_text);
+  pp_string (&pp, ": ");
+  pp_begin_quote (&pp, show_color);
+  pp_gimple_stmt_1 (&pp, m_stmt, 0, TDF_SLIM);
+  pp_end_quote (&pp, show_color);
+
+  const char *msg = pp_formatted_text (&pp);
+
+  inform (gimple_location_safe (m_stmt), "%s", msg);
+}
diff --git a/gcc/opt-problem.h b/gcc/opt-problem.h
new file mode 100644
index 0000000..406f348
--- /dev/null
+++ b/gcc/opt-problem.h
@@ -0,0 +1,45 @@
+/* Rich information on why an optimization wasn't possible.
+   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_OPT_PROBLEM_H
+#define GCC_OPT_PROBLEM_H
+
+/* When -fopt-info is enabled: information about why an optimization
+   failed (e.g. vectorization).  */
+
+class GTY(()) opt_problem
+{
+ public:
+  opt_problem (const char *text, gimple *stmt)
+  : m_text (text), m_stmt (stmt)
+  {
+    /* We shouldn't be bothering to construct these objects if
+       dumping isn't enabled.  */
+    gcc_assert (dump_enabled_p ());
+  }
+
+  void report_reason ();
+
+ private:
+  const char *m_text;
+  gimple *m_stmt;
+};
+
+#endif /* #ifndef GCC_OPT_PROBLEM_H */
diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c
index ea303bd..f7b59cb 100644
--- a/gcc/tree-vect-stmts.c
+++ b/gcc/tree-vect-stmts.c
@@ -9528,14 +9528,7 @@ vect_analyze_stmt (gimple *stmt, bool *need_to_vectorize, slp_tree node,
 
   if (!ok)
     {
-      if (dump_enabled_p ())
-        {
-          dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-                           "not vectorized: relevant stmt not ");
-          dump_printf (MSG_MISSED_OPTIMIZATION, "supported: ");
-          dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM, stmt, 0);
-        }
-
+      push_vect_problem ("relevant stmt not supported", stmt);
       return false;
     }
 
@@ -9545,12 +9538,7 @@ vect_analyze_stmt (gimple *stmt, bool *need_to_vectorize, slp_tree node,
       && STMT_VINFO_TYPE (stmt_info) != reduc_vec_info_type
       && !can_vectorize_live_stmts (stmt, NULL, node, NULL, cost_vec))
     {
-      if (dump_enabled_p ())
-        {
-          dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-                           "not vectorized: live stmt not supported: ");
-          dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM, stmt, 0);
-        }
+      push_vect_problem ("live stmt not supported", stmt);
 
        return false;
     }
diff --git a/gcc/tree-vectorizer.c b/gcc/tree-vectorizer.c
index 8d54fbb..9031374 100644
--- a/gcc/tree-vectorizer.c
+++ b/gcc/tree-vectorizer.c
@@ -79,6 +79,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "stringpool.h"
 #include "attribs.h"
 #include "gimple-pretty-print.h"
+#include "diagnostic-core.h"
+#include "opt-problem.h"
 
 
 /* Loop or bb location, with hotness information.  */
@@ -708,6 +710,15 @@ try_vectorize_loop_1 (hash_table<simduid_to_vf> *&simduid_to_vf_htab,
   loop_vec_info loop_vinfo = vect_analyze_loop (loop, orig_loop_vinfo, &shared);
   loop->aux = loop_vinfo;
 
+  if (the_vect_problem)
+    {
+      if (remark (vect_location.get_location_t (), 0,
+		  "couldn't vectorize loop"))
+	the_vect_problem->report_reason ();
+      delete the_vect_problem;
+      the_vect_problem = NULL;
+    }
+
   if (!loop_vinfo || !LOOP_VINFO_VECTORIZABLE_P (loop_vinfo))
     {
       /* Free existing information if loop is analyzed with some
@@ -1320,3 +1331,25 @@ make_pass_ipa_increase_alignment (gcc::context *ctxt)
 {
   return new pass_ipa_increase_alignment (ctxt);
 }
+
+/* Singleton instance.  */
+
+opt_problem *the_vect_problem;
+
+/* If dumps are enabled emit a "not vectorized" message with the given
+   text relating to STMT, and record a opt_problem instance for later
+   use.  */
+// FIXME: maybe a stack of these?  or not
+
+void
+push_vect_problem (const char *text, gimple *stmt)
+{
+  if (!dump_enabled_p ())
+    return;
+
+  the_vect_problem = new opt_problem (text, stmt);
+
+  dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+		   "not vectorized: %s", text);
+  dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM, stmt, 0);
+}
diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h
index 28be41f..0d4cb18 100644
--- a/gcc/tree-vectorizer.h
+++ b/gcc/tree-vectorizer.h
@@ -1665,4 +1665,11 @@ unsigned vectorize_loops (void);
 bool vect_stmt_in_region_p (vec_info *, gimple *);
 void vect_free_loop_info_assumptions (struct loop *);
 
+/* Singleton instance.  */
+class opt_problem;
+extern opt_problem *the_vect_problem;
+
+extern void push_vect_problem (const char *text, gimple *stmt);
+
+
 #endif  /* GCC_TREE_VECTORIZER_H  */
-- 
1.8.5.3

