public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] [RFC] Higher-level reporting of vectorization problems
@ 2018-06-22 20:26 David Malcolm
  2018-06-25  9:15 ` Richard Biener
  0 siblings, 1 reply; 24+ messages in thread
From: David Malcolm @ 2018-06-22 20:26 UTC (permalink / raw)
  To: gcc-patches, Richard Biener, Richard Sandiford; +Cc: David Malcolm

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

#include <vector>
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 68e79a6..8df859c 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1425,6 +1425,7 @@ OBJS = \
 	optinfo.o \
 	optinfo-emit-diagnostics.o \
 	optinfo-emit-json.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 1181bc9..d9727eb 100644
--- a/gcc/tree-vect-stmts.c
+++ b/gcc/tree-vect-stmts.c
@@ -9559,14 +9559,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;
     }
 
@@ -9576,12 +9569,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 c33f355..2127f2e 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.  */
@@ -682,6 +684,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);
   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
@@ -1294,3 +1305,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 23c05cd..60fca1b 100644
--- a/gcc/tree-vectorizer.h
+++ b/gcc/tree-vectorizer.h
@@ -1638,4 +1638,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

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] [RFC] Higher-level reporting of vectorization problems
  2018-06-22 20:26 [PATCH] [RFC] Higher-level reporting of vectorization problems David Malcolm
@ 2018-06-25  9:15 ` Richard Biener
  2018-07-02 16:35   ` Richard Sandiford
  2018-07-10  0:27   ` [PATCH 0/5] [RFC v2] " David Malcolm
  0 siblings, 2 replies; 24+ messages in thread
From: Richard Biener @ 2018-06-25  9:15 UTC (permalink / raw)
  To: David Malcolm; +Cc: gcc-patches, Richard Sandiford

[-- Attachment #1: Type: text/plain, Size: 16389 bytes --]

On Fri, 22 Jun 2018, David Malcolm wrote:

> NightStrike and I were chatting on IRC last week about
> issues with trying to vectorize the following code:
> 
> #include <vector>
> 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.

Yeah, in particular the vectorizer is way too noisy in its low-level
functions.  IIRC -fopt-info-vec-missed is "somewhat" better:

t.C:4:26: note: step unknown.
t.C:4:26: note: vector alignment may not be reachable
t.C:4:26: note: not ssa-name.
t.C:4:26: note: use not simple.
t.C:4:26: note: not ssa-name.
t.C:4:26: note: use not simple.
t.C:4:26: note: no array mode for V2DI[3]
t.C:4:26: note: Data access with gaps requires scalar epilogue loop
t.C:4:26: note: can't use a fully-masked loop because the target doesn't 
have the appropriate masked load or store.
t.C:4:26: note: not ssa-name.
t.C:4:26: note: use not simple.
t.C:4:26: note: not ssa-name.
t.C:4:26: note: use not simple.
t.C:4:26: note: no array mode for V2DI[3]
t.C:4:26: note: Data access with gaps requires scalar epilogue loop
t.C:4:26: note: op not supported by target.
t.C:4:26: note: not vectorized: relevant stmt not supported: _15 = _14 
/[ex] 4;
t.C:4:26: note: bad operation or unsupported loop bound.
t.C:4:26: note: not vectorized: no grouped stores in basic block.
t.C:4:26: note: not vectorized: no grouped stores in basic block.
t.C:6:12: note: not vectorized: not enough data-refs in basic block.


> 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.

Nice idea.  Of course the issue is then for which issues to
exactly create those.  Like all of the MSG_MISSED_OPTIMIZATION
dumpings?

I guess the vectorizer needs some axing of useless messages
and/or we need a MSG_DEBUG to have an additional level below
MSG_NOTE.

> 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).

Quite likely because we only handle TRUNC_DIV_EXPR and not EXACT_DIV_EXPR
which we can handle the same semantically (EXACT_DIV_EXPR just gives
us stronger guarantees).

diff --git a/gcc/tree-vect-patterns.c b/gcc/tree-vect-patterns.c
index 9654bd7818a..0ab977adf33 100644
--- a/gcc/tree-vect-patterns.c
+++ b/gcc/tree-vect-patterns.c
@@ -2524,6 +2524,7 @@ vect_recog_divmod_pattern (vec<gimple *> *stmts, 
tree *type_out)
   switch (rhs_code)
     {
     case TRUNC_DIV_EXPR:
+    case EXACT_DIV_EXPR:
     case TRUNC_MOD_EXPR:
       break;
     default:
@@ -2573,7 +2574,8 @@ vect_recog_divmod_pattern (vec<gimple *> *stmts, 
tree *type_out)
 
       cond = build2 (LT_EXPR, boolean_type_node, oprnd0,
                     build_int_cst (itype, 0));
-      if (rhs_code == TRUNC_DIV_EXPR)
+      if (rhs_code == TRUNC_DIV_EXPR
+         || rhs_code == EXACT_DIV_EXPR)
        {
          tree var = vect_recog_temp_ssa_var (itype, NULL);
          tree shift;

gets us to

t.C:4:26: note: not vectorized: relevant stmt not supported: patt_25 = _14 
< 0 ? 3 : 0;

or with -mavx2

t.C:4:26: note: not vectorized: relevant stmt not supported: patt_18 = 
patt_19 >> 2;

Richard.

> (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 68e79a6..8df859c 100644
> --- a/gcc/Makefile.in
> +++ b/gcc/Makefile.in
> @@ -1425,6 +1425,7 @@ OBJS = \
>  	optinfo.o \
>  	optinfo-emit-diagnostics.o \
>  	optinfo-emit-json.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 1181bc9..d9727eb 100644
> --- a/gcc/tree-vect-stmts.c
> +++ b/gcc/tree-vect-stmts.c
> @@ -9559,14 +9559,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;
>      }
>  
> @@ -9576,12 +9569,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 c33f355..2127f2e 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.  */
> @@ -682,6 +684,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);
>    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
> @@ -1294,3 +1305,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 23c05cd..60fca1b 100644
> --- a/gcc/tree-vectorizer.h
> +++ b/gcc/tree-vectorizer.h
> @@ -1638,4 +1638,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  */
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nuernberg)

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] [RFC] Higher-level reporting of vectorization problems
  2018-06-25  9:15 ` Richard Biener
@ 2018-07-02 16:35   ` Richard Sandiford
  2018-07-03  7:14     ` Richard Biener
  2018-07-10  0:27   ` [PATCH 0/5] [RFC v2] " David Malcolm
  1 sibling, 1 reply; 24+ messages in thread
From: Richard Sandiford @ 2018-07-02 16:35 UTC (permalink / raw)
  To: Richard Biener; +Cc: David Malcolm, gcc-patches

Richard Biener <rguenther@suse.de> writes:
> On Fri, 22 Jun 2018, David Malcolm wrote:
>
>> NightStrike and I were chatting on IRC last week about
>> issues with trying to vectorize the following code:
>> 
>> #include <vector>
>> 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.
>
> Yeah, in particular the vectorizer is way too noisy in its low-level
> functions.  IIRC -fopt-info-vec-missed is "somewhat" better:
>
> t.C:4:26: note: step unknown.
> t.C:4:26: note: vector alignment may not be reachable
> t.C:4:26: note: not ssa-name.
> t.C:4:26: note: use not simple.
> t.C:4:26: note: not ssa-name.
> t.C:4:26: note: use not simple.
> t.C:4:26: note: no array mode for V2DI[3]
> t.C:4:26: note: Data access with gaps requires scalar epilogue loop
> t.C:4:26: note: can't use a fully-masked loop because the target doesn't 
> have the appropriate masked load or store.
> t.C:4:26: note: not ssa-name.
> t.C:4:26: note: use not simple.
> t.C:4:26: note: not ssa-name.
> t.C:4:26: note: use not simple.
> t.C:4:26: note: no array mode for V2DI[3]
> t.C:4:26: note: Data access with gaps requires scalar epilogue loop
> t.C:4:26: note: op not supported by target.
> t.C:4:26: note: not vectorized: relevant stmt not supported: _15 = _14 
> /[ex] 4;
> t.C:4:26: note: bad operation or unsupported loop bound.
> t.C:4:26: note: not vectorized: no grouped stores in basic block.
> t.C:4:26: note: not vectorized: no grouped stores in basic block.
> t.C:6:12: note: not vectorized: not enough data-refs in basic block.
>
>
>> 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.
>
> Nice idea.  Of course the issue is then for which issues to
> exactly create those.  Like all of the MSG_MISSED_OPTIMIZATION
> dumpings?
>
> I guess the vectorizer needs some axing of useless messages
> and/or we need a MSG_DEBUG to have an additional level below
> MSG_NOTE.

Sounds good.

One of the worst sources of excess noise seems to be vect_is_simple_use:
just looking at an operand usually produces three lines of text.
I did wonder about suggesting we axe that, but I suppose there are
times when it might be useful.

Thanks,
Richard

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] [RFC] Higher-level reporting of vectorization problems
  2018-07-02 16:35   ` Richard Sandiford
@ 2018-07-03  7:14     ` Richard Biener
  0 siblings, 0 replies; 24+ messages in thread
From: Richard Biener @ 2018-07-03  7:14 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: David Malcolm, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 13650 bytes --]

On Mon, 2 Jul 2018, Richard Sandiford wrote:

> Richard Biener <rguenther@suse.de> writes:
> > On Fri, 22 Jun 2018, David Malcolm wrote:
> >
> >> NightStrike and I were chatting on IRC last week about
> >> issues with trying to vectorize the following code:
> >> 
> >> #include <vector>
> >> 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.
> >
> > Yeah, in particular the vectorizer is way too noisy in its low-level
> > functions.  IIRC -fopt-info-vec-missed is "somewhat" better:
> >
> > t.C:4:26: note: step unknown.
> > t.C:4:26: note: vector alignment may not be reachable
> > t.C:4:26: note: not ssa-name.
> > t.C:4:26: note: use not simple.
> > t.C:4:26: note: not ssa-name.
> > t.C:4:26: note: use not simple.
> > t.C:4:26: note: no array mode for V2DI[3]
> > t.C:4:26: note: Data access with gaps requires scalar epilogue loop
> > t.C:4:26: note: can't use a fully-masked loop because the target doesn't 
> > have the appropriate masked load or store.
> > t.C:4:26: note: not ssa-name.
> > t.C:4:26: note: use not simple.
> > t.C:4:26: note: not ssa-name.
> > t.C:4:26: note: use not simple.
> > t.C:4:26: note: no array mode for V2DI[3]
> > t.C:4:26: note: Data access with gaps requires scalar epilogue loop
> > t.C:4:26: note: op not supported by target.
> > t.C:4:26: note: not vectorized: relevant stmt not supported: _15 = _14 
> > /[ex] 4;
> > t.C:4:26: note: bad operation or unsupported loop bound.
> > t.C:4:26: note: not vectorized: no grouped stores in basic block.
> > t.C:4:26: note: not vectorized: no grouped stores in basic block.
> > t.C:6:12: note: not vectorized: not enough data-refs in basic block.
> >
> >
> >> 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.
> >
> > Nice idea.  Of course the issue is then for which issues to
> > exactly create those.  Like all of the MSG_MISSED_OPTIMIZATION
> > dumpings?
> >
> > I guess the vectorizer needs some axing of useless messages
> > and/or we need a MSG_DEBUG to have an additional level below
> > MSG_NOTE.
> 
> Sounds good.
> 
> One of the worst sources of excess noise seems to be vect_is_simple_use:
> just looking at an operand usually produces three lines of text.
> I did wonder about suggesting we axe that, but I suppose there are
> times when it might be useful.

It's easy to prune "obvious" parts, let me do that.

The following doesn't make it very much less noisy, it even adds
(useful) information and makes printing more consistent.

We now get for example

/space/rguenther/src/gcc-slpcost/gcc/testsuite/gcc.dg/vect/pr24300.c:23:3: 
note:  vect_is_simple_use: operand n_77 = PHI <n_10(9), 0(11)>, type of 
def: reduction
/space/rguenther/src/gcc-slpcost/gcc/testsuite/gcc.dg/vect/pr24300.c:23:3: 
note:  vect_is_simple_use: vectype vector(4) int

or when called with the !vectype variant just

/space/rguenther/src/gcc-slpcost/gcc/testsuite/gcc.dg/vect/pr24300.c:23:3: 
note:   vect_is_simple_use: operand (long unsigned int) s_76, type of def: 
internal

I combined printing the operand together with its definition and
always print the resulting *def.

I believe the "unsupported defining stmt" should be "dead" in that
it's STMT_VINFO_DEF_TYPE should be vect_unknown_def_type already
but I'm not 100% sure so I kept it for now.

Bootstrap / regtest in progress.

Richard.

2018-07-03  Richard Biener  <rguenther@suse.de>

	* tree-vect-stmts.c (vect_is_simple_use): Consolidate dumping,
	always set *dt.  Dump vectype in vectype overload.
	* dumpfile.h (dump_gimple_expr): New function.
	(dump_gimple_expr_loc): Likewise.
	* dumpfile.c (dump_gimple_expr): New function.
	(dump_gimple_expr_loc): Likewise.

diff --git a/gcc/dumpfile.c b/gcc/dumpfile.c
index 5f69f9bd646..3296299e86b 100644
--- a/gcc/dumpfile.c
+++ b/gcc/dumpfile.c
@@ -492,6 +492,42 @@ dump_gimple_stmt_loc (dump_flags_t dump_kind, const dump_location_t &loc,
     }
 }
 
+/* Dump gimple statement GS with SPC indentation spaces and
+   EXTRA_DUMP_FLAGS on the dump streams if DUMP_KIND is enabled.
+   Do not terminate with a newline or semicolon.  */
+
+void
+dump_gimple_expr (dump_flags_t dump_kind, dump_flags_t extra_dump_flags,
+		  gimple *gs, int spc)
+{
+  if (dump_file && (dump_kind & pflags))
+    print_gimple_expr (dump_file, gs, spc, dump_flags | extra_dump_flags);
+
+  if (alt_dump_file && (dump_kind & alt_flags))
+    print_gimple_expr (alt_dump_file, gs, spc, dump_flags | extra_dump_flags);
+}
+
+/* Similar to dump_gimple_expr, except additionally print source location.  */
+
+void
+dump_gimple_expr_loc (dump_flags_t dump_kind, const dump_location_t &loc,
+		      dump_flags_t extra_dump_flags, gimple *gs, int spc)
+{
+  location_t srcloc = loc.get_location_t ();
+  if (dump_file && (dump_kind & pflags))
+    {
+      dump_loc (dump_kind, dump_file, srcloc);
+      print_gimple_expr (dump_file, gs, spc, dump_flags | extra_dump_flags);
+    }
+
+  if (alt_dump_file && (dump_kind & alt_flags))
+    {
+      dump_loc (dump_kind, alt_dump_file, srcloc);
+      print_gimple_expr (alt_dump_file, gs, spc, dump_flags | extra_dump_flags);
+    }
+}
+
+
 /* Dump expression tree T using EXTRA_DUMP_FLAGS on dump streams if
    DUMP_KIND is enabled.  */
 
diff --git a/gcc/dumpfile.h b/gcc/dumpfile.h
index 0e588a6dac6..a4172419c1d 100644
--- a/gcc/dumpfile.h
+++ b/gcc/dumpfile.h
@@ -431,6 +431,9 @@ extern void dump_generic_expr (dump_flags_t, dump_flags_t, tree);
 extern void dump_gimple_stmt_loc (dump_flags_t, const dump_location_t &,
 				  dump_flags_t, gimple *, int);
 extern void dump_gimple_stmt (dump_flags_t, dump_flags_t, gimple *, int);
+extern void dump_gimple_expr_loc (dump_flags_t, const dump_location_t &,
+				  dump_flags_t, gimple *, int);
+extern void dump_gimple_expr (dump_flags_t, dump_flags_t, gimple *, int);
 extern void print_combine_total_stats (void);
 extern bool enable_rtl_dump_file (void);
 
diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c
index ab8cc8049a4..ae62fc36401 100644
--- a/gcc/tree-vect-stmts.c
+++ b/gcc/tree-vect-stmts.c
@@ -10036,61 +10036,53 @@ vect_is_simple_use (tree operand, vec_info *vinfo, enum vect_def_type *dt,
     {
       dump_printf_loc (MSG_NOTE, vect_location,
                        "vect_is_simple_use: operand ");
-      dump_generic_expr (MSG_NOTE, TDF_SLIM, operand);
-      dump_printf (MSG_NOTE, "\n");
+      if (TREE_CODE (operand) == SSA_NAME
+	  && !SSA_NAME_IS_DEFAULT_DEF (operand))
+	dump_gimple_expr (MSG_NOTE, TDF_SLIM, SSA_NAME_DEF_STMT (operand), 0);
+      else
+	dump_generic_expr (MSG_NOTE, TDF_SLIM, operand);
     }
 
   if (CONSTANT_CLASS_P (operand))
-    {
-      *dt = vect_constant_def;
-      return true;
-    }
-
-  if (is_gimple_min_invariant (operand))
-    {
-      *dt = vect_external_def;
-      return true;
-    }
-
-  if (TREE_CODE (operand) != SSA_NAME)
-    {
-      if (dump_enabled_p ())
-	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			 "not ssa-name.\n");
-      return false;
-    }
-
-  if (SSA_NAME_IS_DEFAULT_DEF (operand))
-    {
-      *dt = vect_external_def;
-      return true;
-    }
-
-  gimple *def_stmt = SSA_NAME_DEF_STMT (operand);
-  if (dump_enabled_p ())
-    {
-      dump_printf_loc (MSG_NOTE, vect_location, "def_stmt: ");
-      dump_gimple_stmt (MSG_NOTE, TDF_SLIM, def_stmt, 0);
-    }
-
-  if (! vect_stmt_in_region_p (vinfo, def_stmt))
+    *dt = vect_constant_def;
+  else if (is_gimple_min_invariant (operand))
+    *dt = vect_external_def;
+  else if (TREE_CODE (operand) != SSA_NAME)
+    *dt = vect_unknown_def_type;
+  else if (SSA_NAME_IS_DEFAULT_DEF (operand))
     *dt = vect_external_def;
   else
     {
-      stmt_vec_info stmt_vinfo = vinfo_for_stmt (def_stmt);
-      if (STMT_VINFO_IN_PATTERN_P (stmt_vinfo))
+      gimple *def_stmt = SSA_NAME_DEF_STMT (operand);
+      if (! vect_stmt_in_region_p (vinfo, def_stmt))
+	*dt = vect_external_def;
+      else
 	{
-	  def_stmt = STMT_VINFO_RELATED_STMT (stmt_vinfo);
-	  stmt_vinfo = vinfo_for_stmt (def_stmt);
+	  stmt_vec_info stmt_vinfo = vinfo_for_stmt (def_stmt);
+	  if (STMT_VINFO_IN_PATTERN_P (stmt_vinfo))
+	    {
+	      def_stmt = STMT_VINFO_RELATED_STMT (stmt_vinfo);
+	      stmt_vinfo = vinfo_for_stmt (def_stmt);
+	    }
+	  switch (gimple_code (def_stmt))
+	    {
+	    case GIMPLE_PHI:
+	    case GIMPLE_ASSIGN:
+	    case GIMPLE_CALL:
+	      *dt = STMT_VINFO_DEF_TYPE (stmt_vinfo);
+	      break;
+	    default:
+	      *dt = vect_unknown_def_type;
+	      break;
+	    }
 	}
-      *dt = STMT_VINFO_DEF_TYPE (stmt_vinfo);
+      if (def_stmt_out)
+	*def_stmt_out = def_stmt;
     }
-  if (def_stmt_out)
-    *def_stmt_out = def_stmt;
 
   if (dump_enabled_p ())
     {
-      dump_printf_loc (MSG_NOTE, vect_location, "type of def: ");
+      dump_printf (MSG_NOTE, ", type of def: ");
       switch (*dt)
 	{
 	case vect_uninitialized_def:
@@ -10131,19 +10123,6 @@ vect_is_simple_use (tree operand, vec_info *vinfo, enum vect_def_type *dt,
       return false;
     }
 
-  switch (gimple_code (def_stmt))
-    {
-    case GIMPLE_PHI:
-    case GIMPLE_ASSIGN:
-    case GIMPLE_CALL:
-      break;
-    default:
-      if (dump_enabled_p ())
-        dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-                         "unsupported defining stmt:\n");
-      return false;
-    }
-
   return true;
 }
 
@@ -10179,6 +10158,13 @@ vect_is_simple_use (tree operand, vec_info *vinfo, enum vect_def_type *dt,
       stmt_vec_info stmt_info = vinfo_for_stmt (def_stmt);
       *vectype = STMT_VINFO_VECTYPE (stmt_info);
       gcc_assert (*vectype != NULL_TREE);
+      if (dump_enabled_p ())
+	{
+	  dump_printf_loc (MSG_NOTE, vect_location,
+			   "vect_is_simple_use: vectype ");
+	  dump_generic_expr (MSG_NOTE, TDF_SLIM, *vectype);
+	  dump_printf (MSG_NOTE, "\n");
+	}
     }
   else if (*dt == vect_uninitialized_def
 	   || *dt == vect_constant_def

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 2/5] Use opt-problem.h in try_vectorize_loop_1
  2018-07-10  0:27   ` [PATCH 0/5] [RFC v2] " David Malcolm
                       ` (2 preceding siblings ...)
  2018-07-10  0:27     ` [PATCH 1/5] Add opt-problem.h David Malcolm
@ 2018-07-10  0:27     ` David Malcolm
  2018-07-10  0:27     ` [PATCH 5/5] Add opt-problem.cc David Malcolm
  2018-07-11 15:56     ` [PATCH 0/5] [RFC v2] Higher-level reporting of vectorization problems Richard Sandiford
  5 siblings, 0 replies; 24+ messages in thread
From: David Malcolm @ 2018-07-10  0:27 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches, Richard Sandiford, David Malcolm

gcc/ChangeLog:
	* tree-vectorizer.c: Include "opt-problem.h".
	(try_vectorize_loop_1): Convert "loop_vinfo" from loop_vec_info to
	opt_loop_vec_info loop_vinfo, and use opt_report to report any
	opt_problem thus captured.  Use opt_report ro report on successful
	loop vectorization.
---
 gcc/tree-vectorizer.c | 34 ++++++++++++++++++++++++++++------
 1 file changed, 28 insertions(+), 6 deletions(-)

diff --git a/gcc/tree-vectorizer.c b/gcc/tree-vectorizer.c
index 8d54fbb..c60d0d9 100644
--- a/gcc/tree-vectorizer.c
+++ b/gcc/tree-vectorizer.c
@@ -79,6 +79,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "stringpool.h"
 #include "attribs.h"
 #include "gimple-pretty-print.h"
+#include "opt-problem.h"
 
 
 /* Loop or bb location, with hotness information.  */
@@ -705,9 +706,17 @@ try_vectorize_loop_1 (hash_table<simduid_to_vf> *&simduid_to_vf_htab,
 		 LOCATION_FILE (vect_location.get_location_t ()),
 		 LOCATION_LINE (vect_location.get_location_t ()));
 
-  loop_vec_info loop_vinfo = vect_analyze_loop (loop, orig_loop_vinfo, &shared);
+  opt_loop_vec_info loop_vinfo = vect_analyze_loop (loop, orig_loop_vinfo, &shared);
   loop->aux = loop_vinfo;
 
+  if (!loop_vinfo)
+    if (loop_vinfo.get_problem ())
+      {
+	opt_report report;
+	if (report.remark (vect_location, "couldn't vectorize loop"))
+	  loop_vinfo.get_problem ()->report_reason (report);
+      }
+
   if (!loop_vinfo || !LOOP_VINFO_VECTORIZABLE_P (loop_vinfo))
     {
       /* Free existing information if loop is analyzed with some
@@ -775,13 +784,26 @@ try_vectorize_loop_1 (hash_table<simduid_to_vf> *&simduid_to_vf_htab,
 
   unsigned HOST_WIDE_INT bytes;
   if (current_vector_size.is_constant (&bytes))
-    dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, vect_location,
-		     "loop vectorized vectorized using "
+    {
+      dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, vect_location,
+		       "loop vectorized vectorized using "
+		       HOST_WIDE_INT_PRINT_UNSIGNED " byte "
+		       "vectors\n", bytes);
+      opt_report report;
+      // FIXME: is this the correct format code?
+      report.remark (vect_location,
+		     "loop vectorized using "
 		     HOST_WIDE_INT_PRINT_UNSIGNED " byte "
-		     "vectors\n", bytes);
+		     "vectors", bytes);
+    }
   else
-    dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, vect_location,
-		     "loop vectorized using variable length vectors\n");
+    {
+      dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, vect_location,
+		       "loop vectorized using variable length vectors\n");
+      opt_report report;
+      report.remark (vect_location,
+		     "loop vectorized using variable length vectors");
+    }
 
   loop_p new_loop = vect_transform_loop (loop_vinfo);
   (*num_vectorized_loops)++;
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 0/5] [RFC v2] Higher-level reporting of vectorization problems
  2018-06-25  9:15 ` Richard Biener
  2018-07-02 16:35   ` Richard Sandiford
@ 2018-07-10  0:27   ` David Malcolm
  2018-07-10  0:27     ` [PATCH 4/5] Use opt_result throughout vectorizer David Malcolm
                       ` (5 more replies)
  1 sibling, 6 replies; 24+ messages in thread
From: David Malcolm @ 2018-07-10  0:27 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches, Richard Sandiford, David Malcolm

On Mon, 2018-06-25 at 11:10 +0200, Richard Biener wrote:
> On Fri, 22 Jun 2018, David Malcolm wrote:
> 
> > NightStrike and I were chatting on IRC last week about
> > issues with trying to vectorize the following code:
> > 
> > #include <vector>
> > 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.
> 
> Yeah, in particular the vectorizer is way too noisy in its low-level
> functions.  IIRC -fopt-info-vec-missed is "somewhat" better:
> 
> t.C:4:26: note: step unknown.
> t.C:4:26: note: vector alignment may not be reachable
> t.C:4:26: note: not ssa-name.
> t.C:4:26: note: use not simple.
> t.C:4:26: note: not ssa-name.
> t.C:4:26: note: use not simple.
> t.C:4:26: note: no array mode for V2DI[3]
> t.C:4:26: note: Data access with gaps requires scalar epilogue loop
> t.C:4:26: note: can't use a fully-masked loop because the target
> doesn't 
> have the appropriate masked load or store.
> t.C:4:26: note: not ssa-name.
> t.C:4:26: note: use not simple.
> t.C:4:26: note: not ssa-name.
> t.C:4:26: note: use not simple.
> t.C:4:26: note: no array mode for V2DI[3]
> t.C:4:26: note: Data access with gaps requires scalar epilogue loop
> t.C:4:26: note: op not supported by target.
> t.C:4:26: note: not vectorized: relevant stmt not supported: _15 =
> _14 
> /[ex] 4;
> t.C:4:26: note: bad operation or unsupported loop bound.
> t.C:4:26: note: not vectorized: no grouped stores in basic block.
> t.C:4:26: note: not vectorized: no grouped stores in basic block.
> t.C:6:12: note: not vectorized: not enough data-refs in basic block.
> 
> 
> > 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.
> 
> Nice idea.  Of course the issue is then for which issues to
> exactly create those.  Like all of the MSG_MISSED_OPTIMIZATION
> dumpings?
> 
> I guess the vectorizer needs some axing of useless messages
> and/or we need a MSG_DEBUG to have an additional level below
> MSG_NOTE.
> 
> > 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).
> 
> Quite likely because we only handle TRUNC_DIV_EXPR and not
> EXACT_DIV_EXPR
> which we can handle the same semantically (EXACT_DIV_EXPR just gives
> us stronger guarantees).

[...snip...]

I've been experimenting with the idea; here's an updated version of
the patch (on top of the optinfo patch kit, as it happens).

I tried adding more uses of opt_problem, but ran into the issue that it's
hard to find "by hand" the places deep in the callstack where things fail;
I spent a chunk of time stepping through failures, trying to figure out
the best place to capture the opt_problem.

It seemed like something that we could track in C++'s type system.

The following kit solves this by introducing a new class opt_result, which
looks a lot like a bool: it has the same representation in memory.

For instance, at the deepest point of the callstack where the failure
happens, rather than:

     if (!check_something ())
       {
         if (dump_enabled_p ())
           dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
                            "foo is unsupported.\n");
         return false;
       }
     [...lots more checks...]

     // All checks passed:
     return true;

we can capture the cause of the failure via:

     if (!check_something ())
       {
         if (dump_enabled_p ())
           dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
                            "foo is unsupported.\n");
         return opt_result::failure ("foo is unsupported",
                                     stmt);
       }
     [...lots more checks...]

     // All checks passed:
     return opt_result::success ();

which effectively returns true or false, whilst recording any problem.

opt_result::success and opt_result::failure return opt_result values
which "looks like" true/false respectively, via operator bool().
If dump_enabled_p, then opt_result::failure also creates an opt_problem *,
capturing the pertinent data (here, "foo is unsupported" and "stmt").
If dumps are disabled, then opt_problem instances aren't
created, and it's equivalent to just returning a bool (false for failure).

The opt_problem can be propagated via opt_result values back up
the call stack to where it makes most sense to the user.
For instance, rather than:

     bool ok = try_something_that_might_fail ();
     if (!ok)
       {
         if (dump_enabled_p ())
           dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
                            "some message.\n");
         return false;
       }

we can replace the bool with an opt_result, so if dump_enabled_p, we
assume that if try_something_that_might_fail, an opt_problem * will be
created, and we can propagate it up the call chain:

     opt_result ok = try_something_that_might_fail ();
     if (!ok)
       {
         if (dump_enabled_p ())
           dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
                            "some message.\n");
         return ok; // propagating the opt_result
       }

There's currently a way to implicitly construct an opt_result from a
bool, but this is scaffolding: commenting it out allows the compiler to
tell us where we need to capture failure information.

As well as opt_result for "bool", there's a template for wrapping pointers
where non-NULL is "success" and NULL "failure", so that:

      loop_vinfo = vect_analyze_loop_form (loop, shared);
      if (!loop_vinfo)
	{
	  if (dump_enabled_p ())
	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
			     "bad loop form.\n");
	  return NULL;
	}

can simply become:

      loop_vinfo = vect_analyze_loop_form (loop, shared);
      if (!loop_vinfo)
	{
	  if (dump_enabled_p ())
	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
			     "bad loop form.\n");
	  return loop_vinfo;
	}

where the "loop_vinfo" is now an opt_wrapper<loop_vec_info> and can
capture exactly what went wrong inside vect_analyze_loop_form.

In all cases, the classes act as if the opt_problem were one of its
fields, but the opt_problem is actually stored in a global, so that when
compiled, an opt_wrapper<T> is effectively just a T, so that we're
still just passing e.g. a bool around; the opt_wrapper<T> classes
simply provide type-checking and an API to ensure that we provide
error-messages deep in the callstack at the places where problems
occur, and that we propagate them.  This also avoids having
to manage the ownership of the opt_problem instances.

Using opt_result and opt_wrapper<T> documents the intent of the code
for the places where we represent success values, and allows the C++ type
system to track where the deepest points in the callstack are where we
need to emit the failure messages from.

Some examples, showing how it immediately leads to more meaningful
diagnostics from the vectorizer:

gcc.dg/vect/vect-widen-mult-1.c: In function ‘f’:
gcc.dg/vect/vect-widen-mult-1.c:16:3: remark: loop vectorized using 16 byte vectors
   for (__INTPTR_TYPE__ i = 0; i < N; ++i)
   ^~~
gcc.dg/vect/vect-widen-mult-1.c: In function ‘main’:
gcc.dg/vect/vect-widen-mult-1.c:42:10: remark: couldn't vectorize loop
     if (a[i] != (SIGNEDNESS_1 short) ((BASE + i * 5)
         ~^~~
gcc.dg/vect/vect-widen-mult-1.c:42:10: note: control flow in loop [../../src/gcc/tree-vect-loop.c:1200:vect_analyze_loop_form_1]
gcc.dg/vect/vect-widen-mult-1.c:34:3: remark: couldn't vectorize loop
   for (int i = 0; i < N; ++i)
   ^~~
gcc.dg/vect/vect-widen-mult-1.c:38:7: note: statement clobbers memory: ‘__asm__ __volatile__("" :  :  : "memory");’ [../../src/gcc/tree-data-ref.c:5086:find_data_references_in_stmt]
       asm volatile ("" ::: "memory");
       ^~~

by showing the location of the loop that can't be vectorized,
the problematic statement within the loop, and describing what the
problem is.

Note how it also captures the location of where in GCC the problem was
encountered.  Ultimately this would also show hotness information for the
loop in the remark.

I'm not sure exactly what an opt_problem should capture.  There are a few
places in the kit where it looks the "failure" calls might benefit from
being a formatted print API, with format codes for various middle-end
entities (e.g. gimple, tree, --param values, etc).  It's also not clear
to me how this would interact with the optinfo work (e.g. for capturing
things in optimization records), or what the API should look like (though
I like the one in the patch).

(Not yet bootstrapped or regrtested, and has plenty of FIXMEs: I'm posting
this for comment/discussion).

Thoughts?
Does the basic idea look useful and sane? (I think so)

Thanks
Dave

[...snip...]

David Malcolm (5):
  Add opt-problem.h
  Use opt-problem.h in try_vectorize_loop_1
  Add some test coverage
  Use opt_result throughout vectorizer
  Add opt-problem.cc

 gcc/Makefile.in                                |   1 +
 gcc/opt-problem.cc                             |  96 ++++++++
 gcc/opt-problem.h                              | 326 +++++++++++++++++++++++++
 gcc/testsuite/gcc.dg/vect/vect-alias-check-4.c |  11 +-
 gcc/testsuite/gcc.dg/vect/vect-remarks-1.c     |  18 ++
 gcc/tree-data-ref.c                            |  33 +--
 gcc/tree-data-ref.h                            |  10 +-
 gcc/tree-vect-data-refs.c                      | 189 ++++++++------
 gcc/tree-vect-loop.c                           | 212 +++++++++-------
 gcc/tree-vect-slp.c                            |   4 +-
 gcc/tree-vect-stmts.c                          | 130 ++++++----
 gcc/tree-vectorizer.c                          |  34 ++-
 gcc/tree-vectorizer.h                          |  41 ++--
 13 files changed, 842 insertions(+), 263 deletions(-)
 create mode 100644 gcc/opt-problem.cc
 create mode 100644 gcc/opt-problem.h
 create mode 100644 gcc/testsuite/gcc.dg/vect/vect-remarks-1.c

-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 5/5] Add opt-problem.cc
  2018-07-10  0:27   ` [PATCH 0/5] [RFC v2] " David Malcolm
                       ` (3 preceding siblings ...)
  2018-07-10  0:27     ` [PATCH 2/5] Use opt-problem.h in try_vectorize_loop_1 David Malcolm
@ 2018-07-10  0:27     ` David Malcolm
  2018-07-11 15:56     ` [PATCH 0/5] [RFC v2] Higher-level reporting of vectorization problems Richard Sandiford
  5 siblings, 0 replies; 24+ messages in thread
From: David Malcolm @ 2018-07-10  0:27 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches, Richard Sandiford, David Malcolm

gcc/ChangeLog:
	* Makefile.in (OBJS): Add opt-problem.o.
	* opt-problem.cc: New file.
---
 gcc/Makefile.in    |  1 +
 gcc/opt-problem.cc | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 97 insertions(+)
 create mode 100644 gcc/opt-problem.cc

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..f518b16
--- /dev/null
+++ b/gcc/opt-problem.cc
@@ -0,0 +1,96 @@
+/* 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 remark about an optimization.  */
+
+bool
+opt_report::remark (dump_location_t loc, const char *gmsgid, ...)
+{
+  if (!flag_remarks)
+    return false;
+
+  va_list ap;
+  va_start (ap, gmsgid);
+  bool ret = emit_diagnostic_valist (DK_REMARK, loc.get_location_t (), -1,
+				     gmsgid, &ap);
+  va_end (ap);
+
+  // FIXME: how should this interact with optinfo? (we don't want a duplicate remark)
+  return ret;
+}
+
+/* Emit a note about an optimization.  */
+
+bool
+opt_report::note (dump_location_t loc, const char *gmsgid, ...)
+{
+  va_list ap;
+  va_start (ap, gmsgid);
+  bool ret = emit_diagnostic_valist (DK_NOTE, loc.get_location_t (), -1,
+				     gmsgid, &ap);
+  va_end (ap);
+
+  // FIXME: how should this interact with optinfo? (we don't want a duplicate note)
+  return ret;
+}
+
+opt_problem *opt_problem::s_the_problem;
+
+// FIXME: some refactoring is needed, based on exactly where remarks land,
+// and how this interacts with the optinfo stuff.  For now, this decl:
+
+extern void
+print_impl_location (pretty_printer *pp, const dump_impl_location_t &impl_loc);
+
+/* Emit a diagnostic note describing why an optimization wasn't possible.  */
+
+void
+opt_problem::report_reason (opt_report &report)
+{
+  bool show_color = pp_show_color (global_dc->printer);
+
+  pretty_printer pp;
+  pp_show_color (&pp) = pp_show_color (global_dc->printer);
+  pp_string (&pp, m_text);
+  if (m_stmt)
+    {
+      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);
+    }
+
+  print_impl_location (&pp, m_location.get_impl_location ());
+
+  const char *msg = pp_formatted_text (&pp);
+
+  report.note (m_location, "%s", msg);
+}
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 4/5] Use opt_result throughout vectorizer
  2018-07-10  0:27   ` [PATCH 0/5] [RFC v2] " David Malcolm
@ 2018-07-10  0:27     ` David Malcolm
  2018-07-10  0:27     ` [PATCH 3/5] Add some test coverage David Malcolm
                       ` (4 subsequent siblings)
  5 siblings, 0 replies; 24+ messages in thread
From: David Malcolm @ 2018-07-10  0:27 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches, Richard Sandiford, David Malcolm

This patch uses the opt_result framework throughout the vectorizer
(and a few other places) so that specific details on problems are
propagated back up to the top-level of the vectorizer.

The changes are mostly fairly mechanical.

There are various FIXMEs in the code: for example, in various places
it feels like it would be useful to have a formatted printing API
for opt_result::failure etc, or other ways to capture the information
of interest (e.g. if there's a dependence between two data references
that's blocking vectorization, we probably should capture them so
we can highlight them to the user).

Almost everywhere using "bool" to handle error-checking uses "true"
for success, but there was one place where "true" meant "failure":
vect_analyze_data_ref_dependence, so the patch changes the sense
of that function's return value (as well as converting it from
bool to opt_result).

Placeholder ChangeLog follows:

gcc/ChangeLog:
	* tree-data-ref.c: Use opt-problem.h in many places.
	* tree-data-ref.h: Likewise.
	* tree-vect-data-refs.c: Likewise.
	* tree-vect-loop.c: Likewise.
	* tree-vect-slp.c: Likewise.
	* tree-vect-stmts.c: Likewise.
	* tree-vectorizer.h: Likewise.
---
 gcc/tree-data-ref.c       |  33 +++++---
 gcc/tree-data-ref.h       |  10 ++-
 gcc/tree-vect-data-refs.c | 189 ++++++++++++++++++++++++-----------------
 gcc/tree-vect-loop.c      | 212 +++++++++++++++++++++++++++-------------------
 gcc/tree-vect-slp.c       |   4 +-
 gcc/tree-vect-stmts.c     | 130 ++++++++++++++++------------
 gcc/tree-vectorizer.h     |  35 ++++----
 7 files changed, 360 insertions(+), 253 deletions(-)

diff --git a/gcc/tree-data-ref.c b/gcc/tree-data-ref.c
index b163eaf..a6319f83 100644
--- a/gcc/tree-data-ref.c
+++ b/gcc/tree-data-ref.c
@@ -827,7 +827,7 @@ canonicalize_base_object_address (tree addr)
    Return true if the analysis succeeded and store the results in DRB if so.
    BB analysis can only fail for bitfield or reversed-storage accesses.  */
 
-bool
+opt_result
 dr_analyze_innermost (innermost_loop_behavior *drb, tree ref,
 		      struct loop *loop)
 {
@@ -851,14 +851,14 @@ dr_analyze_innermost (innermost_loop_behavior *drb, tree ref,
     {
       if (dump_file && (dump_flags & TDF_DETAILS))
 	fprintf (dump_file, "failed: bit offset alignment.\n");
-      return false;
+      return opt_result::failure ("bit offset alignment", NULL);
     }
 
   if (preversep)
     {
       if (dump_file && (dump_flags & TDF_DETAILS))
 	fprintf (dump_file, "failed: reverse storage order.\n");
-      return false;
+      return opt_result::failure ("reverse storage order", NULL);
     }
 
   /* Calculate the alignment and misalignment for the inner reference.  */
@@ -898,7 +898,9 @@ dr_analyze_innermost (innermost_loop_behavior *drb, tree ref,
         {
 	  if (dump_file && (dump_flags & TDF_DETAILS))
 	    fprintf (dump_file, "failed: evolution of base is not affine.\n");
-	  return false;
+	  // FIXME: should this propagate an opt_problem from simple_iv?
+	  return opt_result::failure ("evolution of base is not affine",
+				      NULL);
         }
     }
   else
@@ -924,7 +926,9 @@ dr_analyze_innermost (innermost_loop_behavior *drb, tree ref,
         {
 	  if (dump_file && (dump_flags & TDF_DETAILS))
 	    fprintf (dump_file, "failed: evolution of offset is not affine.\n");
-	  return false;
+	  // FIXME: should this propagate an opt_problem from simple_iv?
+	  return opt_result::failure ("evolution of offset is not affine",
+				      NULL);
         }
     }
 
@@ -981,7 +985,7 @@ dr_analyze_innermost (innermost_loop_behavior *drb, tree ref,
   if (dump_file && (dump_flags & TDF_DETAILS))
     fprintf (dump_file, "success.\n");
 
-  return true;
+  return opt_result::success ();
 }
 
 /* Return true if OP is a valid component reference for a DR access
@@ -1318,7 +1322,7 @@ data_ref_compare_tree (tree t1, tree t2)
 /* Return TRUE it's possible to resolve data dependence DDR by runtime alias
    check.  */
 
-bool
+opt_result
 runtime_alias_check_p (ddr_p ddr, struct loop *loop, bool speed_p)
 {
   if (dump_enabled_p ())
@@ -1336,7 +1340,8 @@ runtime_alias_check_p (ddr_p ddr, struct loop *loop, bool speed_p)
 	dump_printf (MSG_MISSED_OPTIMIZATION,
 		     "runtime alias check not supported when optimizing "
 		     "for size.\n");
-      return false;
+      return opt_result::failure ("runtime alias check not supported when"
+				  " optimizing for size", NULL);
     }
 
   /* FORNOW: We don't support versioning with outer-loop in either
@@ -1346,10 +1351,11 @@ runtime_alias_check_p (ddr_p ddr, struct loop *loop, bool speed_p)
       if (dump_enabled_p ())
 	dump_printf (MSG_MISSED_OPTIMIZATION,
 		     "runtime alias check not supported for outer loop.\n");
-      return false;
+      return opt_result::failure ("runtime alias check not supported for"
+				  " outer loop", NULL);
     }
 
-  return true;
+  return opt_result::success ();
 }
 
 /* Operator == between two dr_with_seg_len objects.
@@ -5067,18 +5073,17 @@ loop_nest_has_data_refs (loop_p loop)
    reference, returns false, otherwise returns true.  NEST is the outermost
    loop of the loop nest in which the references should be analyzed.  */
 
-bool
+opt_result
 find_data_references_in_stmt (struct loop *nest, gimple *stmt,
 			      vec<data_reference_p> *datarefs)
 {
   unsigned i;
   auto_vec<data_ref_loc, 2> references;
   data_ref_loc *ref;
-  bool ret = true;
   data_reference_p dr;
 
   if (get_references_in_stmt (stmt, &references))
-    return false;
+    return opt_result::failure ("statement clobbers memory", stmt);
 
   FOR_EACH_VEC_ELT (references, i, ref)
     {
@@ -5089,7 +5094,7 @@ find_data_references_in_stmt (struct loop *nest, gimple *stmt,
       datarefs->safe_push (dr);
     }
 
-  return ret;
+  return opt_result::success ();
 }
 
 /* Stores the data references in STMT to DATAREFS.  If there is an
diff --git a/gcc/tree-data-ref.h b/gcc/tree-data-ref.h
index 8739853..d734708 100644
--- a/gcc/tree-data-ref.h
+++ b/gcc/tree-data-ref.h
@@ -23,6 +23,7 @@ along with GCC; see the file COPYING3.  If not see
 
 #include "graphds.h"
 #include "tree-chrec.h"
+#include "opt-problem.h"
 
 /*
   innermost_loop_behavior describes the evolution of the address of the memory
@@ -421,7 +422,8 @@ typedef struct data_dependence_relation *ddr_p;
 #define DDR_COULD_BE_INDEPENDENT_P(DDR) (DDR)->could_be_independent_p
 
 \f
-bool dr_analyze_innermost (innermost_loop_behavior *, tree, struct loop *);
+opt_result dr_analyze_innermost (innermost_loop_behavior *, tree,
+				 struct loop *);
 extern bool compute_data_dependences_for_loop (struct loop *, bool,
 					       vec<loop_p> *,
 					       vec<data_reference_p> *,
@@ -443,8 +445,8 @@ extern void free_dependence_relation (struct data_dependence_relation *);
 extern void free_dependence_relations (vec<ddr_p> );
 extern void free_data_ref (data_reference_p);
 extern void free_data_refs (vec<data_reference_p> );
-extern bool find_data_references_in_stmt (struct loop *, gimple *,
-					  vec<data_reference_p> *);
+extern opt_result find_data_references_in_stmt (struct loop *, gimple *,
+						vec<data_reference_p> *);
 extern bool graphite_find_data_references_in_stmt (edge, loop_p, gimple *,
 						   vec<data_reference_p> *);
 tree find_data_references_in_loop (struct loop *, vec<data_reference_p> *);
@@ -479,7 +481,7 @@ extern bool dr_may_alias_p (const struct data_reference *,
 extern bool dr_equal_offsets_p (struct data_reference *,
                                 struct data_reference *);
 
-extern bool runtime_alias_check_p (ddr_p, struct loop *, bool);
+extern opt_result runtime_alias_check_p (ddr_p, struct loop *, bool);
 extern int data_ref_compare_tree (tree, tree);
 extern void prune_runtime_alias_test_list (vec<dr_with_seg_len_pair_t> *,
 					   poly_uint64);
diff --git a/gcc/tree-vect-data-refs.c b/gcc/tree-vect-data-refs.c
index 63429a3..eceb6f2 100644
--- a/gcc/tree-vect-data-refs.c
+++ b/gcc/tree-vect-data-refs.c
@@ -155,20 +155,25 @@ vect_get_smallest_scalar_type (gimple *stmt, HOST_WIDE_INT *lhs_size_unit,
    tested at run-time.  Return TRUE if DDR was successfully inserted.
    Return false if versioning is not supported.  */
 
-static bool
+static opt_result
 vect_mark_for_runtime_alias_test (ddr_p ddr, loop_vec_info loop_vinfo)
 {
   struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
 
   if ((unsigned) PARAM_VALUE (PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS) == 0)
-    return false;
+    // FIXME: formatted print?
+    return opt_result::failure ("will not create alias checks, as"
+				" --param vect-max-version-for-alias-checks"
+				" == 0", NULL);
 
-  if (!runtime_alias_check_p (ddr, loop,
-			      optimize_loop_nest_for_speed_p (loop)))
-    return false;
+  opt_result res
+    = runtime_alias_check_p (ddr, loop,
+			     optimize_loop_nest_for_speed_p (loop));
+  if (!res)
+    return res;
 
   LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo).safe_push (ddr);
-  return true;
+  return opt_result::success ();
 }
 
 /* Record that loop LOOP_VINFO needs to check that VALUE is nonzero.  */
@@ -280,12 +285,14 @@ vect_analyze_possibly_independent_ddr (data_dependence_relation *ddr,
 
 /* Function vect_analyze_data_ref_dependence.
 
-   Return TRUE if there (might) exist a dependence between a memory-reference
+   FIXME: I needed to change the sense of the returned flag.
+
+   Return FALSE if there (might) exist a dependence between a memory-reference
    DRA and a memory-reference DRB.  When versioning for alias may check a
-   dependence at run-time, return FALSE.  Adjust *MAX_VF according to
+   dependence at run-time, return TRUE.  Adjust *MAX_VF according to
    the data dependence.  */
 
-static bool
+static opt_result
 vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
 				  loop_vec_info loop_vinfo,
 				  unsigned int *max_vf)
@@ -306,11 +313,11 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
 
   /* Independent data accesses.  */
   if (DDR_ARE_DEPENDENT (ddr) == chrec_known)
-    return false;
+    return opt_result::success ();
 
   if (dra == drb
       || (DR_IS_READ (dra) && DR_IS_READ (drb)))
-    return false;
+    return opt_result::success ();
 
   /* We do not have to consider dependences between accesses that belong
      to the same group, unless the stride could be smaller than the
@@ -319,7 +326,7 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
       && (DR_GROUP_FIRST_ELEMENT (stmtinfo_a)
 	  == DR_GROUP_FIRST_ELEMENT (stmtinfo_b))
       && !STMT_VINFO_STRIDED_P (stmtinfo_a))
-    return false;
+    return opt_result::success ();
 
   /* Even if we have an anti-dependence then, as the vectorized loop covers at
      least two scalar iterations, there is always also a true dependence.
@@ -331,7 +338,7 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
        || (DR_IS_WRITE (dra) && DR_IS_READ (drb)))
       && !alias_sets_conflict_p (get_alias_set (DR_REF (dra)),
 				 get_alias_set (DR_REF (drb))))
-    return false;
+    return opt_result::success ();
 
   /* Unknown data dependence.  */
   if (DDR_ARE_DEPENDENT (ddr) == chrec_dont_know)
@@ -343,7 +350,7 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
 	  if ((unsigned int) loop->safelen < *max_vf)
 	    *max_vf = loop->safelen;
 	  LOOP_VINFO_NO_DATA_DEPENDENCIES (loop_vinfo) = false;
-	  return false;
+	  return opt_result::success ();
 	}
 
       if (STMT_VINFO_GATHER_SCATTER_P (stmtinfo_a)
@@ -361,7 +368,8 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
 				 DR_REF (drb));
 	      dump_printf (MSG_MISSED_OPTIMIZATION, "\n");
 	    }
-	  return true;
+	  // FIXME: better message here, capturing the data of interest
+	  return opt_result::failure ("can't determine dependence", NULL);
 	}
 
       if (dump_enabled_p ())
@@ -378,7 +386,7 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
 	}
 
       /* Add to list of ddrs that need to be tested at run-time.  */
-      return !vect_mark_for_runtime_alias_test (ddr, loop_vinfo);
+      return vect_mark_for_runtime_alias_test (ddr, loop_vinfo);
     }
 
   /* Known data dependence.  */
@@ -391,7 +399,7 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
 	  if ((unsigned int) loop->safelen < *max_vf)
 	    *max_vf = loop->safelen;
 	  LOOP_VINFO_NO_DATA_DEPENDENCIES (loop_vinfo) = false;
-	  return false;
+	  return opt_result::success ();
 	}
 
       if (STMT_VINFO_GATHER_SCATTER_P (stmtinfo_a)
@@ -409,7 +417,7 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
 				 DR_REF (drb));
 	      dump_printf (MSG_MISSED_OPTIMIZATION, "\n");
 	    }
-	  return true;
+	  return opt_result::failure ("FIXME", NULL);
 	}
 
       if (dump_enabled_p ())
@@ -423,7 +431,7 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
           dump_printf (MSG_MISSED_OPTIMIZATION, "\n");
         }
       /* Add to list of ddrs that need to be tested at run-time.  */
-      return !vect_mark_for_runtime_alias_test (ddr, loop_vinfo);
+      return vect_mark_for_runtime_alias_test (ddr, loop_vinfo);
     }
 
   loop_depth = index_in_loop_nest (loop->num, DDR_LOOP_NEST (ddr));
@@ -431,7 +439,7 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
   if (DDR_COULD_BE_INDEPENDENT_P (ddr)
       && vect_analyze_possibly_independent_ddr (ddr, loop_vinfo,
 						loop_depth, max_vf))
-    return false;
+    return opt_result::success ();
 
   FOR_EACH_VEC_ELT (DDR_DIST_VECTS (ddr), i, dist_v)
     {
@@ -477,7 +485,9 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
 	      if (dump_enabled_p ())
 		dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 				 "READ_WRITE dependence in interleaving.\n");
-	      return true;
+	      // FIXME: capture stmts
+	      return opt_result::failure ("READ_WRITE dependence in"
+					  " interleaving", NULL);
 	    }
 
 	  if (loop->safelen < 2)
@@ -488,7 +498,9 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
 		  if (dump_enabled_p ())
 		    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 				 "access also has a zero step\n");
-		  return true;
+		  // FIXME: capture stmts
+		  return opt_result::failure ("access also has a zero step",
+					      NULL);
 		}
 	      else if (TREE_CODE (indicator) != INTEGER_CST)
 		vect_check_nonzero_value (loop_vinfo, indicator);
@@ -547,10 +559,12 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
 	  dump_printf (MSG_NOTE,  "\n");
 	}
 
-      return true;
+      // FIXME: capture stmts
+      return opt_result::failure ("possible dependence between data-refs",
+				  NULL);
     }
 
-  return false;
+  return opt_result::success ();
 }
 
 /* Function vect_analyze_data_ref_dependences.
@@ -559,7 +573,7 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
    exist any data dependences between them.  Set *MAX_VF according to
    the maximum vectorization factor the data dependences allow.  */
 
-bool
+opt_result
 vect_analyze_data_ref_dependences (loop_vec_info loop_vinfo,
 				   unsigned int *max_vf)
 {
@@ -591,10 +605,14 @@ vect_analyze_data_ref_dependences (loop_vec_info loop_vinfo,
     *max_vf = LOOP_VINFO_ORIG_MAX_VECT_FACTOR (loop_vinfo);
   else
     FOR_EACH_VEC_ELT (LOOP_VINFO_DDRS (loop_vinfo), i, ddr)
-      if (vect_analyze_data_ref_dependence (ddr, loop_vinfo, max_vf))
-	return false;
+      {
+	opt_result res
+	  = vect_analyze_data_ref_dependence (ddr, loop_vinfo, max_vf);
+	if (!res)
+	  return res;
+      }
 
-  return true;
+  return opt_result::success ();
 }
 
 
@@ -1122,7 +1140,7 @@ vect_update_misalignment_for_peel (struct data_reference *dr,
 
    Return TRUE if DR can be handled with respect to alignment.  */
 
-static bool
+static opt_result
 verify_data_ref_alignment (data_reference_p dr)
 {
   enum dr_alignment_support supportable_dr_alignment
@@ -1143,14 +1161,18 @@ verify_data_ref_alignment (data_reference_p dr)
 			     DR_REF (dr));
 	  dump_printf (MSG_MISSED_OPTIMIZATION, "\n");
 	}
-      return false;
+      // FIXME: show dr here:
+      return opt_result::failure (DR_IS_READ (dr)
+				  ? "unsupported unaligned load"
+				  : "unsupported unaligned store",
+				  NULL);
     }
 
   if (supportable_dr_alignment != dr_aligned && dump_enabled_p ())
     dump_printf_loc (MSG_NOTE, vect_location,
 		     "Vectorizing an unaligned access.\n");
 
-  return true;
+  return opt_result::success ();
 }
 
 /* Function vect_verify_datarefs_alignment
@@ -1158,7 +1180,7 @@ verify_data_ref_alignment (data_reference_p dr)
    Return TRUE if all data references in the loop can be
    handled with respect to alignment.  */
 
-bool
+opt_result
 vect_verify_datarefs_alignment (loop_vec_info vinfo)
 {
   vec<data_reference_p> datarefs = vinfo->shared->datarefs;
@@ -1184,11 +1206,12 @@ vect_verify_datarefs_alignment (loop_vec_info vinfo)
 	  && !STMT_VINFO_GROUPED_ACCESS (stmt_info))
 	continue;
 
-      if (! verify_data_ref_alignment (dr))
-	return false;
+      opt_result res = verify_data_ref_alignment (dr);
+      if (!res)
+	return res;
     }
 
-  return true;
+  return opt_result::success ();
 }
 
 /* Given an memory reference EXP return whether its alignment is less
@@ -1666,7 +1689,7 @@ vect_peeling_supportable (loop_vec_info loop_vinfo, struct data_reference *dr0,
      (whether to generate regular loads/stores, or with special handling for
      misalignment).  */
 
-bool
+opt_result
 vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
 {
   vec<data_reference_p> datarefs = LOOP_VINFO_DATAREFS (loop_vinfo);
@@ -1677,7 +1700,6 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
   unsigned int i, j;
   bool do_peeling = false;
   bool do_versioning = false;
-  bool stat;
   gimple *stmt;
   stmt_vec_info stmt_info;
   unsigned int npeel = 0;
@@ -2065,7 +2087,7 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
       /* Check if all datarefs are supportable and log.  */
       if (do_peeling && known_alignment_for_access_p (dr0) && npeel == 0)
         {
-          stat = vect_verify_datarefs_alignment (loop_vinfo);
+          opt_result stat = vect_verify_datarefs_alignment (loop_vinfo);
           if (!stat)
             do_peeling = false;
           else
@@ -2149,7 +2171,7 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
 	  /* The inside-loop cost will be accounted for in vectorizable_load
 	     and vectorizable_store correctly with adjusted alignments.
 	     Drop the body_cst_vec on the floor here.  */
-	  stat = vect_verify_datarefs_alignment (loop_vinfo);
+	  opt_result stat = vect_verify_datarefs_alignment (loop_vinfo);
 	  gcc_assert (stat);
           return stat;
         }
@@ -2275,7 +2297,7 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
       /* Peeling and versioning can't be done together at this time.  */
       gcc_assert (! (do_peeling && do_versioning));
 
-      stat = vect_verify_datarefs_alignment (loop_vinfo);
+      opt_result stat = vect_verify_datarefs_alignment (loop_vinfo);
       gcc_assert (stat);
       return stat;
     }
@@ -2283,7 +2305,7 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
   /* This point is reached if neither peeling nor versioning is being done.  */
   gcc_assert (! (do_peeling || do_versioning));
 
-  stat = vect_verify_datarefs_alignment (loop_vinfo);
+  opt_result stat = vect_verify_datarefs_alignment (loop_vinfo);
   return stat;
 }
 
@@ -2352,7 +2374,7 @@ vect_find_same_alignment_drs (struct data_dependence_relation *ddr)
    Analyze the alignment of the data-references in the loop.
    Return FALSE if a data reference is found that cannot be vectorized.  */
 
-bool
+opt_result
 vect_analyze_data_refs_alignment (loop_vec_info vinfo)
 {
   DUMP_VECT_SCOPE ("vect_analyze_data_refs_alignment");
@@ -2377,7 +2399,7 @@ vect_analyze_data_refs_alignment (loop_vec_info vinfo)
 	vect_compute_data_ref_alignment (dr);
     }
 
-  return true;
+  return opt_result::success ();
 }
 
 
@@ -2916,7 +2938,7 @@ can_group_stmts_p (gimple *stmt1, gimple *stmt2)
 
    FORNOW: handle only arrays and pointer accesses.  */
 
-bool
+opt_result
 vect_analyze_data_ref_accesses (vec_info *vinfo)
 {
   unsigned int i;
@@ -2926,7 +2948,7 @@ vect_analyze_data_ref_accesses (vec_info *vinfo)
   DUMP_VECT_SCOPE ("vect_analyze_data_ref_accesses");
 
   if (datarefs.is_empty ())
-    return true;
+    return opt_result::success ();
 
   /* Sort the array of datarefs to make building the interleaving chains
      linear.  Don't modify the original vector's order, it is needed for
@@ -3088,12 +3110,13 @@ vect_analyze_data_ref_accesses (vec_info *vinfo)
         else
 	  {
 	    datarefs_copy.release ();
-	    return false;
+	    return opt_result::failure ("complicated access pattern",
+					vect_dr_stmt (dr));
 	  }
       }
 
   datarefs_copy.release ();
-  return true;
+  return opt_result::success ();
 }
 
 /* Function vect_vfa_segment_size.
@@ -3351,7 +3374,7 @@ vectorizable_with_step_bound_p (data_reference *dr_a, data_reference *dr_b,
    Return FALSE if resulting list of ddrs is longer then allowed by
    PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS, otherwise return TRUE.  */
 
-bool
+opt_result
 vect_prune_runtime_alias_test_list (loop_vec_info loop_vinfo)
 {
   typedef pair_hash <tree_operand_hash, tree_operand_hash> tree_pair_hash;
@@ -3385,7 +3408,7 @@ vect_prune_runtime_alias_test_list (loop_vec_info loop_vinfo)
     }
 
   if (may_alias_ddrs.is_empty ())
-    return true;
+    return opt_result::success ();
 
   comp_alias_ddrs.create (may_alias_ddrs.length ());
 
@@ -3560,7 +3583,8 @@ vect_prune_runtime_alias_test_list (loop_vec_info loop_vinfo)
 	      if (dump_enabled_p ())
 		dump_printf_loc (MSG_NOTE, vect_location,
 				 "not vectorized: compilation time alias.\n");
-	      return false;
+	      return opt_result::failure ("compilation time alias", stmt_a);
+	      // FIXME: and stmt_b
 	    }
 	}
 
@@ -3591,10 +3615,13 @@ vect_prune_runtime_alias_test_list (loop_vec_info loop_vinfo)
 			 "run-time tests exceeds %d "
 			 "(--param vect-max-version-for-alias-checks)\n",
 			 PARAM_VALUE (PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS));
-      return false;
+      return opt_result::failure ("number of versioning for alias "
+				  "run-time tests exceeds %d "
+				  "(--param vect-max-version-for-alias-checks)",
+				  NULL); // FIXME: make it variadic!
     }
 
-  return true;
+  return opt_result::success ();
 }
 
 /* Check whether we can use an internal function for a gather load
@@ -3948,7 +3975,7 @@ vect_check_gather_scatter (gimple *stmt, loop_vec_info loop_vinfo,
    append them to DATAREFS.  Return false if datarefs in this stmt cannot
    be handled.  */
 
-bool
+opt_result
 vect_find_stmt_data_reference (loop_p loop, gimple *stmt,
 			       vec<data_reference_p> *datarefs)
 {
@@ -3956,7 +3983,7 @@ vect_find_stmt_data_reference (loop_p loop, gimple *stmt,
      loop vectorization and BB vectorization checks dependences with a
      stmt walk.  */
   if (gimple_clobber_p (stmt))
-    return true;
+    return opt_result::success ();
 
   if (gimple_has_volatile_ops (stmt))
     {
@@ -3966,7 +3993,7 @@ vect_find_stmt_data_reference (loop_p loop, gimple *stmt,
 			   "not vectorized: volatile type ");
 	  dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM, stmt, 0);
 	}
-      return false;
+      return opt_result::failure ("volatile type", stmt);
     }
 
   if (stmt_can_throw_internal (stmt))
@@ -3978,15 +4005,17 @@ vect_find_stmt_data_reference (loop_p loop, gimple *stmt,
 			   "exception ");
 	  dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM, stmt, 0);
 	}
-      return false;
+      return opt_result::failure ("statement can throw an exception", stmt);
     }
 
   auto_vec<data_reference_p, 2> refs;
-  if (!find_data_references_in_stmt (loop, stmt, &refs))
-    return false;
+  opt_result res = find_data_references_in_stmt (loop, stmt, &refs);
+  if (!res)
+    // ^^^ it's failing in here
+    return res;
 
   if (refs.is_empty ())
-    return true;
+    return opt_result::success ();
 
   if (refs.length () > 1)
     {
@@ -3997,7 +4026,7 @@ vect_find_stmt_data_reference (loop_p loop, gimple *stmt,
 			   "in stmt: ");
 	  dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM, stmt, 0);
 	}
-      return false;
+      return opt_result::failure ("more than one data ref in statement", stmt);
     }
 
   if (gcall *call = dyn_cast <gcall *> (stmt))
@@ -4011,7 +4040,7 @@ vect_find_stmt_data_reference (loop_p loop, gimple *stmt,
 			     "not vectorized: dr in a call ");
 	    dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM, stmt, 0);
 	  }
-	return false;
+	return opt_result::failure ("dr in a call", stmt);
       }
 
   data_reference_p dr = refs.pop ();
@@ -4025,7 +4054,7 @@ vect_find_stmt_data_reference (loop_p loop, gimple *stmt,
 			   "access ");
 	  dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM, stmt, 0);
 	}
-      return false;
+	return opt_result::failure ("statement is bitfield access", stmt);
     }
 
   if (DR_BASE_ADDRESS (dr)
@@ -4035,7 +4064,7 @@ vect_find_stmt_data_reference (loop_p loop, gimple *stmt,
 	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 			 "not vectorized: base addr of dr is a "
 			 "constant\n");
-      return false;
+      return opt_result::failure ("base addr of dr is a constant", stmt);
     }
 
   /* Check whether this may be a SIMD lane access and adjust the
@@ -4093,7 +4122,7 @@ vect_find_stmt_data_reference (loop_p loop, gimple *stmt,
 			  newdr->aux = (void *)-1;
 			  free_data_ref (dr);
 			  datarefs->safe_push (newdr);
-			  return true;
+			  return opt_result::success ();
 			}
 		    }
 		}
@@ -4103,7 +4132,7 @@ vect_find_stmt_data_reference (loop_p loop, gimple *stmt,
     }
 
   datarefs->safe_push (dr);
-  return true;
+  return opt_result::success ();
 }
 
 /* Function vect_analyze_data_refs.
@@ -4121,7 +4150,7 @@ vect_find_stmt_data_reference (loop_p loop, gimple *stmt,
 
 */
 
-bool
+opt_result
 vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf)
 {
   struct loop *loop = NULL;
@@ -4194,7 +4223,7 @@ vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf)
 		  STMT_VINFO_VECTORIZABLE (stmt_info) = false;
 		  continue;
 		}
-	      return false;
+	      return opt_result::failure ("data ref analysis failed", stmt);
 	    }
         }
 
@@ -4210,7 +4239,7 @@ vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf)
 				   "failed ");
 		  dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM, stmt, 0);
 		}
-	      return false;
+	      return opt_result::failure ("data ref analysis failed", stmt);
 	    }
 	  STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) = true;
 	}
@@ -4232,7 +4261,8 @@ vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf)
 	      STMT_VINFO_VECTORIZABLE (stmt_info) = false;
 	      continue;
 	    }
-	  return false;
+	  return opt_result::failure ("base object not addressable for stmt",
+				      stmt);
 	}
 
       if (is_a <loop_vec_info> (vinfo)
@@ -4248,7 +4278,8 @@ vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf)
                                    "load ");
 		  dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM, stmt, 0);
 		}
-	      return false;
+	      return opt_result::failure ("not suitable for strided load",
+					  stmt);
 	    }
 	  STMT_VINFO_STRIDED_P (stmt_info) = true;
 	}
@@ -4283,10 +4314,12 @@ vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf)
 	      dump_printf (MSG_NOTE, "\n");
 	    }
 
-	  if (!dr_analyze_innermost (&STMT_VINFO_DR_WRT_VEC_LOOP (stmt_info),
-				     init_ref, loop))
+	  opt_result res
+	    = dr_analyze_innermost (&STMT_VINFO_DR_WRT_VEC_LOOP (stmt_info),
+				    init_ref, loop);
+	  if (!res)
 	    /* dr_analyze_innermost already explained the failure.  */
-	    return false;
+	    return res;
 
           if (dump_enabled_p ())
 	    {
@@ -4342,7 +4375,8 @@ vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf)
 	      STMT_VINFO_VECTORIZABLE (stmt_info) = false;
 	      continue;
 	    }
-	  return false;
+	  return opt_result::bad_type ("no vector type for stmt", stmt,
+				       scalar_type);
         }
       else
 	{
@@ -4379,7 +4413,10 @@ vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf)
 				   "store ");
 		  dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM, stmt, 0);
 		}
-	      return false;
+	      return opt_result::failure ((gatherscatter == GATHER) ?
+					  "not suitable for gather load" :
+					  "not suitable for scatter store",
+					  stmt);
 	    }
 	  STMT_VINFO_GATHER_SCATTER_P (stmt_info) = gatherscatter;
 	}
@@ -4389,7 +4426,7 @@ vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf)
      longer need to.  */
   gcc_assert (i == datarefs.length ());
 
-  return true;
+  return opt_result::success ();
 }
 
 
diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c
index acd1a8c..a3f1041 100644
--- a/gcc/tree-vect-loop.c
+++ b/gcc/tree-vect-loop.c
@@ -159,7 +159,7 @@ static void vect_estimate_min_profitable_iters (loop_vec_info, int *, int *);
    statement.  VECTYPE_MAYBE_SET_P is true if STMT_VINFO_VECTYPE
    may already be set for general statements (not just data refs).  */
 
-static bool
+static opt_result
 vect_determine_vf_for_stmt_1 (stmt_vec_info stmt_info,
 			      bool vectype_maybe_set_p,
 			      poly_uint64 *vf,
@@ -173,13 +173,14 @@ vect_determine_vf_for_stmt_1 (stmt_vec_info stmt_info,
     {
       if (dump_enabled_p ())
 	dump_printf_loc (MSG_NOTE, vect_location, "skip.\n");
-      return true;
+      return opt_result::success ();
     }
 
   tree stmt_vectype, nunits_vectype;
-  if (!vect_get_vector_types_for_stmt (stmt_info, &stmt_vectype,
-				       &nunits_vectype))
-    return false;
+  opt_result res = vect_get_vector_types_for_stmt (stmt_info, &stmt_vectype,
+						   &nunits_vectype);
+  if (!res)
+    return res;
 
   if (stmt_vectype)
     {
@@ -199,7 +200,7 @@ vect_determine_vf_for_stmt_1 (stmt_vec_info stmt_info,
   if (nunits_vectype)
     vect_update_max_nunits (vf, nunits_vectype);
 
-  return true;
+  return opt_result::success ();
 }
 
 /* Subroutine of vect_determine_vectorization_factor.  Set the vector
@@ -209,7 +210,7 @@ vect_determine_vf_for_stmt_1 (stmt_vec_info stmt_info,
    add them to MASK_PRODUCERS.  Return true on success or false if
    something prevented vectorization.  */
 
-static bool
+static opt_result
 vect_determine_vf_for_stmt (stmt_vec_info stmt_info, poly_uint64 *vf,
 			    vec<stmt_vec_info > *mask_producers)
 {
@@ -218,8 +219,10 @@ vect_determine_vf_for_stmt (stmt_vec_info stmt_info, poly_uint64 *vf,
       dump_printf_loc (MSG_NOTE, vect_location, "==> examining statement: ");
       dump_gimple_stmt (MSG_NOTE, TDF_SLIM, stmt_info->stmt, 0);
     }
-  if (!vect_determine_vf_for_stmt_1 (stmt_info, false, vf, mask_producers))
-    return false;
+  opt_result res
+    = vect_determine_vf_for_stmt_1 (stmt_info, false, vf, mask_producers);
+  if (!res)
+    return res;
 
   if (STMT_VINFO_IN_PATTERN_P (stmt_info)
       && STMT_VINFO_RELATED_STMT (stmt_info))
@@ -239,9 +242,10 @@ vect_determine_vf_for_stmt (stmt_vec_info stmt_info, poly_uint64 *vf,
 	      dump_gimple_stmt (MSG_NOTE, TDF_SLIM,
 				def_stmt_info->stmt, 0);
 	    }
-	  if (!vect_determine_vf_for_stmt_1 (def_stmt_info, true,
-					     vf, mask_producers))
-	    return false;
+	  res = vect_determine_vf_for_stmt_1 (def_stmt_info, true,
+					      vf, mask_producers);
+	  if (!res)
+	    return res;
 	}
 
       if (dump_enabled_p ())
@@ -250,11 +254,12 @@ vect_determine_vf_for_stmt (stmt_vec_info stmt_info, poly_uint64 *vf,
 			   "==> examining pattern statement: ");
 	  dump_gimple_stmt (MSG_NOTE, TDF_SLIM, stmt_info->stmt, 0);
 	}
-      if (!vect_determine_vf_for_stmt_1 (stmt_info, true, vf, mask_producers))
-	return false;
+      res = vect_determine_vf_for_stmt_1 (stmt_info, true, vf, mask_producers);
+      if (!res)
+	return res;
     }
 
-  return true;
+  return opt_result::success ();
 }
 
 /* Function vect_determine_vectorization_factor
@@ -282,7 +287,7 @@ vect_determine_vf_for_stmt (stmt_vec_info stmt_info, poly_uint64 *vf,
         }
 */
 
-static bool
+static opt_result
 vect_determine_vectorization_factor (loop_vec_info loop_vinfo)
 {
   struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
@@ -341,7 +346,8 @@ vect_determine_vectorization_factor (loop_vec_info loop_vinfo)
                                          scalar_type);
                       dump_printf (MSG_MISSED_OPTIMIZATION, "\n");
 		    }
-		  return false;
+		  return opt_result::bad_type ("unsupported data-type", phi,
+					       scalar_type);
 		}
 	      STMT_VINFO_VECTYPE (stmt_info) = vectype;
 
@@ -367,9 +373,11 @@ vect_determine_vectorization_factor (loop_vec_info loop_vinfo)
 	   gsi_next (&si))
 	{
 	  stmt_info = vinfo_for_stmt (gsi_stmt (si));
-	  if (!vect_determine_vf_for_stmt (stmt_info, &vectorization_factor,
-					   &mask_producers))
-	    return false;
+	  opt_result res
+	    = vect_determine_vf_for_stmt (stmt_info, &vectorization_factor,
+					  &mask_producers);
+	  if (!res)
+	    return res;
         }
     }
 
@@ -386,7 +394,7 @@ vect_determine_vectorization_factor (loop_vec_info loop_vinfo)
       if (dump_enabled_p ())
         dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
                          "not vectorized: unsupported data-type\n");
-      return false;
+      return opt_result::failure ("unsupported data-type", NULL);
     }
   LOOP_VINFO_VECT_FACTOR (loop_vinfo) = vectorization_factor;
 
@@ -399,7 +407,7 @@ vect_determine_vectorization_factor (loop_vec_info loop_vinfo)
       STMT_VINFO_VECTYPE (stmt_info) = mask_type;
     }
 
-  return true;
+  return opt_result::success ();
 }
 
 
@@ -1159,7 +1167,7 @@ vect_compute_single_scalar_iteration_cost (loop_vec_info loop_vinfo)
    - the number of iterations can be analyzed, i.e, a countable loop.  The
      niter could be analyzed under some assumptions.  */
 
-bool
+opt_result
 vect_analyze_loop_form_1 (struct loop *loop, gcond **loop_cond,
 			  tree *assumptions, tree *number_of_iterationsm1,
 			  tree *number_of_iterations, gcond **inner_loop_cond)
@@ -1189,7 +1197,7 @@ vect_analyze_loop_form_1 (struct loop *loop, gcond **loop_cond,
           if (dump_enabled_p ())
             dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 			     "not vectorized: control flow in loop.\n");
-          return false;
+          return opt_result::failure ("control flow in loop", NULL);
         }
 
       if (empty_block_p (loop->header))
@@ -1197,7 +1205,7 @@ vect_analyze_loop_form_1 (struct loop *loop, gcond **loop_cond,
 	  if (dump_enabled_p ())
 	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 			     "not vectorized: empty loop.\n");
-	  return false;
+          return opt_result::failure ("empty loop", NULL);
 	}
     }
   else
@@ -1227,7 +1235,7 @@ vect_analyze_loop_form_1 (struct loop *loop, gcond **loop_cond,
 	  if (dump_enabled_p ())
 	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 			     "not vectorized: multiple nested loops.\n");
-	  return false;
+          return opt_result::failure ("multiple nested loops", NULL);
 	}
 
       if (loop->num_nodes != 5)
@@ -1235,7 +1243,7 @@ vect_analyze_loop_form_1 (struct loop *loop, gcond **loop_cond,
 	  if (dump_enabled_p ())
 	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 			     "not vectorized: control flow in loop.\n");
-	  return false;
+          return opt_result::failure ("control flow in loop", NULL);
         }
 
       entryedge = loop_preheader_edge (innerloop);
@@ -1246,7 +1254,7 @@ vect_analyze_loop_form_1 (struct loop *loop, gcond **loop_cond,
 	  if (dump_enabled_p ())
 	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 			     "not vectorized: unsupported outerloop form.\n");
-	  return false;
+          return opt_result::failure ("unsupported outerloop form", NULL);
 	}
 
       /* Analyze the inner-loop.  */
@@ -1303,7 +1311,7 @@ vect_analyze_loop_form_1 (struct loop *loop, gcond **loop_cond,
       if (dump_enabled_p ())
 	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 			 "not vectorized: latch block not empty.\n");
-      return false;
+      return opt_result::failure ("latch block not empty", NULL);
     }
 
   /* Make sure the exit is not abnormal.  */
@@ -1313,7 +1321,7 @@ vect_analyze_loop_form_1 (struct loop *loop, gcond **loop_cond,
       if (dump_enabled_p ())
 	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 			 "not vectorized: abnormal loop exit edge.\n");
-      return false;
+      return opt_result::failure ("abnormal loop exit edge", NULL);
     }
 
   *loop_cond = vect_get_loop_niters (loop, assumptions, number_of_iterations,
@@ -1323,7 +1331,7 @@ vect_analyze_loop_form_1 (struct loop *loop, gcond **loop_cond,
       if (dump_enabled_p ())
 	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 			 "not vectorized: complicated exit condition.\n");
-      return false;
+      return opt_result::failure ("complicated exit condition", NULL);
     }
 
   if (integer_zerop (*assumptions)
@@ -1334,7 +1342,8 @@ vect_analyze_loop_form_1 (struct loop *loop, gcond **loop_cond,
 	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 			 "not vectorized: number of iterations cannot be "
 			 "computed.\n");
-      return false;
+      return opt_result::failure ("number of iterations cannot be computed",
+				  NULL);
     }
 
   if (integer_zerop (*number_of_iterations))
@@ -1342,24 +1351,26 @@ vect_analyze_loop_form_1 (struct loop *loop, gcond **loop_cond,
       if (dump_enabled_p ())
 	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 			 "not vectorized: number of iterations = 0.\n");
-      return false;
+      return opt_result::failure ("number of iterations = 0", NULL);
     }
 
-  return true;
+  return opt_result::success ();
 }
 
 /* Analyze LOOP form and return a loop_vec_info if it is of suitable form.  */
 
-loop_vec_info
+opt_loop_vec_info
 vect_analyze_loop_form (struct loop *loop, vec_info_shared *shared)
 {
   tree assumptions, number_of_iterations, number_of_iterationsm1;
   gcond *loop_cond, *inner_loop_cond = NULL;
 
-  if (! vect_analyze_loop_form_1 (loop, &loop_cond,
-				  &assumptions, &number_of_iterationsm1,
-				  &number_of_iterations, &inner_loop_cond))
-    return NULL;
+  opt_result res
+    = vect_analyze_loop_form_1 (loop, &loop_cond,
+				&assumptions, &number_of_iterationsm1,
+				&number_of_iterations, &inner_loop_cond);
+  if (!res)
+    return opt_loop_vec_info::failure (res);
 
   loop_vec_info loop_vinfo = new _loop_vec_info (loop, shared);
   LOOP_VINFO_NITERSM1 (loop_vinfo) = number_of_iterationsm1;
@@ -1397,7 +1408,7 @@ vect_analyze_loop_form (struct loop *loop, vec_info_shared *shared)
 
   gcc_assert (!loop->aux);
   loop->aux = loop_vinfo;
-  return loop_vinfo;
+  return opt_loop_vec_info::success (loop_vinfo);
 }
 
 
@@ -1506,7 +1517,7 @@ vect_active_double_reduction_p (stmt_vec_info stmt_info)
 
    Scan the loop stmts and make sure they are all vectorizable.  */
 
-static bool
+static opt_result
 vect_analyze_loop_operations (loop_vec_info loop_vinfo)
 {
   struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
@@ -1556,7 +1567,8 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo)
 		    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 				     "Unsupported loop-closed phi in "
 				     "outer-loop.\n");
-                  return false;
+                  return opt_result::failure ("Unsupported loop-closed phi in "
+					      "outer-loop", phi);
                 }
 
               /* If PHI is used in the outer loop, we check that its operand
@@ -1567,23 +1579,23 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo)
 		  gimple *op_def_stmt;
 
                   if (gimple_phi_num_args (phi) != 1)
-                    return false;
+                    return opt_result::failure ("unsupported phi", phi);
 
                   phi_op = PHI_ARG_DEF (phi, 0);
                   if (TREE_CODE (phi_op) != SSA_NAME)
-                    return false;
+		    return opt_result::failure ("unsupported phi", phi);
 
                   op_def_stmt = SSA_NAME_DEF_STMT (phi_op);
 		  if (gimple_nop_p (op_def_stmt)
 		      || !flow_bb_inside_loop_p (loop, gimple_bb (op_def_stmt))
 		      || !vinfo_for_stmt (op_def_stmt))
-                    return false;
+                    return opt_result::failure ("unsupported phi", phi);
 
                   if (STMT_VINFO_RELEVANT (vinfo_for_stmt (op_def_stmt))
                         != vect_used_in_outer
                       && STMT_VINFO_RELEVANT (vinfo_for_stmt (op_def_stmt))
                            != vect_used_in_outer_by_reduction)
-                    return false;
+		    return opt_result::failure ("unsupported phi", phi);
                 }
 
               continue;
@@ -1599,7 +1611,7 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo)
               if (dump_enabled_p ())
 		dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 				 "not vectorized: scalar dependence cycle.\n");
-              return false;
+              return opt_result::failure ("scalar dependence cycle", phi);
             }
 
           if (STMT_VINFO_RELEVANT_P (stmt_info))
@@ -1639,10 +1651,14 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo)
 	   gsi_next (&si))
         {
 	  gimple *stmt = gsi_stmt (si);
-	  if (!gimple_clobber_p (stmt)
-	      && !vect_analyze_stmt (stmt, &need_to_vectorize, NULL, NULL,
-				     &cost_vec))
-	    return false;
+	  if (!gimple_clobber_p (stmt))
+	    {
+	      opt_result res
+		= vect_analyze_stmt (stmt, &need_to_vectorize, NULL, NULL,
+				     &cost_vec);
+	      if (!res)
+		return res;
+	    }
         }
     } /* bbs */
 
@@ -1663,10 +1679,11 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo)
 	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 			 "not vectorized: redundant loop. no profit to "
 			 "vectorize.\n");
-      return false;
+      return opt_result::failure ("redundant loop. no profit to vectorize",
+				  NULL);
     }
 
-  return true;
+  return opt_result::success ();
 }
 
 /* Analyze the cost of the loop described by LOOP_VINFO.  Decide if it
@@ -1764,7 +1781,7 @@ vect_analyze_loop_costing (loop_vec_info loop_vinfo)
   return 1;
 }
 
-static bool
+static opt_result
 vect_get_datarefs_in_loop (loop_p loop, basic_block *bbs,
 			   vec<data_reference_p> *datarefs,
 			   unsigned int *n_stmts)
@@ -1778,7 +1795,8 @@ vect_get_datarefs_in_loop (loop_p loop, basic_block *bbs,
 	if (is_gimple_debug (stmt))
 	  continue;
 	++(*n_stmts);
-	if (!vect_find_stmt_data_reference (loop, stmt, datarefs))
+	opt_result res = vect_find_stmt_data_reference (loop, stmt, datarefs);
+	if (!res)
 	  {
 	    if (is_gimple_call (stmt) && loop->safelen)
 	      {
@@ -1786,7 +1804,14 @@ vect_get_datarefs_in_loop (loop_p loop, basic_block *bbs,
 		if (fndecl != NULL_TREE)
 		  {
 		    cgraph_node *node = cgraph_node::get (fndecl);
-		    if (node != NULL && node->simd_clones != NULL)
+		    if (node == NULL)
+		      {
+			// FIXME: should we return something else?
+			return res;
+			//push_vect_problem ("FIXME 1", stmt);
+			//return false;
+		      }
+		    if (node->simd_clones != NULL)
 		      {
 			unsigned int j, n = gimple_call_num_args (stmt);
 			for (j = 0; j < n; j++)
@@ -1810,15 +1835,18 @@ vect_get_datarefs_in_loop (loop_p loop, basic_block *bbs,
 		      }
 		  }
 	      }
-	    return false;
+	    return res;
+	    //push_vect_problem ("FIXME 2", stmt);
+	    //return false;
 	  }
 	/* If dependence analysis will give up due to the limit on the
 	   number of datarefs stop here and fail fatally.  */
 	if (datarefs->length ()
 	    > (unsigned)PARAM_VALUE (PARAM_LOOP_MAX_DATAREFS_FOR_DATADEPS))
-	  return false;
+	  return opt_result::failure ("exceeded param "
+				      "loop-max-datarefs-for-datadeps", stmt);
       }
-  return true;
+  return opt_result::success ();
 }
 
 /* Function vect_analyze_loop_2.
@@ -1826,10 +1854,10 @@ vect_get_datarefs_in_loop (loop_p loop, basic_block *bbs,
    Apply a set of analyses on LOOP, and create a loop_vec_info struct
    for it.  The different analyses will record information in the
    loop_vec_info struct.  */
-static bool
+static opt_result
 vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
 {
-  bool ok;
+  opt_result ok = opt_result::success ();
   int res;
   unsigned int max_vf = MAX_VECTORIZATION_FACTOR;
   poly_uint64 min_vf = 2;
@@ -1845,16 +1873,19 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
   /* Gather the data references and count stmts in the loop.  */
   if (!LOOP_VINFO_DATAREFS (loop_vinfo).exists ())
     {
-      if (!vect_get_datarefs_in_loop (loop, LOOP_VINFO_BBS (loop_vinfo),
-				      &LOOP_VINFO_DATAREFS (loop_vinfo),
-				      n_stmts))
+      opt_result res
+	= vect_get_datarefs_in_loop (loop, LOOP_VINFO_BBS (loop_vinfo),
+				     &LOOP_VINFO_DATAREFS (loop_vinfo),
+				     n_stmts);
+      if (!res)
 	{
+	  // FIXME: something in here: ^
 	  if (dump_enabled_p ())
 	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 			     "not vectorized: loop contains function "
 			     "calls or data references that cannot "
 			     "be analyzed\n");
-	  return false;
+	  return res;
 	}
       loop_vinfo->shared->save_datarefs ();
     }
@@ -1870,7 +1901,7 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
       if (dump_enabled_p ())
 	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 			 "bad data references.\n");
-      return false;
+      return ok;
     }
 
   /* Classify all cross-iteration scalar data-flow cycles.
@@ -1890,7 +1921,7 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
       if (dump_enabled_p ())
 	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 			 "bad data access.\n");
-      return false;
+      return ok;
     }
 
   /* Data-flow analysis to detect stmts that do not need to be vectorized.  */
@@ -1901,7 +1932,7 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
       if (dump_enabled_p ())
 	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 			 "unexpected pattern.\n");
-      return false;
+      return ok;
     }
 
   /* While the rest of the analysis below depends on it in some way.  */
@@ -1920,7 +1951,7 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
       if (dump_enabled_p ())
 	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 			     "bad data dependence.\n");
-      return false;
+      return ok;
     }
   LOOP_VINFO_MAX_VECT_FACTOR (loop_vinfo) = max_vf;
 
@@ -1930,7 +1961,7 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
       if (dump_enabled_p ())
 	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 			 "can't determine vectorization factor.\n");
-      return false;
+      return ok;
     }
   if (max_vf != MAX_VECTORIZATION_FACTOR
       && maybe_lt (max_vf, LOOP_VINFO_VECT_FACTOR (loop_vinfo)))
@@ -1938,7 +1969,7 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
       if (dump_enabled_p ())
 	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 			 "bad data dependence.\n");
-      return false;
+      return ok;
     }
 
   /* Compute the scalar iteration cost.  */
@@ -1950,7 +1981,7 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
   /* Check the SLP opportunities in the loop, analyze and build SLP trees.  */
   ok = vect_analyze_slp (loop_vinfo, *n_stmts);
   if (!ok)
-    return false;
+    return ok;
 
   /* If there are any SLP instances mark them as pure_slp.  */
   bool slp = vect_make_slp_decision (loop_vinfo);
@@ -1997,7 +2028,7 @@ start_over:
       if (dump_enabled_p ())
 	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 			 "bad data alignment.\n");
-      return false;
+      return ok;
     }
 
   /* Prune the list of ddrs to be tested at run-time by versioning for alias.
@@ -2005,7 +2036,7 @@ start_over:
      since we use grouping information gathered by interleaving analysis.  */
   ok = vect_prune_runtime_alias_test_list (loop_vinfo);
   if (!ok)
-    return false;
+    return ok;
 
   /* Do not invoke vect_enhance_data_refs_alignment for eplilogue
      vectorization.  */
@@ -2019,7 +2050,7 @@ start_over:
 	if (dump_enabled_p ())
 	  dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 			   "bad data alignment.\n");
-        return false;
+        return ok;
       }
     }
 
@@ -2042,7 +2073,7 @@ start_over:
       if (dump_enabled_p ())
 	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 			 "bad operation or unsupported loop bound.\n");
-      return false;
+      return ok;
     }
 
   /* Decide whether to use a fully-masked loop for this vectorization
@@ -2076,7 +2107,8 @@ start_over:
 	    dump_printf_loc (MSG_NOTE, vect_location,
 			     "loop has no enough iterations to support"
 			     " peeling for gaps.\n");
-	  return false;
+	  return opt_result::failure ("loop has not enough iterations to"
+				      " support peeling for gaps", NULL);
 	}
     }
 
@@ -2089,7 +2121,7 @@ start_over:
       if (dump_enabled_p ())
 	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 			 "Loop costings not worthwhile.\n");
-      return false;
+      return opt_result::failure ("Loop costings not worthwhile", NULL);
     }
 
   /* Decide whether we need to create an epilogue loop to handle
@@ -2174,7 +2206,7 @@ start_over:
 			LOOP_VINFO_VECT_FACTOR (loop_vinfo)));
 
   /* Ok to vectorize!  */
-  return true;
+  return opt_result::success ();
 
 again:
   /* Try again with SLP forced off but if we didn't do any SLP there is
@@ -2286,11 +2318,10 @@ again:
    for it.  The different analyses will record information in the
    loop_vec_info struct.  If ORIG_LOOP_VINFO is not NULL epilogue must
    be vectorized.  */
-loop_vec_info
+opt_loop_vec_info
 vect_analyze_loop (struct loop *loop, loop_vec_info orig_loop_vinfo,
 		   vec_info_shared *shared)
 {
-  loop_vec_info loop_vinfo;
   auto_vector_sizes vector_sizes;
 
   /* Autodetect first vector size we try.  */
@@ -2307,7 +2338,7 @@ vect_analyze_loop (struct loop *loop, loop_vec_info orig_loop_vinfo,
       if (dump_enabled_p ())
 	dump_printf_loc (MSG_NOTE, vect_location,
 			 "outer-loop already vectorized.\n");
-      return NULL;
+      return opt_loop_vec_info::failure ("outer-loop already vectorized");
     }
 
   if (!find_loop_nest (loop, &shared->loop_nest))
@@ -2317,7 +2348,9 @@ vect_analyze_loop (struct loop *loop, loop_vec_info orig_loop_vinfo,
 			 "not vectorized: loop nest containing two "
 			 "or more consecutive inner loops cannot be "
 			 "vectorized\n");
-      return NULL;
+      return opt_loop_vec_info::failure ("loop nest containing two "
+					 "or more consecutive inner loops"
+					 " cannot be vectorized");
     }
 
   unsigned n_stmts = 0;
@@ -2325,13 +2358,14 @@ vect_analyze_loop (struct loop *loop, loop_vec_info orig_loop_vinfo,
   while (1)
     {
       /* Check the CFG characteristics of the loop (nesting, entry/exit).  */
-      loop_vinfo = vect_analyze_loop_form (loop, shared);
+      opt_loop_vec_info loop_vinfo
+	= vect_analyze_loop_form (loop, shared);
       if (!loop_vinfo)
 	{
 	  if (dump_enabled_p ())
 	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 			     "bad loop form.\n");
-	  return NULL;
+	  return loop_vinfo;
 	}
 
       bool fatal = false;
@@ -2339,13 +2373,17 @@ vect_analyze_loop (struct loop *loop, loop_vec_info orig_loop_vinfo,
       if (orig_loop_vinfo)
 	LOOP_VINFO_ORIG_LOOP_INFO (loop_vinfo) = orig_loop_vinfo;
 
-      if (vect_analyze_loop_2 (loop_vinfo, fatal, &n_stmts))
+      opt_result res = vect_analyze_loop_2 (loop_vinfo, fatal, &n_stmts);
+      if (res)
 	{
 	  LOOP_VINFO_VECTORIZABLE_P (loop_vinfo) = 1;
 
 	  return loop_vinfo;
 	}
 
+      /* FIXME: res is false i.e. a failure, but we're throwing away the
+	 problem information here.  */
+
       delete loop_vinfo;
 
       if (next_size == 0)
@@ -2358,7 +2396,7 @@ vect_analyze_loop (struct loop *loop, loop_vec_info orig_loop_vinfo,
       if (fatal
 	  || next_size == vector_sizes.length ()
 	  || known_eq (current_vector_size, 0U))
-	return NULL;
+	return opt_loop_vec_info::failure (res);
 
       /* Try the next biggest vector size.  */
       current_vector_size = vector_sizes[next_size++];
diff --git a/gcc/tree-vect-slp.c b/gcc/tree-vect-slp.c
index 528e1d5..984f44b 100644
--- a/gcc/tree-vect-slp.c
+++ b/gcc/tree-vect-slp.c
@@ -2169,7 +2169,7 @@ vect_analyze_slp_instance (vec_info *vinfo,
 /* Check if there are stmts in the loop can be vectorized using SLP.  Build SLP
    trees of packed scalar stmts if SLP is possible.  */
 
-bool
+opt_result
 vect_analyze_slp (vec_info *vinfo, unsigned max_tree_size)
 {
   unsigned int i;
@@ -2211,7 +2211,7 @@ vect_analyze_slp (vec_info *vinfo, unsigned max_tree_size)
 				   max_tree_size);
     }
 
-  return true;
+  return opt_result::success ();
 }
 
 
diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c
index ea303bd..53a0788 100644
--- a/gcc/tree-vect-stmts.c
+++ b/gcc/tree-vect-stmts.c
@@ -454,7 +454,7 @@ exist_non_indexing_operands_for_use_p (tree use, gimple *stmt)
 
    Return true if everything is as expected. Return false otherwise.  */
 
-static bool
+static opt_result
 process_use (gimple *stmt, tree use, loop_vec_info loop_vinfo,
 	     enum vect_relevant relevant, vec<gimple *> *worklist,
 	     bool force)
@@ -469,25 +469,26 @@ process_use (gimple *stmt, tree use, loop_vec_info loop_vinfo,
   /* case 1: we are only interested in uses that need to be vectorized.  Uses
      that are used for address computation are not considered relevant.  */
   if (!force && !exist_non_indexing_operands_for_use_p (use, stmt))
-     return true;
+    return opt_result::success ();
 
   if (!vect_is_simple_use (use, loop_vinfo, &dt, &def_stmt))
     {
       if (dump_enabled_p ())
         dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
                          "not vectorized: unsupported use in stmt.\n");
-      return false;
+      // FIXME: have this come from vect_is_simple_use?
+      return opt_result::failure ("unsupported use in stmt", stmt);
     }
 
   if (!def_stmt || gimple_nop_p (def_stmt))
-    return true;
+    return opt_result::success ();
 
   def_bb = gimple_bb (def_stmt);
   if (!flow_bb_inside_loop_p (loop, def_bb))
     {
       if (dump_enabled_p ())
 	dump_printf_loc (MSG_NOTE, vect_location, "def_stmt is out of loop.\n");
-      return true;
+      return opt_result::success ();
     }
 
   /* case 2: A reduction phi (STMT) defined by a reduction stmt (DEF_STMT).
@@ -509,7 +510,7 @@ process_use (gimple *stmt, tree use, loop_vec_info loop_vinfo,
       gcc_assert (STMT_VINFO_RELEVANT (dstmt_vinfo) < vect_used_by_reduction);
       gcc_assert (STMT_VINFO_LIVE_P (dstmt_vinfo)
 		  || STMT_VINFO_RELEVANT (dstmt_vinfo) > vect_unused_in_scope);
-      return true;
+      return opt_result::success ();
     }
 
   /* case 3a: outer-loop stmt defining an inner-loop stmt:
@@ -597,12 +598,12 @@ process_use (gimple *stmt, tree use, loop_vec_info loop_vinfo,
       if (dump_enabled_p ())
 	dump_printf_loc (MSG_NOTE, vect_location,
                          "induction value on backedge.\n");
-      return true;
+      return opt_result::success ();
     }
 
 
   vect_mark_relevant (worklist, def_stmt, relevant, false);
-  return true;
+  return opt_result::success ();
 }
 
 
@@ -622,7 +623,7 @@ process_use (gimple *stmt, tree use, loop_vec_info loop_vinfo,
 
    This pass detects such stmts.  */
 
-bool
+opt_result
 vect_mark_stmts_to_be_vectorized (loop_vec_info loop_vinfo)
 {
   struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
@@ -713,7 +714,8 @@ vect_mark_stmts_to_be_vectorized (loop_vec_info loop_vinfo)
 		if (dump_enabled_p ())
 		  dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 				   "unsupported use of reduction.\n");
-		return false;
+		return opt_result::failure ("unsupported use of reduction",
+					    stmt);
 	      }
 	    break;
 
@@ -725,8 +727,8 @@ vect_mark_stmts_to_be_vectorized (loop_vec_info loop_vinfo)
                 if (dump_enabled_p ())
                   dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
                                    "unsupported use of nested cycle.\n");
-
-                return false;
+		return opt_result::failure ("unsupported use of nested cycle",
+					    stmt);
               }
             break;
 
@@ -738,8 +740,8 @@ vect_mark_stmts_to_be_vectorized (loop_vec_info loop_vinfo)
                 if (dump_enabled_p ())
                   dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
                                    "unsupported use of double reduction.\n");
-
-                return false;
+		return opt_result::failure ("unsupported use of double"
+					    " reduction", stmt);
               }
             break;
 
@@ -760,20 +762,28 @@ vect_mark_stmts_to_be_vectorized (loop_vec_info loop_vinfo)
 	      i = 1;
 	      if (rhs_code == COND_EXPR && COMPARISON_CLASS_P (op))
 		{
-		  if (!process_use (stmt, TREE_OPERAND (op, 0), loop_vinfo,
-				    relevant, &worklist, false)
-		      || !process_use (stmt, TREE_OPERAND (op, 1), loop_vinfo,
-				       relevant, &worklist, false))
-		    return false;
+		  opt_result res
+		    = process_use (stmt, TREE_OPERAND (op, 0), loop_vinfo,
+				   relevant, &worklist, false);
+		  if (!res)
+		    return res;
+		  res = process_use (stmt, TREE_OPERAND (op, 1), loop_vinfo,
+				     relevant, &worklist, false);
+		  if (!res)
+		    return res;
 		  i = 2;
 		}
 	      for (; i < gimple_num_ops (stmt); i++)
                 {
 		  op = gimple_op (stmt, i);
-                  if (TREE_CODE (op) == SSA_NAME
-		      && !process_use (stmt, op, loop_vinfo, relevant,
-				       &worklist, false))
-                    return false;
+                  if (TREE_CODE (op) == SSA_NAME)
+		    {
+		      opt_result res
+			= process_use (stmt, op, loop_vinfo, relevant,
+				       &worklist, false);
+		      if (!res)
+			return res;
+		    }
                  }
             }
           else if (is_gimple_call (stmt))
@@ -781,9 +791,11 @@ vect_mark_stmts_to_be_vectorized (loop_vec_info loop_vinfo)
               for (i = 0; i < gimple_call_num_args (stmt); i++)
                 {
                   tree arg = gimple_call_arg (stmt, i);
-		  if (!process_use (stmt, arg, loop_vinfo, relevant,
-				    &worklist, false))
-                    return false;
+		  opt_result res
+		    = process_use (stmt, arg, loop_vinfo, relevant,
+				   &worklist, false);
+		  if (!res)
+		    return res;
                 }
             }
         }
@@ -791,9 +803,11 @@ vect_mark_stmts_to_be_vectorized (loop_vec_info loop_vinfo)
         FOR_EACH_PHI_OR_STMT_USE (use_p, stmt, iter, SSA_OP_USE)
           {
             tree op = USE_FROM_PTR (use_p);
-	    if (!process_use (stmt, op, loop_vinfo, relevant,
-			      &worklist, false))
-              return false;
+	    opt_result res
+	      = process_use (stmt, op, loop_vinfo, relevant,
+			     &worklist, false);
+	    if (!res)
+	      return res;
           }
 
       if (STMT_VINFO_GATHER_SCATTER_P (stmt_vinfo))
@@ -801,13 +815,15 @@ vect_mark_stmts_to_be_vectorized (loop_vec_info loop_vinfo)
 	  gather_scatter_info gs_info;
 	  if (!vect_check_gather_scatter (stmt, loop_vinfo, &gs_info))
 	    gcc_unreachable ();
-	  if (!process_use (stmt, gs_info.offset, loop_vinfo, relevant,
-			    &worklist, true))
-	    return false;
+	  opt_result res
+	    = process_use (stmt, gs_info.offset, loop_vinfo, relevant,
+			   &worklist, true);
+	  if (!res)
+	    return res;
 	}
     } /* while worklist */
 
-  return true;
+  return opt_result::success ();
 }
 
 /* Compute the prologue cost for invariant or constant operands.  */
@@ -9335,7 +9351,7 @@ can_vectorize_live_stmts (gimple *stmt, gimple_stmt_iterator *gsi,
 
 /* Make sure the statement is vectorizable.  */
 
-bool
+opt_result
 vect_analyze_stmt (gimple *stmt, bool *need_to_vectorize, slp_tree node,
 		   slp_instance node_instance, stmt_vector_for_cost *cost_vec)
 {
@@ -9358,7 +9374,7 @@ vect_analyze_stmt (gimple *stmt, bool *need_to_vectorize, slp_tree node,
         dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
                          "not vectorized: stmt has volatile operands\n");
 
-      return false;
+      return opt_result::failure ("stmt has volatile operands", stmt);
     }
 
   if (STMT_VINFO_IN_PATTERN_P (stmt_info)
@@ -9381,10 +9397,12 @@ vect_analyze_stmt (gimple *stmt, bool *need_to_vectorize, slp_tree node,
 		  dump_gimple_stmt (MSG_NOTE, TDF_SLIM, pattern_def_stmt, 0);
 		}
 
-	      if (!vect_analyze_stmt (pattern_def_stmt,
-				      need_to_vectorize, node, node_instance,
-				      cost_vec))
-		return false;
+	      opt_result res
+		= vect_analyze_stmt (pattern_def_stmt,
+				     need_to_vectorize, node, node_instance,
+				     cost_vec);
+	      if (!res)
+		return res;
 	    }
 	}
     }
@@ -9427,7 +9445,7 @@ vect_analyze_stmt (gimple *stmt, bool *need_to_vectorize, slp_tree node,
           if (dump_enabled_p ())
             dump_printf_loc (MSG_NOTE, vect_location, "irrelevant.\n");
 
-          return true;
+          return opt_result::success ();
         }
     }
   else if (STMT_VINFO_IN_PATTERN_P (stmt_info)
@@ -9444,9 +9462,11 @@ vect_analyze_stmt (gimple *stmt, bool *need_to_vectorize, slp_tree node,
           dump_gimple_stmt (MSG_NOTE, TDF_SLIM, stmt, 0);
         }
 
-      if (!vect_analyze_stmt (pattern_stmt, need_to_vectorize, node,
-			      node_instance, cost_vec))
-        return false;
+      opt_result res
+	= vect_analyze_stmt (pattern_stmt, need_to_vectorize, node,
+			     node_instance, cost_vec);
+      if (!res)
+	return res;
    }
 
   switch (STMT_VINFO_DEF_TYPE (stmt_info))
@@ -9488,7 +9508,7 @@ vect_analyze_stmt (gimple *stmt, bool *need_to_vectorize, slp_tree node,
     {
       dump_printf_loc (MSG_NOTE, vect_location,
 		       "handled only by SLP analysis\n");
-      return true;
+      return opt_result::success ();
     }
 
   ok = true;
@@ -9536,7 +9556,7 @@ vect_analyze_stmt (gimple *stmt, bool *need_to_vectorize, slp_tree node,
           dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM, stmt, 0);
         }
 
-      return false;
+      return opt_result::failure ("relevant stmt not supported", stmt);
     }
 
   /* Stmts that are (also) "live" (i.e. - that are used out of the loop)
@@ -9552,10 +9572,10 @@ vect_analyze_stmt (gimple *stmt, bool *need_to_vectorize, slp_tree node,
           dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM, stmt, 0);
         }
 
-       return false;
+      return opt_result::failure ("live stmt not supported", stmt);
     }
 
-  return true;
+  return opt_result::success ();
 }
 
 
@@ -10622,7 +10642,7 @@ vect_gen_while_not (gimple_seq *seq, tree mask_type, tree start_index,
      number of units needed to vectorize STMT_INFO, or NULL_TREE if the
      statement does not help to determine the overall number of units.  */
 
-bool
+opt_result
 vect_get_vector_types_for_stmt (stmt_vec_info stmt_info,
 				tree *stmt_vectype_out,
 				tree *nunits_vectype_out)
@@ -10645,7 +10665,7 @@ vect_get_vector_types_for_stmt (stmt_vec_info stmt_info,
 	  if (dump_enabled_p ())
 	    dump_printf_loc (MSG_NOTE, vect_location,
 			     "defer to SIMD clone analysis.\n");
-	  return true;
+	  return opt_result::success ();
 	}
 
       if (dump_enabled_p ())
@@ -10654,7 +10674,7 @@ vect_get_vector_types_for_stmt (stmt_vec_info stmt_info,
 			   "not vectorized: irregular stmt.");
 	  dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM, stmt, 0);
 	}
-      return false;
+      return opt_result::failure ("irregular stmt", stmt);
     }
 
   if (VECTOR_MODE_P (TYPE_MODE (gimple_expr_type (stmt))))
@@ -10665,7 +10685,7 @@ vect_get_vector_types_for_stmt (stmt_vec_info stmt_info,
 			   "not vectorized: vector stmt in loop:");
 	  dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM, stmt, 0);
 	}
-      return false;
+      return opt_result::failure ("vector stmt in loop", stmt);
     }
 
   tree vectype;
@@ -10697,7 +10717,7 @@ vect_get_vector_types_for_stmt (stmt_vec_info stmt_info,
 	      if (dump_enabled_p ())
 		dump_printf_loc (MSG_NOTE, vect_location,
 				 "pure bool operation.\n");
-	      return true;
+	      return opt_result::success ();
 	    }
 	}
 
@@ -10782,7 +10802,9 @@ vect_get_vector_types_for_stmt (stmt_vec_info stmt_info,
 	  dump_generic_expr (MSG_MISSED_OPTIMIZATION, TDF_SLIM, nunits_vectype);
 	  dump_printf (MSG_MISSED_OPTIMIZATION, "\n");
 	}
-      return false;
+      // FIXME: capture the types
+      return opt_result::failure ("different sized vector"
+				  " types in statement", NULL);
     }
 
   if (dump_enabled_p ())
@@ -10797,7 +10819,7 @@ vect_get_vector_types_for_stmt (stmt_vec_info stmt_info,
     }
 
   *nunits_vectype_out = nunits_vectype;
-  return true;
+  return opt_result::success ();
 }
 
 /* Try to determine the correct vector type for STMT_INFO, which is a
diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h
index 81b64c6..4673764 100644
--- a/gcc/tree-vectorizer.h
+++ b/gcc/tree-vectorizer.h
@@ -1517,7 +1517,7 @@ extern unsigned record_stmt_cost (stmt_vector_for_cost *, int,
 extern void vect_finish_replace_stmt (gimple *, gimple *);
 extern void vect_finish_stmt_generation (gimple *, gimple *,
                                          gimple_stmt_iterator *);
-extern bool vect_mark_stmts_to_be_vectorized (loop_vec_info);
+extern opt_result vect_mark_stmts_to_be_vectorized (loop_vec_info);
 extern tree vect_get_store_rhs (gimple *);
 extern tree vect_get_vec_def_for_operand_1 (gimple *, enum vect_def_type);
 extern tree vect_get_vec_def_for_operand (tree, gimple *, tree = NULL);
@@ -1531,7 +1531,7 @@ extern tree vect_get_vec_def_for_stmt_copy (enum vect_def_type, tree);
 extern bool vect_transform_stmt (gimple *, gimple_stmt_iterator *,
                                  bool *, slp_tree, slp_instance);
 extern void vect_remove_stores (gimple *);
-extern bool vect_analyze_stmt (gimple *, bool *, slp_tree, slp_instance,
+extern opt_result vect_analyze_stmt (gimple *, bool *, slp_tree, slp_instance,
 			       stmt_vector_for_cost *);
 extern bool vectorizable_condition (gimple *, gimple_stmt_iterator *,
 				    gimple **, tree, int, slp_tree,
@@ -1548,7 +1548,8 @@ extern tree vect_gen_perm_mask_checked (tree, const vec_perm_indices &);
 extern void optimize_mask_stores (struct loop*);
 extern gcall *vect_gen_while (tree, tree, tree);
 extern tree vect_gen_while_not (gimple_seq *, tree, tree, tree);
-extern bool vect_get_vector_types_for_stmt (stmt_vec_info, tree *, tree *);
+extern opt_result vect_get_vector_types_for_stmt (stmt_vec_info, tree *,
+						  tree *);
 extern tree vect_get_mask_type_for_stmt (stmt_vec_info);
 
 /* In tree-vect-data-refs.c.  */
@@ -1557,21 +1558,21 @@ extern enum dr_alignment_support vect_supportable_dr_alignment
                                            (struct data_reference *, bool);
 extern tree vect_get_smallest_scalar_type (gimple *, HOST_WIDE_INT *,
                                            HOST_WIDE_INT *);
-extern bool vect_analyze_data_ref_dependences (loop_vec_info, unsigned int *);
+extern opt_result vect_analyze_data_ref_dependences (loop_vec_info, unsigned int *);
 extern bool vect_slp_analyze_instance_dependence (slp_instance);
-extern bool vect_enhance_data_refs_alignment (loop_vec_info);
-extern bool vect_analyze_data_refs_alignment (loop_vec_info);
-extern bool vect_verify_datarefs_alignment (loop_vec_info);
+extern opt_result vect_enhance_data_refs_alignment (loop_vec_info);
+extern opt_result vect_analyze_data_refs_alignment (loop_vec_info);
+extern opt_result vect_verify_datarefs_alignment (loop_vec_info);
 extern bool vect_slp_analyze_and_verify_instance_alignment (slp_instance);
-extern bool vect_analyze_data_ref_accesses (vec_info *);
-extern bool vect_prune_runtime_alias_test_list (loop_vec_info);
+extern opt_result vect_analyze_data_ref_accesses (vec_info *);
+extern opt_result vect_prune_runtime_alias_test_list (loop_vec_info);
 extern bool vect_gather_scatter_fn_p (bool, bool, tree, tree, unsigned int,
 				      signop, int, internal_fn *, tree *);
 extern bool vect_check_gather_scatter (gimple *, loop_vec_info,
 				       gather_scatter_info *);
-extern bool vect_find_stmt_data_reference (loop_p, gimple *,
-					   vec<data_reference_p> *);
-extern bool vect_analyze_data_refs (vec_info *, poly_uint64 *);
+extern opt_result vect_find_stmt_data_reference (loop_p, gimple *,
+						 vec<data_reference_p> *);
+extern opt_result vect_analyze_data_refs (vec_info *, poly_uint64 *);
 extern void vect_record_base_alignments (vec_info *);
 extern tree vect_create_data_ref_ptr (gimple *, tree, struct loop *, tree,
 				      tree *, gimple_stmt_iterator *,
@@ -1607,8 +1608,9 @@ extern gimple *vect_force_simple_reduction (loop_vec_info, gimple *,
 extern bool check_reduction_path (dump_user_location_t, loop_p, gphi *, tree,
 				  enum tree_code);
 /* Drive for loop analysis stage.  */
-extern loop_vec_info vect_analyze_loop (struct loop *, loop_vec_info,
-					vec_info_shared *);
+extern opt_loop_vec_info vect_analyze_loop (struct loop *,
+					    loop_vec_info,
+					    vec_info_shared *);
 extern tree vect_build_loop_niters (loop_vec_info, bool * = NULL);
 extern void vect_gen_vector_loop_niters (loop_vec_info, tree, tree *,
 					 tree *, bool);
@@ -1621,7 +1623,8 @@ extern tree vect_get_loop_mask (gimple_stmt_iterator *, vec_loop_masks *,
 
 /* Drive for loop transformation stage.  */
 extern struct loop *vect_transform_loop (loop_vec_info);
-extern loop_vec_info vect_analyze_loop_form (struct loop *, vec_info_shared *);
+extern opt_loop_vec_info vect_analyze_loop_form (struct loop *,
+						 vec_info_shared *);
 extern bool vectorizable_live_operation (gimple *, gimple_stmt_iterator *,
 					 slp_tree, int, gimple **,
 					 stmt_vector_for_cost *);
@@ -1646,7 +1649,7 @@ extern bool vect_transform_slp_perm_load (slp_tree, vec<tree> ,
 					  slp_instance, bool, unsigned *);
 extern bool vect_slp_analyze_operations (vec_info *);
 extern bool vect_schedule_slp (vec_info *);
-extern bool vect_analyze_slp (vec_info *, unsigned);
+extern opt_result vect_analyze_slp (vec_info *, unsigned);
 extern bool vect_make_slp_decision (loop_vec_info);
 extern void vect_detect_hybrid_slp (loop_vec_info);
 extern void vect_get_slp_defs (vec<tree> , slp_tree, vec<vec<tree> > *);
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 3/5] Add some test coverage
  2018-07-10  0:27   ` [PATCH 0/5] [RFC v2] " David Malcolm
  2018-07-10  0:27     ` [PATCH 4/5] Use opt_result throughout vectorizer David Malcolm
@ 2018-07-10  0:27     ` David Malcolm
  2018-07-10  0:27     ` [PATCH 1/5] Add opt-problem.h David Malcolm
                       ` (3 subsequent siblings)
  5 siblings, 0 replies; 24+ messages in thread
From: David Malcolm @ 2018-07-10  0:27 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches, Richard Sandiford, David Malcolm

In particular, note how this allows us to highlight specific loops in
testcases (via dg-remark), and to highlight the specific lines that cause
problems to the vectorizer (via dg-message).

gcc/testsuite/ChangeLog:
	* gcc.dg/vect/vect-alias-check-4.c: Add -fremarks to options.  Add
	dg-remark and dg-message directives to the cover the expected
	vectorization failure reports.
	* gcc.dg/vect/vect-remarks-1.c: New test.
---
 gcc/testsuite/gcc.dg/vect/vect-alias-check-4.c | 11 +++++++----
 gcc/testsuite/gcc.dg/vect/vect-remarks-1.c     | 18 ++++++++++++++++++
 2 files changed, 25 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/vect/vect-remarks-1.c

diff --git a/gcc/testsuite/gcc.dg/vect/vect-alias-check-4.c b/gcc/testsuite/gcc.dg/vect/vect-alias-check-4.c
index 1e5fc27..b08b4b4 100644
--- a/gcc/testsuite/gcc.dg/vect/vect-alias-check-4.c
+++ b/gcc/testsuite/gcc.dg/vect/vect-alias-check-4.c
@@ -1,6 +1,6 @@
 /* { dg-do compile } */
 /* { dg-require-effective-target vect_int } */
-/* { dg-additional-options "--param vect-max-version-for-alias-checks=0" } */
+/* { dg-additional-options "--param vect-max-version-for-alias-checks=0 -fremarks" } */
 
 #define N 16
 
@@ -14,22 +14,25 @@ union u { struct s2 f; struct s3 g; };
 void
 f1 (int a[][N], int b[][N])
 {
-  for (int i = 0; i < N; ++i)
+  for (int i = 0; i < N; ++i) /* { dg-remark "couldn't vectorize loop" } */
     a[0][i] += b[0][i];
+  /* { dg-message "will not create alias checks, as --param vect-max-version-for-alias-checks == 0" "" { target *-*-* } .-2 } */
 }
 
 void
 f2 (union u *a, union u *b)
 {
-  for (int i = 0; i < N; ++i)
+  for (int i = 0; i < N; ++i) /* { dg-remark "couldn't vectorize loop" } */
     a->f.b.a[i] += b->g.e.a[i];
+  /* { dg-message "will not create alias checks, as --param vect-max-version-for-alias-checks == 0" "" { target *-*-* } .-2 } */
 }
 
 void
 f3 (struct s1 *a, struct s1 *b)
 {
-  for (int i = 0; i < N - 1; ++i)
+  for (int i = 0; i < N - 1; ++i) /* { dg-remark "couldn't vectorize loop" } */
     a->a[i + 1] += b->a[i];
+  /* { dg-message "possible dependence between data-refs" "" { target *-*-* } .-2 } */
 }
 
 /* { dg-final { scan-tree-dump-not "LOOP VECTORIZED" "vect" } } */
diff --git a/gcc/testsuite/gcc.dg/vect/vect-remarks-1.c b/gcc/testsuite/gcc.dg/vect/vect-remarks-1.c
new file mode 100644
index 0000000..5006742
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-remarks-1.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-fremarks -O3" } */
+
+extern void accumulate (int x, int *a);
+
+int test_1 (int arr[], int n)
+{
+  int sum = 0;
+  for (int i = 0; i < n; ++i) /* { dg-remark "couldn't vectorize loop" } */
+    accumulate (arr[i], &sum); /* { dg-message "statement clobbers memory: 'accumulate .*'" } */
+  return sum;
+}
+
+void test_2 (int *dst, int *src_a, int *src_b, int n)
+{
+  for (int i = 0; i < n; i++) /* { dg-remark "loop vectorized" } */
+    dst[i] = src_a[i] + src_b[i];
+}
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 1/5] Add opt-problem.h
  2018-07-10  0:27   ` [PATCH 0/5] [RFC v2] " David Malcolm
  2018-07-10  0:27     ` [PATCH 4/5] Use opt_result throughout vectorizer David Malcolm
  2018-07-10  0:27     ` [PATCH 3/5] Add some test coverage David Malcolm
@ 2018-07-10  0:27     ` David Malcolm
  2018-07-10  0:27     ` [PATCH 2/5] Use opt-problem.h in try_vectorize_loop_1 David Malcolm
                       ` (2 subsequent siblings)
  5 siblings, 0 replies; 24+ messages in thread
From: David Malcolm @ 2018-07-10  0:27 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches, Richard Sandiford, David Malcolm

gcc/ChangeLog:
	* opt-problem.h: New file.
	* tree-vectorizer.h (opt_loop_vec_info): New typedef.
---
 gcc/opt-problem.h     | 326 ++++++++++++++++++++++++++++++++++++++++++++++++++
 gcc/tree-vectorizer.h |   6 +
 2 files changed, 332 insertions(+)
 create mode 100644 gcc/opt-problem.h

diff --git a/gcc/opt-problem.h b/gcc/opt-problem.h
new file mode 100644
index 0000000..100eed0
--- /dev/null
+++ b/gcc/opt-problem.h
@@ -0,0 +1,326 @@
+/* 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
+
+#include "diagnostic-core.h" /* for ATTRIBUTE_GCC_DIAG.  */
+
+/* This header declares a family of wrapper classes for tracking a
+   success/failure value, while optionally supporting propagating an
+   opt_problem * describing any failure back up the call stack.
+
+   For instance, at the deepest point of the callstack where the failure
+   happens, rather than:
+
+     if (!check_something ())
+       {
+         if (dump_enabled_p ())
+           dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+                            "foo is unsupported.\n");
+         return false;
+       }
+     // [...more checks...]
+
+     // All checks passed:
+     return true;
+
+   we can capture the cause of the failure via:
+
+     if (!check_something ())
+       {
+         if (dump_enabled_p ())
+           dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+                            "foo is unsupported.\n");
+         return opt_result::failure ("foo is unsupported",
+                                     stmt);
+       }
+     // [...more checks...]
+
+     // All checks passed:
+     return opt_result::success ();
+
+   which effectively returns true or false, whilst recording any problem.
+
+   opt_result::success and opt_result::failure return opt_result values
+   which "looks like" true/false respectively, via operator bool().
+   If dump_enabled_p, then opt_result::failure also creates an opt_problem *,
+   capturing the pertinent data (here, "foo is unsupported " and "stmt").
+   If dumps are disabled, then opt_problem instances aren't
+   created, and it's equivalent to just returning a bool.
+
+   The opt_problem can be propagated via opt_result values back up
+   the call stack to where it makes most sense to the user.
+   For instance, rather than:
+
+     bool ok = try_something_that_might_fail ();
+     if (!ok)
+       {
+         if (dump_enabled_p ())
+           dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+                            "some message.\n");
+         return false;
+       }
+
+   we can replace the bool with an opt_result, so if dump_enabled_p, we
+   assume that if try_something_that_might_fail, an opt_problem * will be
+   created, and we can propagate it up the call chain:
+
+     opt_result ok = try_something_that_might_fail ();
+     if (!ok)
+       {
+         if (dump_enabled_p ())
+           dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+                            "some message.\n");
+         return ok; // propagating the opt_result
+       }
+
+   opt_result is an opt_wrapper<bool>, where opt_wrapper<T> is a base
+   class for wrapping a T, optionally propagating an opt_problem in
+   case of failure (when dumps are enabled).  Similarly,
+   opt_pointer_wrapper<T> can be used to wrap pointer types (where non-NULL
+   signifies success, NULL signifies failure).
+
+   In all cases, opt_wrapper<T> acts as if the opt_problem were one of its
+   fields, but the opt_problem is actually stored in a global, so that when
+   compiled, an opt_wrapper<T> is effectively just a T, so that we're
+   still just passing e.g. a bool around; the opt_wrapper<T> classes
+   simply provide type-checking and an API to ensure that we provide
+   error-messages deep in the callstack at the places where problems
+   occur, and that we propagate them.  This also avoids having
+   to manage the ownership of the opt_problem instances.
+
+   Using opt_result and opt_wrapper<T> documents the intent of the code
+   for the places where we represent success values, and allows the C++ type
+   system to track where the deepest points in the callstack are where we
+   need to emit the failure messages from.  */
+
+/* A high-level optimization-reporting API, with responsibility for grouping
+   the remark and any notes into one optimization record.
+
+   For example, in:
+
+     if (!loop_vinfo)
+       if (loop_vinfo.get_problem ())
+         {
+           opt_report report;
+           if (report.remark (vect_location, "couldn't vectorize loop"))
+             loop_vinfo.get_problem ()->report_reason (report);
+         }
+
+   any "note" diagnostics emitted by report_reason can be grouped into
+   the "remark" when written out as an optimization record.
+
+   TODO: notes on user-facing, i18n, etc.  */
+
+class opt_report
+{
+public:
+  bool remark (dump_location_t, const char *, ...)
+    ATTRIBUTE_GCC_DIAG(3,4);
+
+  bool note (dump_location_t, const char *, ...)
+    ATTRIBUTE_GCC_DIAG(3,4);
+};
+
+/* A bundle of information about why an optimization failed (e.g.
+   vectorization), and the location in both the user's code and
+   in GCC itself where the problem occurred.
+
+   Instances are created by static member functions in opt_wrapper
+   subclasses, such as opt_result::failure.
+
+   Instances are only created when dump_enabled_p ().  */
+
+class GTY(()) opt_problem
+{
+ public:
+  /* Factory function, which only makes an opt_problem if dumps are
+     enabled.  */
+  static opt_problem *
+  make (const char *text, gimple *stmt,
+	const dump_impl_location_t &impl_location)
+  {
+    if (!dump_enabled_p ())
+      return NULL;
+    return new opt_problem (text, stmt, impl_location);
+  }
+
+  void report_reason (opt_report &report);
+
+  static opt_problem *get_singleton () { return s_the_problem; }
+
+ private:
+  /* Private constructor, to be called by "make" member function.
+     Keeping this private ensures that instances are only created if
+     dump_enabled_p ().  */
+  opt_problem (const char *text, gimple *stmt,
+	       const dump_impl_location_t &impl_location)
+  : m_text (text), m_stmt (stmt),
+    m_location (dump_location_t (stmt, impl_location))
+  {
+    /* We shouldn't be bothering to construct these objects if
+       dumping isn't enabled.  */
+    gcc_assert (dump_enabled_p ());
+
+    /* Update the singleton.  */
+    delete s_the_problem;
+    s_the_problem = this;
+  }
+
+  const char *m_text;
+  gimple *m_stmt;
+  dump_location_t m_location;
+
+  static opt_problem *s_the_problem;
+};
+
+/* A base class for wrapper classes that track a success/failure value, while
+   optionally supporting propagating an opt_problem * describing any
+   failure back up the call stack.  */
+
+template <typename T>
+class opt_wrapper
+{
+ public:
+  typedef T wrapped_t;
+
+  /* Be accessible as the wrapped type.  */
+  operator wrapped_t () const { return m_result; }
+
+  /* No public ctor.  */
+
+  wrapped_t get_result () const { return m_result; }
+  opt_problem *get_problem () const { return opt_problem::get_singleton (); }
+
+ protected:
+  opt_wrapper (wrapped_t result, opt_problem */*problem*/)
+  : m_result (result)
+  {
+    /* "problem" is ignored: although it looks like a field, we
+       actually just use the opt_problem singleton, so that
+       opt_wrapper<T> in memory is just a T.  */
+  }
+
+ private:
+  wrapped_t m_result;
+};
+
+/* Subclass of opt_wrapper<T> for bool, where
+   - true signifies "success", and
+   - false signifies "failure"
+   whilst effectively propagating an opt_problem * describing any failure
+   back up the call stack.  */
+
+class opt_result : public opt_wrapper <bool>
+{
+ public:
+  /* Deprecated ctor.  During transition, allow construction from bool.
+     We want to eliminate this, as it doesn't capture the reason for
+     failures.  */
+  opt_result (bool result,
+	      const dump_impl_location_t &impl_location
+		= dump_impl_location_t ())
+    : opt_wrapper <bool> (result,
+			  opt_problem::make ("UNKNOWN", NULL, impl_location))
+  {
+  }
+
+  static opt_result success () { return opt_result (true, NULL); }
+  static opt_result failure (const char *gmsgid, gimple *stmt,
+			     const dump_impl_location_t &impl_location
+			       = dump_impl_location_t ())
+  {
+    return opt_result (false,
+		       opt_problem::make (gmsgid, stmt, impl_location));
+  }
+
+  static opt_result bad_type (const char *gmsgid, gimple *stmt, tree /*type*/,
+			      const dump_impl_location_t &impl_location
+				= dump_impl_location_t ())
+  {
+    return failure (gmsgid, stmt, impl_location);
+    // FIXME: for now; ideally we ought to capture the type
+  }
+
+ private:
+  /* Private ctor.  Instances should be created by the success and failure
+     static member functions.  */
+  opt_result (wrapped_t result, opt_problem *problem)
+  : opt_wrapper (result, problem)
+  {}
+};
+
+/* Subclass of opt_wrapper<T> where T is pointer type, for tracking
+   success/failure, where:
+   - a non-NULL value signifies "success", and
+   - a NULL value signifies "failure",
+   whilst effectively propagating an opt_problem * describing any failure
+   back up the call stack.  */
+
+template <typename PtrType_t>
+class opt_pointer_wrapper : public opt_wrapper <PtrType_t>
+{
+ public:
+  typedef PtrType_t wrapped_pointer_t;
+
+  /* Given a non-NULL pointer, make a success object wrapping it.  */
+
+  static opt_pointer_wrapper <wrapped_pointer_t>
+  success (wrapped_pointer_t ptr)
+  {
+    return opt_pointer_wrapper <wrapped_pointer_t> (ptr, NULL);
+  }
+
+  /* Make a NULL pointer failure object, with the given message.  */
+
+  static opt_pointer_wrapper <wrapped_pointer_t>
+  failure (const char *gmsgid,
+	   const dump_impl_location_t &impl_location
+	     = dump_impl_location_t ())
+  {
+    opt_problem *problem = opt_problem::make (gmsgid, NULL, impl_location);
+    return opt_pointer_wrapper <wrapped_pointer_t> (NULL, problem);
+  }
+
+  /* Given a failure wrapper of some other kind, make a NULL pointer
+     failure object, propagating the problem.  */
+
+  template <typename S>
+  static opt_pointer_wrapper <wrapped_pointer_t>
+  failure (opt_wrapper <S> other)
+  {
+    return opt_pointer_wrapper <wrapped_pointer_t> (NULL,
+						    other.get_problem ());
+  }
+
+  /* Support accessing the underlying pointer via ->.  */
+
+  wrapped_pointer_t operator-> () const { return this->get_result (); }
+
+ private:
+  /* Private ctor.  Instances should be built using the static member
+     functions "success" and "failure".  */
+  opt_pointer_wrapper (wrapped_pointer_t result, opt_problem *problem)
+  : opt_wrapper<PtrType_t> (result, problem)
+  {}
+};
+
+#endif /* #ifndef GCC_OPT_PROBLEM_H */
diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h
index 28be41f..81b64c6 100644
--- a/gcc/tree-vectorizer.h
+++ b/gcc/tree-vectorizer.h
@@ -595,6 +595,12 @@ typedef struct _loop_vec_info : public vec_info {
 #define LOOP_VINFO_ORIG_MAX_VECT_FACTOR(L) \
   (LOOP_VINFO_MAX_VECT_FACTOR (LOOP_VINFO_ORIG_LOOP_INFO (L)))
 
+/* Wrapper for loop_vec_info, for tracking success/failure, where a non-NULL
+   value signifies success, and a NULL value signifies failure, supporting
+   propagating an opt_problem * describing the failure back up the call
+   stack.  */
+typedef opt_pointer_wrapper <loop_vec_info> opt_loop_vec_info;
+
 static inline loop_vec_info
 loop_vec_info_for_loop (struct loop *loop)
 {
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 0/5] [RFC v2] Higher-level reporting of vectorization problems
  2018-07-10  0:27   ` [PATCH 0/5] [RFC v2] " David Malcolm
                       ` (4 preceding siblings ...)
  2018-07-10  0:27     ` [PATCH 5/5] Add opt-problem.cc David Malcolm
@ 2018-07-11 15:56     ` Richard Sandiford
  2018-07-11 18:28       ` David Malcolm
  2018-09-28 18:23       ` [PATCH 0/3] Higher-level reporting of vectorization problems (v3) David Malcolm
  5 siblings, 2 replies; 24+ messages in thread
From: Richard Sandiford @ 2018-07-11 15:56 UTC (permalink / raw)
  To: David Malcolm; +Cc: Richard Biener, gcc-patches

David Malcolm <dmalcolm@redhat.com> writes:
> On Mon, 2018-06-25 at 11:10 +0200, Richard Biener wrote:
>> On Fri, 22 Jun 2018, David Malcolm wrote:
>> 
>> > NightStrike and I were chatting on IRC last week about
>> > issues with trying to vectorize the following code:
>> > 
>> > #include <vector>
>> > 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.
>> 
>> Yeah, in particular the vectorizer is way too noisy in its low-level
>> functions.  IIRC -fopt-info-vec-missed is "somewhat" better:
>> 
>> t.C:4:26: note: step unknown.
>> t.C:4:26: note: vector alignment may not be reachable
>> t.C:4:26: note: not ssa-name.
>> t.C:4:26: note: use not simple.
>> t.C:4:26: note: not ssa-name.
>> t.C:4:26: note: use not simple.
>> t.C:4:26: note: no array mode for V2DI[3]
>> t.C:4:26: note: Data access with gaps requires scalar epilogue loop
>> t.C:4:26: note: can't use a fully-masked loop because the target
>> doesn't 
>> have the appropriate masked load or store.
>> t.C:4:26: note: not ssa-name.
>> t.C:4:26: note: use not simple.
>> t.C:4:26: note: not ssa-name.
>> t.C:4:26: note: use not simple.
>> t.C:4:26: note: no array mode for V2DI[3]
>> t.C:4:26: note: Data access with gaps requires scalar epilogue loop
>> t.C:4:26: note: op not supported by target.
>> t.C:4:26: note: not vectorized: relevant stmt not supported: _15 =
>> _14 
>> /[ex] 4;
>> t.C:4:26: note: bad operation or unsupported loop bound.
>> t.C:4:26: note: not vectorized: no grouped stores in basic block.
>> t.C:4:26: note: not vectorized: no grouped stores in basic block.
>> t.C:6:12: note: not vectorized: not enough data-refs in basic block.
>> 
>> 
>> > 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.
>> 
>> Nice idea.  Of course the issue is then for which issues to
>> exactly create those.  Like all of the MSG_MISSED_OPTIMIZATION
>> dumpings?
>> 
>> I guess the vectorizer needs some axing of useless messages
>> and/or we need a MSG_DEBUG to have an additional level below
>> MSG_NOTE.
>> 
>> > 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).
>> 
>> Quite likely because we only handle TRUNC_DIV_EXPR and not
>> EXACT_DIV_EXPR
>> which we can handle the same semantically (EXACT_DIV_EXPR just gives
>> us stronger guarantees).
>
> [...snip...]
>
> I've been experimenting with the idea; here's an updated version of
> the patch (on top of the optinfo patch kit, as it happens).
>
> I tried adding more uses of opt_problem, but ran into the issue that it's
> hard to find "by hand" the places deep in the callstack where things fail;
> I spent a chunk of time stepping through failures, trying to figure out
> the best place to capture the opt_problem.
>
> It seemed like something that we could track in C++'s type system.
>
> The following kit solves this by introducing a new class opt_result, which
> looks a lot like a bool: it has the same representation in memory.
>
> For instance, at the deepest point of the callstack where the failure
> happens, rather than:
>
>      if (!check_something ())
>        {
>          if (dump_enabled_p ())
>            dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
>                             "foo is unsupported.\n");
>          return false;
>        }
>      [...lots more checks...]
>
>      // All checks passed:
>      return true;
>
> we can capture the cause of the failure via:
>
>      if (!check_something ())
>        {
>          if (dump_enabled_p ())
>            dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
>                             "foo is unsupported.\n");
>          return opt_result::failure ("foo is unsupported",
>                                      stmt);
>        }
>      [...lots more checks...]
>
>      // All checks passed:
>      return opt_result::success ();
>
> which effectively returns true or false, whilst recording any problem.
>
> opt_result::success and opt_result::failure return opt_result values
> which "looks like" true/false respectively, via operator bool().
> If dump_enabled_p, then opt_result::failure also creates an opt_problem *,
> capturing the pertinent data (here, "foo is unsupported" and "stmt").
> If dumps are disabled, then opt_problem instances aren't
> created, and it's equivalent to just returning a bool (false for failure).

Since the creation of the opt_problem depends on dump_enabled_p, would
it make sense for the dump_printf_loc to happen automatically on
opt_result::failure, rather than have both?  E.g.:

      if (!check_something ())
	// Also calls dump_printf_loc if appropriate.
	return opt_result::failure ("foo is unsupported", stmt);

I think the aim should be for opt_problem to capture any information
that's useful at the user level, so doing the dump_printf_loc
automatically would help to keep the MISSED_OPTIMIZATIONS messages
clean of information that's too low-level.

> The opt_problem can be propagated via opt_result values back up
> the call stack to where it makes most sense to the user.
> For instance, rather than:
>
>      bool ok = try_something_that_might_fail ();
>      if (!ok)
>        {
>          if (dump_enabled_p ())
>            dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
>                             "some message.\n");
>          return false;
>        }
>
> we can replace the bool with an opt_result, so if dump_enabled_p, we
> assume that if try_something_that_might_fail, an opt_problem * will be
> created, and we can propagate it up the call chain:
>
>      opt_result ok = try_something_that_might_fail ();
>      if (!ok)
>        {
>          if (dump_enabled_p ())
>            dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
>                             "some message.\n");
>          return ok; // propagating the opt_result
>        }
>
> There's currently a way to implicitly construct an opt_result from a
> bool, but this is scaffolding: commenting it out allows the compiler to
> tell us where we need to capture failure information.

I guess this is bike-shedding, but personally I'd prefer an explicit
test for success rather than operator bool, so that:

   opt_result foo = ...;
   bool bar = foo;

is ill-formed.  The danger otherwise might be that we drop a useful
opt_problem and replace it with something more generic.  E.g. the
opt_result form of:

  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;
    }

in vect_analyze_stmt could silently drop the information provided by
the subroutine if we forgot to change "ok" from "bool" to "opt_result".

Same for opt_wrapper<T>, but defining operator* and operator-> would
be useful.

LGTM otherwise (but obviously it's Richard B's call).

Thanks,
Richard

> As well as opt_result for "bool", there's a template for wrapping pointers
> where non-NULL is "success" and NULL "failure", so that:
>
>       loop_vinfo = vect_analyze_loop_form (loop, shared);
>       if (!loop_vinfo)
> 	{
> 	  if (dump_enabled_p ())
> 	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> 			     "bad loop form.\n");
> 	  return NULL;
> 	}
>
> can simply become:
>
>       loop_vinfo = vect_analyze_loop_form (loop, shared);
>       if (!loop_vinfo)
> 	{
> 	  if (dump_enabled_p ())
> 	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> 			     "bad loop form.\n");
> 	  return loop_vinfo;
> 	}
>
> where the "loop_vinfo" is now an opt_wrapper<loop_vec_info> and can
> capture exactly what went wrong inside vect_analyze_loop_form.
>
> In all cases, the classes act as if the opt_problem were one of its
> fields, but the opt_problem is actually stored in a global, so that when
> compiled, an opt_wrapper<T> is effectively just a T, so that we're
> still just passing e.g. a bool around; the opt_wrapper<T> classes
> simply provide type-checking and an API to ensure that we provide
> error-messages deep in the callstack at the places where problems
> occur, and that we propagate them.  This also avoids having
> to manage the ownership of the opt_problem instances.
>
> Using opt_result and opt_wrapper<T> documents the intent of the code
> for the places where we represent success values, and allows the C++ type
> system to track where the deepest points in the callstack are where we
> need to emit the failure messages from.
>
> Some examples, showing how it immediately leads to more meaningful
> diagnostics from the vectorizer:
>
> gcc.dg/vect/vect-widen-mult-1.c: In function ‘f’:
> gcc.dg/vect/vect-widen-mult-1.c:16:3: remark: loop vectorized using 16 byte vectors
>    for (__INTPTR_TYPE__ i = 0; i < N; ++i)
>    ^~~
> gcc.dg/vect/vect-widen-mult-1.c: In function ‘main’:
> gcc.dg/vect/vect-widen-mult-1.c:42:10: remark: couldn't vectorize loop
>      if (a[i] != (SIGNEDNESS_1 short) ((BASE + i * 5)
>          ~^~~
> gcc.dg/vect/vect-widen-mult-1.c:42:10: note: control flow in loop [../../src/gcc/tree-vect-loop.c:1200:vect_analyze_loop_form_1]
> gcc.dg/vect/vect-widen-mult-1.c:34:3: remark: couldn't vectorize loop
>    for (int i = 0; i < N; ++i)
>    ^~~
> gcc.dg/vect/vect-widen-mult-1.c:38:7: note: statement clobbers memory: ‘__asm__ __volatile__("" :  :  : "memory");’ [../../src/gcc/tree-data-ref.c:5086:find_data_references_in_stmt]
>        asm volatile ("" ::: "memory");
>        ^~~
>
> by showing the location of the loop that can't be vectorized,
> the problematic statement within the loop, and describing what the
> problem is.
>
> Note how it also captures the location of where in GCC the problem was
> encountered.  Ultimately this would also show hotness information for the
> loop in the remark.
>
> I'm not sure exactly what an opt_problem should capture.  There are a few
> places in the kit where it looks the "failure" calls might benefit from
> being a formatted print API, with format codes for various middle-end
> entities (e.g. gimple, tree, --param values, etc).  It's also not clear
> to me how this would interact with the optinfo work (e.g. for capturing
> things in optimization records), or what the API should look like (though
> I like the one in the patch).
>
> (Not yet bootstrapped or regrtested, and has plenty of FIXMEs: I'm posting
> this for comment/discussion).
>
> Thoughts?
> Does the basic idea look useful and sane? (I think so)
>
> Thanks
> Dave
>
> [...snip...]
>
> David Malcolm (5):
>   Add opt-problem.h
>   Use opt-problem.h in try_vectorize_loop_1
>   Add some test coverage
>   Use opt_result throughout vectorizer
>   Add opt-problem.cc
>
>  gcc/Makefile.in                                |   1 +
>  gcc/opt-problem.cc                             |  96 ++++++++
>  gcc/opt-problem.h                              | 326 +++++++++++++++++++++++++
>  gcc/testsuite/gcc.dg/vect/vect-alias-check-4.c |  11 +-
>  gcc/testsuite/gcc.dg/vect/vect-remarks-1.c     |  18 ++
>  gcc/tree-data-ref.c                            |  33 +--
>  gcc/tree-data-ref.h                            |  10 +-
>  gcc/tree-vect-data-refs.c                      | 189 ++++++++------
>  gcc/tree-vect-loop.c                           | 212 +++++++++-------
>  gcc/tree-vect-slp.c                            |   4 +-
>  gcc/tree-vect-stmts.c                          | 130 ++++++----
>  gcc/tree-vectorizer.c                          |  34 ++-
>  gcc/tree-vectorizer.h                          |  41 ++--
>  13 files changed, 842 insertions(+), 263 deletions(-)
>  create mode 100644 gcc/opt-problem.cc
>  create mode 100644 gcc/opt-problem.h
>  create mode 100644 gcc/testsuite/gcc.dg/vect/vect-remarks-1.c

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 0/5] [RFC v2] Higher-level reporting of vectorization problems
  2018-07-11 15:56     ` [PATCH 0/5] [RFC v2] Higher-level reporting of vectorization problems Richard Sandiford
@ 2018-07-11 18:28       ` David Malcolm
  2018-09-28 18:23       ` [PATCH 0/3] Higher-level reporting of vectorization problems (v3) David Malcolm
  1 sibling, 0 replies; 24+ messages in thread
From: David Malcolm @ 2018-07-11 18:28 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: Richard Biener, gcc-patches

On Wed, 2018-07-11 at 16:56 +0100, Richard Sandiford wrote:
> David Malcolm <dmalcolm@redhat.com> writes:
> > On Mon, 2018-06-25 at 11:10 +0200, Richard Biener wrote:
> > > On Fri, 22 Jun 2018, David Malcolm wrote:
> > > 
> > > > NightStrike and I were chatting on IRC last week about
> > > > issues with trying to vectorize the following code:
> > > > 
> > > > #include <vector>
> > > > 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.rema
> > > > rks.
> > > > 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.
> > > 
> > > Yeah, in particular the vectorizer is way too noisy in its low-
> > > level
> > > functions.  IIRC -fopt-info-vec-missed is "somewhat" better:
> > > 
> > > t.C:4:26: note: step unknown.
> > > t.C:4:26: note: vector alignment may not be reachable
> > > t.C:4:26: note: not ssa-name.
> > > t.C:4:26: note: use not simple.
> > > t.C:4:26: note: not ssa-name.
> > > t.C:4:26: note: use not simple.
> > > t.C:4:26: note: no array mode for V2DI[3]
> > > t.C:4:26: note: Data access with gaps requires scalar epilogue
> > > loop
> > > t.C:4:26: note: can't use a fully-masked loop because the target
> > > doesn't 
> > > have the appropriate masked load or store.
> > > t.C:4:26: note: not ssa-name.
> > > t.C:4:26: note: use not simple.
> > > t.C:4:26: note: not ssa-name.
> > > t.C:4:26: note: use not simple.
> > > t.C:4:26: note: no array mode for V2DI[3]
> > > t.C:4:26: note: Data access with gaps requires scalar epilogue
> > > loop
> > > t.C:4:26: note: op not supported by target.
> > > t.C:4:26: note: not vectorized: relevant stmt not supported: _15
> > > =
> > > _14 
> > > /[ex] 4;
> > > t.C:4:26: note: bad operation or unsupported loop bound.
> > > t.C:4:26: note: not vectorized: no grouped stores in basic block.
> > > t.C:4:26: note: not vectorized: no grouped stores in basic block.
> > > t.C:6:12: note: not vectorized: not enough data-refs in basic
> > > block.
> > > 
> > > 
> > > > 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.
> > > 
> > > Nice idea.  Of course the issue is then for which issues to
> > > exactly create those.  Like all of the MSG_MISSED_OPTIMIZATION
> > > dumpings?
> > > 
> > > I guess the vectorizer needs some axing of useless messages
> > > and/or we need a MSG_DEBUG to have an additional level below
> > > MSG_NOTE.
> > > 
> > > > 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).
> > > 
> > > Quite likely because we only handle TRUNC_DIV_EXPR and not
> > > EXACT_DIV_EXPR
> > > which we can handle the same semantically (EXACT_DIV_EXPR just
> > > gives
> > > us stronger guarantees).
> > 
> > [...snip...]
> > 
> > I've been experimenting with the idea; here's an updated version of
> > the patch (on top of the optinfo patch kit, as it happens).
> > 
> > I tried adding more uses of opt_problem, but ran into the issue
> > that it's
> > hard to find "by hand" the places deep in the callstack where
> > things fail;
> > I spent a chunk of time stepping through failures, trying to figure
> > out
> > the best place to capture the opt_problem.
> > 
> > It seemed like something that we could track in C++'s type system.
> > 
> > The following kit solves this by introducing a new class
> > opt_result, which
> > looks a lot like a bool: it has the same representation in memory.
> > 
> > For instance, at the deepest point of the callstack where the
> > failure
> > happens, rather than:
> > 
> >      if (!check_something ())
> >        {
> >          if (dump_enabled_p ())
> >            dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> >                             "foo is unsupported.\n");
> >          return false;
> >        }
> >      [...lots more checks...]
> > 
> >      // All checks passed:
> >      return true;
> > 
> > we can capture the cause of the failure via:
> > 
> >      if (!check_something ())
> >        {
> >          if (dump_enabled_p ())
> >            dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> >                             "foo is unsupported.\n");
> >          return opt_result::failure ("foo is unsupported",
> >                                      stmt);
> >        }
> >      [...lots more checks...]
> > 
> >      // All checks passed:
> >      return opt_result::success ();
> > 
> > which effectively returns true or false, whilst recording any
> > problem.
> > 
> > opt_result::success and opt_result::failure return opt_result
> > values
> > which "looks like" true/false respectively, via operator bool().
> > If dump_enabled_p, then opt_result::failure also creates an
> > opt_problem *,
> > capturing the pertinent data (here, "foo is unsupported" and
> > "stmt").
> > If dumps are disabled, then opt_problem instances aren't
> > created, and it's equivalent to just returning a bool (false for
> > failure).
> 
> Since the creation of the opt_problem depends on dump_enabled_p,
> would
> it make sense for the dump_printf_loc to happen automatically on
> opt_result::failure, rather than have both?  E.g.:
> 
>       if (!check_something ())
> 	// Also calls dump_printf_loc if appropriate.
> 	return opt_result::failure ("foo is unsupported", stmt);
> 
> I think the aim should be for opt_problem to capture any information
> that's useful at the user level, so doing the dump_printf_loc
> automatically would help to keep the MISSED_OPTIMIZATIONS messages
> clean of information that's too low-level.

Interesting idea, thanks.

The existing dump_* calls are "time-ordered": they can be thought of as
log of the events that happened as the optimizer ran.  The time-ordered 
log looks like:

  [...lots of messages...]
  note: foo is unsupported
  [...probably more messages...]
  note: loop could not be vectorized

This patch kit inverts the message ordering somewhat: it's storing away
details for later use, so that we can print:

  remark: loop could not be vectorized
  note: foo is unsupported: DETAILS OF STMT

where the note "happened" before the remark, but providing a good
message to the user suggests doing it in that
  "what happened" then
  "why (with details)"
order.

One of the "unknowns" in this patch kit is the relationship between the
"high-level messages" that I'm proposing to eventually emit at the top
level, and the existing dump_* messages.

I'm wondering if the existing dump_* messages should continue to be
time-ordered, as a log for debugging purposes, and to have these high-
level messages as a more user-facing thing.

Then the opt_result::failure would internally do a dump_printf_loc for
logging purposes, but an end-user might be looking at the remarks/notes
thing as a separate stream of messages.

(I'm thinking aloud here)

> > The opt_problem can be propagated via opt_result values back up
> > the call stack to where it makes most sense to the user.
> > For instance, rather than:
> > 
> >      bool ok = try_something_that_might_fail ();
> >      if (!ok)
> >        {
> >          if (dump_enabled_p ())
> >            dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> >                             "some message.\n");
> >          return false;
> >        }
> > 
> > we can replace the bool with an opt_result, so if dump_enabled_p,
> > we
> > assume that if try_something_that_might_fail, an opt_problem * will
> > be
> > created, and we can propagate it up the call chain:
> > 
> >      opt_result ok = try_something_that_might_fail ();
> >      if (!ok)
> >        {
> >          if (dump_enabled_p ())
> >            dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> >                             "some message.\n");
> >          return ok; // propagating the opt_result
> >        }
> > 
> > There's currently a way to implicitly construct an opt_result from
> > a
> > bool, but this is scaffolding: commenting it out allows the
> > compiler to
> > tell us where we need to capture failure information.
> 
> I guess this is bike-shedding, but personally I'd prefer an explicit
> test for success rather than operator bool, so that:
> 
>    opt_result foo = ...;
>    bool bar = foo;
> 
> is ill-formed.  The danger otherwise might be that we drop a useful
> opt_problem and replace it with something more generic.  E.g. the
> opt_result form of:
> 
>   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;
>     }
> 
> in vect_analyze_stmt could silently drop the information provided by
> the subroutine if we forgot to change "ok" from "bool" to
> "opt_result".

I think that's handled already, kind-of.  If the function's return type
is opt_result, then an attempt to "return false;" will only work if an
opt_result can be constructed from bool.

Currently, opt_result does have this ctor from bool:

  /* Deprecated ctor.  During transition, allow construction from bool.
     We want to eliminate this, as it doesn't capture the reason for
     failures.  */
  opt_result (bool result,
	      const dump_impl_location_t &impl_location
		= dump_impl_location_t ())
    : opt_wrapper <bool> (result,
			  opt_problem::make ("UNKNOWN", NULL, impl_location))
  {
  }

and I've been working towards eliminating it.  If I comment it out, the
compiler immediately provides an error on all of the places where we
would silent discard the opt_result.

So I think I just need to finish eliminating that transitional
constructor; hopefully that would alleviate your concern here.

> Same for opt_wrapper<T>, but defining operator* and operator-> would
> be useful.
> 
> LGTM otherwise (but obviously it's Richard B's call).

Thanks for taking a look.
Dave

> Thanks,
> Richard
> 
> > As well as opt_result for "bool", there's a template for wrapping
> > pointers
> > where non-NULL is "success" and NULL "failure", so that:
> > 
> >       loop_vinfo = vect_analyze_loop_form (loop, shared);
> >       if (!loop_vinfo)
> > 	{
> > 	  if (dump_enabled_p ())
> > 	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> > 			     "bad loop form.\n");
> > 	  return NULL;
> > 	}
> > 
> > can simply become:
> > 
> >       loop_vinfo = vect_analyze_loop_form (loop, shared);
> >       if (!loop_vinfo)
> > 	{
> > 	  if (dump_enabled_p ())
> > 	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> > 			     "bad loop form.\n");
> > 	  return loop_vinfo;
> > 	}
> > 
> > where the "loop_vinfo" is now an opt_wrapper<loop_vec_info> and can
> > capture exactly what went wrong inside vect_analyze_loop_form.
> > 
> > In all cases, the classes act as if the opt_problem were one of its
> > fields, but the opt_problem is actually stored in a global, so that
> > when
> > compiled, an opt_wrapper<T> is effectively just a T, so that we're
> > still just passing e.g. a bool around; the opt_wrapper<T> classes
> > simply provide type-checking and an API to ensure that we provide
> > error-messages deep in the callstack at the places where problems
> > occur, and that we propagate them.  This also avoids having
> > to manage the ownership of the opt_problem instances.
> > 
> > Using opt_result and opt_wrapper<T> documents the intent of the
> > code
> > for the places where we represent success values, and allows the
> > C++ type
> > system to track where the deepest points in the callstack are where
> > we
> > need to emit the failure messages from.
> > 
> > Some examples, showing how it immediately leads to more meaningful
> > diagnostics from the vectorizer:
> > 
> > gcc.dg/vect/vect-widen-mult-1.c: In function ‘f’:
> > gcc.dg/vect/vect-widen-mult-1.c:16:3: remark: loop vectorized using
> > 16 byte vectors
> >    for (__INTPTR_TYPE__ i = 0; i < N; ++i)
> >    ^~~
> > gcc.dg/vect/vect-widen-mult-1.c: In function ‘main’:
> > gcc.dg/vect/vect-widen-mult-1.c:42:10: remark: couldn't vectorize
> > loop
> >      if (a[i] != (SIGNEDNESS_1 short) ((BASE + i * 5)
> >          ~^~~
> > gcc.dg/vect/vect-widen-mult-1.c:42:10: note: control flow in loop
> > [../../src/gcc/tree-vect-loop.c:1200:vect_analyze_loop_form_1]
> > gcc.dg/vect/vect-widen-mult-1.c:34:3: remark: couldn't vectorize
> > loop
> >    for (int i = 0; i < N; ++i)
> >    ^~~
> > gcc.dg/vect/vect-widen-mult-1.c:38:7: note: statement clobbers
> > memory: ‘__asm__ __volatile__("" :  :  : "memory");’
> > [../../src/gcc/tree-data-ref.c:5086:find_data_references_in_stmt]
> >        asm volatile ("" ::: "memory");
> >        ^~~
> > 
> > by showing the location of the loop that can't be vectorized,
> > the problematic statement within the loop, and describing what the
> > problem is.
> > 
> > Note how it also captures the location of where in GCC the problem
> > was
> > encountered.  Ultimately this would also show hotness information
> > for the
> > loop in the remark.
> > 
> > I'm not sure exactly what an opt_problem should capture.  There are
> > a few
> > places in the kit where it looks the "failure" calls might benefit
> > from
> > being a formatted print API, with format codes for various middle-
> > end
> > entities (e.g. gimple, tree, --param values, etc).  It's also not
> > clear
> > to me how this would interact with the optinfo work (e.g. for
> > capturing
> > things in optimization records), or what the API should look like
> > (though
> > I like the one in the patch).
> > 
> > (Not yet bootstrapped or regrtested, and has plenty of FIXMEs: I'm
> > posting
> > this for comment/discussion).
> > 
> > Thoughts?
> > Does the basic idea look useful and sane? (I think so)
> > 
> > Thanks
> > Dave
> > 
> > [...snip...]
> > 
> > David Malcolm (5):
> >   Add opt-problem.h
> >   Use opt-problem.h in try_vectorize_loop_1
> >   Add some test coverage
> >   Use opt_result throughout vectorizer
> >   Add opt-problem.cc
> > 
> >  gcc/Makefile.in                                |   1 +
> >  gcc/opt-problem.cc                             |  96 ++++++++
> >  gcc/opt-problem.h                              | 326
> > +++++++++++++++++++++++++
> >  gcc/testsuite/gcc.dg/vect/vect-alias-check-4.c |  11 +-
> >  gcc/testsuite/gcc.dg/vect/vect-remarks-1.c     |  18 ++
> >  gcc/tree-data-ref.c                            |  33 +--
> >  gcc/tree-data-ref.h                            |  10 +-
> >  gcc/tree-vect-data-refs.c                      | 189 ++++++++-----
> > -
> >  gcc/tree-vect-loop.c                           | 212 +++++++++--
> > -----
> >  gcc/tree-vect-slp.c                            |   4 +-
> >  gcc/tree-vect-stmts.c                          | 130 ++++++----
> >  gcc/tree-vectorizer.c                          |  34 ++-
> >  gcc/tree-vectorizer.h                          |  41 ++--
> >  13 files changed, 842 insertions(+), 263 deletions(-)
> >  create mode 100644 gcc/opt-problem.cc
> >  create mode 100644 gcc/opt-problem.h
> >  create mode 100644 gcc/testsuite/gcc.dg/vect/vect-remarks-1.c

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 0/3] Higher-level reporting of vectorization problems (v3)
  2018-07-11 15:56     ` [PATCH 0/5] [RFC v2] Higher-level reporting of vectorization problems Richard Sandiford
  2018-07-11 18:28       ` David Malcolm
@ 2018-09-28 18:23       ` David Malcolm
  2018-09-28 18:24         ` [PATCH 2/3] Add -fopt-info-internals David Malcolm
                           ` (2 more replies)
  1 sibling, 3 replies; 24+ messages in thread
From: David Malcolm @ 2018-09-28 18:23 UTC (permalink / raw)
  To: Richard Sandiford, Richard Biener; +Cc: gcc-patches, David Malcolm

This is v3 of this patch kit; previous versions were:
  v2: https://gcc.gnu.org/ml/gcc-patches/2018-07/msg00446.html
  v1: https://gcc.gnu.org/ml/gcc-patches/2018-06/msg01462.html

The overall goal of this patch kit is to make the output of
-fopt-info more readable for technically-advanced end-users,
whilst preserving the existing output for dump files.

The aim is to (by default) replace the current "wall of text"
output for -fopt-info-vec-all with a summary of the status for
each loop, giving either:

  <LOOP-LOCATION>: vectorized this loop via <METHOD>

or:

  <LOOP-LOCATION>: couldn't vectorize this loop
  <PROBLEM-LOCATION>: because of <REASON>

In particular, the "reason" message uses the location of the
problematic construct, rather than reusing that of the loop.
  
For example:
    
  no-vfa-vect-102.c:24:3: missed: couldn't vectorize loop
  no-vfa-vect-102.c:27:7: missed: statement clobbers memory: __asm__ __volatile__("" :  :  : "memory");

Patch 1 fixes an bug in -fopt-info with plugin passes, needed by
the other patches since they add a plugin to the testsuite to test
-fopt-info output.

Patches 2 and 3 introduce a verbosity level to dump messages:
"user-facing" vs "internals", suppressing "internals" messages by
default within -fopt-info, along with a way to propagate
information about a specific problem back up to the top level
and report it (class opt_problem), and a way to re-enable the
"internals" output in -fopt-info; see those patches for more
information.

The patches now bootstrap & pass regression testing on
x86_64-pc-linux-gnu; I'm hoping to get this into trunk for GCC 9.

Thanks
Dave

David Malcolm (3):
  Fix -fopt-info for plugin passes
  Add -fopt-info-internals
  v3: Report vectorization problems via a new opt_problem class

 gcc/Makefile.in                                    |   1 +
 gcc/doc/invoke.texi                                |  31 +-
 gcc/dump-context.h                                 | 106 ++++-
 gcc/dumpfile.c                                     | 490 ++++++++++++---------
 gcc/dumpfile.h                                     |  60 ++-
 gcc/opt-problem.cc                                 | 335 ++++++++++++++
 gcc/opt-problem.h                                  | 289 ++++++++++++
 gcc/optinfo-emit-json.cc                           |   2 +-
 gcc/optinfo.cc                                     |  44 +-
 gcc/optinfo.h                                      |   7 +-
 gcc/passes.c                                       |  30 +-
 gcc/selftest-run-tests.c                           |   1 +
 gcc/selftest.h                                     |   1 +
 gcc/testsuite/gcc.dg/plugin/dump-1.c               |  24 +
 gcc/testsuite/gcc.dg/plugin/dump-2.c               |  30 ++
 gcc/testsuite/gcc.dg/plugin/dump_plugin.c          | 143 ++++++
 gcc/testsuite/gcc.dg/plugin/plugin.exp             |   3 +
 gcc/testsuite/gcc.dg/vect/nodump-vect-opt-info-2.c |  12 +
 gcc/testsuite/gcc.dg/vect/vect-alias-check-4.c     |  18 +-
 gcc/tree-data-ref.c                                |  70 ++-
 gcc/tree-data-ref.h                                |  10 +-
 gcc/tree-predcom.c                                 |   3 +-
 gcc/tree-vect-data-refs.c                          | 347 +++++++--------
 gcc/tree-vect-loop-manip.c                         |   6 +-
 gcc/tree-vect-loop.c                               | 442 ++++++++-----------
 gcc/tree-vect-slp.c                                |   4 +-
 gcc/tree-vect-stmts.c                              | 275 +++++-------
 gcc/tree-vectorizer.c                              |  17 +-
 gcc/tree-vectorizer.h                              |  51 ++-
 29 files changed, 1932 insertions(+), 920 deletions(-)
 create mode 100644 gcc/opt-problem.cc
 create mode 100644 gcc/opt-problem.h
 create mode 100644 gcc/testsuite/gcc.dg/plugin/dump-1.c
 create mode 100644 gcc/testsuite/gcc.dg/plugin/dump-2.c
 create mode 100644 gcc/testsuite/gcc.dg/plugin/dump_plugin.c
 create mode 100644 gcc/testsuite/gcc.dg/vect/nodump-vect-opt-info-2.c

-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 3/3] v3: Report vectorization problems via a new opt_problem class
  2018-09-28 18:23       ` [PATCH 0/3] Higher-level reporting of vectorization problems (v3) David Malcolm
  2018-09-28 18:24         ` [PATCH 2/3] Add -fopt-info-internals David Malcolm
@ 2018-09-28 18:24         ` David Malcolm
  2018-10-04 11:28           ` Richard Biener
  2018-09-28 18:25         ` [PATCH 1/3] Fix -fopt-info for plugin passes David Malcolm
  2 siblings, 1 reply; 24+ messages in thread
From: David Malcolm @ 2018-09-28 18:24 UTC (permalink / raw)
  To: Richard Sandiford, Richard Biener; +Cc: gcc-patches, David Malcolm

This is v3 of the patch; previous versions were:
  v2: https://gcc.gnu.org/ml/gcc-patches/2018-07/msg00446.html
  v1: https://gcc.gnu.org/ml/gcc-patches/2018-06/msg01462.html

This patch introduces a class opt_problem, along with wrapper
classes for bool (opt_result) and for pointers (e.g. opt_loop_vec_info
for loop_vec_info).

opt_problem instances are created when an optimization problem
is encountered, but only if dump_enabled_p.  They are manually
propagated up the callstack, and are manually reported at the
"top level" of an optimization if dumping is enabled, to give the user
a concise summary of the problem *after* the failure is reported.
In particular, the location of the problematic statement is
captured and emitted, rather than just the loop's location.

For example:

no-vfa-vect-102.c:24:3: missed: couldn't vectorize loop
no-vfa-vect-102.c:27:7: missed: statement clobbers memory: __asm__ __volatile__("" :  :  : "memory");

Changed in v3:
* This version bootstraps and passes regression testing (on
  x86_64-pc-linux-gnu).
* added selftests, to exercise the opt_problem machinery
* removed the "bool to opt_result" ctor, so that attempts to
  use e.g. return a bool from an opt_result-returning function
  will fail at compile time
* use formatted printing within opt_problem ctor to replace the
  various dump_printf_loc calls
* dropped i18n
* changed the sense of vect_analyze_data_ref_dependence's return
  value (see the ChangeLog)
* add MSG_PRIORITY_REEMITTED, so that -fopt-info can show the
  messages, without them messing up the counts in scan-tree-dump-times
  in DejaGnu tests

Re Richard Sandiford's feedback on the v2 patch:
  https://gcc.gnu.org/ml/gcc-patches/2018-07/msg00560.html
> Since the creation of the opt_problem depends on dump_enabled_p, would
> it make sense for the dump_printf_loc to happen automatically on
> opt_result::failure, rather than have both?

Yes; this v3 patch does that: opt_result::failure_at is passed a format
string with variadic args.  If dumping is enabled, it performs the
equivalent of dump_printf_loc in a form that will reach dumpfiles
(and -fopt-info-internals), stashing the dumped items in the opt_problem.
When the opt_problem is emitted at the top-level, the message is re-emitted
(but only for -fopt-info, not for dumpfiles, to avoid duplicates that mess
up scan-tree-dump-times in DejaGnu tests)

> I guess this is bike-shedding, but personally I'd prefer an explicit
> test for success rather than operator bool, so that:
>
>    opt_result foo = ...;
>    bool bar = foo;
>
> is ill-formed.  The danger otherwise might be that we drop a useful
> opt_problem and replace it with something more generic.  E.g. the
> opt_result form of:
>   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;
>     }
>
> in vect_analyze_stmt could silently drop the information provided by
> the subroutine if we forgot to change "ok" from "bool" to "opt_result".

I didn't make that change in v3: if the function returns an opt_result, then
the "return false;" will be a compile-time failure, alerting us to the
problem.

I guess this is a matter of style, whether explicit is better than
implicit.  Dropping the operator bool would require an explicit approach,
with something like:

    // Explicit style:
    opt_result res = ...;
    if (res.failed_p ())
       return res;

and:

    // Explicit style:
    // It's often currently called "ok":
    opt_result ok = ...;
    if (ok.failed_p ())
       return ok;

as opposed to:

    // Implicit style:
    opt_result res = ...;
    if (!res)
       return res;

and:

    // Implicit style:
    opt_result ok = ...;
    if (!ok)
       return ok;

I think I went with the implicit style to minimize the lines touched by
the patch, but I'm happy with either approach.  [If we're bikeshedding,
would renaming those "ok" to "res" be acceptable also?  "ok" reads to
me like a "success" value for a status variable, rather than the status
variable itself; it's presumably meant to be pronounced with a rising
interrogative as it were a question - "ok?" - but that's not visible in
the code when reading the usage sites].

Similarly, the pointer wrappers use an implicit style:

  // Implicit style:

  opt_loop_vec_info loop_vinfo
    = vect_analyze_loop (loop, orig_loop_vinfo, &shared);
  loop->aux = loop_vinfo;

  if (!loop_vinfo)
    if (dump_enabled_p ())
      if (opt_problem *problem = loop_vinfo.get_problem ())
	{

but maybe an explicit style is more readable:

  // Explicit style:

  opt_loop_vec_info opt_loop_vinfo
    = vect_analyze_loop (loop, orig_loop_vinfo, &shared);
  loop_vec_info loop_vinfo = loop_vinfo.get_pointer ();
  loop->aux = loop_vinfo

  if (opt_loop_vinfo.failed_p ())
    if (dump_enabled_p ())
      if (opt_problem *problem = loop_vinfo.get_problem ())
	{


How would you want the code to look?

Richi: do you have an opinion here?

(or is that style in the patch OK as-is?)

Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.

OK for trunk?

gcc/ChangeLog:
	* Makefile.in (OBJS): Add opt-problem.o.
	* dump-context.h: Include "selftest.h.
	(selftest::temp_dump_context): New forward decl.
	(class dump_context): Make friend of class
	selftest::temp_dump_context.
	(dump_context::dump_loc_immediate): New decl.
	(class dump_pretty_printer): Move here from dumpfile.c.
	(class temp_dump_context): Move to namespace selftest.
	(temp_dump_context::temp_dump_context): Add param
	"forcibly_enable_dumping".
	(selftest::verify_dumped_text):
	(ASSERT_DUMPED_TEXT_EQ): Move here from dumpfile.c.
	(selftest::verify_item):
	(ASSERT_IS_TEXT): Move here from dumpfile.c.
	(ASSERT_IS_TREE): Likewise.
	(ASSERT_IS_GIMPLE): Likewise.
	* dumpfile.c (dump_context::dump_loc): Move immediate dumping
	to...
	(dump_context::dump_loc_immediate): ...this new function.
	(class dump_pretty_printer): Move to dump-context.h.
	(dump_switch_p_1): Don't enable MSG_PRIORITY_REEMITTED.
	(opt_info_switch_p_1): Enable MSG_PRIORITY_REEMITTED.
	(temp_dump_context::temp_dump_context): Move to "selftest"
	namespace.  Add param "forcibly_enable_dumping", and use it to
	conditionalize the use of m_pp;
	(selftest::verify_dumped_text): Make non-static.
	(ASSERT_DUMPED_TEXT_EQ): Move to dump-context.h.
	(selftest::verify_item): Make non-static.
	(ASSERT_IS_TEXT): Move to dump-context.h.
	(ASSERT_IS_TREE): Likewise.
	(ASSERT_IS_GIMPLE): Likewise.
	(selftest::test_capture_of_dump_calls): Pass "true" for new
	param of temp_dump_context.
	* dumpfile.h (enum dump_flag): Add MSG_PRIORITY_REEMITTED, adding
	it to MSG_ALL_PRIORITIES.  Update values of TDF_COMPARE_DEBUG and
	TDF_COMPARE_DEBUG.
	* opt-problem.cc: New file.
	* opt-problem.h: New file.
	* optinfo-emit-json.cc
	(selftest::test_building_json_from_dump_calls): Pass "true" for
	new param of temp_dump_context.
	* optinfo.cc (optinfo_kind_to_dump_flag): New function.
	(optinfo::emit_for_opt_problem): New function.
	(optinfo::emit): Clarity which emit_item is used.
	* optinfo.h (optinfo::get_dump_location): New accessor.
	(optinfo::emit_for_opt_problem): New decl.
	(optinfo::emit): Make const.
	* selftest-run-tests.c (selftest::run_tests): Call
	selftest::opt_problem_cc_tests.
	* selftest.h (selftest::opt_problem_cc_tests): New decl.
	* tree-data-ref.c (dr_analyze_innermost): Convert return type from
	bool to opt_result, converting fprintf messages to
	opt_result::failure_at calls.  Add "stmt" param for use by the
	failure_at calls.
	(create_data_ref): Pass "stmt" to the dr_analyze_innermost call.
	(runtime_alias_check_p): Convert return type from bool to
	opt_result, converting dump_printf calls to
	opt_result::failure_at, using the statement DDR_A for their
	location.
	(find_data_references_in_stmt): Convert return type from bool to
	opt_result, converting "return false" to opt_result::failure_at
	with a new message.
	* tree-data-ref.h: Include "opt-problem.h".
	(dr_analyze_innermost): Convert return type from bool to opt_result,
	and add a const gimple * param.
	(find_data_references_in_stmt): Convert return type from bool to
	opt_result.
	(runtime_alias_check_p): Likewise.
	* tree-predcom.c (find_looparound_phi): Pass "init_stmt" to
	dr_analyze_innermost.
	* tree-vect-data-refs.c (vect_mark_for_runtime_alias_test):
	Convert return type from bool to opt_result, adding a message for
	the PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS zero case.
	(vect_analyze_data_ref_dependence): Convert return type from bool
	to opt_result.  Change sense of return type from "false"
	effectively meaning "no problems" to "false" meaning a problem,
	so that "return false" becomes "return opt_result::success".
	Convert "return true" calls to opt_result::failure_at, using
	the location of statement A rather than vect_location.
	(vect_analyze_data_ref_dependences): Convert return type from bool
	to opt_result.
	(verify_data_ref_alignment): Likewise, converting dump_printf_loc
	calls to opt_result::failure_at, using the stmt location rather
	than vect_location.
	(vect_verify_datarefs_alignment): Convert return type from bool
	to opt_result.
	(vect_enhance_data_refs_alignment): Likewise.  Split local "stat"
	into multiple more-tightly-scoped copies.
	(vect_analyze_data_refs_alignment): Convert return type from bool
	to opt_result.
	(vect_analyze_data_ref_accesses): Likewise, converting a
	"return false" to a "return opt_result::failure_at", adding a
	new message.
	(vect_prune_runtime_alias_test_list): Convert return type from
	bool to opt_result, converting dump_printf_loc to
	opt_result::failure_at.  Add a %G to show the pertinent statement,
	and use the stmt's location rather than vect_location.
	(vect_find_stmt_data_reference): Convert return type from
	bool to opt_result, converting dump_printf_loc to
	opt_result::failure_at, using stmt's location.
	(vect_analyze_data_refs):  Convert return type from bool to
	opt_result.  Convert "return false" to "return
	opt_result::failure_at", adding messages as needed.
	* tree-vect-loop.c (vect_determine_vf_for_stmt_1): Convert return
	type from bool to opt_result.
	(vect_determine_vf_for_stmt): Likewise.
	(vect_determine_vectorization_factor): Likewise, converting
	dump_printf_loc to opt_result::failure_at, using location of phi
	rather than vect_location.
	(vect_analyze_loop_form_1): Convert return type from bool to
	opt_result, converting dump_printf_loc calls, retaining the use of
	vect_location.
	(vect_analyze_loop_form): Convert return type from loop_vec_info
	to opt_loop_vec_info.
	(vect_analyze_loop_operations): Convert return type from bool to
	opt_result, converting dump_printf_loc calls, using the location
	of phi/stmt rather than vect_location where available.  Convert
	various "return false" to "return opt_result::failure_at" with
	"unsupported phi" messages.
	(vect_get_datarefs_in_loop): Convert return type from bool to
	opt_result.  Add a message for the
	PARAM_LOOP_MAX_DATAREFS_FOR_DATADEPS failure.
	(vect_analyze_loop_2): Convert return type from bool to
	opt_result.  Ensure "ok" is set to a opt_result::failure_at before
	each "goto again;", adding new messages where needed.
	Add "unsupported grouped {store|load}" messages.
	(vect_analyze_loop): Convert return type from loop_vec_info to
	opt_loop_vec_info.
	* tree-vect-slp.c (vect_analyze_slp): Convert return type from
	bool to opt_result.
	* tree-vect-stmts.c (process_use): Likewise, converting
	dump_printf_loc call and using stmt location, rather than
	vect_location.
	(vect_mark_stmts_to_be_vectorized): Likeise.
	(vect_analyze_stmt): Likewise, adding a %G.
	(vect_get_vector_types_for_stmt): Convert return type from bool to
	opt_result, converting dump_printf_loc calls and using stmt
	location, rather than vect_location.
	(vect_get_mask_type_for_stmt): Convert return type from tree to
	opt_tree, converting dump_printf_loc calls and using stmt location.
	* tree-vectorizer.c: Include "opt-problem.h.
	(try_vectorize_loop_1): Flag "Analyzing loop at" dump message as
	MSG_PRIORITY_INTERNALS.  Convert local "loop_vinfo" from
	loop_vec_info to opt_loop_vec_info.  If if fails, and dumping is
	enabled, use it to report at the top level "couldn't vectorize
	loop" followed by the problem.
	* tree-vectorizer.h (opt_loop_vec_info): New typedef.
	(vect_mark_stmts_to_be_vectorized): Convert return type from bool
	to opt_result.
	(vect_analyze_stmt): Likewise.
	(vect_get_vector_types_for_stmt): Likewise.
	(tree vect_get_mask_type_for_stmt): Likewise.
	(vect_analyze_data_ref_dependences): Likewise.
	(vect_enhance_data_refs_alignment): Likewise.
	(vect_analyze_data_refs_alignment): Likewise.
	(vect_verify_datarefs_alignment): Likewise.
	(vect_analyze_data_ref_accesses): Likewise.
	(vect_prune_runtime_alias_test_list): Likewise.
	(vect_find_stmt_data_reference): Likewise.
	(vect_analyze_data_refs): Likewise.
	(vect_analyze_loop): Convert return type from loop_vec_info to
	opt_loop_vec_info.
	(vect_analyze_loop_form): Likewise.
	(vect_analyze_slp): Convert return type from bool to opt_result.

gcc/testsuite/ChangeLog:
	* gcc.dg/vect/nodump-vect-opt-info-2.c: New test.
	* gcc.dg/vect/vect-alias-check-4.c: Add "-fopt-info-vec-all" to
	dg-additional-options.  Add dg-message and dg-missed directives
	to verify that -fopt-info messages are written at the correct
	locations.
---
 gcc/Makefile.in                                    |   1 +
 gcc/dump-context.h                                 | 104 ++++-
 gcc/dumpfile.c                                     | 160 +++-----
 gcc/dumpfile.h                                     |  13 +-
 gcc/opt-problem.cc                                 | 335 ++++++++++++++++
 gcc/opt-problem.h                                  | 289 ++++++++++++++
 gcc/optinfo-emit-json.cc                           |   2 +-
 gcc/optinfo.cc                                     |  44 +-
 gcc/optinfo.h                                      |   7 +-
 gcc/selftest-run-tests.c                           |   1 +
 gcc/selftest.h                                     |   1 +
 gcc/testsuite/gcc.dg/vect/nodump-vect-opt-info-2.c |  12 +
 gcc/testsuite/gcc.dg/vect/vect-alias-check-4.c     |  18 +-
 gcc/tree-data-ref.c                                |  70 ++--
 gcc/tree-data-ref.h                                |  10 +-
 gcc/tree-predcom.c                                 |   3 +-
 gcc/tree-vect-data-refs.c                          | 347 ++++++++--------
 gcc/tree-vect-loop.c                               | 442 +++++++++------------
 gcc/tree-vect-slp.c                                |   4 +-
 gcc/tree-vect-stmts.c                              | 275 ++++++-------
 gcc/tree-vectorizer.c                              |  17 +-
 gcc/tree-vectorizer.h                              |  45 ++-
 22 files changed, 1408 insertions(+), 792 deletions(-)
 create mode 100644 gcc/opt-problem.cc
 create mode 100644 gcc/opt-problem.h
 create mode 100644 gcc/testsuite/gcc.dg/vect/nodump-vect-opt-info-2.c

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 4b7cec8..116ed6e 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1423,6 +1423,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/dump-context.h b/gcc/dump-context.h
index 20b94a7..3a45f23 100644
--- a/gcc/dump-context.h
+++ b/gcc/dump-context.h
@@ -24,6 +24,9 @@ along with GCC; see the file COPYING3.  If not see
 
 #include "dumpfile.h"
 #include "pretty-print.h"
+#include "selftest.h"
+
+namespace selftest { class temp_dump_context; }
 
 /* A class for handling the various dump_* calls.
 
@@ -36,7 +39,8 @@ along with GCC; see the file COPYING3.  If not see
 
 class dump_context
 {
-  friend class temp_dump_context;
+  friend class selftest::temp_dump_context;
+
  public:
   static dump_context &get () { return *s_current; }
 
@@ -45,6 +49,7 @@ class dump_context
   void refresh_dumps_are_enabled ();
 
   void dump_loc (dump_flags_t dump_kind, const dump_location_t &loc);
+  void dump_loc_immediate (dump_flags_t dump_kind, const dump_location_t &loc);
 
   void dump_gimple_stmt (dump_flags_t dump_kind, dump_flags_t extra_dump_flags,
 			 gimple *gs, int spc);
@@ -129,8 +134,53 @@ class dump_context
   static dump_context s_default;
 };
 
+/* A subclass of pretty_printer for implementing dump_context::dump_printf_va.
+   In particular, the formatted chunks are captured as optinfo_item instances,
+   thus retaining metadata about the entities being dumped (e.g. source
+   locations), rather than just as plain text.  */
+
+class dump_pretty_printer : public pretty_printer
+{
+public:
+  dump_pretty_printer (dump_context *context, dump_flags_t dump_kind);
+
+  void emit_items (optinfo *dest);
+
+private:
+  /* Information on an optinfo_item that was generated during phase 2 of
+     formatting.  */
+  struct stashed_item
+  {
+    stashed_item (const char **buffer_ptr_, optinfo_item *item_)
+      : buffer_ptr (buffer_ptr_), item (item_) {}
+    const char **buffer_ptr;
+    optinfo_item *item;
+  };
+
+  static bool format_decoder_cb (pretty_printer *pp, text_info *text,
+				 const char *spec, int /*precision*/,
+				 bool /*wide*/, bool /*set_locus*/,
+				 bool /*verbose*/, bool */*quoted*/,
+				 const char **buffer_ptr);
+
+  bool decode_format (text_info *text, const char *spec,
+		      const char **buffer_ptr);
+
+  void stash_item (const char **buffer_ptr, optinfo_item *item);
+
+  void emit_any_pending_textual_chunks (optinfo *dest);
+
+  void emit_item (optinfo_item *item, optinfo *dest);
+
+  dump_context *m_context;
+  dump_flags_t m_dump_kind;
+  auto_vec<stashed_item> m_stashed_items;
+};
+
 #if CHECKING_P
 
+namespace selftest {
+
 /* An RAII-style class for use in selftests for temporarily using a different
    dump_context.  */
 
@@ -138,6 +188,7 @@ class temp_dump_context
 {
  public:
   temp_dump_context (bool forcibly_enable_optinfo,
+		     bool forcibly_enable_dumping,
 		     dump_flags_t test_pp_flags);
   ~temp_dump_context ();
 
@@ -151,6 +202,57 @@ class temp_dump_context
   dump_context *m_saved;
 };
 
+/* Implementation detail of ASSERT_DUMPED_TEXT_EQ.  */
+
+extern void verify_dumped_text (const location &loc,
+				temp_dump_context *context,
+				const char *expected_text);
+
+/* Verify that the text dumped so far in CONTEXT equals
+   EXPECTED_TEXT.
+   As a side-effect, the internal buffer is 0-terminated.  */
+
+#define ASSERT_DUMPED_TEXT_EQ(CONTEXT, EXPECTED_TEXT)			\
+  SELFTEST_BEGIN_STMT							\
+    verify_dumped_text (SELFTEST_LOCATION, &(CONTEXT), (EXPECTED_TEXT)); \
+  SELFTEST_END_STMT
+
+
+/* Verify that ITEM has the expected values.  */
+
+void
+verify_item (const location &loc,
+	     const optinfo_item *item,
+	     enum optinfo_item_kind expected_kind,
+	     location_t expected_location,
+	     const char *expected_text);
+
+/* Verify that ITEM is a text item, with EXPECTED_TEXT.  */
+
+#define ASSERT_IS_TEXT(ITEM, EXPECTED_TEXT) \
+  SELFTEST_BEGIN_STMT						    \
+    verify_item (SELFTEST_LOCATION, (ITEM), OPTINFO_ITEM_KIND_TEXT, \
+		 UNKNOWN_LOCATION, (EXPECTED_TEXT));		    \
+  SELFTEST_END_STMT
+
+/* Verify that ITEM is a tree item, with the expected values.  */
+
+#define ASSERT_IS_TREE(ITEM, EXPECTED_LOCATION, EXPECTED_TEXT) \
+  SELFTEST_BEGIN_STMT						    \
+    verify_item (SELFTEST_LOCATION, (ITEM), OPTINFO_ITEM_KIND_TREE, \
+		 (EXPECTED_LOCATION), (EXPECTED_TEXT));	    \
+  SELFTEST_END_STMT
+
+/* Verify that ITEM is a gimple item, with the expected values.  */
+
+#define ASSERT_IS_GIMPLE(ITEM, EXPECTED_LOCATION, EXPECTED_TEXT) \
+  SELFTEST_BEGIN_STMT						    \
+    verify_item (SELFTEST_LOCATION, (ITEM), OPTINFO_ITEM_KIND_GIMPLE, \
+		 (EXPECTED_LOCATION), (EXPECTED_TEXT));	    \
+  SELFTEST_END_STMT
+
+} // namespace selftest
+
 #endif /* CHECKING_P */
 
 #endif /* GCC_DUMP_CONTEXT_H */
diff --git a/gcc/dumpfile.c b/gcc/dumpfile.c
index e15edc7..0b140ff 100644
--- a/gcc/dumpfile.c
+++ b/gcc/dumpfile.c
@@ -562,6 +562,21 @@ dump_context::dump_loc (dump_flags_t dump_kind, const dump_location_t &loc)
 {
   end_any_optinfo ();
 
+  dump_loc_immediate (dump_kind, loc);
+
+  if (optinfo_enabled_p ())
+    {
+      optinfo &info = begin_next_optinfo (loc);
+      info.handle_dump_file_kind (dump_kind);
+    }
+}
+
+/* As dump_loc above, but without starting a new optinfo. */
+
+void
+dump_context::dump_loc_immediate (dump_flags_t dump_kind,
+				  const dump_location_t &loc)
+{
   location_t srcloc = loc.get_location_t ();
 
   if (dump_file && apply_dump_filter_p (dump_kind, pflags))
@@ -573,12 +588,6 @@ dump_context::dump_loc (dump_flags_t dump_kind, const dump_location_t &loc)
   /* Support for temp_dump_context in selftests.  */
   if (m_test_pp && apply_dump_filter_p (dump_kind, m_test_pp_flags))
     ::dump_loc (dump_kind, m_test_pp, srcloc);
-
-  if (optinfo_enabled_p ())
-    {
-      optinfo &info = begin_next_optinfo (loc);
-      info.handle_dump_file_kind (dump_kind);
-    }
 }
 
 /* Make an item for the given dump call, equivalent to print_gimple_stmt.  */
@@ -739,49 +748,6 @@ dump_context::dump_generic_expr_loc (dump_flags_t dump_kind,
   dump_generic_expr (dump_kind, extra_dump_flags, t);
 }
 
-/* A subclass of pretty_printer for implementing dump_context::dump_printf_va.
-   In particular, the formatted chunks are captured as optinfo_item instances,
-   thus retaining metadata about the entities being dumped (e.g. source
-   locations), rather than just as plain text.  */
-
-class dump_pretty_printer : public pretty_printer
-{
-public:
-  dump_pretty_printer (dump_context *context, dump_flags_t dump_kind);
-
-  void emit_items (optinfo *dest);
-
-private:
-  /* Information on an optinfo_item that was generated during phase 2 of
-     formatting.  */
-  struct stashed_item
-  {
-    stashed_item (const char **buffer_ptr_, optinfo_item *item_)
-      : buffer_ptr (buffer_ptr_), item (item_) {}
-    const char **buffer_ptr;
-    optinfo_item *item;
-  };
-
-  static bool format_decoder_cb (pretty_printer *pp, text_info *text,
-				 const char *spec, int /*precision*/,
-				 bool /*wide*/, bool /*set_locus*/,
-				 bool /*verbose*/, bool */*quoted*/,
-				 const char **buffer_ptr);
-
-  bool decode_format (text_info *text, const char *spec,
-		      const char **buffer_ptr);
-
-  void stash_item (const char **buffer_ptr, optinfo_item *item);
-
-  void emit_any_pending_textual_chunks (optinfo *dest);
-
-  void emit_item (optinfo_item *item, optinfo *dest);
-
-  dump_context *m_context;
-  dump_flags_t m_dump_kind;
-  auto_vec<stashed_item> m_stashed_items;
-};
-
 /* dump_pretty_printer's ctor.  */
 
 dump_pretty_printer::dump_pretty_printer (dump_context *context,
@@ -1732,7 +1698,12 @@ dump_switch_p_1 (const char *arg, struct dump_file_info *dfi, bool doglob)
     return 0;
 
   ptr = option_value;
-  flags = MSG_ALL_PRIORITIES;
+
+  /* Retain "user-facing" and "internals" messages, but filter out
+     those from an opt_problem being re-emitted at the top level
+     (MSG_PRIORITY_REEMITTED), so as to avoid duplicate messages
+     messing up scan-tree-dump-times" in DejaGnu tests.  */
+  flags = MSG_PRIORITY_USER_FACING | MSG_PRIORITY_INTERNALS;
 
   while (*ptr)
     {
@@ -1830,8 +1801,9 @@ opt_info_switch_p_1 (const char *arg, dump_flags_t *flags,
   *filename = NULL;
 
   /* Default to filtering out "internals" messages, and retaining
-     "user-facing" messages.  */
-  *flags = MSG_PRIORITY_USER_FACING;
+     "user-facing" messages, and those from an opt_problem being
+     re-emitted at the top level.  */
+  *flags = MSG_PRIORITY_USER_FACING | MSG_PRIORITY_REEMITTED;
 
   *optgroup_flags = OPTGROUP_NONE;
 
@@ -1981,19 +1953,26 @@ enable_rtl_dump_file (void)
 
 #if CHECKING_P
 
+namespace selftest {
+
 /* temp_dump_context's ctor.  Temporarily override the dump_context
    (to forcibly enable optinfo-generation).  */
 
 temp_dump_context::temp_dump_context (bool forcibly_enable_optinfo,
+				      bool forcibly_enable_dumping,
 				      dump_flags_t test_pp_flags)
-
 : m_context (),
   m_saved (&dump_context ().get ())
 {
   dump_context::s_current = &m_context;
   m_context.m_forcibly_enable_optinfo = forcibly_enable_optinfo;
-  m_context.m_test_pp = &m_pp;
-  m_context.m_test_pp_flags = test_pp_flags;
+  /* Conditionally enable the test dump, so that we can verify both the
+     dump_enabled_p and the !dump_enabled_p cases in selftests.  */
+  if (forcibly_enable_dumping)
+    {
+      m_context.m_test_pp = &m_pp;
+      m_context.m_test_pp_flags = test_pp_flags;
+    }
 
   dump_context::get ().refresh_dumps_are_enabled ();
 }
@@ -2015,8 +1994,6 @@ temp_dump_context::get_dumped_text ()
   return pp_formatted_text (&m_pp);
 }
 
-namespace selftest {
-
 /* Verify that the dump_location_t constructors capture the source location
    at which they were called (provided that the build compiler is sufficiently
    recent).  */
@@ -2055,7 +2032,7 @@ test_impl_location ()
    EXPECTED_TEXT, using LOC for the location of any failure.
    As a side-effect, the internal buffer is 0-terminated.  */
 
-static void
+void
 verify_dumped_text (const location &loc,
 		    temp_dump_context *context,
 		    const char *expected_text)
@@ -2065,18 +2042,9 @@ verify_dumped_text (const location &loc,
 		   expected_text);
 }
 
-/* Verify that the text dumped so far in CONTEXT equals
-   EXPECTED_TEXT.
-   As a side-effect, the internal buffer is 0-terminated.  */
-
-#define ASSERT_DUMPED_TEXT_EQ(CONTEXT, EXPECTED_TEXT)			\
-  SELFTEST_BEGIN_STMT							\
-    verify_dumped_text (SELFTEST_LOCATION, &(CONTEXT), (EXPECTED_TEXT)); \
-  SELFTEST_END_STMT
-
 /* Verify that ITEM has the expected values.  */
 
-static void
+void
 verify_item (const location &loc,
 	     const optinfo_item *item,
 	     enum optinfo_item_kind expected_kind,
@@ -2088,30 +2056,6 @@ verify_item (const location &loc,
   ASSERT_STREQ_AT (loc, item->get_text (), expected_text);
 }
 
-/* Verify that ITEM is a text item, with EXPECTED_TEXT.  */
-
-#define ASSERT_IS_TEXT(ITEM, EXPECTED_TEXT) \
-  SELFTEST_BEGIN_STMT						    \
-    verify_item (SELFTEST_LOCATION, (ITEM), OPTINFO_ITEM_KIND_TEXT, \
-		 UNKNOWN_LOCATION, (EXPECTED_TEXT));		    \
-  SELFTEST_END_STMT
-
-/* Verify that ITEM is a tree item, with the expected values.  */
-
-#define ASSERT_IS_TREE(ITEM, EXPECTED_LOCATION, EXPECTED_TEXT) \
-  SELFTEST_BEGIN_STMT						    \
-    verify_item (SELFTEST_LOCATION, (ITEM), OPTINFO_ITEM_KIND_TREE, \
-		 (EXPECTED_LOCATION), (EXPECTED_TEXT));	    \
-  SELFTEST_END_STMT
-
-/* Verify that ITEM is a gimple item, with the expected values.  */
-
-#define ASSERT_IS_GIMPLE(ITEM, EXPECTED_LOCATION, EXPECTED_TEXT) \
-  SELFTEST_BEGIN_STMT						    \
-    verify_item (SELFTEST_LOCATION, (ITEM), OPTINFO_ITEM_KIND_GIMPLE, \
-		 (EXPECTED_LOCATION), (EXPECTED_TEXT));	    \
-  SELFTEST_END_STMT
-
 /* Verify that calls to the dump_* API are captured and consolidated into
    optimization records. */
 
@@ -2144,7 +2088,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
 
       /* Test of dump_printf.  */
       {
-	temp_dump_context tmp (with_optinfo,
+	temp_dump_context tmp (with_optinfo, true,
 			       MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
 	dump_printf (MSG_NOTE, "int: %i str: %s", 42, "foo");
 
@@ -2161,7 +2105,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
 
       /* Test of dump_printf with %T.  */
       {
-	temp_dump_context tmp (with_optinfo,
+	temp_dump_context tmp (with_optinfo, true,
 			       MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
 	dump_printf (MSG_NOTE, "tree: %T", integer_zero_node);
 
@@ -2179,7 +2123,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
 
       /* Test of dump_printf with %E.  */
       {
-	temp_dump_context tmp (with_optinfo,
+	temp_dump_context tmp (with_optinfo, true,
 			       MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
 	dump_printf (MSG_NOTE, "gimple: %E", stmt);
 
@@ -2197,7 +2141,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
 
       /* Test of dump_printf with %G.  */
       {
-	temp_dump_context tmp (with_optinfo,
+	temp_dump_context tmp (with_optinfo, true,
 			       MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
 	dump_printf (MSG_NOTE, "gimple: %G", stmt);
 
@@ -2220,7 +2164,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
 	 - multiple dump-specific format codes: some consecutive, others
 	 separated by text, trailing text after the final one.  */
       {
-	temp_dump_context tmp (with_optinfo,
+	temp_dump_context tmp (with_optinfo, true,
 			       MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
 	dump_printf_loc (MSG_NOTE, loc, "before %T and %T"
 			 " %i consecutive %E%E after\n",
@@ -2248,7 +2192,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
 
       /* Tree, via dump_generic_expr.  */
       {
-	temp_dump_context tmp (with_optinfo,
+	temp_dump_context tmp (with_optinfo, true,
 			       MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
 	dump_printf_loc (MSG_NOTE, loc, "test of tree: ");
 	dump_generic_expr (MSG_NOTE, TDF_SLIM, integer_zero_node);
@@ -2268,7 +2212,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
 
       /* Tree, via dump_generic_expr_loc.  */
       {
-	temp_dump_context tmp (with_optinfo,
+	temp_dump_context tmp (with_optinfo, true,
 			       MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
 	dump_generic_expr_loc (MSG_NOTE, loc, TDF_SLIM, integer_one_node);
 
@@ -2288,7 +2232,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
       {
 	/* dump_gimple_stmt_loc.  */
 	{
-	  temp_dump_context tmp (with_optinfo,
+	  temp_dump_context tmp (with_optinfo, true,
 				 MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
 	  dump_gimple_stmt_loc (MSG_NOTE, loc, TDF_SLIM, stmt, 2);
 
@@ -2304,7 +2248,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
 
 	/* dump_gimple_stmt.  */
 	{
-	  temp_dump_context tmp (with_optinfo,
+	  temp_dump_context tmp (with_optinfo, true,
 				 MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
 	  dump_gimple_stmt (MSG_NOTE, TDF_SLIM, stmt, 2);
 
@@ -2320,7 +2264,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
 
 	/* dump_gimple_expr_loc.  */
 	{
-	  temp_dump_context tmp (with_optinfo,
+	  temp_dump_context tmp (with_optinfo, true,
 				 MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
 	  dump_gimple_expr_loc (MSG_NOTE, loc, TDF_SLIM, stmt, 2);
 
@@ -2336,7 +2280,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
 
 	/* dump_gimple_expr.  */
 	{
-	  temp_dump_context tmp (with_optinfo,
+	  temp_dump_context tmp (with_optinfo, true,
 				 MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
 	  dump_gimple_expr (MSG_NOTE, TDF_SLIM, stmt, 2);
 
@@ -2353,7 +2297,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
 
       /* poly_int.  */
       {
-	temp_dump_context tmp (with_optinfo,
+	temp_dump_context tmp (with_optinfo, true,
 			       MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
 	dump_dec (MSG_NOTE, poly_int64 (42));
 
@@ -2378,7 +2322,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
 	  if (j / 2)
 	    dump_filter |= MSG_PRIORITY_INTERNALS;
 
-	  temp_dump_context tmp (with_optinfo, dump_filter);
+	  temp_dump_context tmp (with_optinfo, true, dump_filter);
 	  /* Emit various messages, mostly with implicit priority.  */
 	  dump_printf_loc (MSG_NOTE, stmt, "msg 1\n");
 	  dump_printf_loc (MSG_NOTE | MSG_PRIORITY_INTERNALS, stmt,
@@ -2460,7 +2404,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
   {
     /* MSG_OPTIMIZED_LOCATIONS.  */
     {
-      temp_dump_context tmp (true, MSG_ALL_KINDS);
+      temp_dump_context tmp (true, true, MSG_ALL_KINDS);
       dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc, "test");
       ASSERT_EQ (tmp.get_pending_optinfo ()->get_kind (),
 		 OPTINFO_KIND_SUCCESS);
@@ -2468,7 +2412,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
 
     /* MSG_MISSED_OPTIMIZATION.  */
     {
-      temp_dump_context tmp (true, MSG_ALL_KINDS);
+      temp_dump_context tmp (true, true, MSG_ALL_KINDS);
       dump_printf_loc (MSG_MISSED_OPTIMIZATION, loc, "test");
       ASSERT_EQ (tmp.get_pending_optinfo ()->get_kind (),
 		 OPTINFO_KIND_FAILURE);
@@ -2477,7 +2421,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
 
   /* Verify that MSG_* affect AUTO_DUMP_SCOPE and the dump calls.  */
   {
-    temp_dump_context tmp (false,
+    temp_dump_context tmp (false, true,
 			   MSG_OPTIMIZED_LOCATIONS | MSG_ALL_PRIORITIES);
     dump_printf_loc (MSG_NOTE, stmt, "msg 1\n");
     {
diff --git a/gcc/dumpfile.h b/gcc/dumpfile.h
index 5933905..c82157d 100644
--- a/gcc/dumpfile.h
+++ b/gcc/dumpfile.h
@@ -179,15 +179,22 @@ enum dump_flag
   /* Implicitly supplied for messages within nested dump scopes.  */
   MSG_PRIORITY_INTERNALS = (1 << 26),
 
+  /* Supplied when an opt_problem generated in a nested scope is re-emitted
+     at the top-level.   We want to default to showing these in -fopt-info
+     output, but to *not* show them in dump files, as the message would be
+     shown twice, messing up "scan-tree-dump-times" in DejaGnu tests.  */
+  MSG_PRIORITY_REEMITTED = (1 << 27),
+
   /* Mask for selecting MSG_PRIORITY_* flags.  */
   MSG_ALL_PRIORITIES = (MSG_PRIORITY_USER_FACING
-			| MSG_PRIORITY_INTERNALS),
+			| MSG_PRIORITY_INTERNALS
+			| MSG_PRIORITY_REEMITTED),
 
   /* Dumping for -fcompare-debug.  */
-  TDF_COMPARE_DEBUG = (1 << 27),
+  TDF_COMPARE_DEBUG = (1 << 28),
 
   /* All values.  */
-  TDF_ALL_VALUES = (1 << 28) - 1
+  TDF_ALL_VALUES = (1 << 29) - 1
 };
 
 /* Dump flags type.  */
diff --git a/gcc/opt-problem.cc b/gcc/opt-problem.cc
new file mode 100644
index 0000000..dad3a8c
--- /dev/null
+++ b/gcc/opt-problem.cc
@@ -0,0 +1,335 @@
+/* Rich optional 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 "tree.h"
+#include "gimple.h"
+#include "pretty-print.h"
+#include "opt-problem.h"
+#include "dump-context.h"
+#include "tree-pass.h"
+#include "selftest.h"
+
+/* opt_problem's ctor.
+
+   Use FMT and AP to emit a message to the "immediate" dump destinations
+   as if via:
+     dump_printf_loc (MSG_MISSED_OPTIMIZATION, loc, ...)
+
+   The optinfo_item instances are not emitted yet.  Instead, they
+   are retained internally so that the message can be replayed and
+   emitted when this problem is handled, higher up the call stack.  */
+
+opt_problem::opt_problem (const dump_location_t &loc,
+			  const char *fmt, va_list *ap)
+: m_optinfo (loc, OPTINFO_KIND_FAILURE, current_pass)
+{
+  /* We shouldn't be bothering to construct these objects if
+     dumping isn't enabled.  */
+  gcc_assert (dump_enabled_p ());
+
+  /* Update the singleton.  */
+  delete s_the_problem;
+  s_the_problem = this;
+
+  /* Print the location to the "immediate" dump destinations.  */
+  dump_context &dc = dump_context::get ();
+  dc.dump_loc (MSG_MISSED_OPTIMIZATION, loc);
+
+  /* Print the formatted string to this opt_problem's optinfo, dumping
+     the items to the "immediate" dump destinations, and storing items
+     for later retrieval.  */
+  {
+    dump_pretty_printer pp (&dump_context::get (), MSG_MISSED_OPTIMIZATION);
+
+    text_info text;
+    text.err_no = errno;
+    text.args_ptr = ap;
+    text.format_spec = fmt; /* No i18n is performed.  */
+
+    /* Phases 1 and 2, using pp_format.  */
+    pp_format (&pp, &text);
+
+    /* Phase 3: dump the items to the "immediate" dump destinations,
+       and storing them into m_optinfo for later retrieval.  */
+    pp.emit_items (&m_optinfo);
+  }
+}
+
+/* Emit this problem and delete it, clearing the current opt_problem.  */
+
+void
+opt_problem::emit_and_clear ()
+{
+  gcc_assert (this == s_the_problem);
+
+  m_optinfo.emit_for_opt_problem ();
+
+  delete this;
+  s_the_problem = NULL;
+}
+
+/* The singleton opt_problem *.  */
+
+opt_problem *opt_problem::s_the_problem;
+
+#if CHECKING_P
+
+namespace selftest {
+
+static opt_result
+function_that_succeeds ()
+{
+  return opt_result::success ();
+}
+
+/* Verify that opt_result::success works.  */
+
+static void
+test_opt_result_success ()
+{
+  /* Run all tests twice, with and then without dumping enabled.  */
+  for (int i = 0 ; i < 2; i++)
+    {
+      bool with_dumping = (i == 0);
+
+      temp_dump_context tmp (with_dumping, with_dumping,
+			     MSG_ALL_KINDS | MSG_ALL_PRIORITIES);
+
+      if (with_dumping)
+	gcc_assert (dump_enabled_p ());
+      else
+	gcc_assert (!dump_enabled_p ());
+
+      opt_result res = function_that_succeeds ();
+
+      /* Verify that "success" can be used as a "true" boolean.  */
+      ASSERT_TRUE (res);
+
+      /* Verify the underlying opt_wrapper<bool>.  */
+      ASSERT_TRUE (res.get_result ());
+      ASSERT_EQ (res.get_problem (), NULL);
+
+      /* Nothing should have been dumped.  */
+      ASSERT_DUMPED_TEXT_EQ (tmp, "");
+      optinfo *info = tmp.get_pending_optinfo ();
+      ASSERT_EQ (info, NULL);
+    }
+}
+
+/* Example of a function that fails, with a non-trivial
+   pre-canned error message.  */
+
+static opt_result
+function_that_fails (const greturn *stmt)
+{
+  gcc_assert (stmt);
+  gcc_assert (gimple_return_retval (stmt));
+
+  AUTO_DUMP_SCOPE ("function_that_fails", stmt);
+
+  return opt_result::failure_at (stmt,
+				 "can't handle return type: %T for stmt: %G",
+				 TREE_TYPE (gimple_return_retval (stmt)),
+				 static_cast <const gimple *> (stmt));
+}
+
+/* Example of a function that indirectly fails.  */
+
+static opt_result
+function_that_indirectly_fails (const greturn *stmt)
+{
+  AUTO_DUMP_SCOPE ("function_that_indirectly_fails", stmt);
+
+  opt_result res = function_that_fails (stmt);
+  if (!res)
+    return res;
+  return opt_result::success ();
+}
+
+/* Verify that opt_result::failure_at works.
+   Simulate a failure handling a stmt at one location whilst considering
+   an optimization that's notionally at another location (as a microcosm
+   of e.g. a problematic statement within a loop that prevents loop
+   vectorization).  */
+
+static void
+test_opt_result_failure_at (const line_table_case &case_)
+{
+  /* Generate a location_t for testing.  */
+  line_table_test ltt (case_);
+  const line_map_ordinary *ord_map
+    = linemap_check_ordinary (linemap_add (line_table, LC_ENTER, false,
+					   "test.c", 0));
+  linemap_line_start (line_table, 5, 100);
+
+  /* A test location: "test.c:5:10".  */
+  const location_t line_5 = linemap_position_for_column (line_table, 10);
+
+  /* Another test location: "test.c:6:12".  */
+  const location_t line_6
+    = linemap_position_for_line_and_column (line_table, ord_map, 6, 12);
+
+  if (line_6 > LINE_MAP_MAX_LOCATION_WITH_COLS)
+    return;
+
+  /* Generate statements using "line_5" and "line_6" for testing.  */
+  greturn *stmt_at_5 = gimple_build_return (integer_one_node);
+  gimple_set_location (stmt_at_5, line_5);
+
+  greturn *stmt_at_6 = gimple_build_return (integer_zero_node);
+  gimple_set_location (stmt_at_6, line_6);
+
+  /* Run with and then without dumping enabled.  */
+  for (int i = 0; i < 2; i++)
+    {
+      bool with_dumping = (i == 0);
+
+      /* Run with all 4 combinations of
+	 with and without MSG_PRIORITY_INTERNALS and
+	 with and without MSG_PRIORITY_REEMITTED.  */
+      for (int j = 0; j < 4; j++)
+	{
+	  dump_flags_t filter = MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING;
+	  if (j / 2)
+	    filter |= MSG_PRIORITY_INTERNALS;
+	  if (j % 2)
+	    filter |= MSG_PRIORITY_REEMITTED;
+
+	  temp_dump_context tmp (with_dumping, with_dumping, filter);
+
+	  if (with_dumping)
+	    gcc_assert (dump_enabled_p ());
+	  else
+	    gcc_assert (!dump_enabled_p ());
+
+	  /* Simulate attempting to optimize "stmt_at_6".  */
+	  opt_result res = function_that_indirectly_fails (stmt_at_6);
+
+	  /* Verify that "failure" can be used as a "false" boolean.  */
+	  ASSERT_FALSE (res);
+
+	  /* Verify the underlying opt_wrapper<bool>.  */
+	  ASSERT_FALSE (res.get_result ());
+	  opt_problem *problem = res.get_problem ();
+
+	  if (with_dumping)
+	    {
+	      ASSERT_NE (problem, NULL);
+	      ASSERT_EQ (problem->get_dump_location ().get_location_t (),
+			 line_6);
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)
+	      /* Verify that the problem captures the implementation location
+		 it was emitted from.  */
+	      const dump_impl_location_t &impl_location
+		= problem->get_dump_location ().get_impl_location ();
+	      ASSERT_STR_CONTAINS (impl_location.m_function,
+				   "function_that_fails");
+#endif
+
+	      /* Verify that the underlying dump items are retained in the
+		 opt_problem.  */
+	      const optinfo &info = problem->get_optinfo ();
+	      ASSERT_EQ (info.get_dump_location ().get_location_t (), line_6);
+	      ASSERT_EQ (info.num_items (), 4);
+	      ASSERT_IS_TEXT (info.get_item (0), "can't handle return type: ");
+	      ASSERT_IS_TREE (info.get_item (1), UNKNOWN_LOCATION, "int");
+	      ASSERT_IS_TEXT (info.get_item (2), " for stmt: ");
+	      ASSERT_IS_GIMPLE (info.get_item (3), line_6, "return 0;\n");
+
+	      /* ...but not in the dump_context's pending_optinfo.  */
+	      ASSERT_EQ (tmp.get_pending_optinfo (), NULL);
+
+	      /* Simulate emitting a high-level summary message, followed
+		 by the problem.  */
+	      dump_printf_loc (MSG_MISSED_OPTIMIZATION, stmt_at_5,
+			       "can't optimize loop\n");
+	      problem->emit_and_clear ();
+	      ASSERT_EQ (res.get_problem (), NULL);
+
+	      /* Verify that the error message was dumped (when the failure
+		 occurred).  We can't use a switch here as not all of the
+		 values are const expressions (using C++98).  */
+	      dump_flags_t effective_filter
+		= filter & (MSG_PRIORITY_INTERNALS | MSG_PRIORITY_REEMITTED);
+	      if (effective_filter
+		  == (MSG_PRIORITY_INTERNALS | MSG_PRIORITY_REEMITTED))
+		/* The -fopt-info-internals case.  */
+		ASSERT_DUMPED_TEXT_EQ
+		  (tmp,
+		   "test.c:6:12: note:  === function_that_indirectly_fails"
+		   " ===\n"
+		   "test.c:6:12: note:   === function_that_fails ===\n"
+		   "test.c:6:12: missed:   can't handle return type: int"
+		   " for stmt: return 0;\n"
+		   "test.c:5:10: missed: can't optimize loop\n"
+		   "test.c:6:12: missed: can't handle return type: int"
+		   " for stmt: return 0;\n");
+	      else if (effective_filter == MSG_PRIORITY_INTERNALS)
+		/* The default for dump files.  */
+		ASSERT_DUMPED_TEXT_EQ
+		  (tmp,
+		   "test.c:6:12: note:  === function_that_indirectly_fails"
+		   " ===\n"
+		   "test.c:6:12: note:   === function_that_fails ===\n"
+		   "test.c:6:12: missed:   can't handle return type: int"
+		     " for stmt: return 0;\n"
+		   "test.c:5:10: missed: can't optimize loop\n");
+	      else if (effective_filter == MSG_PRIORITY_REEMITTED)
+		/* The default when -fopt-info is enabled.  */
+		ASSERT_DUMPED_TEXT_EQ
+		  (tmp,
+		   "test.c:5:10: missed: can't optimize loop\n"
+		   "test.c:6:12: missed: can't handle return type: int"
+		   " for stmt: return 0;\n");
+	      else
+		{
+		  gcc_assert (effective_filter == 0);
+		  ASSERT_DUMPED_TEXT_EQ
+		    (tmp,
+		     "test.c:5:10: missed: can't optimize loop\n");
+		}
+	    }
+	  else
+	    {
+	      /* If dumping was disabled, then no problem should have been
+		 created, and nothing should have been dumped.  */
+	      ASSERT_EQ (problem, NULL);
+	      ASSERT_DUMPED_TEXT_EQ (tmp, "");
+	    }
+	}
+    }
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+opt_problem_cc_tests ()
+{
+  test_opt_result_success ();
+  for_each_line_table_case (test_opt_result_failure_at);
+}
+
+} // namespace selftest
+
+#endif /* CHECKING_P */
diff --git a/gcc/opt-problem.h b/gcc/opt-problem.h
new file mode 100644
index 0000000..68d7e4a
--- /dev/null
+++ b/gcc/opt-problem.h
@@ -0,0 +1,289 @@
+/* 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
+
+#include "diagnostic-core.h" /* for ATTRIBUTE_GCC_DIAG.  */
+#include "optinfo.h" /* for optinfo.  */
+
+/* This header declares a family of wrapper classes for tracking a
+   success/failure value, while optionally supporting propagating an
+   opt_problem * describing any failure back up the call stack.
+
+   For instance, at the deepest point of the callstack where the failure
+   happens, rather than:
+
+     if (!check_something ())
+       {
+         if (dump_enabled_p ())
+           dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+                            "foo is unsupported.\n");
+         return false;
+       }
+     // [...more checks...]
+
+     // All checks passed:
+     return true;
+
+   we can capture the cause of the failure via:
+
+     if (!check_something ())
+       return opt_result::failure_at (stmt, "foo is unsupported");
+     // [...more checks...]
+
+     // All checks passed:
+     return opt_result::success ();
+
+   which effectively returns true or false, whilst recording any problem.
+
+   opt_result::success and opt_result::failure return opt_result values
+   which "looks like" true/false respectively, via operator bool().
+   If dump_enabled_p, then opt_result::failure also creates an opt_problem *,
+   capturing the pertinent data (here, "foo is unsupported " and "stmt").
+   If dumps are disabled, then opt_problem instances aren't
+   created, and it's equivalent to just returning a bool.
+
+   The opt_problem can be propagated via opt_result values back up
+   the call stack to where it makes most sense to the user.
+   For instance, rather than:
+
+     bool ok = try_something_that_might_fail ();
+     if (!ok)
+       {
+         if (dump_enabled_p ())
+           dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+                            "some message.\n");
+         return false;
+       }
+
+   we can replace the bool with an opt_result, so if dump_enabled_p, we
+   assume that if try_something_that_might_fail, an opt_problem * will be
+   created, and we can propagate it up the call chain:
+
+     opt_result ok = try_something_that_might_fail ();
+     if (!ok)
+       {
+         if (dump_enabled_p ())
+           dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+                            "some message.\n");
+         return ok; // propagating the opt_result
+       }
+
+   opt_result is an opt_wrapper<bool>, where opt_wrapper<T> is a base
+   class for wrapping a T, optionally propagating an opt_problem in
+   case of failure_at (when dumps are enabled).  Similarly,
+   opt_pointer_wrapper<T> can be used to wrap pointer types (where non-NULL
+   signifies success, NULL signifies failure).
+
+   In all cases, opt_wrapper<T> acts as if the opt_problem were one of its
+   fields, but the opt_problem is actually stored in a global, so that when
+   compiled, an opt_wrapper<T> is effectively just a T, so that we're
+   still just passing e.g. a bool around; the opt_wrapper<T> classes
+   simply provide type-checking and an API to ensure that we provide
+   error-messages deep in the callstack at the places where problems
+   occur, and that we propagate them.  This also avoids having
+   to manage the ownership of the opt_problem instances.
+
+   Using opt_result and opt_wrapper<T> documents the intent of the code
+   for the places where we represent success values, and allows the C++ type
+   system to track where the deepest points in the callstack are where we
+   need to emit the failure messages from.  */
+
+/* A bundle of information about why an optimization failed (e.g.
+   vectorization), and the location in both the user's code and
+   in GCC itself where the problem occurred.
+
+   Instances are created by static member functions in opt_wrapper
+   subclasses, such as opt_result::failure.
+
+   Instances are only created when dump_enabled_p ().  */
+
+class opt_problem
+{
+ public:
+  static opt_problem *get_singleton () { return s_the_problem; }
+
+  opt_problem (const dump_location_t &loc,
+	       const char *fmt, va_list *ap)
+    ATTRIBUTE_GCC_DUMP_PRINTF (3, 0);
+
+  const dump_location_t &
+  get_dump_location () const { return m_optinfo.get_dump_location (); }
+
+  const optinfo & get_optinfo () const { return m_optinfo; }
+
+  void emit_and_clear ();
+
+ private:
+  optinfo m_optinfo;
+
+  static opt_problem *s_the_problem;
+};
+
+/* A base class for wrapper classes that track a success/failure value, while
+   optionally supporting propagating an opt_problem * describing any
+   failure back up the call stack.  */
+
+template <typename T>
+class opt_wrapper
+{
+ public:
+  typedef T wrapped_t;
+
+  /* Be accessible as the wrapped type.  */
+  operator wrapped_t () const { return m_result; }
+
+  /* No public ctor.  */
+
+  wrapped_t get_result () const { return m_result; }
+  opt_problem *get_problem () const { return opt_problem::get_singleton (); }
+
+ protected:
+  opt_wrapper (wrapped_t result, opt_problem */*problem*/)
+  : m_result (result)
+  {
+    /* "problem" is ignored: although it looks like a field, we
+       actually just use the opt_problem singleton, so that
+       opt_wrapper<T> in memory is just a T.  */
+  }
+
+ private:
+  wrapped_t m_result;
+};
+
+/* Subclass of opt_wrapper<T> for bool, where
+   - true signifies "success", and
+   - false signifies "failure"
+   whilst effectively propagating an opt_problem * describing any failure
+   back up the call stack.  */
+
+class opt_result : public opt_wrapper <bool>
+{
+ public:
+  /* Generate a "success" value: a wrapper around "true".  */
+
+  static opt_result success () { return opt_result (true, NULL); }
+
+  /* Generate a "failure" value: a wrapper around "false", and,
+     if dump_enabled_p, an opt_problem.  */
+
+  static opt_result failure_at (const dump_location_t &loc,
+				const char *fmt, ...)
+	  ATTRIBUTE_GCC_DUMP_PRINTF (2, 3)
+  {
+    opt_problem *problem = NULL;
+    if (dump_enabled_p ())
+      {
+	va_list ap;
+	va_start (ap, fmt);
+	problem = new opt_problem (loc, fmt, &ap);
+	va_end (ap);
+      }
+    return opt_result (false, problem);
+  }
+
+  /* Given a failure wrapper of some other kind, make an opt_result failure
+     object, for propagating the opt_problem up the call stack.  */
+
+  template <typename S>
+  static opt_result
+  propagate_failure (opt_wrapper <S> other)
+  {
+    return opt_result (false, other.get_problem ());
+  }
+
+ private:
+  /* Private ctor.  Instances should be created by the success and failure
+     static member functions.  */
+  opt_result (wrapped_t result, opt_problem *problem)
+  : opt_wrapper (result, problem)
+  {}
+};
+
+/* Subclass of opt_wrapper<T> where T is a pointer type, for tracking
+   success/failure, where:
+   - a non-NULL value signifies "success", and
+   - a NULL value signifies "failure",
+   whilst effectively propagating an opt_problem * describing any failure
+   back up the call stack.  */
+
+template <typename PtrType_t>
+class opt_pointer_wrapper : public opt_wrapper <PtrType_t>
+{
+ public:
+  typedef PtrType_t wrapped_pointer_t;
+
+  /* Given a non-NULL pointer, make a success object wrapping it.  */
+
+  static opt_pointer_wrapper <wrapped_pointer_t>
+  success (wrapped_pointer_t ptr)
+  {
+    return opt_pointer_wrapper <wrapped_pointer_t> (ptr, NULL);
+  }
+
+  /* Make a NULL pointer failure object, with the given message
+     (if dump_enabled_p).  */
+
+  static opt_pointer_wrapper <wrapped_pointer_t>
+  failure_at (const dump_location_t &loc,
+	      const char *fmt, ...)
+    ATTRIBUTE_GCC_DUMP_PRINTF (2, 3)
+  {
+    opt_problem *problem = NULL;
+    if (dump_enabled_p ())
+      {
+	va_list ap;
+	va_start (ap, fmt);
+	problem = new opt_problem (loc, fmt, &ap);
+	va_end (ap);
+      }
+    return opt_pointer_wrapper <wrapped_pointer_t> (NULL, problem);
+  }
+
+  /* Given a failure wrapper of some other kind, make a NULL pointer
+     failure object, propagating the problem.  */
+
+  template <typename S>
+  static opt_pointer_wrapper <wrapped_pointer_t>
+  propagate_failure (opt_wrapper <S> other)
+  {
+    return opt_pointer_wrapper <wrapped_pointer_t> (NULL,
+						    other.get_problem ());
+  }
+
+  /* Support accessing the underlying pointer via ->.  */
+
+  wrapped_pointer_t operator-> () const { return this->get_result (); }
+
+ private:
+  /* Private ctor.  Instances should be built using the static member
+     functions "success" and "failure".  */
+  opt_pointer_wrapper (wrapped_pointer_t result, opt_problem *problem)
+  : opt_wrapper<PtrType_t> (result, problem)
+  {}
+};
+
+/* A typedef for wrapping "tree" so that NULL_TREE can carry an
+   opt_problem describing the failure (if dump_enabled_p).  */
+
+typedef opt_pointer_wrapper<tree> opt_tree;
+
+#endif /* #ifndef GCC_OPT_PROBLEM_H */
diff --git a/gcc/optinfo-emit-json.cc b/gcc/optinfo-emit-json.cc
index efdbdb3..31029ad 100644
--- a/gcc/optinfo-emit-json.cc
+++ b/gcc/optinfo-emit-json.cc
@@ -531,7 +531,7 @@ namespace selftest {
 static void
 test_building_json_from_dump_calls ()
 {
-  temp_dump_context tmp (true, MSG_NOTE);
+  temp_dump_context tmp (true, true, MSG_NOTE);
   dump_location_t loc;
   dump_printf_loc (MSG_NOTE, loc, "test of tree: ");
   dump_generic_expr (MSG_NOTE, TDF_SLIM, integer_zero_node);
diff --git a/gcc/optinfo.cc b/gcc/optinfo.cc
index b858c3c..de781a5 100644
--- a/gcc/optinfo.cc
+++ b/gcc/optinfo.cc
@@ -89,11 +89,51 @@ optinfo::add_item (optinfo_item *item)
   m_items.safe_push (item);
 }
 
+/* Get MSG_* flags corresponding to KIND.  */
+
+static dump_flags_t
+optinfo_kind_to_dump_flag (enum optinfo_kind kind)
+{
+  switch (kind)
+    {
+    default:
+      gcc_unreachable ();
+    case OPTINFO_KIND_SUCCESS:
+      return MSG_OPTIMIZED_LOCATIONS;
+    case OPTINFO_KIND_FAILURE:
+      return MSG_MISSED_OPTIMIZATION;
+    case OPTINFO_KIND_NOTE:
+    case OPTINFO_KIND_SCOPE:
+      return MSG_NOTE;
+    }
+}
+
+/* Re-emit this optinfo, both to the "non-immediate" destinations,
+   *and* to the "immediate" destinations.  */
+
+void
+optinfo::emit_for_opt_problem () const
+{
+  dump_flags_t dump_kind = optinfo_kind_to_dump_flag (get_kind ());
+  dump_kind |= MSG_PRIORITY_REEMITTED;
+
+  /* Re-emit to "immediate" destinations, without creating a new optinfo.  */
+  dump_context::get ().dump_loc_immediate (dump_kind, get_dump_location ());
+  unsigned i;
+  optinfo_item *item;
+  FOR_EACH_VEC_ELT (m_items, i, item)
+    dump_context::get ().emit_item (item, dump_kind);
+
+  /* Re-emit to "non-immediate" destinations.  */
+  emit ();
+}
+
 /* Emit the optinfo to all of the "non-immediate" destinations
-   (emission to "immediate" destinations is done by emit_item).  */
+   (emission to "immediate" destinations is done by
+   dump_context::emit_item).  */
 
 void
-optinfo::emit ()
+optinfo::emit () const
 {
   /* -fsave-optimization-record.  */
   optimization_records_maybe_record_optinfo (this);
diff --git a/gcc/optinfo.h b/gcc/optinfo.h
index 8ac961c..99bd22c 100644
--- a/gcc/optinfo.h
+++ b/gcc/optinfo.h
@@ -108,6 +108,9 @@ class optinfo
   {}
   ~optinfo ();
 
+  const dump_location_t &
+  get_dump_location () const { return m_loc; }
+
   const dump_user_location_t &
   get_user_location () const { return m_loc.get_user_location (); }
 
@@ -124,8 +127,10 @@ class optinfo
 
   void add_item (optinfo_item *item);
 
+  void emit_for_opt_problem () const;
+
  private:
-  void emit ();
+  void emit () const;
 
   /* Pre-canned ways of manipulating the optinfo, for use by friend class
      dump_context.  */
diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c
index 5adb033..562ada7 100644
--- a/gcc/selftest-run-tests.c
+++ b/gcc/selftest-run-tests.c
@@ -74,6 +74,7 @@ selftest::run_tests ()
   opt_proposer_c_tests ();
   json_cc_tests ();
   optinfo_emit_json_cc_tests ();
+  opt_problem_cc_tests ();
 
   /* Mid-level data structures.  */
   input_c_tests ();
diff --git a/gcc/selftest.h b/gcc/selftest.h
index ede7732..8da7c4a 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -229,6 +229,7 @@ extern void hash_map_tests_c_tests ();
 extern void hash_set_tests_c_tests ();
 extern void input_c_tests ();
 extern void json_cc_tests ();
+extern void opt_problem_cc_tests ();
 extern void optinfo_emit_json_cc_tests ();
 extern void predict_c_tests ();
 extern void pretty_print_c_tests ();
diff --git a/gcc/testsuite/gcc.dg/vect/nodump-vect-opt-info-2.c b/gcc/testsuite/gcc.dg/vect/nodump-vect-opt-info-2.c
new file mode 100644
index 0000000..94c55a9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/nodump-vect-opt-info-2.c
@@ -0,0 +1,12 @@
+/* { dg-do compile { target vect_int } } */
+/* { dg-additional-options "-fopt-info-vec-all -O3" } */
+
+extern void accumulate (int x, int *a);
+
+int test_missing_function_defn (int *arr, int n) /* { dg-message "vectorized 0 loops in function" } */
+{
+  int sum = 0;
+  for (int i = 0; i < n; ++i) /* { dg-missed "couldn't vectorize loop" } */
+    accumulate (arr[i], &sum); /* { dg-missed "statement clobbers memory: accumulate \\(.*\\);" } */
+  return sum;
+}
diff --git a/gcc/testsuite/gcc.dg/vect/vect-alias-check-4.c b/gcc/testsuite/gcc.dg/vect/vect-alias-check-4.c
index 1e5fc27..750193e 100644
--- a/gcc/testsuite/gcc.dg/vect/vect-alias-check-4.c
+++ b/gcc/testsuite/gcc.dg/vect/vect-alias-check-4.c
@@ -1,6 +1,6 @@
 /* { dg-do compile } */
 /* { dg-require-effective-target vect_int } */
-/* { dg-additional-options "--param vect-max-version-for-alias-checks=0" } */
+/* { dg-additional-options "--param vect-max-version-for-alias-checks=0 -fopt-info-vec-all" } */
 
 #define N 16
 
@@ -12,24 +12,26 @@ union u { struct s2 f; struct s3 g; };
 /* We allow a and b to overlap arbitrarily.  */
 
 void
-f1 (int a[][N], int b[][N])
+f1 (int a[][N], int b[][N]) /* { dg-message "vectorized 0 loops in function" } */
 {
-  for (int i = 0; i < N; ++i)
+  for (int i = 0; i < N; ++i) /* { dg-missed "couldn't vectorize loop" } */
     a[0][i] += b[0][i];
+  /* { dg-message "will not create alias checks, as --param vect-max-version-for-alias-checks == 0" "" { target *-*-* } .-2 } */
 }
 
 void
-f2 (union u *a, union u *b)
+f2 (union u *a, union u *b) /* { dg-message "vectorized 0 loops in function" } */
 {
-  for (int i = 0; i < N; ++i)
+  for (int i = 0; i < N; ++i) /* { dg-missed "couldn't vectorize loop" } */
     a->f.b.a[i] += b->g.e.a[i];
+  /* { dg-message "will not create alias checks, as --param vect-max-version-for-alias-checks == 0" "" { target *-*-* } .-2 } */
 }
 
 void
-f3 (struct s1 *a, struct s1 *b)
+f3 (struct s1 *a, struct s1 *b) /* { dg-message "vectorized 0 loops in function" } */
 {
-  for (int i = 0; i < N - 1; ++i)
-    a->a[i + 1] += b->a[i];
+  for (int i = 0; i < N - 1; ++i) /* { dg-missed "couldn't vectorize loop" } */
+    a->a[i + 1] += b->a[i]; /* { dg-missed "possible dependence between data-refs" } */
 }
 
 /* { dg-final { scan-tree-dump-not "LOOP VECTORIZED" "vect" } } */
diff --git a/gcc/tree-data-ref.c b/gcc/tree-data-ref.c
index bf30a61..69c5f7b 100644
--- a/gcc/tree-data-ref.c
+++ b/gcc/tree-data-ref.c
@@ -807,7 +807,8 @@ canonicalize_base_object_address (tree addr)
   return build_fold_addr_expr (TREE_OPERAND (addr, 0));
 }
 
-/* Analyze the behavior of memory reference REF.  There are two modes:
+/* Analyze the behavior of memory reference REF within STMT.
+   There are two modes:
 
    - BB analysis.  In this case we simply split the address into base,
      init and offset components, without reference to any containing loop.
@@ -827,9 +828,9 @@ canonicalize_base_object_address (tree addr)
    Return true if the analysis succeeded and store the results in DRB if so.
    BB analysis can only fail for bitfield or reversed-storage accesses.  */
 
-bool
+opt_result
 dr_analyze_innermost (innermost_loop_behavior *drb, tree ref,
-		      struct loop *loop)
+		      struct loop *loop, const gimple *stmt)
 {
   poly_int64 pbitsize, pbitpos;
   tree base, poffset;
@@ -848,18 +849,12 @@ dr_analyze_innermost (innermost_loop_behavior *drb, tree ref,
 
   poly_int64 pbytepos;
   if (!multiple_p (pbitpos, BITS_PER_UNIT, &pbytepos))
-    {
-      if (dump_file && (dump_flags & TDF_DETAILS))
-	fprintf (dump_file, "failed: bit offset alignment.\n");
-      return false;
-    }
+    return opt_result::failure_at (stmt,
+				   "failed: bit offset alignment.\n");
 
   if (preversep)
-    {
-      if (dump_file && (dump_flags & TDF_DETAILS))
-	fprintf (dump_file, "failed: reverse storage order.\n");
-      return false;
-    }
+    return opt_result::failure_at (stmt,
+				   "failed: reverse storage order.\n");
 
   /* Calculate the alignment and misalignment for the inner reference.  */
   unsigned int HOST_WIDE_INT bit_base_misalignment;
@@ -895,11 +890,8 @@ dr_analyze_innermost (innermost_loop_behavior *drb, tree ref,
   if (in_loop)
     {
       if (!simple_iv (loop, loop, base, &base_iv, true))
-        {
-	  if (dump_file && (dump_flags & TDF_DETAILS))
-	    fprintf (dump_file, "failed: evolution of base is not affine.\n");
-	  return false;
-        }
+	return opt_result::failure_at
+	  (stmt, "failed: evolution of base is not affine.\n");
     }
   else
     {
@@ -921,11 +913,8 @@ dr_analyze_innermost (innermost_loop_behavior *drb, tree ref,
           offset_iv.step = ssize_int (0);
         }
       else if (!simple_iv (loop, loop, poffset, &offset_iv, true))
-        {
-	  if (dump_file && (dump_flags & TDF_DETAILS))
-	    fprintf (dump_file, "failed: evolution of offset is not affine.\n");
-	  return false;
-        }
+	return opt_result::failure_at
+	  (stmt, "failed: evolution of offset is not affine.\n");
     }
 
   init = ssize_int (pbytepos);
@@ -981,7 +970,7 @@ dr_analyze_innermost (innermost_loop_behavior *drb, tree ref,
   if (dump_file && (dump_flags & TDF_DETAILS))
     fprintf (dump_file, "success.\n");
 
-  return true;
+  return opt_result::success ();
 }
 
 /* Return true if OP is a valid component reference for a DR access
@@ -1205,7 +1194,7 @@ create_data_ref (edge nest, loop_p loop, tree memref, gimple *stmt,
   DR_IS_CONDITIONAL_IN_STMT (dr) = is_conditional_in_stmt;
 
   dr_analyze_innermost (&DR_INNERMOST (dr), memref,
-			nest != NULL ? loop : NULL);
+			nest != NULL ? loop : NULL, stmt);
   dr_analyze_indices (dr, nest, loop);
   dr_analyze_alias (dr);
 
@@ -1318,7 +1307,7 @@ data_ref_compare_tree (tree t1, tree t2)
 /* Return TRUE it's possible to resolve data dependence DDR by runtime alias
    check.  */
 
-bool
+opt_result
 runtime_alias_check_p (ddr_p ddr, struct loop *loop, bool speed_p)
 {
   if (dump_enabled_p ())
@@ -1327,25 +1316,18 @@ runtime_alias_check_p (ddr_p ddr, struct loop *loop, bool speed_p)
 		 DR_REF (DDR_A (ddr)), DR_REF (DDR_B (ddr)));
 
   if (!speed_p)
-    {
-      if (dump_enabled_p ())
-	dump_printf (MSG_MISSED_OPTIMIZATION,
-		     "runtime alias check not supported when optimizing "
-		     "for size.\n");
-      return false;
-    }
+    return opt_result::failure_at (DR_STMT (DDR_A (ddr)),
+				   "runtime alias check not supported when"
+				   " optimizing for size.\n");
 
   /* FORNOW: We don't support versioning with outer-loop in either
      vectorization or loop distribution.  */
   if (loop != NULL && loop->inner != NULL)
-    {
-      if (dump_enabled_p ())
-	dump_printf (MSG_MISSED_OPTIMIZATION,
-		     "runtime alias check not supported for outer loop.\n");
-      return false;
-    }
+    return opt_result::failure_at (DR_STMT (DDR_A (ddr)),
+				   "runtime alias check not supported for"
+				   " outer loop.\n");
 
-  return true;
+  return opt_result::success ();
 }
 
 /* Operator == between two dr_with_seg_len objects.
@@ -5043,18 +5025,18 @@ loop_nest_has_data_refs (loop_p loop)
    reference, returns false, otherwise returns true.  NEST is the outermost
    loop of the loop nest in which the references should be analyzed.  */
 
-bool
+opt_result
 find_data_references_in_stmt (struct loop *nest, gimple *stmt,
 			      vec<data_reference_p> *datarefs)
 {
   unsigned i;
   auto_vec<data_ref_loc, 2> references;
   data_ref_loc *ref;
-  bool ret = true;
   data_reference_p dr;
 
   if (get_references_in_stmt (stmt, &references))
-    return false;
+    return opt_result::failure_at (stmt, "statement clobbers memory: %G",
+				   stmt);
 
   FOR_EACH_VEC_ELT (references, i, ref)
     {
@@ -5065,7 +5047,7 @@ find_data_references_in_stmt (struct loop *nest, gimple *stmt,
       datarefs->safe_push (dr);
     }
 
-  return ret;
+  return opt_result::success ();
 }
 
 /* Stores the data references in STMT to DATAREFS.  If there is an
diff --git a/gcc/tree-data-ref.h b/gcc/tree-data-ref.h
index 8739853..525d27f 100644
--- a/gcc/tree-data-ref.h
+++ b/gcc/tree-data-ref.h
@@ -23,6 +23,7 @@ along with GCC; see the file COPYING3.  If not see
 
 #include "graphds.h"
 #include "tree-chrec.h"
+#include "opt-problem.h"
 
 /*
   innermost_loop_behavior describes the evolution of the address of the memory
@@ -421,7 +422,8 @@ typedef struct data_dependence_relation *ddr_p;
 #define DDR_COULD_BE_INDEPENDENT_P(DDR) (DDR)->could_be_independent_p
 
 \f
-bool dr_analyze_innermost (innermost_loop_behavior *, tree, struct loop *);
+opt_result dr_analyze_innermost (innermost_loop_behavior *, tree,
+				 struct loop *, const gimple *);
 extern bool compute_data_dependences_for_loop (struct loop *, bool,
 					       vec<loop_p> *,
 					       vec<data_reference_p> *,
@@ -443,8 +445,8 @@ extern void free_dependence_relation (struct data_dependence_relation *);
 extern void free_dependence_relations (vec<ddr_p> );
 extern void free_data_ref (data_reference_p);
 extern void free_data_refs (vec<data_reference_p> );
-extern bool find_data_references_in_stmt (struct loop *, gimple *,
-					  vec<data_reference_p> *);
+extern opt_result find_data_references_in_stmt (struct loop *, gimple *,
+						vec<data_reference_p> *);
 extern bool graphite_find_data_references_in_stmt (edge, loop_p, gimple *,
 						   vec<data_reference_p> *);
 tree find_data_references_in_loop (struct loop *, vec<data_reference_p> *);
@@ -479,7 +481,7 @@ extern bool dr_may_alias_p (const struct data_reference *,
 extern bool dr_equal_offsets_p (struct data_reference *,
                                 struct data_reference *);
 
-extern bool runtime_alias_check_p (ddr_p, struct loop *, bool);
+extern opt_result runtime_alias_check_p (ddr_p, struct loop *, bool);
 extern int data_ref_compare_tree (tree, tree);
 extern void prune_runtime_alias_test_list (vec<dr_with_seg_len_pair_t> *,
 					   poly_uint64);
diff --git a/gcc/tree-predcom.c b/gcc/tree-predcom.c
index 2bde732..1711027 100644
--- a/gcc/tree-predcom.c
+++ b/gcc/tree-predcom.c
@@ -1280,7 +1280,8 @@ find_looparound_phi (struct loop *loop, dref ref, dref root)
   memset (&init_dr, 0, sizeof (struct data_reference));
   DR_REF (&init_dr) = init_ref;
   DR_STMT (&init_dr) = phi;
-  if (!dr_analyze_innermost (&DR_INNERMOST (&init_dr), init_ref, loop))
+  if (!dr_analyze_innermost (&DR_INNERMOST (&init_dr), init_ref, loop,
+			     init_stmt))
     return NULL;
 
   if (!valid_initializer_p (&init_dr, ref->distance + 1, root->ref))
diff --git a/gcc/tree-vect-data-refs.c b/gcc/tree-vect-data-refs.c
index 56b7968..c4805e7 100644
--- a/gcc/tree-vect-data-refs.c
+++ b/gcc/tree-vect-data-refs.c
@@ -156,20 +156,25 @@ vect_get_smallest_scalar_type (stmt_vec_info stmt_info,
    tested at run-time.  Return TRUE if DDR was successfully inserted.
    Return false if versioning is not supported.  */
 
-static bool
+static opt_result
 vect_mark_for_runtime_alias_test (ddr_p ddr, loop_vec_info loop_vinfo)
 {
   struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
 
   if ((unsigned) PARAM_VALUE (PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS) == 0)
-    return false;
+    return opt_result::failure_at (vect_location,
+				   "will not create alias checks, as"
+				   " --param vect-max-version-for-alias-checks"
+				   " == 0\n");
 
-  if (!runtime_alias_check_p (ddr, loop,
-			      optimize_loop_nest_for_speed_p (loop)))
-    return false;
+  opt_result res
+    = runtime_alias_check_p (ddr, loop,
+			     optimize_loop_nest_for_speed_p (loop));
+  if (!res)
+    return res;
 
   LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo).safe_push (ddr);
-  return true;
+  return opt_result::success ();
 }
 
 /* Record that loop LOOP_VINFO needs to check that VALUE is nonzero.  */
@@ -277,12 +282,14 @@ vect_analyze_possibly_independent_ddr (data_dependence_relation *ddr,
 
 /* Function vect_analyze_data_ref_dependence.
 
-   Return TRUE if there (might) exist a dependence between a memory-reference
+   FIXME: I needed to change the sense of the returned flag.
+
+   Return FALSE if there (might) exist a dependence between a memory-reference
    DRA and a memory-reference DRB.  When versioning for alias may check a
-   dependence at run-time, return FALSE.  Adjust *MAX_VF according to
+   dependence at run-time, return TRUE.  Adjust *MAX_VF according to
    the data dependence.  */
 
-static bool
+static opt_result
 vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
 				  loop_vec_info loop_vinfo,
 				  unsigned int *max_vf)
@@ -305,11 +312,11 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
 
   /* Independent data accesses.  */
   if (DDR_ARE_DEPENDENT (ddr) == chrec_known)
-    return false;
+    return opt_result::success ();
 
   if (dra == drb
       || (DR_IS_READ (dra) && DR_IS_READ (drb)))
-    return false;
+    return opt_result::success ();
 
   /* We do not have to consider dependences between accesses that belong
      to the same group, unless the stride could be smaller than the
@@ -318,7 +325,7 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
       && (DR_GROUP_FIRST_ELEMENT (stmtinfo_a)
 	  == DR_GROUP_FIRST_ELEMENT (stmtinfo_b))
       && !STMT_VINFO_STRIDED_P (stmtinfo_a))
-    return false;
+    return opt_result::success ();
 
   /* Even if we have an anti-dependence then, as the vectorized loop covers at
      least two scalar iterations, there is always also a true dependence.
@@ -330,7 +337,7 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
        || (DR_IS_WRITE (dra) && DR_IS_READ (drb)))
       && !alias_sets_conflict_p (get_alias_set (DR_REF (dra)),
 				 get_alias_set (DR_REF (drb))))
-    return false;
+    return opt_result::success ();
 
   /* Unknown data dependence.  */
   if (DDR_ARE_DEPENDENT (ddr) == chrec_dont_know)
@@ -342,28 +349,25 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
 	  if ((unsigned int) loop->safelen < *max_vf)
 	    *max_vf = loop->safelen;
 	  LOOP_VINFO_NO_DATA_DEPENDENCIES (loop_vinfo) = false;
-	  return false;
+	  return opt_result::success ();
 	}
 
       if (STMT_VINFO_GATHER_SCATTER_P (stmtinfo_a)
 	  || STMT_VINFO_GATHER_SCATTER_P (stmtinfo_b))
-	{
-	  if (dump_enabled_p ())
-	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			     "versioning for alias not supported for: "
-			     "can't determine dependence between %T and %T\n",
-			     DR_REF (dra), DR_REF (drb));
-	  return true;
-	}
+	return opt_result::failure_at
+	  (stmtinfo_a->stmt,
+	   "versioning for alias not supported for: "
+	   "can't determine dependence between %T and %T\n",
+	   DR_REF (dra), DR_REF (drb));
 
       if (dump_enabled_p ())
-	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+	dump_printf_loc (MSG_MISSED_OPTIMIZATION, stmtinfo_a->stmt,
 			 "versioning for alias required: "
 			 "can't determine dependence between %T and %T\n",
 			 DR_REF (dra), DR_REF (drb));
 
       /* Add to list of ddrs that need to be tested at run-time.  */
-      return !vect_mark_for_runtime_alias_test (ddr, loop_vinfo);
+      return vect_mark_for_runtime_alias_test (ddr, loop_vinfo);
     }
 
   /* Known data dependence.  */
@@ -376,27 +380,24 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
 	  if ((unsigned int) loop->safelen < *max_vf)
 	    *max_vf = loop->safelen;
 	  LOOP_VINFO_NO_DATA_DEPENDENCIES (loop_vinfo) = false;
-	  return false;
+	  return opt_result::success ();
 	}
 
       if (STMT_VINFO_GATHER_SCATTER_P (stmtinfo_a)
 	  || STMT_VINFO_GATHER_SCATTER_P (stmtinfo_b))
-	{
-	  if (dump_enabled_p ())
-	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			     "versioning for alias not supported for: "
-			     "bad dist vector for %T and %T\n",
-			     DR_REF (dra), DR_REF (drb));
-	  return true;
-	}
+	return opt_result::failure_at
+	  (stmtinfo_a->stmt,
+	   "versioning for alias not supported for: "
+	   "bad dist vector for %T and %T\n",
+	   DR_REF (dra), DR_REF (drb));
 
       if (dump_enabled_p ())
-	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+	dump_printf_loc (MSG_MISSED_OPTIMIZATION, stmtinfo_a->stmt,
 			 "versioning for alias required: "
 			 "bad dist vector for %T and %T\n",
 			 DR_REF (dra), DR_REF (drb));
       /* Add to list of ddrs that need to be tested at run-time.  */
-      return !vect_mark_for_runtime_alias_test (ddr, loop_vinfo);
+      return vect_mark_for_runtime_alias_test (ddr, loop_vinfo);
     }
 
   loop_depth = index_in_loop_nest (loop->num, DDR_LOOP_NEST (ddr));
@@ -404,7 +405,7 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
   if (DDR_COULD_BE_INDEPENDENT_P (ddr)
       && vect_analyze_possibly_independent_ddr (ddr, loop_vinfo,
 						loop_depth, max_vf))
-    return false;
+    return opt_result::success ();
 
   FOR_EACH_VEC_ELT (DDR_DIST_VECTS (ddr), i, dist_v)
     {
@@ -440,23 +441,16 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
 		a[i+1] = ...;
 	     where loads from the group interleave with the store.  */
 	  if (!vect_preserves_scalar_order_p (dr_info_a, dr_info_b))
-	    {
-	      if (dump_enabled_p ())
-		dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-				 "READ_WRITE dependence in interleaving.\n");
-	      return true;
-	    }
+	    return opt_result::failure_at (stmtinfo_a->stmt,
+					   "READ_WRITE dependence"
+					   " in interleaving.\n");
 
 	  if (loop->safelen < 2)
 	    {
 	      tree indicator = dr_zero_step_indicator (dra);
 	      if (!indicator || integer_zerop (indicator))
-		{
-		  if (dump_enabled_p ())
-		    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-				 "access also has a zero step\n");
-		  return true;
-		}
+		return opt_result::failure_at (stmtinfo_a->stmt,
+					       "access also has a zero step\n");
 	      else if (TREE_CODE (indicator) != INTEGER_CST)
 		vect_check_nonzero_value (loop_vinfo, indicator);
 	    }
@@ -503,16 +497,13 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
 	  continue;
 	}
 
-      if (dump_enabled_p ())
-	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			 "not vectorized, possible dependence "
-			 "between data-refs %T and %T\n",
-			 DR_REF (dra), DR_REF (drb));
-
-      return true;
+      return opt_result::failure_at (stmtinfo_a->stmt,
+				     "not vectorized, possible dependence "
+				     "between data-refs %T and %T\n",
+				     DR_REF (dra), DR_REF (drb));
     }
 
-  return false;
+  return opt_result::success ();
 }
 
 /* Function vect_analyze_data_ref_dependences.
@@ -521,7 +512,7 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
    exist any data dependences between them.  Set *MAX_VF according to
    the maximum vectorization factor the data dependences allow.  */
 
-bool
+opt_result
 vect_analyze_data_ref_dependences (loop_vec_info loop_vinfo,
 				   unsigned int *max_vf)
 {
@@ -553,10 +544,14 @@ vect_analyze_data_ref_dependences (loop_vec_info loop_vinfo,
     *max_vf = LOOP_VINFO_ORIG_MAX_VECT_FACTOR (loop_vinfo);
   else
     FOR_EACH_VEC_ELT (LOOP_VINFO_DDRS (loop_vinfo), i, ddr)
-      if (vect_analyze_data_ref_dependence (ddr, loop_vinfo, max_vf))
-	return false;
+      {
+	opt_result res
+	  = vect_analyze_data_ref_dependence (ddr, loop_vinfo, max_vf);
+	if (!res)
+	  return res;
+      }
 
-  return true;
+  return opt_result::success ();
 }
 
 
@@ -1055,33 +1050,24 @@ vect_update_misalignment_for_peel (dr_vec_info *dr_info,
 
    Return TRUE if DR_INFO can be handled with respect to alignment.  */
 
-static bool
+static opt_result
 verify_data_ref_alignment (dr_vec_info *dr_info)
 {
   enum dr_alignment_support supportable_dr_alignment
     = vect_supportable_dr_alignment (dr_info, false);
   if (!supportable_dr_alignment)
-    {
-      if (dump_enabled_p ())
-	{
-	  if (DR_IS_READ (dr_info->dr))
-	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			     "not vectorized: unsupported unaligned load.");
-	  else
-	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			     "not vectorized: unsupported unaligned "
-			     "store.");
-
-	  dump_printf (MSG_MISSED_OPTIMIZATION, "%T\n", DR_REF (dr_info->dr));
-	}
-      return false;
-    }
+    return opt_result::failure_at
+      (dr_info->stmt->stmt,
+       DR_IS_READ (dr_info->dr)
+	? "not vectorized: unsupported unaligned load: %T\n"
+	: "not vectorized: unsupported unaligned store: %T\n",
+       DR_REF (dr_info->dr));
 
   if (supportable_dr_alignment != dr_aligned && dump_enabled_p ())
     dump_printf_loc (MSG_NOTE, vect_location,
 		     "Vectorizing an unaligned access.\n");
 
-  return true;
+  return opt_result::success ();
 }
 
 /* Function vect_verify_datarefs_alignment
@@ -1089,7 +1075,7 @@ verify_data_ref_alignment (dr_vec_info *dr_info)
    Return TRUE if all data references in the loop can be
    handled with respect to alignment.  */
 
-bool
+opt_result
 vect_verify_datarefs_alignment (loop_vec_info vinfo)
 {
   vec<data_reference_p> datarefs = vinfo->shared->datarefs;
@@ -1115,11 +1101,12 @@ vect_verify_datarefs_alignment (loop_vec_info vinfo)
 	  && !STMT_VINFO_GROUPED_ACCESS (stmt_info))
 	continue;
 
-      if (! verify_data_ref_alignment (dr_info))
-	return false;
+      opt_result res = verify_data_ref_alignment (dr_info);
+      if (!res)
+	return res;
     }
 
-  return true;
+  return opt_result::success ();
 }
 
 /* Given an memory reference EXP return whether its alignment is less
@@ -1593,7 +1580,7 @@ vect_peeling_supportable (loop_vec_info loop_vinfo, dr_vec_info *dr0_info,
      (whether to generate regular loads/stores, or with special handling for
      misalignment).  */
 
-bool
+opt_result
 vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
 {
   vec<data_reference_p> datarefs = LOOP_VINFO_DATAREFS (loop_vinfo);
@@ -1605,7 +1592,6 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
   unsigned int i, j;
   bool do_peeling = false;
   bool do_versioning = false;
-  bool stat;
   unsigned int npeel = 0;
   bool one_misalignment_known = false;
   bool one_misalignment_unknown = false;
@@ -1992,7 +1978,7 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
       /* Check if all datarefs are supportable and log.  */
       if (do_peeling && known_alignment_for_access_p (dr0_info) && npeel == 0)
         {
-          stat = vect_verify_datarefs_alignment (loop_vinfo);
+          opt_result stat = vect_verify_datarefs_alignment (loop_vinfo);
           if (!stat)
             do_peeling = false;
           else
@@ -2078,7 +2064,7 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
 	  /* The inside-loop cost will be accounted for in vectorizable_load
 	     and vectorizable_store correctly with adjusted alignments.
 	     Drop the body_cst_vec on the floor here.  */
-	  stat = vect_verify_datarefs_alignment (loop_vinfo);
+	  opt_result stat = vect_verify_datarefs_alignment (loop_vinfo);
 	  gcc_assert (stat);
           return stat;
         }
@@ -2201,7 +2187,7 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
       /* Peeling and versioning can't be done together at this time.  */
       gcc_assert (! (do_peeling && do_versioning));
 
-      stat = vect_verify_datarefs_alignment (loop_vinfo);
+      opt_result stat = vect_verify_datarefs_alignment (loop_vinfo);
       gcc_assert (stat);
       return stat;
     }
@@ -2209,7 +2195,7 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
   /* This point is reached if neither peeling nor versioning is being done.  */
   gcc_assert (! (do_peeling || do_versioning));
 
-  stat = vect_verify_datarefs_alignment (loop_vinfo);
+  opt_result stat = vect_verify_datarefs_alignment (loop_vinfo);
   return stat;
 }
 
@@ -2275,7 +2261,7 @@ vect_find_same_alignment_drs (vec_info *vinfo, data_dependence_relation *ddr)
    Analyze the alignment of the data-references in the loop.
    Return FALSE if a data reference is found that cannot be vectorized.  */
 
-bool
+opt_result
 vect_analyze_data_refs_alignment (loop_vec_info vinfo)
 {
   DUMP_VECT_SCOPE ("vect_analyze_data_refs_alignment");
@@ -2300,7 +2286,7 @@ vect_analyze_data_refs_alignment (loop_vec_info vinfo)
 	vect_compute_data_ref_alignment (dr_info);
     }
 
-  return true;
+  return opt_result::success ();
 }
 
 
@@ -2825,7 +2811,7 @@ can_group_stmts_p (stmt_vec_info stmt1_info, stmt_vec_info stmt2_info)
 
    FORNOW: handle only arrays and pointer accesses.  */
 
-bool
+opt_result
 vect_analyze_data_ref_accesses (vec_info *vinfo)
 {
   unsigned int i;
@@ -2835,7 +2821,7 @@ vect_analyze_data_ref_accesses (vec_info *vinfo)
   DUMP_VECT_SCOPE ("vect_analyze_data_ref_accesses");
 
   if (datarefs.is_empty ())
-    return true;
+    return opt_result::success ();
 
   /* Sort the array of datarefs to make building the interleaving chains
      linear.  Don't modify the original vector's order, it is needed for
@@ -2994,13 +2980,15 @@ vect_analyze_data_ref_accesses (vec_info *vinfo)
 	  else
 	    {
 	      datarefs_copy.release ();
-	      return false;
+	      return opt_result::failure_at (dr_info->stmt->stmt,
+					     "not vectorized:"
+					     " complicated access pattern.\n");
 	    }
 	}
     }
 
   datarefs_copy.release ();
-  return true;
+  return opt_result::success ();
 }
 
 /* Function vect_vfa_segment_size.
@@ -3258,7 +3246,7 @@ vectorizable_with_step_bound_p (dr_vec_info *dr_info_a, dr_vec_info *dr_info_b,
    Return FALSE if resulting list of ddrs is longer then allowed by
    PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS, otherwise return TRUE.  */
 
-bool
+opt_result
 vect_prune_runtime_alias_test_list (loop_vec_info loop_vinfo)
 {
   typedef pair_hash <tree_operand_hash, tree_operand_hash> tree_pair_hash;
@@ -3292,7 +3280,7 @@ vect_prune_runtime_alias_test_list (loop_vec_info loop_vinfo)
     }
 
   if (may_alias_ddrs.is_empty ())
-    return true;
+    return opt_result::success ();
 
   comp_alias_ddrs.create (may_alias_ddrs.length ());
 
@@ -3452,12 +3440,11 @@ vect_prune_runtime_alias_test_list (loop_vec_info loop_vinfo)
 	    continue;
 
 	  if (res == 1)
-	    {
-	      if (dump_enabled_p ())
-		dump_printf_loc (MSG_NOTE, vect_location,
-				 "not vectorized: compilation time alias.\n");
-	      return false;
-	    }
+	    return opt_result::failure_at (stmt_info_b->stmt,
+					   "not vectorized:"
+					   " compilation time alias: %G%G",
+					   stmt_info_a->stmt,
+					   stmt_info_b->stmt);
 	}
 
       dr_with_seg_len_pair_t dr_with_seg_len_pair
@@ -3482,17 +3469,14 @@ vect_prune_runtime_alias_test_list (loop_vec_info loop_vinfo)
 		   "improved number of alias checks from %d to %d\n",
 		   may_alias_ddrs.length (), count);
   if ((int) count > PARAM_VALUE (PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS))
-    {
-      if (dump_enabled_p ())
-	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			 "number of versioning for alias "
-			 "run-time tests exceeds %d "
-			 "(--param vect-max-version-for-alias-checks)\n",
-			 PARAM_VALUE (PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS));
-      return false;
-    }
-
-  return true;
+    return opt_result::failure_at
+      (vect_location,
+       "number of versioning for alias "
+       "run-time tests exceeds %d "
+       "(--param vect-max-version-for-alias-checks)\n",
+       PARAM_VALUE (PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS));
+
+  return opt_result::success ();
 }
 
 /* Check whether we can use an internal function for a gather load
@@ -3846,7 +3830,7 @@ vect_check_gather_scatter (stmt_vec_info stmt_info, loop_vec_info loop_vinfo,
    append them to DATAREFS.  Return false if datarefs in this stmt cannot
    be handled.  */
 
-bool
+opt_result
 vect_find_stmt_data_reference (loop_p loop, gimple *stmt,
 			       vec<data_reference_p> *datarefs)
 {
@@ -3854,72 +3838,50 @@ vect_find_stmt_data_reference (loop_p loop, gimple *stmt,
      loop vectorization and BB vectorization checks dependences with a
      stmt walk.  */
   if (gimple_clobber_p (stmt))
-    return true;
+    return opt_result::success ();
 
   if (gimple_has_volatile_ops (stmt))
-    {
-      if (dump_enabled_p ())
-	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			 "not vectorized: volatile type %G", stmt);
-      return false;
-    }
+    return opt_result::failure_at (stmt, "not vectorized: volatile type: %G",
+				   stmt);
 
   if (stmt_can_throw_internal (stmt))
-    {
-      if (dump_enabled_p ())
-	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			 "not vectorized: statement can throw an exception %G",
-			 stmt);
-      return false;
-    }
+    return opt_result::failure_at (stmt,
+				   "not vectorized:"
+				   " statement can throw an exception: %G",
+				   stmt);
 
   auto_vec<data_reference_p, 2> refs;
-  if (!find_data_references_in_stmt (loop, stmt, &refs))
-    return false;
+  opt_result res = find_data_references_in_stmt (loop, stmt, &refs);
+  if (!res)
+    return res;
 
   if (refs.is_empty ())
-    return true;
+    return opt_result::success ();
 
   if (refs.length () > 1)
-    {
-      if (dump_enabled_p ())
-	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			 "not vectorized: more than one data ref "
-			 "in stmt: %G", stmt);
-      return false;
-    }
+    return opt_result::failure_at (stmt,
+				   "not vectorized:"
+				   " more than one data ref in stmt: %G", stmt);
 
   if (gcall *call = dyn_cast <gcall *> (stmt))
     if (!gimple_call_internal_p (call)
 	|| (gimple_call_internal_fn (call) != IFN_MASK_LOAD
 	    && gimple_call_internal_fn (call) != IFN_MASK_STORE))
-      {
-	if (dump_enabled_p ())
-	  dump_printf_loc (MSG_MISSED_OPTIMIZATION,  vect_location,
-			   "not vectorized: dr in a call %G", stmt);
-	return false;
-      }
+      return opt_result::failure_at (stmt,
+				     "not vectorized: dr in a call %G", stmt);
 
   data_reference_p dr = refs.pop ();
   if (TREE_CODE (DR_REF (dr)) == COMPONENT_REF
       && DECL_BIT_FIELD (TREE_OPERAND (DR_REF (dr), 1)))
-    {
-      if (dump_enabled_p ())
-	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			 "not vectorized: statement is bitfield "
-			 "access %G", stmt);
-      return false;
-    }
+    return opt_result::failure_at (stmt,
+				   "not vectorized:"
+				   " statement is bitfield access %G", stmt);
 
   if (DR_BASE_ADDRESS (dr)
       && TREE_CODE (DR_BASE_ADDRESS (dr)) == INTEGER_CST)
-    {
-      if (dump_enabled_p ())
-	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			 "not vectorized: base addr of dr is a "
-			 "constant\n");
-      return false;
-    }
+    return opt_result::failure_at (stmt,
+				   "not vectorized:"
+				   " base addr of dr is a constant\n");
 
   /* Check whether this may be a SIMD lane access and adjust the
      DR to make it easier for us to handle it.  */
@@ -3976,7 +3938,7 @@ vect_find_stmt_data_reference (loop_p loop, gimple *stmt,
 			  newdr->aux = (void *)-1;
 			  free_data_ref (dr);
 			  datarefs->safe_push (newdr);
-			  return true;
+			  return opt_result::success ();
 			}
 		    }
 		}
@@ -3986,7 +3948,7 @@ vect_find_stmt_data_reference (loop_p loop, gimple *stmt,
     }
 
   datarefs->safe_push (dr);
-  return true;
+  return opt_result::success ();
 }
 
 /* Function vect_analyze_data_refs.
@@ -4004,7 +3966,7 @@ vect_find_stmt_data_reference (loop_p loop, gimple *stmt,
 
 */
 
-bool
+opt_result
 vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf)
 {
   struct loop *loop = NULL;
@@ -4074,7 +4036,10 @@ vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf)
 		  STMT_VINFO_VECTORIZABLE (stmt_info) = false;
 		  continue;
 		}
-	      return false;
+	      return opt_result::failure_at (stmt_info->stmt,
+					     "not vectorized:"
+					     " data ref analysis failed: %G",
+					     stmt_info->stmt);
 	    }
         }
 
@@ -4082,13 +4047,10 @@ vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf)
       if (dr->aux == (void *)-1)
 	{
 	  if (nested_in_vect_loop_p (loop, stmt_info))
-	    {
-	      if (dump_enabled_p ())
-		dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-				 "not vectorized: data ref analysis "
-				 "failed %G", stmt_info->stmt);
-	      return false;
-	    }
+	    return opt_result::failure_at (stmt_info->stmt,
+					   "not vectorized:"
+					   " data ref analysis failed: %G",
+					   stmt_info->stmt);
 	  STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) = true;
 	}
 
@@ -4106,7 +4068,10 @@ vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf)
 	      STMT_VINFO_VECTORIZABLE (stmt_info) = false;
 	      continue;
 	    }
-	  return false;
+	  return opt_result::failure_at (stmt_info->stmt,
+					 "not vectorized: base object not"
+					 " addressable for stmt: %G",
+					 stmt_info->stmt);
 	}
 
       if (is_a <loop_vec_info> (vinfo)
@@ -4114,13 +4079,10 @@ vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf)
 	  && TREE_CODE (DR_STEP (dr)) != INTEGER_CST)
 	{
 	  if (nested_in_vect_loop_p (loop, stmt_info))
-	    {
-	      if (dump_enabled_p ())
-		dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-				 "not vectorized: not suitable for strided "
-				 "load %G", stmt_info->stmt);
-	      return false;
-	    }
+	    return opt_result::failure_at (stmt_info->stmt,
+					   "not vectorized:"
+					   "not suitable for strided load %G",
+					   stmt_info->stmt);
 	  STMT_VINFO_STRIDED_P (stmt_info) = true;
 	}
 
@@ -4150,10 +4112,12 @@ vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf)
 	    dump_printf_loc (MSG_NOTE, vect_location,
 			     "analyze in outer loop: %T\n", init_ref);
 
-	  if (!dr_analyze_innermost (&STMT_VINFO_DR_WRT_VEC_LOOP (stmt_info),
-				     init_ref, loop))
+	  opt_result res
+	    = dr_analyze_innermost (&STMT_VINFO_DR_WRT_VEC_LOOP (stmt_info),
+				    init_ref, loop, stmt_info->stmt);
+	  if (!res)
 	    /* dr_analyze_innermost already explained the failure.  */
-	    return false;
+	    return res;
 
           if (dump_enabled_p ())
 	    dump_printf_loc (MSG_NOTE, vect_location,
@@ -4199,7 +4163,11 @@ vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf)
 	      STMT_VINFO_VECTORIZABLE (stmt_info) = false;
 	      continue;
 	    }
-	  return false;
+	  return opt_result::failure_at (stmt_info->stmt,
+					 "not vectorized:"
+					 " no vectype for stmt: %G"
+					 " scalar_type: %T\n",
+					 stmt_info->stmt, scalar_type);
         }
       else
 	{
@@ -4221,17 +4189,12 @@ vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf)
 					  as_a <loop_vec_info> (vinfo),
 					  &gs_info)
 	      || !get_vectype_for_scalar_type (TREE_TYPE (gs_info.offset)))
-	    {
-	      if (dump_enabled_p ())
-		dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-				 (gatherscatter == GATHER) ?
-				 "not vectorized: not suitable for gather "
-				 "load %G" :
-				 "not vectorized: not suitable for scatter "
-				 "store %G",
-				 stmt_info->stmt);
-	      return false;
-	    }
+	    return opt_result::failure_at
+	      (stmt_info->stmt,
+	       (gatherscatter == GATHER) ?
+	       "not vectorized: not suitable for gather load %G" :
+	       "not vectorized: not suitable for scatter store %G",
+	       stmt_info->stmt);
 	  STMT_VINFO_GATHER_SCATTER_P (stmt_info) = gatherscatter;
 	}
     }
@@ -4240,7 +4203,7 @@ vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf)
      longer need to.  */
   gcc_assert (i == datarefs.length ());
 
-  return true;
+  return opt_result::success ();
 }
 
 
diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c
index fdac10b..6ea1e77 100644
--- a/gcc/tree-vect-loop.c
+++ b/gcc/tree-vect-loop.c
@@ -159,7 +159,7 @@ static void vect_estimate_min_profitable_iters (loop_vec_info, int *, int *);
    statement.  VECTYPE_MAYBE_SET_P is true if STMT_VINFO_VECTYPE
    may already be set for general statements (not just data refs).  */
 
-static bool
+static opt_result
 vect_determine_vf_for_stmt_1 (stmt_vec_info stmt_info,
 			      bool vectype_maybe_set_p,
 			      poly_uint64 *vf,
@@ -173,13 +173,14 @@ vect_determine_vf_for_stmt_1 (stmt_vec_info stmt_info,
     {
       if (dump_enabled_p ())
 	dump_printf_loc (MSG_NOTE, vect_location, "skip.\n");
-      return true;
+      return opt_result::success ();
     }
 
   tree stmt_vectype, nunits_vectype;
-  if (!vect_get_vector_types_for_stmt (stmt_info, &stmt_vectype,
-				       &nunits_vectype))
-    return false;
+  opt_result res = vect_get_vector_types_for_stmt (stmt_info, &stmt_vectype,
+						   &nunits_vectype);
+  if (!res)
+    return res;
 
   if (stmt_vectype)
     {
@@ -199,7 +200,7 @@ vect_determine_vf_for_stmt_1 (stmt_vec_info stmt_info,
   if (nunits_vectype)
     vect_update_max_nunits (vf, nunits_vectype);
 
-  return true;
+  return opt_result::success ();
 }
 
 /* Subroutine of vect_determine_vectorization_factor.  Set the vector
@@ -209,7 +210,7 @@ vect_determine_vf_for_stmt_1 (stmt_vec_info stmt_info,
    add them to MASK_PRODUCERS.  Return true on success or false if
    something prevented vectorization.  */
 
-static bool
+static opt_result
 vect_determine_vf_for_stmt (stmt_vec_info stmt_info, poly_uint64 *vf,
 			    vec<stmt_vec_info > *mask_producers)
 {
@@ -217,8 +218,10 @@ vect_determine_vf_for_stmt (stmt_vec_info stmt_info, poly_uint64 *vf,
   if (dump_enabled_p ())
     dump_printf_loc (MSG_NOTE, vect_location, "==> examining statement: %G",
 		     stmt_info->stmt);
-  if (!vect_determine_vf_for_stmt_1 (stmt_info, false, vf, mask_producers))
-    return false;
+  opt_result res
+    = vect_determine_vf_for_stmt_1 (stmt_info, false, vf, mask_producers);
+  if (!res)
+    return res;
 
   if (STMT_VINFO_IN_PATTERN_P (stmt_info)
       && STMT_VINFO_RELATED_STMT (stmt_info))
@@ -237,18 +240,22 @@ vect_determine_vf_for_stmt (stmt_vec_info stmt_info, poly_uint64 *vf,
 			     def_stmt_info->stmt);
 	  if (!vect_determine_vf_for_stmt_1 (def_stmt_info, true,
 					     vf, mask_producers))
-	    return false;
+	  res = vect_determine_vf_for_stmt_1 (def_stmt_info, true,
+					      vf, mask_producers);
+	  if (!res)
+	    return res;
 	}
 
       if (dump_enabled_p ())
 	dump_printf_loc (MSG_NOTE, vect_location,
 			 "==> examining pattern statement: %G",
 			 stmt_info->stmt);
-      if (!vect_determine_vf_for_stmt_1 (stmt_info, true, vf, mask_producers))
-	return false;
+      res = vect_determine_vf_for_stmt_1 (stmt_info, true, vf, mask_producers);
+      if (!res)
+	return res;
     }
 
-  return true;
+  return opt_result::success ();
 }
 
 /* Function vect_determine_vectorization_factor
@@ -276,7 +283,7 @@ vect_determine_vf_for_stmt (stmt_vec_info stmt_info, poly_uint64 *vf,
         }
 */
 
-static bool
+static opt_result
 vect_determine_vectorization_factor (loop_vec_info loop_vinfo)
 {
   struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
@@ -320,14 +327,10 @@ vect_determine_vectorization_factor (loop_vec_info loop_vinfo)
 
 	      vectype = get_vectype_for_scalar_type (scalar_type);
 	      if (!vectype)
-		{
-		  if (dump_enabled_p ())
-		    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-				     "not vectorized: unsupported "
-				     "data-type %T\n",
-				     scalar_type);
-		  return false;
-		}
+		return opt_result::failure_at (phi,
+					       "not vectorized: unsupported "
+					       "data-type %T\n",
+					       scalar_type);
 	      STMT_VINFO_VECTYPE (stmt_info) = vectype;
 
 	      if (dump_enabled_p ())
@@ -349,9 +352,11 @@ vect_determine_vectorization_factor (loop_vec_info loop_vinfo)
 	   gsi_next (&si))
 	{
 	  stmt_info = loop_vinfo->lookup_stmt (gsi_stmt (si));
-	  if (!vect_determine_vf_for_stmt (stmt_info, &vectorization_factor,
-					   &mask_producers))
-	    return false;
+	  opt_result res
+	    = vect_determine_vf_for_stmt (stmt_info, &vectorization_factor,
+					  &mask_producers);
+	  if (!res)
+	    return res;
         }
     }
 
@@ -364,24 +369,20 @@ vect_determine_vectorization_factor (loop_vec_info loop_vinfo)
     }
 
   if (known_le (vectorization_factor, 1U))
-    {
-      if (dump_enabled_p ())
-        dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-                         "not vectorized: unsupported data-type\n");
-      return false;
-    }
+    return opt_result::failure_at (vect_location,
+				   "not vectorized: unsupported data-type\n");
   LOOP_VINFO_VECT_FACTOR (loop_vinfo) = vectorization_factor;
 
   for (i = 0; i < mask_producers.length (); i++)
     {
       stmt_info = mask_producers[i];
-      tree mask_type = vect_get_mask_type_for_stmt (stmt_info);
+      opt_tree mask_type = vect_get_mask_type_for_stmt (stmt_info);
       if (!mask_type)
-	return false;
+	return opt_result::propagate_failure (mask_type);
       STMT_VINFO_VECTYPE (stmt_info) = mask_type;
     }
 
-  return true;
+  return opt_result::success ();
 }
 
 
@@ -1145,7 +1146,7 @@ vect_compute_single_scalar_iteration_cost (loop_vec_info loop_vinfo)
    - the number of iterations can be analyzed, i.e, a countable loop.  The
      niter could be analyzed under some assumptions.  */
 
-bool
+opt_result
 vect_analyze_loop_form_1 (struct loop *loop, gcond **loop_cond,
 			  tree *assumptions, tree *number_of_iterationsm1,
 			  tree *number_of_iterations, gcond **inner_loop_cond)
@@ -1171,20 +1172,13 @@ vect_analyze_loop_form_1 (struct loop *loop, gcond **loop_cond,
                         (exit-bb)  */
 
       if (loop->num_nodes != 2)
-        {
-          if (dump_enabled_p ())
-            dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			     "not vectorized: control flow in loop.\n");
-          return false;
-        }
+	return opt_result::failure_at (vect_location,
+				       "not vectorized:"
+				       " control flow in loop.\n");
 
       if (empty_block_p (loop->header))
-	{
-	  if (dump_enabled_p ())
-	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			     "not vectorized: empty loop.\n");
-	  return false;
-	}
+	return opt_result::failure_at (vect_location,
+				       "not vectorized: empty loop.\n");
     }
   else
     {
@@ -1209,75 +1203,60 @@ vect_analyze_loop_form_1 (struct loop *loop, gcond **loop_cond,
 	 as described above.  */
 
       if ((loop->inner)->inner || (loop->inner)->next)
-	{
-	  if (dump_enabled_p ())
-	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			     "not vectorized: multiple nested loops.\n");
-	  return false;
-	}
+	return opt_result::failure_at (vect_location,
+				       "not vectorized:"
+				       " multiple nested loops.\n");
 
       if (loop->num_nodes != 5)
-        {
-	  if (dump_enabled_p ())
-	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			     "not vectorized: control flow in loop.\n");
-	  return false;
-        }
+	return opt_result::failure_at (vect_location,
+				       "not vectorized:"
+				       " control flow in loop.\n");
 
       entryedge = loop_preheader_edge (innerloop);
       if (entryedge->src != loop->header
 	  || !single_exit (innerloop)
 	  || single_exit (innerloop)->dest != EDGE_PRED (loop->latch, 0)->src)
-	{
-	  if (dump_enabled_p ())
-	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			     "not vectorized: unsupported outerloop form.\n");
-	  return false;
-	}
+	return opt_result::failure_at (vect_location,
+				       "not vectorized:"
+				       " unsupported outerloop form.\n");
 
       /* Analyze the inner-loop.  */
       tree inner_niterm1, inner_niter, inner_assumptions;
-      if (! vect_analyze_loop_form_1 (loop->inner, inner_loop_cond,
-				      &inner_assumptions, &inner_niterm1,
-				      &inner_niter, NULL)
-	  /* Don't support analyzing niter under assumptions for inner
-	     loop.  */
-	  || !integer_onep (inner_assumptions))
+      opt_result res
+	= vect_analyze_loop_form_1 (loop->inner, inner_loop_cond,
+				    &inner_assumptions, &inner_niterm1,
+				    &inner_niter, NULL);
+      if (!res)
 	{
 	  if (dump_enabled_p ())
-            dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 			     "not vectorized: Bad inner loop.\n");
-	  return false;
+	  return res;
 	}
 
+      /* Don't support analyzing niter under assumptions for inner
+	 loop.  */
+      if (!integer_onep (inner_assumptions))
+	return opt_result::failure_at (vect_location,
+				       "not vectorized: Bad inner loop.\n");
+
       if (!expr_invariant_in_loop_p (loop, inner_niter))
-	{
-	  if (dump_enabled_p ())
-	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			     "not vectorized: inner-loop count not"
-                             " invariant.\n");
-	  return false;
-	}
+	return opt_result::failure_at (vect_location,
+				       "not vectorized: inner-loop count not"
+				       " invariant.\n");
 
       if (dump_enabled_p ())
         dump_printf_loc (MSG_NOTE, vect_location,
 			 "Considering outer-loop vectorization.\n");
     }
 
-  if (!single_exit (loop)
-      || EDGE_COUNT (loop->header->preds) != 2)
-    {
-      if (dump_enabled_p ())
-        {
-          if (!single_exit (loop))
-	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			     "not vectorized: multiple exits.\n");
-          else if (EDGE_COUNT (loop->header->preds) != 2)
-	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			     "not vectorized: too many incoming edges.\n");
-        }
-      return false;
-    }
+  if (!single_exit (loop))
+    return opt_result::failure_at (vect_location,
+				   "not vectorized: multiple exits.\n");
+  if (EDGE_COUNT (loop->header->preds) != 2)
+    return opt_result::failure_at (vect_location,
+				   "not vectorized:"
+				   " too many incoming edges.\n");
 
   /* We assume that the loop exit condition is at the end of the loop. i.e,
      that the loop is represented as a do-while (with a proper if-guard
@@ -1285,67 +1264,52 @@ vect_analyze_loop_form_1 (struct loop *loop, gcond **loop_cond,
      executable statements, and the latch is empty.  */
   if (!empty_block_p (loop->latch)
       || !gimple_seq_empty_p (phi_nodes (loop->latch)))
-    {
-      if (dump_enabled_p ())
-	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			 "not vectorized: latch block not empty.\n");
-      return false;
-    }
+    return opt_result::failure_at (vect_location,
+				   "not vectorized: latch block not empty.\n");
 
   /* Make sure the exit is not abnormal.  */
   edge e = single_exit (loop);
   if (e->flags & EDGE_ABNORMAL)
-    {
-      if (dump_enabled_p ())
-	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			 "not vectorized: abnormal loop exit edge.\n");
-      return false;
-    }
+    return opt_result::failure_at (vect_location,
+				   "not vectorized:"
+				   " abnormal loop exit edge.\n");
 
   *loop_cond = vect_get_loop_niters (loop, assumptions, number_of_iterations,
 				     number_of_iterationsm1);
   if (!*loop_cond)
-    {
-      if (dump_enabled_p ())
-	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			 "not vectorized: complicated exit condition.\n");
-      return false;
-    }
+    return opt_result::failure_at
+      (vect_location,
+       "not vectorized: complicated exit condition.\n");
 
   if (integer_zerop (*assumptions)
       || !*number_of_iterations
       || chrec_contains_undetermined (*number_of_iterations))
-    {
-      if (dump_enabled_p ())
-	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			 "not vectorized: number of iterations cannot be "
-			 "computed.\n");
-      return false;
-    }
+    return opt_result::failure_at
+      (*loop_cond,
+       "not vectorized: number of iterations cannot be computed.\n");
 
   if (integer_zerop (*number_of_iterations))
-    {
-      if (dump_enabled_p ())
-	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			 "not vectorized: number of iterations = 0.\n");
-      return false;
-    }
+    return opt_result::failure_at
+      (*loop_cond,
+       "not vectorized: number of iterations = 0.\n");
 
-  return true;
+  return opt_result::success ();
 }
 
 /* Analyze LOOP form and return a loop_vec_info if it is of suitable form.  */
 
-loop_vec_info
+opt_loop_vec_info
 vect_analyze_loop_form (struct loop *loop, vec_info_shared *shared)
 {
   tree assumptions, number_of_iterations, number_of_iterationsm1;
   gcond *loop_cond, *inner_loop_cond = NULL;
 
-  if (! vect_analyze_loop_form_1 (loop, &loop_cond,
-				  &assumptions, &number_of_iterationsm1,
-				  &number_of_iterations, &inner_loop_cond))
-    return NULL;
+  opt_result res
+    = vect_analyze_loop_form_1 (loop, &loop_cond,
+				&assumptions, &number_of_iterationsm1,
+				&number_of_iterations, &inner_loop_cond);
+  if (!res)
+    return opt_loop_vec_info::propagate_failure (res);
 
   loop_vec_info loop_vinfo = new _loop_vec_info (loop, shared);
   LOOP_VINFO_NITERSM1 (loop_vinfo) = number_of_iterationsm1;
@@ -1387,7 +1351,7 @@ vect_analyze_loop_form (struct loop *loop, vec_info_shared *shared)
 
   gcc_assert (!loop->aux);
   loop->aux = loop_vinfo;
-  return loop_vinfo;
+  return opt_loop_vec_info::success (loop_vinfo);
 }
 
 
@@ -1489,7 +1453,7 @@ vect_active_double_reduction_p (stmt_vec_info stmt_info)
 
    Scan the loop stmts and make sure they are all vectorizable.  */
 
-static bool
+static opt_result
 vect_analyze_loop_operations (loop_vec_info loop_vinfo)
 {
   struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
@@ -1531,13 +1495,9 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo)
                  requires to actually do something here.  */
               if (STMT_VINFO_LIVE_P (stmt_info)
 		  && !vect_active_double_reduction_p (stmt_info))
-                {
-                  if (dump_enabled_p ())
-		    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-				     "Unsupported loop-closed phi in "
-				     "outer-loop.\n");
-                  return false;
-                }
+		return opt_result::failure_at (phi,
+					       "Unsupported loop-closed phi"
+					       " in outer-loop.\n");
 
               /* If PHI is used in the outer loop, we check that its operand
                  is defined in the inner loop.  */
@@ -1546,17 +1506,17 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo)
                   tree phi_op;
 
                   if (gimple_phi_num_args (phi) != 1)
-                    return false;
+                    return opt_result::failure_at (phi, "unsupported phi");
 
                   phi_op = PHI_ARG_DEF (phi, 0);
 		  stmt_vec_info op_def_info = loop_vinfo->lookup_def (phi_op);
 		  if (!op_def_info)
-                    return false;
+		    return opt_result::failure_at (phi, "unsupported phi");
 
 		  if (STMT_VINFO_RELEVANT (op_def_info) != vect_used_in_outer
 		      && (STMT_VINFO_RELEVANT (op_def_info)
 			  != vect_used_in_outer_by_reduction))
-		    return false;
+		    return opt_result::failure_at (phi, "unsupported phi");
                 }
 
               continue;
@@ -1567,13 +1527,10 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo)
           if ((STMT_VINFO_RELEVANT (stmt_info) == vect_used_in_scope
                || STMT_VINFO_LIVE_P (stmt_info))
               && STMT_VINFO_DEF_TYPE (stmt_info) != vect_induction_def)
-            {
-              /* A scalar-dependence cycle that we don't support.  */
-              if (dump_enabled_p ())
-		dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-				 "not vectorized: scalar dependence cycle.\n");
-              return false;
-            }
+	    /* A scalar-dependence cycle that we don't support.  */
+	    return opt_result::failure_at (phi,
+					   "not vectorized:"
+					   " scalar dependence cycle.\n");
 
           if (STMT_VINFO_RELEVANT_P (stmt_info))
             {
@@ -1597,24 +1554,25 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo)
 					      &cost_vec);
 
           if (!ok)
-            {
-              if (dump_enabled_p ())
-		dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-				 "not vectorized: relevant phi not "
-				 "supported: %G", phi);
-	      return false;
-            }
+	    return opt_result::failure_at (phi,
+					   "not vectorized: relevant phi not "
+					   "supported: %G",
+					   static_cast <gimple *> (phi));
         }
 
       for (gimple_stmt_iterator si = gsi_start_bb (bb); !gsi_end_p (si);
 	   gsi_next (&si))
         {
 	  gimple *stmt = gsi_stmt (si);
-	  if (!gimple_clobber_p (stmt)
-	      && !vect_analyze_stmt (loop_vinfo->lookup_stmt (stmt),
+	  if (!gimple_clobber_p (stmt))
+	    {
+	      opt_result res
+		= vect_analyze_stmt (loop_vinfo->lookup_stmt (stmt),
 				     &need_to_vectorize,
-				     NULL, NULL, &cost_vec))
-	    return false;
+				     NULL, NULL, &cost_vec);
+	      if (!res)
+		return res;
+	    }
         }
     } /* bbs */
 
@@ -1631,14 +1589,12 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo)
       if (dump_enabled_p ())
         dump_printf_loc (MSG_NOTE, vect_location,
 			 "All the computation can be taken out of the loop.\n");
-      if (dump_enabled_p ())
-	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			 "not vectorized: redundant loop. no profit to "
-			 "vectorize.\n");
-      return false;
+      return opt_result::failure_at
+	(vect_location,
+	 "not vectorized: redundant loop. no profit to vectorize.\n");
     }
 
-  return true;
+  return opt_result::success ();
 }
 
 /* Analyze the cost of the loop described by LOOP_VINFO.  Decide if it
@@ -1736,7 +1692,7 @@ vect_analyze_loop_costing (loop_vec_info loop_vinfo)
   return 1;
 }
 
-static bool
+static opt_result
 vect_get_datarefs_in_loop (loop_p loop, basic_block *bbs,
 			   vec<data_reference_p> *datarefs,
 			   unsigned int *n_stmts)
@@ -1750,7 +1706,8 @@ vect_get_datarefs_in_loop (loop_p loop, basic_block *bbs,
 	if (is_gimple_debug (stmt))
 	  continue;
 	++(*n_stmts);
-	if (!vect_find_stmt_data_reference (loop, stmt, datarefs))
+	opt_result res = vect_find_stmt_data_reference (loop, stmt, datarefs);
+	if (!res)
 	  {
 	    if (is_gimple_call (stmt) && loop->safelen)
 	      {
@@ -1782,15 +1739,16 @@ vect_get_datarefs_in_loop (loop_p loop, basic_block *bbs,
 		      }
 		  }
 	      }
-	    return false;
+	    return res;
 	  }
 	/* If dependence analysis will give up due to the limit on the
 	   number of datarefs stop here and fail fatally.  */
 	if (datarefs->length ()
 	    > (unsigned)PARAM_VALUE (PARAM_LOOP_MAX_DATAREFS_FOR_DATADEPS))
-	  return false;
+	  return opt_result::failure_at (stmt, "exceeded param "
+					 "loop-max-datarefs-for-datadeps\n");
       }
-  return true;
+  return opt_result::success ();
 }
 
 /* Function vect_analyze_loop_2.
@@ -1798,10 +1756,10 @@ vect_get_datarefs_in_loop (loop_p loop, basic_block *bbs,
    Apply a set of analyses on LOOP, and create a loop_vec_info struct
    for it.  The different analyses will record information in the
    loop_vec_info struct.  */
-static bool
+static opt_result
 vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
 {
-  bool ok;
+  opt_result ok = opt_result::success ();
   int res;
   unsigned int max_vf = MAX_VECTORIZATION_FACTOR;
   poly_uint64 min_vf = 2;
@@ -1817,16 +1775,18 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
   /* Gather the data references and count stmts in the loop.  */
   if (!LOOP_VINFO_DATAREFS (loop_vinfo).exists ())
     {
-      if (!vect_get_datarefs_in_loop (loop, LOOP_VINFO_BBS (loop_vinfo),
-				      &LOOP_VINFO_DATAREFS (loop_vinfo),
-				      n_stmts))
+      opt_result res
+	= vect_get_datarefs_in_loop (loop, LOOP_VINFO_BBS (loop_vinfo),
+				     &LOOP_VINFO_DATAREFS (loop_vinfo),
+				     n_stmts);
+      if (!res)
 	{
 	  if (dump_enabled_p ())
 	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 			     "not vectorized: loop contains function "
 			     "calls or data references that cannot "
 			     "be analyzed\n");
-	  return false;
+	  return res;
 	}
       loop_vinfo->shared->save_datarefs ();
     }
@@ -1842,7 +1802,7 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
       if (dump_enabled_p ())
 	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 			 "bad data references.\n");
-      return false;
+      return ok;
     }
 
   /* Classify all cross-iteration scalar data-flow cycles.
@@ -1862,7 +1822,7 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
       if (dump_enabled_p ())
 	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 			 "bad data access.\n");
-      return false;
+      return ok;
     }
 
   /* Data-flow analysis to detect stmts that do not need to be vectorized.  */
@@ -1873,7 +1833,7 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
       if (dump_enabled_p ())
 	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 			 "unexpected pattern.\n");
-      return false;
+      return ok;
     }
 
   /* While the rest of the analysis below depends on it in some way.  */
@@ -1885,15 +1845,16 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
      FORNOW: fail at the first data dependence that we encounter.  */
 
   ok = vect_analyze_data_ref_dependences (loop_vinfo, &max_vf);
-  if (!ok
-      || (max_vf != MAX_VECTORIZATION_FACTOR
-	  && maybe_lt (max_vf, min_vf)))
+  if (!ok)
     {
       if (dump_enabled_p ())
-	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			     "bad data dependence.\n");
-      return false;
+	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+			 "bad data dependence.\n");
+      return ok;
     }
+  if (max_vf != MAX_VECTORIZATION_FACTOR
+      && maybe_lt (max_vf, min_vf))
+    return opt_result::failure_at (vect_location, "bad data dependence.\n");
   LOOP_VINFO_MAX_VECT_FACTOR (loop_vinfo) = max_vf;
 
   ok = vect_determine_vectorization_factor (loop_vinfo);
@@ -1902,16 +1863,11 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
       if (dump_enabled_p ())
 	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 			 "can't determine vectorization factor.\n");
-      return false;
+      return ok;
     }
   if (max_vf != MAX_VECTORIZATION_FACTOR
       && maybe_lt (max_vf, LOOP_VINFO_VECT_FACTOR (loop_vinfo)))
-    {
-      if (dump_enabled_p ())
-	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			 "bad data dependence.\n");
-      return false;
-    }
+    return opt_result::failure_at (vect_location, "bad data dependence.\n");
 
   /* Compute the scalar iteration cost.  */
   vect_compute_single_scalar_iteration_cost (loop_vinfo);
@@ -1922,7 +1878,7 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
   /* Check the SLP opportunities in the loop, analyze and build SLP trees.  */
   ok = vect_analyze_slp (loop_vinfo, *n_stmts);
   if (!ok)
-    return false;
+    return ok;
 
   /* If there are any SLP instances mark them as pure_slp.  */
   bool slp = vect_make_slp_decision (loop_vinfo);
@@ -1969,7 +1925,7 @@ start_over:
       if (dump_enabled_p ())
 	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 			 "bad data alignment.\n");
-      return false;
+      return ok;
     }
 
   /* Prune the list of ddrs to be tested at run-time by versioning for alias.
@@ -1977,7 +1933,7 @@ start_over:
      since we use grouping information gathered by interleaving analysis.  */
   ok = vect_prune_runtime_alias_test_list (loop_vinfo);
   if (!ok)
-    return false;
+    return ok;
 
   /* Do not invoke vect_enhance_data_refs_alignment for epilogue
      vectorization, since we do not want to add extra peeling or
@@ -1989,12 +1945,7 @@ start_over:
   else
     ok = vect_verify_datarefs_alignment (loop_vinfo);
   if (!ok)
-    {
-      if (dump_enabled_p ())
-	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			 "bad data alignment.\n");
-      return false;
-    }
+    return ok;
 
   if (slp)
     {
@@ -2004,7 +1955,11 @@ start_over:
       unsigned old_size = LOOP_VINFO_SLP_INSTANCES (loop_vinfo).length ();
       vect_slp_analyze_operations (loop_vinfo);
       if (LOOP_VINFO_SLP_INSTANCES (loop_vinfo).length () != old_size)
-	goto again;
+	{
+	  ok = opt_result::failure_at (vect_location,
+				       "unsupported SLP instances\n");
+	  goto again;
+	}
     }
 
   /* Scan all the remaining operations in the loop that are not subject
@@ -2015,7 +1970,7 @@ start_over:
       if (dump_enabled_p ())
 	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 			 "bad operation or unsupported loop bound.\n");
-      return false;
+      return ok;
     }
 
   /* Decide whether to use a fully-masked loop for this vectorization
@@ -2044,26 +1999,22 @@ start_over:
       tree scalar_niters = LOOP_VINFO_NITERSM1 (loop_vinfo);
 
       if (known_lt (wi::to_widest (scalar_niters), vf))
-	{
-	  if (dump_enabled_p ())
-	    dump_printf_loc (MSG_NOTE, vect_location,
-			     "loop has no enough iterations to support"
-			     " peeling for gaps.\n");
-	  return false;
-	}
+	return opt_result::failure_at (vect_location,
+				       "loop has no enough iterations to"
+				       " support peeling for gaps.\n");
     }
 
   /* Check the costings of the loop make vectorizing worthwhile.  */
   res = vect_analyze_loop_costing (loop_vinfo);
   if (res < 0)
-    goto again;
-  if (!res)
     {
-      if (dump_enabled_p ())
-	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			 "Loop costings not worthwhile.\n");
-      return false;
+      ok = opt_result::failure_at (vect_location,
+				   "Loop costings may not be worthwhile.\n");
+      goto again;
     }
+  if (!res)
+    return opt_result::failure_at (vect_location,
+				   "Loop costings not worthwhile.\n");
 
   /* Decide whether we need to create an epilogue loop to handle
      remaining scalar iterations.  */
@@ -2112,10 +2063,9 @@ start_over:
 					   single_exit (LOOP_VINFO_LOOP
 							 (loop_vinfo))))
         {
-          if (dump_enabled_p ())
-	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			     "not vectorized: can't create required "
-			     "epilog loop\n");
+	  ok = opt_result::failure_at (vect_location,
+				       "not vectorized: can't create required "
+				       "epilog loop\n");
           goto again;
         }
     }
@@ -2154,17 +2104,20 @@ start_over:
 			LOOP_VINFO_VECT_FACTOR (loop_vinfo)));
 
   /* Ok to vectorize!  */
-  return true;
+  return opt_result::success ();
 
 again:
+  /* Ensure that "ok" is false (with an opt_problem if dumping is enabled).  */
+  gcc_assert (!ok);
+
   /* Try again with SLP forced off but if we didn't do any SLP there is
      no point in re-trying.  */
   if (!slp)
-    return false;
+    return ok;
 
   /* If there are reduction chains re-trying will fail anyway.  */
   if (! LOOP_VINFO_REDUCTION_CHAINS (loop_vinfo).is_empty ())
-    return false;
+    return ok;
 
   /* Likewise if the grouped loads or stores in the SLP cannot be handled
      via interleaving or lane instructions.  */
@@ -2183,7 +2136,8 @@ again:
       if (! vect_store_lanes_supported (vectype, size, false)
 	 && ! known_eq (TYPE_VECTOR_SUBPARTS (vectype), 1U)
 	 && ! vect_grouped_store_supported (vectype, size))
-       return false;
+	return opt_result::failure_at (vinfo->stmt,
+				       "unsupported grouped store\n");
       FOR_EACH_VEC_ELT (SLP_INSTANCE_LOADS (instance), j, node)
 	{
 	  vinfo = SLP_TREE_SCALAR_STMTS (node)[0];
@@ -2194,7 +2148,8 @@ again:
 	  if (! vect_load_lanes_supported (vectype, size, false)
 	      && ! vect_grouped_load_supported (vectype, single_element_p,
 						size))
-	    return false;
+	    return opt_result::failure_at (vinfo->stmt,
+					   "unsupported grouped load\n");
 	}
     }
 
@@ -2263,11 +2218,10 @@ again:
    for it.  The different analyses will record information in the
    loop_vec_info struct.  If ORIG_LOOP_VINFO is not NULL epilogue must
    be vectorized.  */
-loop_vec_info
+opt_loop_vec_info
 vect_analyze_loop (struct loop *loop, loop_vec_info orig_loop_vinfo,
 		   vec_info_shared *shared)
 {
-  loop_vec_info loop_vinfo;
   auto_vector_sizes vector_sizes;
 
   /* Autodetect first vector size we try.  */
@@ -2280,35 +2234,28 @@ vect_analyze_loop (struct loop *loop, loop_vec_info orig_loop_vinfo,
   if (loop_outer (loop)
       && loop_vec_info_for_loop (loop_outer (loop))
       && LOOP_VINFO_VECTORIZABLE_P (loop_vec_info_for_loop (loop_outer (loop))))
-    {
-      if (dump_enabled_p ())
-	dump_printf_loc (MSG_NOTE, vect_location,
-			 "outer-loop already vectorized.\n");
-      return NULL;
-    }
+    return opt_loop_vec_info::failure_at (vect_location,
+					  "outer-loop already vectorized.\n");
 
   if (!find_loop_nest (loop, &shared->loop_nest))
-    {
-      if (dump_enabled_p ())
-	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			 "not vectorized: loop nest containing two "
-			 "or more consecutive inner loops cannot be "
-			 "vectorized\n");
-      return NULL;
-    }
+    return opt_loop_vec_info::failure_at
+      (vect_location,
+       "not vectorized: loop nest containing two or more consecutive inner"
+       " loops cannot be vectorized\n");
 
   unsigned n_stmts = 0;
   poly_uint64 autodetected_vector_size = 0;
   while (1)
     {
       /* Check the CFG characteristics of the loop (nesting, entry/exit).  */
-      loop_vinfo = vect_analyze_loop_form (loop, shared);
+      opt_loop_vec_info loop_vinfo
+	= vect_analyze_loop_form (loop, shared);
       if (!loop_vinfo)
 	{
 	  if (dump_enabled_p ())
 	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 			     "bad loop form.\n");
-	  return NULL;
+	  return loop_vinfo;
 	}
 
       bool fatal = false;
@@ -2316,7 +2263,8 @@ vect_analyze_loop (struct loop *loop, loop_vec_info orig_loop_vinfo,
       if (orig_loop_vinfo)
 	LOOP_VINFO_ORIG_LOOP_INFO (loop_vinfo) = orig_loop_vinfo;
 
-      if (vect_analyze_loop_2 (loop_vinfo, fatal, &n_stmts))
+      opt_result res = vect_analyze_loop_2 (loop_vinfo, fatal, &n_stmts);
+      if (res)
 	{
 	  LOOP_VINFO_VECTORIZABLE_P (loop_vinfo) = 1;
 
@@ -2335,7 +2283,7 @@ vect_analyze_loop (struct loop *loop, loop_vec_info orig_loop_vinfo,
       if (fatal
 	  || next_size == vector_sizes.length ()
 	  || known_eq (current_vector_size, 0U))
-	return NULL;
+	return opt_loop_vec_info::propagate_failure (res);
 
       /* Try the next biggest vector size.  */
       current_vector_size = vector_sizes[next_size++];
diff --git a/gcc/tree-vect-slp.c b/gcc/tree-vect-slp.c
index ae1c453..f60fea0 100644
--- a/gcc/tree-vect-slp.c
+++ b/gcc/tree-vect-slp.c
@@ -2071,7 +2071,7 @@ vect_analyze_slp_instance (vec_info *vinfo,
 /* Check if there are stmts in the loop can be vectorized using SLP.  Build SLP
    trees of packed scalar stmts if SLP is possible.  */
 
-bool
+opt_result
 vect_analyze_slp (vec_info *vinfo, unsigned max_tree_size)
 {
   unsigned int i;
@@ -2111,7 +2111,7 @@ vect_analyze_slp (vec_info *vinfo, unsigned max_tree_size)
 				   max_tree_size);
     }
 
-  return true;
+  return opt_result::success ();
 }
 
 
diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c
index 7a6efdb..8108d52 100644
--- a/gcc/tree-vect-stmts.c
+++ b/gcc/tree-vect-stmts.c
@@ -448,7 +448,7 @@ exist_non_indexing_operands_for_use_p (tree use, stmt_vec_info stmt_info)
 
    Return true if everything is as expected. Return false otherwise.  */
 
-static bool
+static opt_result
 process_use (stmt_vec_info stmt_vinfo, tree use, loop_vec_info loop_vinfo,
 	     enum vect_relevant relevant, vec<stmt_vec_info> *worklist,
 	     bool force)
@@ -460,18 +460,15 @@ process_use (stmt_vec_info stmt_vinfo, tree use, loop_vec_info loop_vinfo,
   /* case 1: we are only interested in uses that need to be vectorized.  Uses
      that are used for address computation are not considered relevant.  */
   if (!force && !exist_non_indexing_operands_for_use_p (use, stmt_vinfo))
-     return true;
+    return opt_result::success ();
 
   if (!vect_is_simple_use (use, loop_vinfo, &dt, &dstmt_vinfo))
-    {
-      if (dump_enabled_p ())
-        dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-                         "not vectorized: unsupported use in stmt.\n");
-      return false;
-    }
+    return opt_result::failure_at (stmt_vinfo->stmt,
+				   "not vectorized:"
+				   " unsupported use in stmt.\n");
 
   if (!dstmt_vinfo)
-    return true;
+    return opt_result::success ();
 
   def_bb = gimple_bb (dstmt_vinfo->stmt);
 
@@ -493,7 +490,7 @@ process_use (stmt_vec_info stmt_vinfo, tree use, loop_vec_info loop_vinfo,
       gcc_assert (STMT_VINFO_RELEVANT (dstmt_vinfo) < vect_used_by_reduction);
       gcc_assert (STMT_VINFO_LIVE_P (dstmt_vinfo)
 		  || STMT_VINFO_RELEVANT (dstmt_vinfo) > vect_unused_in_scope);
-      return true;
+      return opt_result::success ();
     }
 
   /* case 3a: outer-loop stmt defining an inner-loop stmt:
@@ -582,12 +579,12 @@ process_use (stmt_vec_info stmt_vinfo, tree use, loop_vec_info loop_vinfo,
       if (dump_enabled_p ())
 	dump_printf_loc (MSG_NOTE, vect_location,
                          "induction value on backedge.\n");
-      return true;
+      return opt_result::success ();
     }
 
 
   vect_mark_relevant (worklist, dstmt_vinfo, relevant, false);
-  return true;
+  return opt_result::success ();
 }
 
 
@@ -607,7 +604,7 @@ process_use (stmt_vec_info stmt_vinfo, tree use, loop_vec_info loop_vinfo,
 
    This pass detects such stmts.  */
 
-bool
+opt_result
 vect_mark_stmts_to_be_vectorized (loop_vec_info loop_vinfo)
 {
   struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
@@ -684,38 +681,24 @@ vect_mark_stmts_to_be_vectorized (loop_vec_info loop_vinfo)
 		&& relevant != vect_used_in_scope
 		&& relevant != vect_used_by_reduction
 		&& relevant != vect_used_only_live)
-	      {
-		if (dump_enabled_p ())
-		  dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-				   "unsupported use of reduction.\n");
-		return false;
-	      }
+	      return opt_result::failure_at
+		(stmt_vinfo->stmt, "unsupported use of reduction.\n");
 	    break;
 
           case vect_nested_cycle:
 	    if (relevant != vect_unused_in_scope
 		&& relevant != vect_used_in_outer_by_reduction
 		&& relevant != vect_used_in_outer)
-              {
-                if (dump_enabled_p ())
-                  dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-                                   "unsupported use of nested cycle.\n");
-
-                return false;
-              }
+	      return opt_result::failure_at
+		(stmt_vinfo->stmt, "unsupported use of nested cycle.\n");
             break;
 
           case vect_double_reduction_def:
 	    if (relevant != vect_unused_in_scope
 		&& relevant != vect_used_by_reduction
 		&& relevant != vect_used_only_live)
-              {
-                if (dump_enabled_p ())
-                  dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-                                   "unsupported use of double reduction.\n");
-
-                return false;
-              }
+	      return opt_result::failure_at
+		(stmt_vinfo->stmt, "unsupported use of double reduction.\n");
             break;
 
           default:
@@ -735,20 +718,28 @@ vect_mark_stmts_to_be_vectorized (loop_vec_info loop_vinfo)
 	      i = 1;
 	      if (rhs_code == COND_EXPR && COMPARISON_CLASS_P (op))
 		{
-		  if (!process_use (stmt_vinfo, TREE_OPERAND (op, 0),
-				    loop_vinfo, relevant, &worklist, false)
-		      || !process_use (stmt_vinfo, TREE_OPERAND (op, 1),
-				       loop_vinfo, relevant, &worklist, false))
-		    return false;
+		  opt_result res
+		    = process_use (stmt_vinfo, TREE_OPERAND (op, 0),
+				   loop_vinfo, relevant, &worklist, false);
+		  if (!res)
+		    return res;
+		  res = process_use (stmt_vinfo, TREE_OPERAND (op, 1),
+				     loop_vinfo, relevant, &worklist, false);
+		  if (!res)
+		    return res;
 		  i = 2;
 		}
 	      for (; i < gimple_num_ops (assign); i++)
 		{
 		  op = gimple_op (assign, i);
-                  if (TREE_CODE (op) == SSA_NAME
-		      && !process_use (stmt_vinfo, op, loop_vinfo, relevant,
-				       &worklist, false))
-                    return false;
+                  if (TREE_CODE (op) == SSA_NAME)
+		    {
+		      opt_result res
+			= process_use (stmt_vinfo, op, loop_vinfo, relevant,
+				       &worklist, false);
+		      if (!res)
+			return res;
+		    }
                  }
             }
 	  else if (gcall *call = dyn_cast <gcall *> (stmt_vinfo->stmt))
@@ -756,9 +747,11 @@ vect_mark_stmts_to_be_vectorized (loop_vec_info loop_vinfo)
 	      for (i = 0; i < gimple_call_num_args (call); i++)
 		{
 		  tree arg = gimple_call_arg (call, i);
-		  if (!process_use (stmt_vinfo, arg, loop_vinfo, relevant,
-				    &worklist, false))
-                    return false;
+		  opt_result res
+		    = process_use (stmt_vinfo, arg, loop_vinfo, relevant,
+				   &worklist, false);
+		  if (!res)
+		    return res;
 		}
 	    }
         }
@@ -766,9 +759,11 @@ vect_mark_stmts_to_be_vectorized (loop_vec_info loop_vinfo)
 	FOR_EACH_PHI_OR_STMT_USE (use_p, stmt_vinfo->stmt, iter, SSA_OP_USE)
           {
             tree op = USE_FROM_PTR (use_p);
-	    if (!process_use (stmt_vinfo, op, loop_vinfo, relevant,
-			      &worklist, false))
-              return false;
+	    opt_result res
+	      = process_use (stmt_vinfo, op, loop_vinfo, relevant,
+			     &worklist, false);
+	    if (!res)
+	      return res;
           }
 
       if (STMT_VINFO_GATHER_SCATTER_P (stmt_vinfo))
@@ -776,13 +771,15 @@ vect_mark_stmts_to_be_vectorized (loop_vec_info loop_vinfo)
 	  gather_scatter_info gs_info;
 	  if (!vect_check_gather_scatter (stmt_vinfo, loop_vinfo, &gs_info))
 	    gcc_unreachable ();
-	  if (!process_use (stmt_vinfo, gs_info.offset, loop_vinfo, relevant,
-			    &worklist, true))
-	    return false;
+	  opt_result res
+	    = process_use (stmt_vinfo, gs_info.offset, loop_vinfo, relevant,
+			   &worklist, true);
+	  if (!res)
+	    return res;
 	}
     } /* while worklist */
 
-  return true;
+  return opt_result::success ();
 }
 
 /* Compute the prologue cost for invariant or constant operands.  */
@@ -9382,7 +9379,7 @@ can_vectorize_live_stmts (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
 
 /* Make sure the statement is vectorizable.  */
 
-bool
+opt_result
 vect_analyze_stmt (stmt_vec_info stmt_info, bool *need_to_vectorize,
 		   slp_tree node, slp_instance node_instance,
 		   stmt_vector_for_cost *cost_vec)
@@ -9398,13 +9395,10 @@ vect_analyze_stmt (stmt_vec_info stmt_info, bool *need_to_vectorize,
 		     stmt_info->stmt);
 
   if (gimple_has_volatile_ops (stmt_info->stmt))
-    {
-      if (dump_enabled_p ())
-        dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-                         "not vectorized: stmt has volatile operands\n");
-
-      return false;
-    }
+    return opt_result::failure_at (stmt_info->stmt,
+				   "not vectorized:"
+				   " stmt has volatile operands: %G\n",
+				   stmt_info->stmt);
 
   if (STMT_VINFO_IN_PATTERN_P (stmt_info)
       && node == NULL
@@ -9425,10 +9419,12 @@ vect_analyze_stmt (stmt_vec_info stmt_info, bool *need_to_vectorize,
 				 "==> examining pattern def statement: %G",
 				 pattern_def_stmt_info->stmt);
 
-	      if (!vect_analyze_stmt (pattern_def_stmt_info,
-				      need_to_vectorize, node, node_instance,
-				      cost_vec))
-		return false;
+	      opt_result res
+		= vect_analyze_stmt (pattern_def_stmt_info,
+				     need_to_vectorize, node, node_instance,
+				     cost_vec);
+	      if (!res)
+		return res;
 	    }
 	}
     }
@@ -9468,7 +9464,7 @@ vect_analyze_stmt (stmt_vec_info stmt_info, bool *need_to_vectorize,
           if (dump_enabled_p ())
             dump_printf_loc (MSG_NOTE, vect_location, "irrelevant.\n");
 
-          return true;
+          return opt_result::success ();
         }
     }
   else if (STMT_VINFO_IN_PATTERN_P (stmt_info)
@@ -9483,9 +9479,11 @@ vect_analyze_stmt (stmt_vec_info stmt_info, bool *need_to_vectorize,
 			 "==> examining pattern statement: %G",
 			 pattern_stmt_info->stmt);
 
-      if (!vect_analyze_stmt (pattern_stmt_info, need_to_vectorize, node,
-			      node_instance, cost_vec))
-        return false;
+      opt_result res
+	= vect_analyze_stmt (pattern_stmt_info, need_to_vectorize, node,
+			     node_instance, cost_vec);
+      if (!res)
+	return res;
    }
 
   switch (STMT_VINFO_DEF_TYPE (stmt_info))
@@ -9528,7 +9526,7 @@ vect_analyze_stmt (stmt_vec_info stmt_info, bool *need_to_vectorize,
     {
       dump_printf_loc (MSG_NOTE, vect_location,
 		       "handled only by SLP analysis\n");
-      return true;
+      return opt_result::success ();
     }
 
   ok = true;
@@ -9573,30 +9571,22 @@ vect_analyze_stmt (stmt_vec_info stmt_info, bool *need_to_vectorize,
     }
 
   if (!ok)
-    {
-      if (dump_enabled_p ())
-	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			 "not vectorized: relevant stmt not supported: %G",
-			 stmt_info->stmt);
-
-      return false;
-    }
+    return opt_result::failure_at (stmt_info->stmt,
+				   "not vectorized:"
+				   " relevant stmt not supported: %G",
+				   stmt_info->stmt);
 
   /* Stmts that are (also) "live" (i.e. - that are used out of the loop)
       need extra handling, except for vectorizable reductions.  */
   if (!bb_vinfo
       && STMT_VINFO_TYPE (stmt_info) != reduc_vec_info_type
       && !can_vectorize_live_stmts (stmt_info, NULL, node, NULL, cost_vec))
-    {
-      if (dump_enabled_p ())
-	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			 "not vectorized: live stmt not supported: %G",
-			 stmt_info->stmt);
+    return opt_result::failure_at (stmt_info->stmt,
+				   "not vectorized:"
+				   " live stmt not supported: %G",
+				   stmt_info->stmt);
 
-       return false;
-    }
-
-  return true;
+  return opt_result::success ();
 }
 
 
@@ -10537,7 +10527,7 @@ vect_gen_while_not (gimple_seq *seq, tree mask_type, tree start_index,
      number of units needed to vectorize STMT_INFO, or NULL_TREE if the
      statement does not help to determine the overall number of units.  */
 
-bool
+opt_result
 vect_get_vector_types_for_stmt (stmt_vec_info stmt_info,
 				tree *stmt_vectype_out,
 				tree *nunits_vectype_out)
@@ -10560,22 +10550,17 @@ vect_get_vector_types_for_stmt (stmt_vec_info stmt_info,
 	  if (dump_enabled_p ())
 	    dump_printf_loc (MSG_NOTE, vect_location,
 			     "defer to SIMD clone analysis.\n");
-	  return true;
+	  return opt_result::success ();
 	}
 
-      if (dump_enabled_p ())
-	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			 "not vectorized: irregular stmt.%G", stmt);
-      return false;
+      return opt_result::failure_at (stmt,
+				     "not vectorized: irregular stmt.%G", stmt);
     }
 
   if (VECTOR_MODE_P (TYPE_MODE (gimple_expr_type (stmt))))
-    {
-      if (dump_enabled_p ())
-	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			 "not vectorized: vector stmt in loop:%G", stmt);
-      return false;
-    }
+    return opt_result::failure_at (stmt,
+				   "not vectorized: vector stmt in loop:%G",
+				   stmt);
 
   tree vectype;
   tree scalar_type = NULL_TREE;
@@ -10606,7 +10591,7 @@ vect_get_vector_types_for_stmt (stmt_vec_info stmt_info,
 	      if (dump_enabled_p ())
 		dump_printf_loc (MSG_NOTE, vect_location,
 				 "pure bool operation.\n");
-	      return true;
+	      return opt_result::success ();
 	    }
 	}
 
@@ -10615,13 +10600,10 @@ vect_get_vector_types_for_stmt (stmt_vec_info stmt_info,
 			 "get vectype for scalar type:  %T\n", scalar_type);
       vectype = get_vectype_for_scalar_type (scalar_type);
       if (!vectype)
-	{
-	  if (dump_enabled_p ())
-	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			     "not vectorized: unsupported data-type %T\n",
-			     scalar_type);
-	  return false;
-	}
+	return opt_result::failure_at (stmt,
+				       "not vectorized:"
+				       " unsupported data-type %T\n",
+				       scalar_type);
 
       if (!*stmt_vectype_out)
 	*stmt_vectype_out = vectype;
@@ -10652,24 +10634,16 @@ vect_get_vector_types_for_stmt (stmt_vec_info stmt_info,
       nunits_vectype = get_vectype_for_scalar_type (scalar_type);
     }
   if (!nunits_vectype)
-    {
-      if (dump_enabled_p ())
-	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			 "not vectorized: unsupported data-type %T\n",
-			 scalar_type);
-      return false;
-    }
+    return opt_result::failure_at (stmt,
+				   "not vectorized: unsupported data-type %T\n",
+				   scalar_type);
 
   if (maybe_ne (GET_MODE_SIZE (TYPE_MODE (vectype)),
 		GET_MODE_SIZE (TYPE_MODE (nunits_vectype))))
-    {
-      if (dump_enabled_p ())
-	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			 "not vectorized: different sized vector "
-			 "types in statement, %T and %T\n",
-			 vectype, nunits_vectype);
-      return false;
-    }
+    return opt_result::failure_at (stmt,
+				   "not vectorized: different sized vector "
+				   "types in statement, %T and %T\n",
+				   vectype, nunits_vectype);
 
   if (dump_enabled_p ())
     {
@@ -10682,14 +10656,14 @@ vect_get_vector_types_for_stmt (stmt_vec_info stmt_info,
     }
 
   *nunits_vectype_out = nunits_vectype;
-  return true;
+  return opt_result::success ();
 }
 
 /* Try to determine the correct vector type for STMT_INFO, which is a
    statement that produces a scalar boolean result.  Return the vector
    type on success, otherwise return NULL_TREE.  */
 
-tree
+opt_tree
 vect_get_mask_type_for_stmt (stmt_vec_info stmt_info)
 {
   gimple *stmt = stmt_info->stmt;
@@ -10704,12 +10678,8 @@ vect_get_mask_type_for_stmt (stmt_vec_info stmt_info)
       mask_type = get_mask_type_for_scalar_type (scalar_type);
 
       if (!mask_type)
-	{
-	  if (dump_enabled_p ())
-	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-			     "not vectorized: unsupported mask\n");
-	  return NULL_TREE;
-	}
+	return opt_tree::failure_at (stmt,
+				     "not vectorized: unsupported mask\n");
     }
   else
     {
@@ -10720,13 +10690,9 @@ vect_get_mask_type_for_stmt (stmt_vec_info stmt_info)
       FOR_EACH_SSA_TREE_OPERAND (rhs, stmt, iter, SSA_OP_USE)
 	{
 	  if (!vect_is_simple_use (rhs, stmt_info->vinfo, &dt, &vectype))
-	    {
-	      if (dump_enabled_p ())
-		dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-				 "not vectorized: can't compute mask type "
-				 "for statement, %G", stmt);
-	      return NULL_TREE;
-	    }
+	    return opt_tree::failure_at (stmt,
+					 "not vectorized:can't compute mask"
+					 " type for statement, %G", stmt);
 
 	  /* No vectype probably means external definition.
 	     Allow it in case there is another operand which
@@ -10738,25 +10704,17 @@ vect_get_mask_type_for_stmt (stmt_vec_info stmt_info)
 	    mask_type = vectype;
 	  else if (maybe_ne (TYPE_VECTOR_SUBPARTS (mask_type),
 			     TYPE_VECTOR_SUBPARTS (vectype)))
-	    {
-	      if (dump_enabled_p ())
-		dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-				 "not vectorized: different sized masks "
-				 "types in statement, %T and %T\n",
-				 mask_type, vectype);
-	      return NULL_TREE;
-	    }
+	    return opt_tree::failure_at (stmt,
+					 "not vectorized: different sized mask"
+					 " types in statement, %T and %T\n",
+					 mask_type, vectype);
 	  else if (VECTOR_BOOLEAN_TYPE_P (mask_type)
 		   != VECTOR_BOOLEAN_TYPE_P (vectype))
-	    {
-	      if (dump_enabled_p ())
-		dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-				 "not vectorized: mixed mask and "
-				 "nonmask vector types in statement, "
-				 "%T and %T\n",
-				 mask_type, vectype);
-	      return NULL_TREE;
-	    }
+	    return opt_tree::failure_at (stmt,
+					 "not vectorized: mixed mask and "
+					 "nonmask vector types in statement, "
+					 "%T and %T\n",
+					 mask_type, vectype);
 	}
 
       /* We may compare boolean value loaded as vector of integers.
@@ -10770,9 +10728,10 @@ vect_get_mask_type_for_stmt (stmt_vec_info stmt_info)
 
   /* No mask_type should mean loop invariant predicate.
      This is probably a subject for optimization in if-conversion.  */
-  if (!mask_type && dump_enabled_p ())
-    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
-		     "not vectorized: can't compute mask type "
-		     "for statement, %G", stmt);
-  return mask_type;
+  if (!mask_type)
+    return opt_tree::failure_at (stmt,
+				 "not vectorized: can't compute mask type "
+				 "for statement: %G", stmt);
+
+  return opt_tree::success (mask_type);
 }
diff --git a/gcc/tree-vectorizer.c b/gcc/tree-vectorizer.c
index 23bddf3..747fb67 100644
--- a/gcc/tree-vectorizer.c
+++ b/gcc/tree-vectorizer.c
@@ -79,6 +79,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "stringpool.h"
 #include "attribs.h"
 #include "gimple-pretty-print.h"
+#include "opt-problem.h"
 
 
 /* Loop or bb location, with hotness information.  */
@@ -860,13 +861,25 @@ try_vectorize_loop_1 (hash_table<simduid_to_vf> *&simduid_to_vf_htab,
   vect_location = find_loop_location (loop);
   if (LOCATION_LOCUS (vect_location.get_location_t ()) != UNKNOWN_LOCATION
       && dump_enabled_p ())
-    dump_printf (MSG_NOTE, "\nAnalyzing loop at %s:%d\n",
+    dump_printf (MSG_NOTE | MSG_PRIORITY_INTERNALS,
+		 "\nAnalyzing loop at %s:%d\n",
 		 LOCATION_FILE (vect_location.get_location_t ()),
 		 LOCATION_LINE (vect_location.get_location_t ()));
 
-  loop_vec_info loop_vinfo = vect_analyze_loop (loop, orig_loop_vinfo, &shared);
+  /* Try to analyze the loop, retaining an opt_problem if dump_enabled_p.  */
+  opt_loop_vec_info loop_vinfo
+    = vect_analyze_loop (loop, orig_loop_vinfo, &shared);
   loop->aux = loop_vinfo;
 
+  if (!loop_vinfo)
+    if (dump_enabled_p ())
+      if (opt_problem *problem = loop_vinfo.get_problem ())
+	{
+	  dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+			   "couldn't vectorize loop\n");
+	  problem->emit_and_clear ();
+	}
+
   if (!loop_vinfo || !LOOP_VINFO_VECTORIZABLE_P (loop_vinfo))
     {
       /* Free existing information if loop is analyzed with some
diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h
index af5d5bf..63cff79 100644
--- a/gcc/tree-vectorizer.h
+++ b/gcc/tree-vectorizer.h
@@ -612,6 +612,12 @@ typedef struct _loop_vec_info : public vec_info {
 #define LOOP_VINFO_ORIG_MAX_VECT_FACTOR(L) \
   (LOOP_VINFO_MAX_VECT_FACTOR (LOOP_VINFO_ORIG_LOOP_INFO (L)))
 
+/* Wrapper for loop_vec_info, for tracking success/failure, where a non-NULL
+   value signifies success, and a NULL value signifies failure, supporting
+   propagating an opt_problem * describing the failure back up the call
+   stack.  */
+typedef opt_pointer_wrapper <loop_vec_info> opt_loop_vec_info;
+
 static inline loop_vec_info
 loop_vec_info_for_loop (struct loop *loop)
 {
@@ -1473,7 +1479,7 @@ extern unsigned record_stmt_cost (stmt_vector_for_cost *, int,
 extern stmt_vec_info vect_finish_replace_stmt (stmt_vec_info, gimple *);
 extern stmt_vec_info vect_finish_stmt_generation (stmt_vec_info, gimple *,
 						  gimple_stmt_iterator *);
-extern bool vect_mark_stmts_to_be_vectorized (loop_vec_info);
+extern opt_result vect_mark_stmts_to_be_vectorized (loop_vec_info);
 extern tree vect_get_store_rhs (stmt_vec_info);
 extern tree vect_get_vec_def_for_operand_1 (stmt_vec_info, enum vect_def_type);
 extern tree vect_get_vec_def_for_operand (tree, stmt_vec_info, tree = NULL);
@@ -1487,8 +1493,8 @@ extern tree vect_get_vec_def_for_stmt_copy (vec_info *, tree);
 extern bool vect_transform_stmt (stmt_vec_info, gimple_stmt_iterator *,
 				 slp_tree, slp_instance);
 extern void vect_remove_stores (stmt_vec_info);
-extern bool vect_analyze_stmt (stmt_vec_info, bool *, slp_tree, slp_instance,
-			       stmt_vector_for_cost *);
+extern opt_result vect_analyze_stmt (stmt_vec_info, bool *, slp_tree,
+				     slp_instance, stmt_vector_for_cost *);
 extern bool vectorizable_condition (stmt_vec_info, gimple_stmt_iterator *,
 				    stmt_vec_info *, tree, int, slp_tree,
 				    stmt_vector_for_cost *);
@@ -1504,8 +1510,9 @@ extern tree vect_gen_perm_mask_checked (tree, const vec_perm_indices &);
 extern void optimize_mask_stores (struct loop*);
 extern gcall *vect_gen_while (tree, tree, tree);
 extern tree vect_gen_while_not (gimple_seq *, tree, tree, tree);
-extern bool vect_get_vector_types_for_stmt (stmt_vec_info, tree *, tree *);
-extern tree vect_get_mask_type_for_stmt (stmt_vec_info);
+extern opt_result vect_get_vector_types_for_stmt (stmt_vec_info, tree *,
+						  tree *);
+extern opt_tree vect_get_mask_type_for_stmt (stmt_vec_info);
 
 /* In tree-vect-data-refs.c.  */
 extern bool vect_can_force_dr_alignment_p (const_tree, unsigned int);
@@ -1513,21 +1520,21 @@ extern enum dr_alignment_support vect_supportable_dr_alignment
                                            (dr_vec_info *, bool);
 extern tree vect_get_smallest_scalar_type (stmt_vec_info, HOST_WIDE_INT *,
                                            HOST_WIDE_INT *);
-extern bool vect_analyze_data_ref_dependences (loop_vec_info, unsigned int *);
+extern opt_result vect_analyze_data_ref_dependences (loop_vec_info, unsigned int *);
 extern bool vect_slp_analyze_instance_dependence (slp_instance);
-extern bool vect_enhance_data_refs_alignment (loop_vec_info);
-extern bool vect_analyze_data_refs_alignment (loop_vec_info);
-extern bool vect_verify_datarefs_alignment (loop_vec_info);
+extern opt_result vect_enhance_data_refs_alignment (loop_vec_info);
+extern opt_result vect_analyze_data_refs_alignment (loop_vec_info);
+extern opt_result vect_verify_datarefs_alignment (loop_vec_info);
 extern bool vect_slp_analyze_and_verify_instance_alignment (slp_instance);
-extern bool vect_analyze_data_ref_accesses (vec_info *);
-extern bool vect_prune_runtime_alias_test_list (loop_vec_info);
+extern opt_result vect_analyze_data_ref_accesses (vec_info *);
+extern opt_result vect_prune_runtime_alias_test_list (loop_vec_info);
 extern bool vect_gather_scatter_fn_p (bool, bool, tree, tree, unsigned int,
 				      signop, int, internal_fn *, tree *);
 extern bool vect_check_gather_scatter (stmt_vec_info, loop_vec_info,
 				       gather_scatter_info *);
-extern bool vect_find_stmt_data_reference (loop_p, gimple *,
-					   vec<data_reference_p> *);
-extern bool vect_analyze_data_refs (vec_info *, poly_uint64 *);
+extern opt_result vect_find_stmt_data_reference (loop_p, gimple *,
+						 vec<data_reference_p> *);
+extern opt_result vect_analyze_data_refs (vec_info *, poly_uint64 *);
 extern void vect_record_base_alignments (vec_info *);
 extern tree vect_create_data_ref_ptr (stmt_vec_info, tree, struct loop *, tree,
 				      tree *, gimple_stmt_iterator *,
@@ -1563,8 +1570,9 @@ extern stmt_vec_info vect_force_simple_reduction (loop_vec_info, stmt_vec_info,
 extern bool check_reduction_path (dump_user_location_t, loop_p, gphi *, tree,
 				  enum tree_code);
 /* Drive for loop analysis stage.  */
-extern loop_vec_info vect_analyze_loop (struct loop *, loop_vec_info,
-					vec_info_shared *);
+extern opt_loop_vec_info vect_analyze_loop (struct loop *,
+					    loop_vec_info,
+					    vec_info_shared *);
 extern tree vect_build_loop_niters (loop_vec_info, bool * = NULL);
 extern void vect_gen_vector_loop_niters (loop_vec_info, tree, tree *,
 					 tree *, bool);
@@ -1577,7 +1585,8 @@ extern tree vect_get_loop_mask (gimple_stmt_iterator *, vec_loop_masks *,
 
 /* Drive for loop transformation stage.  */
 extern struct loop *vect_transform_loop (loop_vec_info);
-extern loop_vec_info vect_analyze_loop_form (struct loop *, vec_info_shared *);
+extern opt_loop_vec_info vect_analyze_loop_form (struct loop *,
+						 vec_info_shared *);
 extern bool vectorizable_live_operation (stmt_vec_info, gimple_stmt_iterator *,
 					 slp_tree, int, stmt_vec_info *,
 					 stmt_vector_for_cost *);
@@ -1602,7 +1611,7 @@ extern bool vect_transform_slp_perm_load (slp_tree, vec<tree> ,
 					  slp_instance, bool, unsigned *);
 extern bool vect_slp_analyze_operations (vec_info *);
 extern void vect_schedule_slp (vec_info *);
-extern bool vect_analyze_slp (vec_info *, unsigned);
+extern opt_result vect_analyze_slp (vec_info *, unsigned);
 extern bool vect_make_slp_decision (loop_vec_info);
 extern void vect_detect_hybrid_slp (loop_vec_info);
 extern void vect_get_slp_defs (vec<tree> , slp_tree, vec<vec<tree> > *);
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 2/3] Add -fopt-info-internals
  2018-09-28 18:23       ` [PATCH 0/3] Higher-level reporting of vectorization problems (v3) David Malcolm
@ 2018-09-28 18:24         ` David Malcolm
  2018-10-04 11:09           ` Richard Biener
  2018-09-28 18:24         ` [PATCH 3/3] v3: Report vectorization problems via a new opt_problem class David Malcolm
  2018-09-28 18:25         ` [PATCH 1/3] Fix -fopt-info for plugin passes David Malcolm
  2 siblings, 1 reply; 24+ messages in thread
From: David Malcolm @ 2018-09-28 18:24 UTC (permalink / raw)
  To: Richard Sandiford, Richard Biener; +Cc: gcc-patches, David Malcolm

This patch introduces a verbosity level to dump messages:
"user-facing" vs "internals".

By default, messages at the top-level dump scope are "user-facing",
whereas those that are in nested scopes are implicitly "internals",
and are filtered out by -fopt-info unless a new "-internals" sub-option
of "-fopt-info" is supplied (intended purely for use by GCC developers).
Dumpfiles are unaffected by the change.

Given that the vectorizer is the only subsystem using AUTO_DUMP_SCOPE
(via DUMP_VECT_SCOPE), this only affects the vectorizer.

Filtering out these implementation-detail messages goes a long way
towards making -fopt-info-vec-all more accessible to advanced end-users;
the follow-up patch restores the most pertinent missing details.

Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.

OK for trunk?

gcc/ChangeLog:
	* doc/invoke.texi (-fopt-info): Document new "internals"
	sub-option.
	* dump-context.h (dump_context::apply_dump_filter_p): New decl.
	* dumpfile.c (dump_options): Update for renaming of MSG_ALL to
	MSG_ALL_KINDS.
	(optinfo_verbosity_options): Add "internals".
	(kind_as_string): Update for renaming of MSG_ALL to MSG_ALL_KINDS.
	(dump_context::apply_dump_filter_p): New member function.
	(dump_context::dump_loc): Use apply_dump_filter_p rather than
	explicitly masking the dump_kind.
	(dump_context::begin_scope): Increment the scope depth first.  Use
	apply_dump_filter_p rather than explicitly masking the dump_kind.
	(dump_context::emit_item): Use apply_dump_filter_p rather than
	explicitly masking the dump_kind.
	(dump_dec): Likewise.
	(dump_hex): Likewise.
	(dump_switch_p_1): Default to MSG_ALL_PRIORITIES.
	(opt_info_switch_p_1): Default to MSG_PRIORITY_USER_FACING.
	(opt_info_switch_p): Update handling of default
	MSG_OPTIMIZED_LOCATIONS to cope with default of
	MSG_PRIORITY_USER_FACING.
	(dump_basic_block): Use apply_dump_filter_p rather than explicitly
	masking the dump_kind.
	(selftest::test_capture_of_dump_calls): Update test_dump_context
	instances to use MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING rather
	than MSG_ALL.  Generalize scope test to be run at all four
	combinations of with/without MSG_PRIORITY_USER_FACING and
	MSG_PRIORITY_INTERNALS, adding examples of explicit priority
	for each of the two values.
	* dumpfile.h (enum dump_flag): Add comment about the MSG_* flags.
	Rename MSG_ALL to MSG_ALL_KINDS.  Add MSG_PRIORITY_USER_FACING,
	MSG_PRIORITY_INTERNALS, and MSG_ALL_PRIORITIES, updating the
	values for TDF_COMPARE_DEBUG and TDF_ALL_VALUES.
	(AUTO_DUMP_SCOPE): Add a note to the comment about the interaction
	with MSG_PRIORITY_*.
	* tree-vect-loop-manip.c (vect_loop_versioning): Mark versioning
	dump messages as MSG_PRIORITY_USER_FACING.
	* tree-vectorizer.h (DUMP_VECT_SCOPE): Add a note to the comment
	about the interaction with MSG_PRIORITY_*.

gcc/testsuite/ChangeLog:
	* gcc.dg/plugin/dump-1.c: Update expected output for test_scopes
	due to "-internals" not being selected.
	* gcc.dg/plugin/dump-2.c: New test, based on dump-1.c, with
	"-internals" added to re-enable the output from test_scopes.
	* gcc.dg/plugin/plugin.exp (plugin_test_list): Add dump-2.c.
---
 gcc/doc/invoke.texi                    |  31 ++++-
 gcc/dump-context.h                     |   2 +
 gcc/dumpfile.c                         | 248 +++++++++++++++++++++++----------
 gcc/dumpfile.h                         |  41 +++++-
 gcc/testsuite/gcc.dg/plugin/dump-1.c   |  10 +-
 gcc/testsuite/gcc.dg/plugin/dump-2.c   |  30 ++++
 gcc/testsuite/gcc.dg/plugin/plugin.exp |   3 +-
 gcc/tree-vect-loop-manip.c             |   6 +-
 gcc/tree-vectorizer.h                  |   6 +-
 9 files changed, 279 insertions(+), 98 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/plugin/dump-2.c

diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 5c95f67..ab8d9b7e8 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -14207,14 +14207,21 @@ Controls optimization dumps from various optimization passes. If the
 @samp{-} separated option keywords to select the dump details and
 optimizations.  
 
-The @var{options} can be divided into two groups: options describing the
-verbosity of the dump, and options describing which optimizations
-should be included. The options from both the groups can be freely
-mixed as they are non-overlapping. However, in case of any conflicts,
+The @var{options} can be divided into three groups:
+@enumerate
+@item
+options describing what kinds of messages should be emitted,
+@item
+options describing the verbosity of the dump, and
+@item
+options describing which optimizations should be included.
+@end enumerate
+The options from each group can be freely mixed as they are
+non-overlapping. However, in case of any conflicts,
 the later options override the earlier options on the command
 line. 
 
-The following options control the dump verbosity:
+The following options control which kinds of messages should be emitted:
 
 @table @samp
 @item optimized
@@ -14233,6 +14240,15 @@ Print detailed optimization information. This includes
 @samp{optimized}, @samp{missed}, and @samp{note}.
 @end table
 
+The following option controls the dump verbosity:
+
+@table @samp
+@item internals
+By default, only ``high-level'' messages are emitted. This option enables
+additional, more detailed, messages, which are likely to only be of interest
+to GCC developers.
+@end table
+
 One or more of the following option keywords can be used to describe a
 group of optimizations:
 
@@ -14253,8 +14269,9 @@ the optimization groups listed above.
 @end table
 
 If @var{options} is
-omitted, it defaults to @samp{optimized-optall}, which means to dump all
-info about successful optimizations from all the passes.  
+omitted, it defaults to @samp{optimized-optall}, which means to dump messages
+about successful optimizations from all the passes, omitting messages
+that are treated as ``internals''.
 
 If the @var{filename} is provided, then the dumps from all the
 applicable optimizations are concatenated into the @var{filename}.
diff --git a/gcc/dump-context.h b/gcc/dump-context.h
index 5b20c15..20b94a7 100644
--- a/gcc/dump-context.h
+++ b/gcc/dump-context.h
@@ -100,6 +100,8 @@ class dump_context
 
   void emit_item (optinfo_item *item, dump_flags_t dump_kind);
 
+  bool apply_dump_filter_p (dump_flags_t dump_kind, dump_flags_t filter) const;
+
  private:
   optinfo &ensure_pending_optinfo ();
   optinfo &begin_next_optinfo (const dump_location_t &loc);
diff --git a/gcc/dumpfile.c b/gcc/dumpfile.c
index d359e41..e15edc7 100644
--- a/gcc/dumpfile.c
+++ b/gcc/dumpfile.c
@@ -141,7 +141,7 @@ static const kv_pair<dump_flags_t> dump_options[] =
   {"optimized", MSG_OPTIMIZED_LOCATIONS},
   {"missed", MSG_MISSED_OPTIMIZATION},
   {"note", MSG_NOTE},
-  {"optall", MSG_ALL},
+  {"optall", MSG_ALL_KINDS},
   {"all", dump_flags_t (TDF_ALL_VALUES
 			& ~(TDF_RAW | TDF_SLIM | TDF_LINENO | TDF_GRAPH
 			    | TDF_STMTADDR | TDF_RHS_ONLY | TDF_NOUID
@@ -157,7 +157,8 @@ static const kv_pair<dump_flags_t> optinfo_verbosity_options[] =
   {"optimized", MSG_OPTIMIZED_LOCATIONS},
   {"missed", MSG_MISSED_OPTIMIZATION},
   {"note", MSG_NOTE},
-  {"all", MSG_ALL},
+  {"all", MSG_ALL_KINDS},
+  {"internals", MSG_PRIORITY_INTERNALS},
   {NULL, TDF_NONE}
 };
 
@@ -449,7 +450,7 @@ dump_user_location_t::from_function_decl (tree fndecl)
 static const char *
 kind_as_string (dump_flags_t dump_kind)
 {
-  switch (dump_kind & MSG_ALL)
+  switch (dump_kind & MSG_ALL_KINDS)
     {
     default:
       gcc_unreachable ();
@@ -524,6 +525,35 @@ dump_context::refresh_dumps_are_enabled ()
 		       || m_test_pp);
 }
 
+/* Determine if a message of kind DUMP_KIND and at the current scope depth
+   should be printed.
+
+   Only show messages that match FILTER both on their kind *and*
+   their priority.  */
+
+bool
+dump_context::apply_dump_filter_p (dump_flags_t dump_kind,
+				   dump_flags_t filter) const
+{
+  /* Few messages, if any, have an explicit MSG_PRIORITY.
+     If DUMP_KIND does, we'll use it.
+     Otherwise, generate an implicit priority value for the message based
+     on the current scope depth.
+     Messages at the top-level scope are MSG_PRIORITY_USER_FACING,
+     whereas those in nested scopes are MSG_PRIORITY_INTERNALS.  */
+  if (!(dump_kind & MSG_ALL_PRIORITIES))
+    {
+      dump_flags_t implicit_priority
+	=  (m_scope_depth > 0
+	    ? MSG_PRIORITY_INTERNALS
+	    : MSG_PRIORITY_USER_FACING);
+      dump_kind |= implicit_priority;
+    }
+
+  return (dump_kind & (filter & MSG_ALL_KINDS)
+	  && dump_kind & (filter & MSG_ALL_PRIORITIES));
+}
+
 /* Print LOC to the appropriate dump destinations, given DUMP_KIND.
    If optinfos are enabled, begin a new optinfo.  */
 
@@ -534,14 +564,14 @@ dump_context::dump_loc (dump_flags_t dump_kind, const dump_location_t &loc)
 
   location_t srcloc = loc.get_location_t ();
 
-  if (dump_file && (dump_kind & pflags))
+  if (dump_file && apply_dump_filter_p (dump_kind, pflags))
     ::dump_loc (dump_kind, dump_file, srcloc);
 
-  if (alt_dump_file && (dump_kind & alt_flags))
+  if (alt_dump_file && apply_dump_filter_p (dump_kind, alt_flags))
     ::dump_loc (dump_kind, alt_dump_file, srcloc);
 
   /* Support for temp_dump_context in selftests.  */
-  if (m_test_pp && (dump_kind & m_test_pp_flags))
+  if (m_test_pp && apply_dump_filter_p (dump_kind, m_test_pp_flags))
     ::dump_loc (dump_kind, m_test_pp, srcloc);
 
   if (optinfo_enabled_p ())
@@ -1067,22 +1097,24 @@ dump_context::get_scope_depth () const
 }
 
 /* Push a nested dump scope.
+   Increment the scope depth.
    Print "=== NAME ===\n" to the dumpfile, if any, and to the -fopt-info
    destination, if any.
-   Emit a "scope" optinfo if optinfos are enabled.
-   Increment the scope depth.  */
+   Emit a "scope" optinfo if optinfos are enabled.  */
 
 void
 dump_context::begin_scope (const char *name, const dump_location_t &loc)
 {
-  if (dump_file && (MSG_NOTE & pflags))
+  m_scope_depth++;
+
+  if (dump_file && apply_dump_filter_p (MSG_NOTE, pflags))
     ::dump_loc (MSG_NOTE, dump_file, loc.get_location_t ());
 
-  if (alt_dump_file && (MSG_NOTE & alt_flags))
+  if (alt_dump_file && apply_dump_filter_p (MSG_NOTE, alt_flags))
     ::dump_loc (MSG_NOTE, alt_dump_file, loc.get_location_t ());
 
   /* Support for temp_dump_context in selftests.  */
-  if (m_test_pp && (MSG_NOTE & m_test_pp_flags))
+  if (m_test_pp && apply_dump_filter_p (MSG_NOTE, m_test_pp_flags))
     ::dump_loc (MSG_NOTE, m_test_pp, loc.get_location_t ());
 
   pretty_printer pp;
@@ -1100,8 +1132,6 @@ dump_context::begin_scope (const char *name, const dump_location_t &loc)
     }
   else
     delete item;
-
-  m_scope_depth++;
 }
 
 /* Pop a nested dump scope.  */
@@ -1155,14 +1185,14 @@ dump_context::end_any_optinfo ()
 void
 dump_context::emit_item (optinfo_item *item, dump_flags_t dump_kind)
 {
-  if (dump_file && (dump_kind & pflags))
+  if (dump_file && apply_dump_filter_p (dump_kind, pflags))
     fprintf (dump_file, "%s", item->get_text ());
 
-  if (alt_dump_file && (dump_kind & alt_flags))
+  if (alt_dump_file && apply_dump_filter_p (dump_kind, alt_flags))
     fprintf (alt_dump_file, "%s", item->get_text ());
 
   /* Support for temp_dump_context in selftests.  */
-  if (m_test_pp && (dump_kind & m_test_pp_flags))
+  if (m_test_pp && apply_dump_filter_p (dump_kind, m_test_pp_flags))
     pp_string (m_test_pp, item->get_text ());
 }
 
@@ -1278,10 +1308,12 @@ template void dump_dec (dump_flags_t, const poly_widest_int &);
 void
 dump_dec (dump_flags_t dump_kind, const poly_wide_int &value, signop sgn)
 {
-  if (dump_file && (dump_kind & pflags))
+  if (dump_file
+      && dump_context::get ().apply_dump_filter_p (dump_kind, pflags))
     print_dec (value, dump_file, sgn);
 
-  if (alt_dump_file && (dump_kind & alt_flags))
+  if (alt_dump_file
+      && dump_context::get ().apply_dump_filter_p (dump_kind, alt_flags))
     print_dec (value, alt_dump_file, sgn);
 }
 
@@ -1290,10 +1322,12 @@ dump_dec (dump_flags_t dump_kind, const poly_wide_int &value, signop sgn)
 void
 dump_hex (dump_flags_t dump_kind, const poly_wide_int &value)
 {
-  if (dump_file && (dump_kind & pflags))
+  if (dump_file
+      && dump_context::get ().apply_dump_filter_p (dump_kind, pflags))
     print_hex (value, dump_file);
 
-  if (alt_dump_file && (dump_kind & alt_flags))
+  if (alt_dump_file
+      && dump_context::get ().apply_dump_filter_p (dump_kind, alt_flags))
     print_hex (value, alt_dump_file);
 }
 
@@ -1698,7 +1732,7 @@ dump_switch_p_1 (const char *arg, struct dump_file_info *dfi, bool doglob)
     return 0;
 
   ptr = option_value;
-  flags = TDF_NONE;
+  flags = MSG_ALL_PRIORITIES;
 
   while (*ptr)
     {
@@ -1794,7 +1828,11 @@ opt_info_switch_p_1 (const char *arg, dump_flags_t *flags,
   ptr = option_value;
 
   *filename = NULL;
-  *flags = TDF_NONE;
+
+  /* Default to filtering out "internals" messages, and retaining
+     "user-facing" messages.  */
+  *flags = MSG_PRIORITY_USER_FACING;
+
   *optgroup_flags = OPTGROUP_NONE;
 
   if (!ptr)
@@ -1883,8 +1921,8 @@ opt_info_switch_p (const char *arg)
     }
 
   file_seen = xstrdup (filename);
-  if (!flags)
-    flags = MSG_OPTIMIZED_LOCATIONS;
+  if (!(flags & MSG_ALL_KINDS))
+    flags |= MSG_OPTIMIZED_LOCATIONS;
   if (!optgroup_flags)
     optgroup_flags = OPTGROUP_ALL;
 
@@ -1896,9 +1934,11 @@ opt_info_switch_p (const char *arg)
 void
 dump_basic_block (dump_flags_t dump_kind, basic_block bb, int indent)
 {
-  if (dump_file && (dump_kind & pflags))
+  if (dump_file
+      && dump_context::get ().apply_dump_filter_p (dump_kind, pflags))
     dump_bb (dump_file, bb, indent, TDF_DETAILS);
-  if (alt_dump_file && (dump_kind & alt_flags))
+  if (alt_dump_file
+      && dump_context::get ().apply_dump_filter_p (dump_kind, alt_flags))
     dump_bb (alt_dump_file, bb, indent, TDF_DETAILS);
 }
 
@@ -2104,7 +2144,8 @@ test_capture_of_dump_calls (const line_table_case &case_)
 
       /* Test of dump_printf.  */
       {
-	temp_dump_context tmp (with_optinfo, MSG_ALL);
+	temp_dump_context tmp (with_optinfo,
+			       MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
 	dump_printf (MSG_NOTE, "int: %i str: %s", 42, "foo");
 
 	ASSERT_DUMPED_TEXT_EQ (tmp, "int: 42 str: foo");
@@ -2120,7 +2161,8 @@ test_capture_of_dump_calls (const line_table_case &case_)
 
       /* Test of dump_printf with %T.  */
       {
-	temp_dump_context tmp (with_optinfo, MSG_ALL);
+	temp_dump_context tmp (with_optinfo,
+			       MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
 	dump_printf (MSG_NOTE, "tree: %T", integer_zero_node);
 
 	ASSERT_DUMPED_TEXT_EQ (tmp, "tree: 0");
@@ -2137,7 +2179,8 @@ test_capture_of_dump_calls (const line_table_case &case_)
 
       /* Test of dump_printf with %E.  */
       {
-	temp_dump_context tmp (with_optinfo, MSG_ALL);
+	temp_dump_context tmp (with_optinfo,
+			       MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
 	dump_printf (MSG_NOTE, "gimple: %E", stmt);
 
 	ASSERT_DUMPED_TEXT_EQ (tmp, "gimple: return;");
@@ -2154,7 +2197,8 @@ test_capture_of_dump_calls (const line_table_case &case_)
 
       /* Test of dump_printf with %G.  */
       {
-	temp_dump_context tmp (with_optinfo, MSG_ALL);
+	temp_dump_context tmp (with_optinfo,
+			       MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
 	dump_printf (MSG_NOTE, "gimple: %G", stmt);
 
 	ASSERT_DUMPED_TEXT_EQ (tmp, "gimple: return;\n");
@@ -2176,7 +2220,8 @@ test_capture_of_dump_calls (const line_table_case &case_)
 	 - multiple dump-specific format codes: some consecutive, others
 	 separated by text, trailing text after the final one.  */
       {
-	temp_dump_context tmp (with_optinfo, MSG_ALL);
+	temp_dump_context tmp (with_optinfo,
+			       MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
 	dump_printf_loc (MSG_NOTE, loc, "before %T and %T"
 			 " %i consecutive %E%E after\n",
 			 integer_zero_node, test_decl, 42, stmt, stmt);
@@ -2203,7 +2248,8 @@ test_capture_of_dump_calls (const line_table_case &case_)
 
       /* Tree, via dump_generic_expr.  */
       {
-	temp_dump_context tmp (with_optinfo, MSG_ALL);
+	temp_dump_context tmp (with_optinfo,
+			       MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
 	dump_printf_loc (MSG_NOTE, loc, "test of tree: ");
 	dump_generic_expr (MSG_NOTE, TDF_SLIM, integer_zero_node);
 
@@ -2222,7 +2268,8 @@ test_capture_of_dump_calls (const line_table_case &case_)
 
       /* Tree, via dump_generic_expr_loc.  */
       {
-	temp_dump_context tmp (with_optinfo, MSG_ALL);
+	temp_dump_context tmp (with_optinfo,
+			       MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
 	dump_generic_expr_loc (MSG_NOTE, loc, TDF_SLIM, integer_one_node);
 
 	ASSERT_DUMPED_TEXT_EQ (tmp, "test.txt:5:10: note: 1");
@@ -2241,7 +2288,8 @@ test_capture_of_dump_calls (const line_table_case &case_)
       {
 	/* dump_gimple_stmt_loc.  */
 	{
-	  temp_dump_context tmp (with_optinfo, MSG_ALL);
+	  temp_dump_context tmp (with_optinfo,
+				 MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
 	  dump_gimple_stmt_loc (MSG_NOTE, loc, TDF_SLIM, stmt, 2);
 
 	  ASSERT_DUMPED_TEXT_EQ (tmp, "test.txt:5:10: note: return;\n");
@@ -2256,7 +2304,8 @@ test_capture_of_dump_calls (const line_table_case &case_)
 
 	/* dump_gimple_stmt.  */
 	{
-	  temp_dump_context tmp (with_optinfo, MSG_ALL);
+	  temp_dump_context tmp (with_optinfo,
+				 MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
 	  dump_gimple_stmt (MSG_NOTE, TDF_SLIM, stmt, 2);
 
 	  ASSERT_DUMPED_TEXT_EQ (tmp, "return;\n");
@@ -2271,7 +2320,8 @@ test_capture_of_dump_calls (const line_table_case &case_)
 
 	/* dump_gimple_expr_loc.  */
 	{
-	  temp_dump_context tmp (with_optinfo, MSG_ALL);
+	  temp_dump_context tmp (with_optinfo,
+				 MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
 	  dump_gimple_expr_loc (MSG_NOTE, loc, TDF_SLIM, stmt, 2);
 
 	  ASSERT_DUMPED_TEXT_EQ (tmp, "test.txt:5:10: note: return;");
@@ -2286,7 +2336,8 @@ test_capture_of_dump_calls (const line_table_case &case_)
 
 	/* dump_gimple_expr.  */
 	{
-	  temp_dump_context tmp (with_optinfo, MSG_ALL);
+	  temp_dump_context tmp (with_optinfo,
+				 MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
 	  dump_gimple_expr (MSG_NOTE, TDF_SLIM, stmt, 2);
 
 	  ASSERT_DUMPED_TEXT_EQ (tmp, "return;");
@@ -2302,7 +2353,8 @@ test_capture_of_dump_calls (const line_table_case &case_)
 
       /* poly_int.  */
       {
-	temp_dump_context tmp (with_optinfo, MSG_ALL);
+	temp_dump_context tmp (with_optinfo,
+			       MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
 	dump_dec (MSG_NOTE, poly_int64 (42));
 
 	ASSERT_DUMPED_TEXT_EQ (tmp, "42");
@@ -2315,45 +2367,92 @@ test_capture_of_dump_calls (const line_table_case &case_)
 	  }
       }
 
-      /* scopes.  */
-      {
-	temp_dump_context tmp (with_optinfo, MSG_ALL);
-	dump_printf_loc (MSG_NOTE, stmt, "msg 1\n");
+      /* Scopes.  Test with all 4 combinations of
+	 filtering by MSG_PRIORITY_USER_FACING
+	 and/or filtering by MSG_PRIORITY_INTERNALS.  */
+      for (int j = 0; j < 3; j++)
 	{
-	  AUTO_DUMP_SCOPE ("outer scope", stmt);
-	  dump_printf_loc (MSG_NOTE, stmt, "msg 2\n");
+	  dump_flags_t dump_filter = MSG_ALL_KINDS;
+	  if (j % 2)
+	    dump_filter |= MSG_PRIORITY_USER_FACING;
+	  if (j / 2)
+	    dump_filter |= MSG_PRIORITY_INTERNALS;
+
+	  temp_dump_context tmp (with_optinfo, dump_filter);
+	  /* Emit various messages, mostly with implicit priority.  */
+	  dump_printf_loc (MSG_NOTE, stmt, "msg 1\n");
+	  dump_printf_loc (MSG_NOTE | MSG_PRIORITY_INTERNALS, stmt,
+			   "explicitly internal msg\n");
 	  {
-	    AUTO_DUMP_SCOPE ("middle scope", stmt);
-	    dump_printf_loc (MSG_NOTE, stmt, "msg 3\n");
+	    AUTO_DUMP_SCOPE ("outer scope", stmt);
+	    dump_printf_loc (MSG_NOTE, stmt, "msg 2\n");
 	    {
-	      AUTO_DUMP_SCOPE ("inner scope", stmt);
-	      dump_printf_loc (MSG_NOTE, stmt, "msg 4\n");
+	      AUTO_DUMP_SCOPE ("middle scope", stmt);
+	      dump_printf_loc (MSG_NOTE, stmt, "msg 3\n");
+	      {
+		AUTO_DUMP_SCOPE ("inner scope", stmt);
+		dump_printf_loc (MSG_NOTE, stmt, "msg 4\n");
+		dump_printf_loc (MSG_NOTE | MSG_PRIORITY_USER_FACING, stmt,
+				 "explicitly user-facing msg\n");
+	      }
+	      dump_printf_loc (MSG_NOTE, stmt, "msg 5\n");
 	    }
-	    dump_printf_loc (MSG_NOTE, stmt, "msg 5\n");
+	    dump_printf_loc (MSG_NOTE, stmt, "msg 6\n");
 	  }
-	  dump_printf_loc (MSG_NOTE, stmt, "msg 6\n");
-	}
-	dump_printf_loc (MSG_NOTE, stmt, "msg 7\n");
+	  dump_printf_loc (MSG_NOTE, stmt, "msg 7\n");
 
-	ASSERT_DUMPED_TEXT_EQ (tmp,
-			       "test.txt:5:10: note: msg 1\n"
-			       "test.txt:5:10: note: === outer scope ===\n"
-			       "test.txt:5:10: note:  msg 2\n"
-			       "test.txt:5:10: note:  === middle scope ===\n"
-			       "test.txt:5:10: note:   msg 3\n"
-			       "test.txt:5:10: note:   === inner scope ===\n"
-			       "test.txt:5:10: note:    msg 4\n"
-			       "test.txt:5:10: note:   msg 5\n"
-			       "test.txt:5:10: note:  msg 6\n"
-			       "test.txt:5:10: note: msg 7\n");
-	if (with_optinfo)
-	  {
-	    optinfo *info = tmp.get_pending_optinfo ();
-	    ASSERT_TRUE (info != NULL);
-	    ASSERT_EQ (info->num_items (), 1);
-	    ASSERT_IS_TEXT (info->get_item (0), "msg 7\n");
-	  }
-      }
+	  switch (dump_filter & MSG_ALL_PRIORITIES)
+	    {
+	    default:
+	      gcc_unreachable ();
+	    case 0:
+	      ASSERT_DUMPED_TEXT_EQ (tmp, "");
+	      break;
+	    case MSG_PRIORITY_USER_FACING:
+	      ASSERT_DUMPED_TEXT_EQ
+		(tmp,
+		 "test.txt:5:10: note: msg 1\n"
+		 "test.txt:5:10: note:    explicitly user-facing msg\n"
+		 "test.txt:5:10: note: msg 7\n");
+	      break;
+	    case MSG_PRIORITY_INTERNALS:
+	      ASSERT_DUMPED_TEXT_EQ
+		(tmp,
+		 "test.txt:5:10: note: explicitly internal msg\n"
+		 "test.txt:5:10: note:  === outer scope ===\n"
+		 "test.txt:5:10: note:  msg 2\n"
+		 "test.txt:5:10: note:   === middle scope ===\n"
+		 "test.txt:5:10: note:   msg 3\n"
+		 "test.txt:5:10: note:    === inner scope ===\n"
+		 "test.txt:5:10: note:    msg 4\n"
+		 "test.txt:5:10: note:   msg 5\n"
+		 "test.txt:5:10: note:  msg 6\n");
+	      break;
+	    case MSG_ALL_PRIORITIES:
+	      ASSERT_DUMPED_TEXT_EQ
+		(tmp,
+		 "test.txt:5:10: note: msg 1\n"
+		 "test.txt:5:10: note: explicitly internal msg\n"
+		 "test.txt:5:10: note: === outer scope ===\n"
+		 "test.txt:5:10: note:  msg 2\n"
+		 "test.txt:5:10: note:  === middle scope ===\n"
+		 "test.txt:5:10: note:   msg 3\n"
+		 "test.txt:5:10: note:   === inner scope ===\n"
+		 "test.txt:5:10: note:    msg 4\n"
+		 "test.txt:5:10: note:    explicitly user-facing msg\n"
+		 "test.txt:5:10: note:   msg 5\n"
+		 "test.txt:5:10: note:  msg 6\n"
+		 "test.txt:5:10: note: msg 7\n");
+	      break;
+	    }
+	  if (with_optinfo)
+	    {
+	      optinfo *info = tmp.get_pending_optinfo ();
+	      ASSERT_TRUE (info != NULL);
+	      ASSERT_EQ (info->num_items (), 1);
+	      ASSERT_IS_TEXT (info->get_item (0), "msg 7\n");
+	    }
+	}
     }
 
   /* Verify that MSG_* affects optinfo->get_kind (); we tested MSG_NOTE
@@ -2361,7 +2460,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
   {
     /* MSG_OPTIMIZED_LOCATIONS.  */
     {
-      temp_dump_context tmp (true, MSG_ALL);
+      temp_dump_context tmp (true, MSG_ALL_KINDS);
       dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc, "test");
       ASSERT_EQ (tmp.get_pending_optinfo ()->get_kind (),
 		 OPTINFO_KIND_SUCCESS);
@@ -2369,7 +2468,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
 
     /* MSG_MISSED_OPTIMIZATION.  */
     {
-      temp_dump_context tmp (true, MSG_ALL);
+      temp_dump_context tmp (true, MSG_ALL_KINDS);
       dump_printf_loc (MSG_MISSED_OPTIMIZATION, loc, "test");
       ASSERT_EQ (tmp.get_pending_optinfo ()->get_kind (),
 		 OPTINFO_KIND_FAILURE);
@@ -2378,7 +2477,8 @@ test_capture_of_dump_calls (const line_table_case &case_)
 
   /* Verify that MSG_* affect AUTO_DUMP_SCOPE and the dump calls.  */
   {
-    temp_dump_context tmp (false, MSG_OPTIMIZED_LOCATIONS);
+    temp_dump_context tmp (false,
+			   MSG_OPTIMIZED_LOCATIONS | MSG_ALL_PRIORITIES);
     dump_printf_loc (MSG_NOTE, stmt, "msg 1\n");
     {
       AUTO_DUMP_SCOPE ("outer scope", stmt);
diff --git a/gcc/dumpfile.h b/gcc/dumpfile.h
index 057ca46..5933905 100644
--- a/gcc/dumpfile.h
+++ b/gcc/dumpfile.h
@@ -145,6 +145,9 @@ enum dump_flag
   /* Dump folding details.  */
   TDF_FOLDING = (1 << 21),
 
+  /* MSG_* flags for expressing the kinds of message to
+     be emitted by -fopt-info.  */
+
   /* -fopt-info optimized sources.  */
   MSG_OPTIMIZED_LOCATIONS = (1 << 22),
 
@@ -154,15 +157,37 @@ enum dump_flag
   /* General optimization info.  */
   MSG_NOTE = (1 << 24),
 
-  MSG_ALL = (MSG_OPTIMIZED_LOCATIONS
-	     | MSG_MISSED_OPTIMIZATION
-	     | MSG_NOTE),
+  /* Mask for selecting MSG_-kind flags.  */
+  MSG_ALL_KINDS = (MSG_OPTIMIZED_LOCATIONS
+		   | MSG_MISSED_OPTIMIZATION
+		   | MSG_NOTE),
+
+  /* MSG_PRIORITY_* flags for expressing the priority levels of message
+     to be emitted by -fopt-info, and filtering on them.
+     By default, messages at the top-level dump scope are "user-facing",
+     whereas those that are in nested scopes are implicitly "internals".
+     This behavior can be overridden for a given dump message by explicitly
+     specifying one of the MSG_PRIORITY_* flags.
+
+     By default, dump files show both kinds of message, whereas -fopt-info
+     only shows "user-facing" messages, and requires the "-internals"
+     sub-option of -fopt-info to show the internal messages.  */
+
+  /* Implicitly supplied for messages at the top-level dump scope.  */
+  MSG_PRIORITY_USER_FACING = (1 << 25),
+
+  /* Implicitly supplied for messages within nested dump scopes.  */
+  MSG_PRIORITY_INTERNALS = (1 << 26),
+
+  /* Mask for selecting MSG_PRIORITY_* flags.  */
+  MSG_ALL_PRIORITIES = (MSG_PRIORITY_USER_FACING
+			| MSG_PRIORITY_INTERNALS),
 
   /* Dumping for -fcompare-debug.  */
-  TDF_COMPARE_DEBUG = (1 << 25),
+  TDF_COMPARE_DEBUG = (1 << 27),
 
   /* All values.  */
-  TDF_ALL_VALUES = (1 << 26) - 1
+  TDF_ALL_VALUES = (1 << 28) - 1
 };
 
 /* Dump flags type.  */
@@ -549,7 +574,11 @@ class auto_dump_scope
    and then calling
      dump_end_scope ();
    once the object goes out of scope, thus capturing the nesting of
-   the scopes.  */
+   the scopes.
+
+   These scopes affect dump messages within them: dump messages at the
+   top level implicitly default to MSG_PRIORITY_USER_FACING, whereas those
+   in a nested scope implicitly default to MSG_PRIORITY_INTERNALS.  */
 
 #define AUTO_DUMP_SCOPE(NAME, LOC) \
   auto_dump_scope scope (NAME, LOC)
diff --git a/gcc/testsuite/gcc.dg/plugin/dump-1.c b/gcc/testsuite/gcc.dg/plugin/dump-1.c
index 165a9c1..95bd7a4 100644
--- a/gcc/testsuite/gcc.dg/plugin/dump-1.c
+++ b/gcc/testsuite/gcc.dg/plugin/dump-1.c
@@ -18,11 +18,7 @@ void test_remarks (void)
   test_wide_int (); /* { dg-message "test of wide int: 0" } */
   test_poly_int (); /* { dg-message "test of poly int: 42" } */
 
-  test_scopes (); /* { dg-line test_scopes_line } */
-  /* { dg-message "=== outer scope ===" "" { target *-*-* } test_scopes_line } */
-  /* { dg-message " at outer scope" "" { target *-*-* } test_scopes_line } */
-  /* { dg-message " === middle scope ===" "" { target *-*-* } test_scopes_line } */
-  /* { dg-message "  at middle scope" "" { target *-*-* } test_scopes_line } */
-  /* { dg-message "  === innermost scope ===" "" { target *-*-* } test_scopes_line } */
-  /* { dg-message "   at innermost scope" "" { target *-*-* } test_scopes_line } */
+  /* Dump messages in nested scopes are not printed by default, and
+     require "-internals".  */
+  test_scopes ();
 }
diff --git a/gcc/testsuite/gcc.dg/plugin/dump-2.c b/gcc/testsuite/gcc.dg/plugin/dump-2.c
new file mode 100644
index 0000000..961a3d3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/plugin/dump-2.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-fopt-info-note-internals" } */
+
+extern void test_string_literal (void);
+extern void test_tree (void);
+extern void test_gimple (int);
+extern void test_cgraph_node (void);
+extern void test_wide_int (void);
+extern void test_poly_int (void);
+extern void test_scopes (void);
+
+void test_remarks (void)
+{
+  test_string_literal (); /* { dg-message "test of dump for 'test_string_literal'" } */
+  test_tree (); /* { dg-message "test of tree: 0" } */
+  test_gimple (42); /* { dg-message "test of gimple: test_gimple \\(42\\);" } */
+  test_cgraph_node (); /* { dg-message "test of callgraph node: test_cgraph_node/\[0-9\]+" } */
+  test_wide_int (); /* { dg-message "test of wide int: 0" } */
+  test_poly_int (); /* { dg-message "test of poly int: 42" } */
+
+  /* Dump messages in nested scopes are not printed by default, and
+     require "-internals".  */
+  test_scopes (); /* { dg-line test_scopes_line } */
+  /* { dg-message "=== outer scope ===" "" { target *-*-* } test_scopes_line } */
+  /* { dg-message " at outer scope" "" { target *-*-* } test_scopes_line } */
+  /* { dg-message " === middle scope ===" "" { target *-*-* } test_scopes_line } */
+  /* { dg-message "  at middle scope" "" { target *-*-* } test_scopes_line } */
+  /* { dg-message "  === innermost scope ===" "" { target *-*-* } test_scopes_line } */
+  /* { dg-message "   at innermost scope" "" { target *-*-* } test_scopes_line } */
+}
diff --git a/gcc/testsuite/gcc.dg/plugin/plugin.exp b/gcc/testsuite/gcc.dg/plugin/plugin.exp
index 50db3ae..1d06c04 100644
--- a/gcc/testsuite/gcc.dg/plugin/plugin.exp
+++ b/gcc/testsuite/gcc.dg/plugin/plugin.exp
@@ -102,7 +102,8 @@ set plugin_test_list [list \
     { expensive_selftests_plugin.c \
 	  expensive-selftests-1.c } \
     { dump_plugin.c \
-	  dump-1.c } \
+	  dump-1.c \
+	  dump-2.c } \
 ]
 
 foreach plugin_test $plugin_test_list {
diff --git a/gcc/tree-vect-loop-manip.c b/gcc/tree-vect-loop-manip.c
index a93c6ee..1d1d114 100644
--- a/gcc/tree-vect-loop-manip.c
+++ b/gcc/tree-vect-loop-manip.c
@@ -3068,11 +3068,13 @@ vect_loop_versioning (loop_vec_info loop_vinfo,
       && dump_enabled_p ())
     {
       if (version_alias)
-        dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, vect_location,
+        dump_printf_loc (MSG_OPTIMIZED_LOCATIONS | MSG_PRIORITY_USER_FACING,
+			 vect_location,
                          "loop versioned for vectorization because of "
 			 "possible aliasing\n");
       if (version_align)
-        dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, vect_location,
+        dump_printf_loc (MSG_OPTIMIZED_LOCATIONS | MSG_PRIORITY_USER_FACING,
+			 vect_location,
                          "loop versioned for vectorization to enhance "
 			 "alignment\n");
 
diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h
index d91cc07..af5d5bf 100644
--- a/gcc/tree-vectorizer.h
+++ b/gcc/tree-vectorizer.h
@@ -1420,7 +1420,11 @@ extern dump_user_location_t vect_location;
    and then calling
      dump_end_scope ();
    once the object goes out of scope, thus capturing the nesting of
-   the scopes.  */
+   the scopes.
+
+   These scopes affect dump messages within them: dump messages at the
+   top level implicitly default to MSG_PRIORITY_USER_FACING, whereas those
+   in a nested scope implicitly default to MSG_PRIORITY_INTERNALS.  */
 
 #define DUMP_VECT_SCOPE(MSG) \
   AUTO_DUMP_SCOPE (MSG, vect_location)
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 1/3] Fix -fopt-info for plugin passes
  2018-09-28 18:23       ` [PATCH 0/3] Higher-level reporting of vectorization problems (v3) David Malcolm
  2018-09-28 18:24         ` [PATCH 2/3] Add -fopt-info-internals David Malcolm
  2018-09-28 18:24         ` [PATCH 3/3] v3: Report vectorization problems via a new opt_problem class David Malcolm
@ 2018-09-28 18:25         ` David Malcolm
  2018-10-04 10:52           ` Richard Biener
  2 siblings, 1 reply; 24+ messages in thread
From: David Malcolm @ 2018-09-28 18:25 UTC (permalink / raw)
  To: Richard Sandiford, Richard Biener; +Cc: gcc-patches, David Malcolm

Attempts to dump via -fopt-info from a plugin pass fail, due
to the dfi->alt_state for such passes never being set.

This is because the -fopt-info options were being set up per-pass
during option-parsing (via gcc::dump_manager::opt_info_enable_passes),
but this data was not retained or used it for passes created later
(for plugins and target-specific passes).

This patch fixes the issue by storing the -fopt-info options into
gcc::dump_manager, refactoring the dfi-setup code out of
opt_info_enable_passes, and reusing it for such passes, fixing the
issue.  The patch adds a demo plugin to test that dumping from a
plugin works.

Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.

OK for trunk?

gcc/ChangeLog:
	* dumpfile.c (gcc::dump_manager::dump_manager): Initialize new
	fields.
	(gcc::dump_manager::~dump_manager): Free m_optinfo_filename.
	(gcc::dump_manager::register_pass): New member function, adapted
	from loop body in gcc::pass_manager::register_pass, adding a
	call to update_dfi_for_opt_info.
	(gcc::dump_manager::opt_info_enable_passes): Store the
	-fopt-info options into the new fields.  Move the loop
	bodies into...
	(gcc::dump_manager::update_dfi_for_opt_info): ...this new member
	function.
	* dumpfile.h (struct opt_pass): New forward decl.
	(gcc::dump_manager::register_pass): New decl.
	(gcc::dump_manager::update_dfi_for_opt_info): New decl.
	(class gcc::dump_manager): Add fields "m_optgroup_flags",
	"m_optinfo_flags", and "m_optinfo_filename".
	* passes.c (gcc::pass_manager::register_pass): Move all of the
	dump-handling code to gcc::dump_manager::register_pass.

gcc/testsuite/ChangeLog:
	* gcc.dg/plugin/dump-1.c: New test.
	* gcc.dg/plugin/dump_plugin.c: New test plugin.
	* gcc.dg/plugin/plugin.exp (plugin_test_list): Add the above.
---
 gcc/dumpfile.c                            | 120 +++++++++++++++++--------
 gcc/dumpfile.h                            |  12 +++
 gcc/passes.c                              |  30 ++-----
 gcc/testsuite/gcc.dg/plugin/dump-1.c      |  28 ++++++
 gcc/testsuite/gcc.dg/plugin/dump_plugin.c | 143 ++++++++++++++++++++++++++++++
 gcc/testsuite/gcc.dg/plugin/plugin.exp    |   2 +
 6 files changed, 275 insertions(+), 60 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/plugin/dump-1.c
 create mode 100644 gcc/testsuite/gcc.dg/plugin/dump_plugin.c

diff --git a/gcc/dumpfile.c b/gcc/dumpfile.c
index d430ea3..d359e41 100644
--- a/gcc/dumpfile.c
+++ b/gcc/dumpfile.c
@@ -177,12 +177,16 @@ gcc::dump_manager::dump_manager ():
   m_next_dump (FIRST_AUTO_NUMBERED_DUMP),
   m_extra_dump_files (NULL),
   m_extra_dump_files_in_use (0),
-  m_extra_dump_files_alloced (0)
+  m_extra_dump_files_alloced (0),
+  m_optgroup_flags (OPTGROUP_NONE),
+  m_optinfo_flags (TDF_NONE),
+  m_optinfo_filename (NULL)
 {
 }
 
 gcc::dump_manager::~dump_manager ()
 {
+  free (m_optinfo_filename);
   for (size_t i = 0; i < m_extra_dump_files_in_use; i++)
     {
       dump_file_info *dfi = &m_extra_dump_files[i];
@@ -1512,6 +1516,50 @@ dump_flag_name (int phase) const
   return dfi->swtch;
 }
 
+/* Handle -fdump-* and -fopt-info for a pass added after
+   command-line options are parsed (those from plugins and
+   those from backends).
+
+   Because the registration of plugin/backend passes happens after the
+   command-line options are parsed, the options that specify single
+   pass dumping (e.g. -fdump-tree-PASSNAME) cannot be used for new
+   passes. Therefore we currently can only enable dumping of
+   new passes when the 'dump-all' flags (e.g. -fdump-tree-all)
+   are specified.  This is done here.
+
+   Similarly, the saved -fopt-info options are wired up to the new pass.  */
+
+void
+gcc::dump_manager::register_pass (opt_pass *pass)
+{
+  gcc_assert (pass);
+
+  register_one_dump_file (pass);
+
+  dump_file_info *pass_dfi = get_dump_file_info (pass->static_pass_number);
+  gcc_assert (pass_dfi);
+
+  enum tree_dump_index tdi;
+  if (pass->type == SIMPLE_IPA_PASS
+      || pass->type == IPA_PASS)
+    tdi = TDI_ipa_all;
+  else if (pass->type == GIMPLE_PASS)
+    tdi = TDI_tree_all;
+  else
+    tdi = TDI_rtl_all;
+  const dump_file_info *tdi_dfi = get_dump_file_info (tdi);
+  gcc_assert (tdi_dfi);
+
+  /* Check if dump-all flag is specified.  */
+  if (tdi_dfi->pstate)
+    {
+      pass_dfi->pstate = tdi_dfi->pstate;
+      pass_dfi->pflags = tdi_dfi->pflags;
+    }
+
+  update_dfi_for_opt_info (pass_dfi);
+}
+
 /* Finish a tree dump for PHASE. STREAM is the stream created by
    dump_begin.  */
 
@@ -1587,47 +1635,47 @@ opt_info_enable_passes (optgroup_flags_t optgroup_flags, dump_flags_t flags,
 			const char *filename)
 {
   int n = 0;
-  size_t i;
 
-  for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
-    {
-      if ((dump_files[i].optgroup_flags & optgroup_flags))
-        {
-          const char *old_filename = dump_files[i].alt_filename;
-          /* Since this file is shared among different passes, it
-             should be opened in append mode.  */
-          dump_files[i].alt_state = 1;
-          dump_files[i].alt_flags |= flags;
-          n++;
-          /* Override the existing filename.  */
-          if (filename)
-            dump_files[i].alt_filename = xstrdup (filename);
-          if (old_filename && filename != old_filename)
-            free (CONST_CAST (char *, old_filename));
-        }
-    }
+  m_optgroup_flags = optgroup_flags;
+  m_optinfo_flags = flags;
+  m_optinfo_filename = xstrdup (filename);
 
-  for (i = 0; i < m_extra_dump_files_in_use; i++)
-    {
-      if ((m_extra_dump_files[i].optgroup_flags & optgroup_flags))
-        {
-          const char *old_filename = m_extra_dump_files[i].alt_filename;
-          /* Since this file is shared among different passes, it
-             should be opened in append mode.  */
-          m_extra_dump_files[i].alt_state = 1;
-          m_extra_dump_files[i].alt_flags |= flags;
-          n++;
-          /* Override the existing filename.  */
-          if (filename)
-            m_extra_dump_files[i].alt_filename = xstrdup (filename);
-          if (old_filename && filename != old_filename)
-            free (CONST_CAST (char *, old_filename));
-        }
-    }
+  for (size_t i = TDI_none + 1; i < (size_t) TDI_end; i++)
+    if (update_dfi_for_opt_info (&dump_files[i]))
+      n++;
+
+  for (size_t i = 0; i < m_extra_dump_files_in_use; i++)
+    if (update_dfi_for_opt_info (&m_extra_dump_files[i]))
+      n++;
 
   return n;
 }
 
+/* Use the saved -fopt-info options to update DFI.
+   Return true if the dump is enabled.  */
+
+bool
+gcc::dump_manager::update_dfi_for_opt_info (dump_file_info *dfi) const
+{
+  gcc_assert (dfi);
+
+  if (!(dfi->optgroup_flags & m_optgroup_flags))
+    return false;
+
+  const char *old_filename = dfi->alt_filename;
+  /* Since this file is shared among different passes, it
+     should be opened in append mode.  */
+  dfi->alt_state = 1;
+  dfi->alt_flags |= m_optinfo_flags;
+  /* Override the existing filename.  */
+  if (m_optinfo_filename)
+    dfi->alt_filename = xstrdup (m_optinfo_filename);
+  if (old_filename && m_optinfo_filename != old_filename)
+    free (CONST_CAST (char *, old_filename));
+
+  return true;
+}
+
 /* Parse ARG as a dump switch. Return nonzero if it is, and store the
    relevant details in the dump_files array.  */
 
diff --git a/gcc/dumpfile.h b/gcc/dumpfile.h
index 671b7b9..057ca46 100644
--- a/gcc/dumpfile.h
+++ b/gcc/dumpfile.h
@@ -566,6 +566,8 @@ extern void dump_combine_total_stats (FILE *);
 /* In cfghooks.c  */
 extern void dump_bb (FILE *, basic_block, int, dump_flags_t);
 
+struct opt_pass;
+
 namespace gcc {
 
 /* A class for managing all of the various dump files used by the
@@ -634,6 +636,8 @@ public:
   const char *
   dump_flag_name (int phase) const;
 
+  void register_pass (opt_pass *pass);
+
 private:
 
   int
@@ -649,6 +653,8 @@ private:
   opt_info_enable_passes (optgroup_flags_t optgroup_flags, dump_flags_t flags,
 			  const char *filename);
 
+  bool update_dfi_for_opt_info (dump_file_info *dfi) const;
+
 private:
 
   /* Dynamically registered dump files and switches.  */
@@ -657,6 +663,12 @@ private:
   size_t m_extra_dump_files_in_use;
   size_t m_extra_dump_files_alloced;
 
+  /* Stored values from -fopt-info, for handling passes created after
+     option-parsing (by backends and by plugins).  */
+  optgroup_flags_t m_optgroup_flags;
+  dump_flags_t m_optinfo_flags;
+  char *m_optinfo_filename;
+
   /* Grant access to dump_enable_all.  */
   friend bool ::enable_rtl_dump_file (void);
 
diff --git a/gcc/passes.c b/gcc/passes.c
index 832f0b3..d838d90 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -1404,7 +1404,6 @@ void
 pass_manager::register_pass (struct register_pass_info *pass_info)
 {
   bool all_instances, success;
-  gcc::dump_manager *dumps = m_ctxt->get_dumps ();
 
   /* The checks below could fail in buggy plugins.  Existing GCC
      passes should never fail these checks, so we mention plugin in
@@ -1442,33 +1441,16 @@ pass_manager::register_pass (struct register_pass_info *pass_info)
 
   /* OK, we have successfully inserted the new pass. We need to register
      the dump files for the newly added pass and its duplicates (if any).
-     Because the registration of plugin/backend passes happens after the
-     command-line options are parsed, the options that specify single
-     pass dumping (e.g. -fdump-tree-PASSNAME) cannot be used for new
-     passes. Therefore we currently can only enable dumping of
-     new passes when the 'dump-all' flags (e.g. -fdump-tree-all)
-     are specified. While doing so, we also delete the pass_list_node
+     While doing so, we also delete the pass_list_node
      objects created during pass positioning.  */
+  gcc::dump_manager *dumps = m_ctxt->get_dumps ();
   while (added_pass_nodes)
     {
       struct pass_list_node *next_node = added_pass_nodes->next;
-      enum tree_dump_index tdi;
-      register_one_dump_file (added_pass_nodes->pass);
-      if (added_pass_nodes->pass->type == SIMPLE_IPA_PASS
-          || added_pass_nodes->pass->type == IPA_PASS)
-        tdi = TDI_ipa_all;
-      else if (added_pass_nodes->pass->type == GIMPLE_PASS)
-        tdi = TDI_tree_all;
-      else
-        tdi = TDI_rtl_all;
-      /* Check if dump-all flag is specified.  */
-      if (dumps->get_dump_file_info (tdi)->pstate)
-	{
-	  dumps->get_dump_file_info (added_pass_nodes->pass->static_pass_number)
-            ->pstate = dumps->get_dump_file_info (tdi)->pstate;
-	  dumps->get_dump_file_info (added_pass_nodes->pass->static_pass_number)
-	    ->pflags = dumps->get_dump_file_info (tdi)->pflags;
-	}
+
+      /* Handle -fdump-* and -fopt-info.  */
+      dumps->register_pass (added_pass_nodes->pass);
+
       XDELETE (added_pass_nodes);
       added_pass_nodes = next_node;
     }
diff --git a/gcc/testsuite/gcc.dg/plugin/dump-1.c b/gcc/testsuite/gcc.dg/plugin/dump-1.c
new file mode 100644
index 0000000..165a9c1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/plugin/dump-1.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-fopt-info-note" } */
+
+extern void test_string_literal (void);
+extern void test_tree (void);
+extern void test_gimple (int);
+extern void test_cgraph_node (void);
+extern void test_wide_int (void);
+extern void test_poly_int (void);
+extern void test_scopes (void);
+
+void test_remarks (void)
+{
+  test_string_literal (); /* { dg-message "test of dump for 'test_string_literal'" } */
+  test_tree (); /* { dg-message "test of tree: 0" } */
+  test_gimple (42); /* { dg-message "test of gimple: test_gimple \\(42\\);" } */
+  test_cgraph_node (); /* { dg-message "test of callgraph node: test_cgraph_node/\[0-9\]+" } */
+  test_wide_int (); /* { dg-message "test of wide int: 0" } */
+  test_poly_int (); /* { dg-message "test of poly int: 42" } */
+
+  test_scopes (); /* { dg-line test_scopes_line } */
+  /* { dg-message "=== outer scope ===" "" { target *-*-* } test_scopes_line } */
+  /* { dg-message " at outer scope" "" { target *-*-* } test_scopes_line } */
+  /* { dg-message " === middle scope ===" "" { target *-*-* } test_scopes_line } */
+  /* { dg-message "  at middle scope" "" { target *-*-* } test_scopes_line } */
+  /* { dg-message "  === innermost scope ===" "" { target *-*-* } test_scopes_line } */
+  /* { dg-message "   at innermost scope" "" { target *-*-* } test_scopes_line } */
+}
diff --git a/gcc/testsuite/gcc.dg/plugin/dump_plugin.c b/gcc/testsuite/gcc.dg/plugin/dump_plugin.c
new file mode 100644
index 0000000..12573d6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/plugin/dump_plugin.c
@@ -0,0 +1,143 @@
+/* Plugin for testing dumpfile.c.  */
+
+#include "gcc-plugin.h"
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "tree-pass.h"
+#include "intl.h"
+#include "plugin-version.h"
+#include "diagnostic.h"
+#include "context.h"
+#include "optinfo.h"
+#include "gimple.h"
+#include "gimple-iterator.h"
+#include "cgraph.h"
+
+int plugin_is_GPL_compatible;
+
+const pass_data pass_data_test_dumping =
+{
+  GIMPLE_PASS, /* type */
+  "test_dumping", /* name */
+  OPTGROUP_LOOP, /* optinfo_flags */
+  TV_NONE, /* tv_id */
+  PROP_ssa, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
+};
+
+class pass_test_dumping : public gimple_opt_pass
+{
+public:
+  pass_test_dumping (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_test_dumping, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  bool gate (function *) { return true; }
+  virtual unsigned int execute (function *);
+
+}; // class pass_test_dumping
+
+unsigned int
+pass_test_dumping::execute (function *fun)
+{
+  basic_block bb;
+
+  if (!dump_enabled_p ())
+    return 0;
+
+  FOR_ALL_BB_FN (bb, fun)
+    for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
+	 !gsi_end_p (gsi); gsi_next (&gsi))
+      {
+	gimple *stmt = gsi_stmt (gsi);
+	gcall *call = dyn_cast <gcall *> (stmt);
+	if (!call)
+	  continue;
+	tree callee_decl = gimple_call_fndecl (call);
+	if (!callee_decl)
+	  continue;
+	tree callee_name = DECL_NAME (callee_decl);
+	if (!callee_name)
+	  continue;
+	const char *callee = IDENTIFIER_POINTER (callee_name);
+
+	/* Various dumping tests, done at callsites,
+	   controlled by the callee name.  */
+	if (strcmp (callee, "test_string_literal") == 0)
+	  dump_printf_loc (MSG_NOTE, stmt, "test of dump for %qs\n",
+			   callee);
+	else if (strcmp (callee, "test_tree") == 0)
+	  dump_printf_loc (MSG_NOTE, stmt, "test of tree: %T\n",
+			   integer_zero_node);
+	else if (strcmp (callee, "test_gimple") == 0)
+	  dump_printf_loc (MSG_NOTE, stmt, "test of gimple: %G", stmt);
+	else if (strcmp (callee, "test_cgraph_node") == 0)
+	  {
+	    dump_printf_loc (MSG_NOTE, stmt, "test of callgraph node: ");
+	    dump_symtab_node (MSG_NOTE, cgraph_node::get (callee_decl));
+	    dump_printf (MSG_NOTE, "\n");
+	  }
+	else if (strcmp (callee, "test_wide_int") == 0)
+	  {
+	    HOST_WIDE_INT val = 0;
+	    dump_printf_loc (MSG_NOTE, stmt,
+			     "test of wide int: " HOST_WIDE_INT_PRINT_DEC "\n",
+			     val);
+	  }
+	else if (strcmp (callee, "test_poly_int") == 0)
+	  {
+	    dump_printf_loc (MSG_NOTE, stmt, "test of poly int: ");
+	    dump_dec (MSG_NOTE, poly_int64 (42));
+	    dump_printf (MSG_NOTE, "\n");
+	  }
+	else if (strcmp (callee, "test_scopes") == 0)
+	  {
+	    AUTO_DUMP_SCOPE ("outer scope", stmt);
+	    {
+	      dump_printf_loc (MSG_NOTE, stmt, "at outer scope\n");
+	      AUTO_DUMP_SCOPE ("middle scope", stmt);
+	      {
+		dump_printf_loc (MSG_NOTE, stmt, "at middle scope\n");
+		AUTO_DUMP_SCOPE ("innermost scope", stmt);
+		dump_printf_loc (MSG_NOTE, stmt, "at innermost scope\n");
+	      }
+	    }
+	  }
+      }
+
+  return 0;
+}
+
+static gimple_opt_pass *
+make_pass_test_dumping (gcc::context *ctxt)
+{
+  return new pass_test_dumping (ctxt);
+}
+
+int
+plugin_init (struct plugin_name_args *plugin_info,
+	     struct plugin_gcc_version *version)
+{
+  struct register_pass_info pass_info;
+  const char *plugin_name = plugin_info->base_name;
+  int argc = plugin_info->argc;
+  struct plugin_argument *argv = plugin_info->argv;
+
+  if (!plugin_default_version_check (version, &gcc_version))
+    return 1;
+
+  pass_info.pass = make_pass_test_dumping (g);
+  pass_info.reference_pass_name = "ssa";
+  pass_info.ref_pass_instance_number = 1;
+  pass_info.pos_op = PASS_POS_INSERT_AFTER;
+  register_callback (plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL,
+		     &pass_info);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/plugin/plugin.exp b/gcc/testsuite/gcc.dg/plugin/plugin.exp
index 46246a2..50db3ae 100644
--- a/gcc/testsuite/gcc.dg/plugin/plugin.exp
+++ b/gcc/testsuite/gcc.dg/plugin/plugin.exp
@@ -101,6 +101,8 @@ set plugin_test_list [list \
 	  must-tail-call-2.c } \
     { expensive_selftests_plugin.c \
 	  expensive-selftests-1.c } \
+    { dump_plugin.c \
+	  dump-1.c } \
 ]
 
 foreach plugin_test $plugin_test_list {
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 1/3] Fix -fopt-info for plugin passes
  2018-09-28 18:25         ` [PATCH 1/3] Fix -fopt-info for plugin passes David Malcolm
@ 2018-10-04 10:52           ` Richard Biener
  0 siblings, 0 replies; 24+ messages in thread
From: Richard Biener @ 2018-10-04 10:52 UTC (permalink / raw)
  To: David Malcolm; +Cc: Richard Sandiford, gcc-patches

On Fri, 28 Sep 2018, David Malcolm wrote:

> Attempts to dump via -fopt-info from a plugin pass fail, due
> to the dfi->alt_state for such passes never being set.
> 
> This is because the -fopt-info options were being set up per-pass
> during option-parsing (via gcc::dump_manager::opt_info_enable_passes),
> but this data was not retained or used it for passes created later
> (for plugins and target-specific passes).
> 
> This patch fixes the issue by storing the -fopt-info options into
> gcc::dump_manager, refactoring the dfi-setup code out of
> opt_info_enable_passes, and reusing it for such passes, fixing the
> issue.  The patch adds a demo plugin to test that dumping from a
> plugin works.
> 
> Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
> 
> OK for trunk?

OK.

Richard.

> gcc/ChangeLog:
> 	* dumpfile.c (gcc::dump_manager::dump_manager): Initialize new
> 	fields.
> 	(gcc::dump_manager::~dump_manager): Free m_optinfo_filename.
> 	(gcc::dump_manager::register_pass): New member function, adapted
> 	from loop body in gcc::pass_manager::register_pass, adding a
> 	call to update_dfi_for_opt_info.
> 	(gcc::dump_manager::opt_info_enable_passes): Store the
> 	-fopt-info options into the new fields.  Move the loop
> 	bodies into...
> 	(gcc::dump_manager::update_dfi_for_opt_info): ...this new member
> 	function.
> 	* dumpfile.h (struct opt_pass): New forward decl.
> 	(gcc::dump_manager::register_pass): New decl.
> 	(gcc::dump_manager::update_dfi_for_opt_info): New decl.
> 	(class gcc::dump_manager): Add fields "m_optgroup_flags",
> 	"m_optinfo_flags", and "m_optinfo_filename".
> 	* passes.c (gcc::pass_manager::register_pass): Move all of the
> 	dump-handling code to gcc::dump_manager::register_pass.
> 
> gcc/testsuite/ChangeLog:
> 	* gcc.dg/plugin/dump-1.c: New test.
> 	* gcc.dg/plugin/dump_plugin.c: New test plugin.
> 	* gcc.dg/plugin/plugin.exp (plugin_test_list): Add the above.
> ---
>  gcc/dumpfile.c                            | 120 +++++++++++++++++--------
>  gcc/dumpfile.h                            |  12 +++
>  gcc/passes.c                              |  30 ++-----
>  gcc/testsuite/gcc.dg/plugin/dump-1.c      |  28 ++++++
>  gcc/testsuite/gcc.dg/plugin/dump_plugin.c | 143 ++++++++++++++++++++++++++++++
>  gcc/testsuite/gcc.dg/plugin/plugin.exp    |   2 +
>  6 files changed, 275 insertions(+), 60 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/plugin/dump-1.c
>  create mode 100644 gcc/testsuite/gcc.dg/plugin/dump_plugin.c
> 
> diff --git a/gcc/dumpfile.c b/gcc/dumpfile.c
> index d430ea3..d359e41 100644
> --- a/gcc/dumpfile.c
> +++ b/gcc/dumpfile.c
> @@ -177,12 +177,16 @@ gcc::dump_manager::dump_manager ():
>    m_next_dump (FIRST_AUTO_NUMBERED_DUMP),
>    m_extra_dump_files (NULL),
>    m_extra_dump_files_in_use (0),
> -  m_extra_dump_files_alloced (0)
> +  m_extra_dump_files_alloced (0),
> +  m_optgroup_flags (OPTGROUP_NONE),
> +  m_optinfo_flags (TDF_NONE),
> +  m_optinfo_filename (NULL)
>  {
>  }
>  
>  gcc::dump_manager::~dump_manager ()
>  {
> +  free (m_optinfo_filename);
>    for (size_t i = 0; i < m_extra_dump_files_in_use; i++)
>      {
>        dump_file_info *dfi = &m_extra_dump_files[i];
> @@ -1512,6 +1516,50 @@ dump_flag_name (int phase) const
>    return dfi->swtch;
>  }
>  
> +/* Handle -fdump-* and -fopt-info for a pass added after
> +   command-line options are parsed (those from plugins and
> +   those from backends).
> +
> +   Because the registration of plugin/backend passes happens after the
> +   command-line options are parsed, the options that specify single
> +   pass dumping (e.g. -fdump-tree-PASSNAME) cannot be used for new
> +   passes. Therefore we currently can only enable dumping of
> +   new passes when the 'dump-all' flags (e.g. -fdump-tree-all)
> +   are specified.  This is done here.
> +
> +   Similarly, the saved -fopt-info options are wired up to the new pass.  */
> +
> +void
> +gcc::dump_manager::register_pass (opt_pass *pass)
> +{
> +  gcc_assert (pass);
> +
> +  register_one_dump_file (pass);
> +
> +  dump_file_info *pass_dfi = get_dump_file_info (pass->static_pass_number);
> +  gcc_assert (pass_dfi);
> +
> +  enum tree_dump_index tdi;
> +  if (pass->type == SIMPLE_IPA_PASS
> +      || pass->type == IPA_PASS)
> +    tdi = TDI_ipa_all;
> +  else if (pass->type == GIMPLE_PASS)
> +    tdi = TDI_tree_all;
> +  else
> +    tdi = TDI_rtl_all;
> +  const dump_file_info *tdi_dfi = get_dump_file_info (tdi);
> +  gcc_assert (tdi_dfi);
> +
> +  /* Check if dump-all flag is specified.  */
> +  if (tdi_dfi->pstate)
> +    {
> +      pass_dfi->pstate = tdi_dfi->pstate;
> +      pass_dfi->pflags = tdi_dfi->pflags;
> +    }
> +
> +  update_dfi_for_opt_info (pass_dfi);
> +}
> +
>  /* Finish a tree dump for PHASE. STREAM is the stream created by
>     dump_begin.  */
>  
> @@ -1587,47 +1635,47 @@ opt_info_enable_passes (optgroup_flags_t optgroup_flags, dump_flags_t flags,
>  			const char *filename)
>  {
>    int n = 0;
> -  size_t i;
>  
> -  for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
> -    {
> -      if ((dump_files[i].optgroup_flags & optgroup_flags))
> -        {
> -          const char *old_filename = dump_files[i].alt_filename;
> -          /* Since this file is shared among different passes, it
> -             should be opened in append mode.  */
> -          dump_files[i].alt_state = 1;
> -          dump_files[i].alt_flags |= flags;
> -          n++;
> -          /* Override the existing filename.  */
> -          if (filename)
> -            dump_files[i].alt_filename = xstrdup (filename);
> -          if (old_filename && filename != old_filename)
> -            free (CONST_CAST (char *, old_filename));
> -        }
> -    }
> +  m_optgroup_flags = optgroup_flags;
> +  m_optinfo_flags = flags;
> +  m_optinfo_filename = xstrdup (filename);
>  
> -  for (i = 0; i < m_extra_dump_files_in_use; i++)
> -    {
> -      if ((m_extra_dump_files[i].optgroup_flags & optgroup_flags))
> -        {
> -          const char *old_filename = m_extra_dump_files[i].alt_filename;
> -          /* Since this file is shared among different passes, it
> -             should be opened in append mode.  */
> -          m_extra_dump_files[i].alt_state = 1;
> -          m_extra_dump_files[i].alt_flags |= flags;
> -          n++;
> -          /* Override the existing filename.  */
> -          if (filename)
> -            m_extra_dump_files[i].alt_filename = xstrdup (filename);
> -          if (old_filename && filename != old_filename)
> -            free (CONST_CAST (char *, old_filename));
> -        }
> -    }
> +  for (size_t i = TDI_none + 1; i < (size_t) TDI_end; i++)
> +    if (update_dfi_for_opt_info (&dump_files[i]))
> +      n++;
> +
> +  for (size_t i = 0; i < m_extra_dump_files_in_use; i++)
> +    if (update_dfi_for_opt_info (&m_extra_dump_files[i]))
> +      n++;
>  
>    return n;
>  }
>  
> +/* Use the saved -fopt-info options to update DFI.
> +   Return true if the dump is enabled.  */
> +
> +bool
> +gcc::dump_manager::update_dfi_for_opt_info (dump_file_info *dfi) const
> +{
> +  gcc_assert (dfi);
> +
> +  if (!(dfi->optgroup_flags & m_optgroup_flags))
> +    return false;
> +
> +  const char *old_filename = dfi->alt_filename;
> +  /* Since this file is shared among different passes, it
> +     should be opened in append mode.  */
> +  dfi->alt_state = 1;
> +  dfi->alt_flags |= m_optinfo_flags;
> +  /* Override the existing filename.  */
> +  if (m_optinfo_filename)
> +    dfi->alt_filename = xstrdup (m_optinfo_filename);
> +  if (old_filename && m_optinfo_filename != old_filename)
> +    free (CONST_CAST (char *, old_filename));
> +
> +  return true;
> +}
> +
>  /* Parse ARG as a dump switch. Return nonzero if it is, and store the
>     relevant details in the dump_files array.  */
>  
> diff --git a/gcc/dumpfile.h b/gcc/dumpfile.h
> index 671b7b9..057ca46 100644
> --- a/gcc/dumpfile.h
> +++ b/gcc/dumpfile.h
> @@ -566,6 +566,8 @@ extern void dump_combine_total_stats (FILE *);
>  /* In cfghooks.c  */
>  extern void dump_bb (FILE *, basic_block, int, dump_flags_t);
>  
> +struct opt_pass;
> +
>  namespace gcc {
>  
>  /* A class for managing all of the various dump files used by the
> @@ -634,6 +636,8 @@ public:
>    const char *
>    dump_flag_name (int phase) const;
>  
> +  void register_pass (opt_pass *pass);
> +
>  private:
>  
>    int
> @@ -649,6 +653,8 @@ private:
>    opt_info_enable_passes (optgroup_flags_t optgroup_flags, dump_flags_t flags,
>  			  const char *filename);
>  
> +  bool update_dfi_for_opt_info (dump_file_info *dfi) const;
> +
>  private:
>  
>    /* Dynamically registered dump files and switches.  */
> @@ -657,6 +663,12 @@ private:
>    size_t m_extra_dump_files_in_use;
>    size_t m_extra_dump_files_alloced;
>  
> +  /* Stored values from -fopt-info, for handling passes created after
> +     option-parsing (by backends and by plugins).  */
> +  optgroup_flags_t m_optgroup_flags;
> +  dump_flags_t m_optinfo_flags;
> +  char *m_optinfo_filename;
> +
>    /* Grant access to dump_enable_all.  */
>    friend bool ::enable_rtl_dump_file (void);
>  
> diff --git a/gcc/passes.c b/gcc/passes.c
> index 832f0b3..d838d90 100644
> --- a/gcc/passes.c
> +++ b/gcc/passes.c
> @@ -1404,7 +1404,6 @@ void
>  pass_manager::register_pass (struct register_pass_info *pass_info)
>  {
>    bool all_instances, success;
> -  gcc::dump_manager *dumps = m_ctxt->get_dumps ();
>  
>    /* The checks below could fail in buggy plugins.  Existing GCC
>       passes should never fail these checks, so we mention plugin in
> @@ -1442,33 +1441,16 @@ pass_manager::register_pass (struct register_pass_info *pass_info)
>  
>    /* OK, we have successfully inserted the new pass. We need to register
>       the dump files for the newly added pass and its duplicates (if any).
> -     Because the registration of plugin/backend passes happens after the
> -     command-line options are parsed, the options that specify single
> -     pass dumping (e.g. -fdump-tree-PASSNAME) cannot be used for new
> -     passes. Therefore we currently can only enable dumping of
> -     new passes when the 'dump-all' flags (e.g. -fdump-tree-all)
> -     are specified. While doing so, we also delete the pass_list_node
> +     While doing so, we also delete the pass_list_node
>       objects created during pass positioning.  */
> +  gcc::dump_manager *dumps = m_ctxt->get_dumps ();
>    while (added_pass_nodes)
>      {
>        struct pass_list_node *next_node = added_pass_nodes->next;
> -      enum tree_dump_index tdi;
> -      register_one_dump_file (added_pass_nodes->pass);
> -      if (added_pass_nodes->pass->type == SIMPLE_IPA_PASS
> -          || added_pass_nodes->pass->type == IPA_PASS)
> -        tdi = TDI_ipa_all;
> -      else if (added_pass_nodes->pass->type == GIMPLE_PASS)
> -        tdi = TDI_tree_all;
> -      else
> -        tdi = TDI_rtl_all;
> -      /* Check if dump-all flag is specified.  */
> -      if (dumps->get_dump_file_info (tdi)->pstate)
> -	{
> -	  dumps->get_dump_file_info (added_pass_nodes->pass->static_pass_number)
> -            ->pstate = dumps->get_dump_file_info (tdi)->pstate;
> -	  dumps->get_dump_file_info (added_pass_nodes->pass->static_pass_number)
> -	    ->pflags = dumps->get_dump_file_info (tdi)->pflags;
> -	}
> +
> +      /* Handle -fdump-* and -fopt-info.  */
> +      dumps->register_pass (added_pass_nodes->pass);
> +
>        XDELETE (added_pass_nodes);
>        added_pass_nodes = next_node;
>      }
> diff --git a/gcc/testsuite/gcc.dg/plugin/dump-1.c b/gcc/testsuite/gcc.dg/plugin/dump-1.c
> new file mode 100644
> index 0000000..165a9c1
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/plugin/dump-1.c
> @@ -0,0 +1,28 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fopt-info-note" } */
> +
> +extern void test_string_literal (void);
> +extern void test_tree (void);
> +extern void test_gimple (int);
> +extern void test_cgraph_node (void);
> +extern void test_wide_int (void);
> +extern void test_poly_int (void);
> +extern void test_scopes (void);
> +
> +void test_remarks (void)
> +{
> +  test_string_literal (); /* { dg-message "test of dump for 'test_string_literal'" } */
> +  test_tree (); /* { dg-message "test of tree: 0" } */
> +  test_gimple (42); /* { dg-message "test of gimple: test_gimple \\(42\\);" } */
> +  test_cgraph_node (); /* { dg-message "test of callgraph node: test_cgraph_node/\[0-9\]+" } */
> +  test_wide_int (); /* { dg-message "test of wide int: 0" } */
> +  test_poly_int (); /* { dg-message "test of poly int: 42" } */
> +
> +  test_scopes (); /* { dg-line test_scopes_line } */
> +  /* { dg-message "=== outer scope ===" "" { target *-*-* } test_scopes_line } */
> +  /* { dg-message " at outer scope" "" { target *-*-* } test_scopes_line } */
> +  /* { dg-message " === middle scope ===" "" { target *-*-* } test_scopes_line } */
> +  /* { dg-message "  at middle scope" "" { target *-*-* } test_scopes_line } */
> +  /* { dg-message "  === innermost scope ===" "" { target *-*-* } test_scopes_line } */
> +  /* { dg-message "   at innermost scope" "" { target *-*-* } test_scopes_line } */
> +}
> diff --git a/gcc/testsuite/gcc.dg/plugin/dump_plugin.c b/gcc/testsuite/gcc.dg/plugin/dump_plugin.c
> new file mode 100644
> index 0000000..12573d6
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/plugin/dump_plugin.c
> @@ -0,0 +1,143 @@
> +/* Plugin for testing dumpfile.c.  */
> +
> +#include "gcc-plugin.h"
> +#include "config.h"
> +#include "system.h"
> +#include "coretypes.h"
> +#include "tree.h"
> +#include "tree-pass.h"
> +#include "intl.h"
> +#include "plugin-version.h"
> +#include "diagnostic.h"
> +#include "context.h"
> +#include "optinfo.h"
> +#include "gimple.h"
> +#include "gimple-iterator.h"
> +#include "cgraph.h"
> +
> +int plugin_is_GPL_compatible;
> +
> +const pass_data pass_data_test_dumping =
> +{
> +  GIMPLE_PASS, /* type */
> +  "test_dumping", /* name */
> +  OPTGROUP_LOOP, /* optinfo_flags */
> +  TV_NONE, /* tv_id */
> +  PROP_ssa, /* properties_required */
> +  0, /* properties_provided */
> +  0, /* properties_destroyed */
> +  0, /* todo_flags_start */
> +  0, /* todo_flags_finish */
> +};
> +
> +class pass_test_dumping : public gimple_opt_pass
> +{
> +public:
> +  pass_test_dumping (gcc::context *ctxt)
> +    : gimple_opt_pass (pass_data_test_dumping, ctxt)
> +  {}
> +
> +  /* opt_pass methods: */
> +  bool gate (function *) { return true; }
> +  virtual unsigned int execute (function *);
> +
> +}; // class pass_test_dumping
> +
> +unsigned int
> +pass_test_dumping::execute (function *fun)
> +{
> +  basic_block bb;
> +
> +  if (!dump_enabled_p ())
> +    return 0;
> +
> +  FOR_ALL_BB_FN (bb, fun)
> +    for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
> +	 !gsi_end_p (gsi); gsi_next (&gsi))
> +      {
> +	gimple *stmt = gsi_stmt (gsi);
> +	gcall *call = dyn_cast <gcall *> (stmt);
> +	if (!call)
> +	  continue;
> +	tree callee_decl = gimple_call_fndecl (call);
> +	if (!callee_decl)
> +	  continue;
> +	tree callee_name = DECL_NAME (callee_decl);
> +	if (!callee_name)
> +	  continue;
> +	const char *callee = IDENTIFIER_POINTER (callee_name);
> +
> +	/* Various dumping tests, done at callsites,
> +	   controlled by the callee name.  */
> +	if (strcmp (callee, "test_string_literal") == 0)
> +	  dump_printf_loc (MSG_NOTE, stmt, "test of dump for %qs\n",
> +			   callee);
> +	else if (strcmp (callee, "test_tree") == 0)
> +	  dump_printf_loc (MSG_NOTE, stmt, "test of tree: %T\n",
> +			   integer_zero_node);
> +	else if (strcmp (callee, "test_gimple") == 0)
> +	  dump_printf_loc (MSG_NOTE, stmt, "test of gimple: %G", stmt);
> +	else if (strcmp (callee, "test_cgraph_node") == 0)
> +	  {
> +	    dump_printf_loc (MSG_NOTE, stmt, "test of callgraph node: ");
> +	    dump_symtab_node (MSG_NOTE, cgraph_node::get (callee_decl));
> +	    dump_printf (MSG_NOTE, "\n");
> +	  }
> +	else if (strcmp (callee, "test_wide_int") == 0)
> +	  {
> +	    HOST_WIDE_INT val = 0;
> +	    dump_printf_loc (MSG_NOTE, stmt,
> +			     "test of wide int: " HOST_WIDE_INT_PRINT_DEC "\n",
> +			     val);
> +	  }
> +	else if (strcmp (callee, "test_poly_int") == 0)
> +	  {
> +	    dump_printf_loc (MSG_NOTE, stmt, "test of poly int: ");
> +	    dump_dec (MSG_NOTE, poly_int64 (42));
> +	    dump_printf (MSG_NOTE, "\n");
> +	  }
> +	else if (strcmp (callee, "test_scopes") == 0)
> +	  {
> +	    AUTO_DUMP_SCOPE ("outer scope", stmt);
> +	    {
> +	      dump_printf_loc (MSG_NOTE, stmt, "at outer scope\n");
> +	      AUTO_DUMP_SCOPE ("middle scope", stmt);
> +	      {
> +		dump_printf_loc (MSG_NOTE, stmt, "at middle scope\n");
> +		AUTO_DUMP_SCOPE ("innermost scope", stmt);
> +		dump_printf_loc (MSG_NOTE, stmt, "at innermost scope\n");
> +	      }
> +	    }
> +	  }
> +      }
> +
> +  return 0;
> +}
> +
> +static gimple_opt_pass *
> +make_pass_test_dumping (gcc::context *ctxt)
> +{
> +  return new pass_test_dumping (ctxt);
> +}
> +
> +int
> +plugin_init (struct plugin_name_args *plugin_info,
> +	     struct plugin_gcc_version *version)
> +{
> +  struct register_pass_info pass_info;
> +  const char *plugin_name = plugin_info->base_name;
> +  int argc = plugin_info->argc;
> +  struct plugin_argument *argv = plugin_info->argv;
> +
> +  if (!plugin_default_version_check (version, &gcc_version))
> +    return 1;
> +
> +  pass_info.pass = make_pass_test_dumping (g);
> +  pass_info.reference_pass_name = "ssa";
> +  pass_info.ref_pass_instance_number = 1;
> +  pass_info.pos_op = PASS_POS_INSERT_AFTER;
> +  register_callback (plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL,
> +		     &pass_info);
> +
> +  return 0;
> +}
> diff --git a/gcc/testsuite/gcc.dg/plugin/plugin.exp b/gcc/testsuite/gcc.dg/plugin/plugin.exp
> index 46246a2..50db3ae 100644
> --- a/gcc/testsuite/gcc.dg/plugin/plugin.exp
> +++ b/gcc/testsuite/gcc.dg/plugin/plugin.exp
> @@ -101,6 +101,8 @@ set plugin_test_list [list \
>  	  must-tail-call-2.c } \
>      { expensive_selftests_plugin.c \
>  	  expensive-selftests-1.c } \
> +    { dump_plugin.c \
> +	  dump-1.c } \
>  ]
>  
>  foreach plugin_test $plugin_test_list {
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nuernberg)

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 2/3] Add -fopt-info-internals
  2018-09-28 18:24         ` [PATCH 2/3] Add -fopt-info-internals David Malcolm
@ 2018-10-04 11:09           ` Richard Biener
  2018-10-04 17:12             ` David Malcolm
  0 siblings, 1 reply; 24+ messages in thread
From: Richard Biener @ 2018-10-04 11:09 UTC (permalink / raw)
  To: David Malcolm; +Cc: Richard Sandiford, gcc-patches

On Fri, 28 Sep 2018, David Malcolm wrote:

> This patch introduces a verbosity level to dump messages:
> "user-facing" vs "internals".
> 
> By default, messages at the top-level dump scope are "user-facing",
> whereas those that are in nested scopes are implicitly "internals",
> and are filtered out by -fopt-info unless a new "-internals" sub-option
> of "-fopt-info" is supplied (intended purely for use by GCC developers).
> Dumpfiles are unaffected by the change.
> 
> Given that the vectorizer is the only subsystem using AUTO_DUMP_SCOPE
> (via DUMP_VECT_SCOPE), this only affects the vectorizer.
> 
> Filtering out these implementation-detail messages goes a long way
> towards making -fopt-info-vec-all more accessible to advanced end-users;
> the follow-up patch restores the most pertinent missing details.
> 
> Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
> 
> OK for trunk?

What happens for flags & MSG_ALL_PRIORITIES == 0?  That is,
do we require two bits for the priority at all?

It's an implementation detail of course, generally I like this
(maybe not so much conflating with nesting, but ...).

Richard.

> gcc/ChangeLog:
> 	* doc/invoke.texi (-fopt-info): Document new "internals"
> 	sub-option.
> 	* dump-context.h (dump_context::apply_dump_filter_p): New decl.
> 	* dumpfile.c (dump_options): Update for renaming of MSG_ALL to
> 	MSG_ALL_KINDS.
> 	(optinfo_verbosity_options): Add "internals".
> 	(kind_as_string): Update for renaming of MSG_ALL to MSG_ALL_KINDS.
> 	(dump_context::apply_dump_filter_p): New member function.
> 	(dump_context::dump_loc): Use apply_dump_filter_p rather than
> 	explicitly masking the dump_kind.
> 	(dump_context::begin_scope): Increment the scope depth first.  Use
> 	apply_dump_filter_p rather than explicitly masking the dump_kind.
> 	(dump_context::emit_item): Use apply_dump_filter_p rather than
> 	explicitly masking the dump_kind.
> 	(dump_dec): Likewise.
> 	(dump_hex): Likewise.
> 	(dump_switch_p_1): Default to MSG_ALL_PRIORITIES.
> 	(opt_info_switch_p_1): Default to MSG_PRIORITY_USER_FACING.
> 	(opt_info_switch_p): Update handling of default
> 	MSG_OPTIMIZED_LOCATIONS to cope with default of
> 	MSG_PRIORITY_USER_FACING.
> 	(dump_basic_block): Use apply_dump_filter_p rather than explicitly
> 	masking the dump_kind.
> 	(selftest::test_capture_of_dump_calls): Update test_dump_context
> 	instances to use MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING rather
> 	than MSG_ALL.  Generalize scope test to be run at all four
> 	combinations of with/without MSG_PRIORITY_USER_FACING and
> 	MSG_PRIORITY_INTERNALS, adding examples of explicit priority
> 	for each of the two values.
> 	* dumpfile.h (enum dump_flag): Add comment about the MSG_* flags.
> 	Rename MSG_ALL to MSG_ALL_KINDS.  Add MSG_PRIORITY_USER_FACING,
> 	MSG_PRIORITY_INTERNALS, and MSG_ALL_PRIORITIES, updating the
> 	values for TDF_COMPARE_DEBUG and TDF_ALL_VALUES.
> 	(AUTO_DUMP_SCOPE): Add a note to the comment about the interaction
> 	with MSG_PRIORITY_*.
> 	* tree-vect-loop-manip.c (vect_loop_versioning): Mark versioning
> 	dump messages as MSG_PRIORITY_USER_FACING.
> 	* tree-vectorizer.h (DUMP_VECT_SCOPE): Add a note to the comment
> 	about the interaction with MSG_PRIORITY_*.
> 
> gcc/testsuite/ChangeLog:
> 	* gcc.dg/plugin/dump-1.c: Update expected output for test_scopes
> 	due to "-internals" not being selected.
> 	* gcc.dg/plugin/dump-2.c: New test, based on dump-1.c, with
> 	"-internals" added to re-enable the output from test_scopes.
> 	* gcc.dg/plugin/plugin.exp (plugin_test_list): Add dump-2.c.
> ---
>  gcc/doc/invoke.texi                    |  31 ++++-
>  gcc/dump-context.h                     |   2 +
>  gcc/dumpfile.c                         | 248 +++++++++++++++++++++++----------
>  gcc/dumpfile.h                         |  41 +++++-
>  gcc/testsuite/gcc.dg/plugin/dump-1.c   |  10 +-
>  gcc/testsuite/gcc.dg/plugin/dump-2.c   |  30 ++++
>  gcc/testsuite/gcc.dg/plugin/plugin.exp |   3 +-
>  gcc/tree-vect-loop-manip.c             |   6 +-
>  gcc/tree-vectorizer.h                  |   6 +-
>  9 files changed, 279 insertions(+), 98 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/plugin/dump-2.c
> 
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 5c95f67..ab8d9b7e8 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -14207,14 +14207,21 @@ Controls optimization dumps from various optimization passes. If the
>  @samp{-} separated option keywords to select the dump details and
>  optimizations.  
>  
> -The @var{options} can be divided into two groups: options describing the
> -verbosity of the dump, and options describing which optimizations
> -should be included. The options from both the groups can be freely
> -mixed as they are non-overlapping. However, in case of any conflicts,
> +The @var{options} can be divided into three groups:
> +@enumerate
> +@item
> +options describing what kinds of messages should be emitted,
> +@item
> +options describing the verbosity of the dump, and
> +@item
> +options describing which optimizations should be included.
> +@end enumerate
> +The options from each group can be freely mixed as they are
> +non-overlapping. However, in case of any conflicts,
>  the later options override the earlier options on the command
>  line. 
>  
> -The following options control the dump verbosity:
> +The following options control which kinds of messages should be emitted:
>  
>  @table @samp
>  @item optimized
> @@ -14233,6 +14240,15 @@ Print detailed optimization information. This includes
>  @samp{optimized}, @samp{missed}, and @samp{note}.
>  @end table
>  
> +The following option controls the dump verbosity:
> +
> +@table @samp
> +@item internals
> +By default, only ``high-level'' messages are emitted. This option enables
> +additional, more detailed, messages, which are likely to only be of interest
> +to GCC developers.
> +@end table
> +
>  One or more of the following option keywords can be used to describe a
>  group of optimizations:
>  
> @@ -14253,8 +14269,9 @@ the optimization groups listed above.
>  @end table
>  
>  If @var{options} is
> -omitted, it defaults to @samp{optimized-optall}, which means to dump all
> -info about successful optimizations from all the passes.  
> +omitted, it defaults to @samp{optimized-optall}, which means to dump messages
> +about successful optimizations from all the passes, omitting messages
> +that are treated as ``internals''.
>  
>  If the @var{filename} is provided, then the dumps from all the
>  applicable optimizations are concatenated into the @var{filename}.
> diff --git a/gcc/dump-context.h b/gcc/dump-context.h
> index 5b20c15..20b94a7 100644
> --- a/gcc/dump-context.h
> +++ b/gcc/dump-context.h
> @@ -100,6 +100,8 @@ class dump_context
>  
>    void emit_item (optinfo_item *item, dump_flags_t dump_kind);
>  
> +  bool apply_dump_filter_p (dump_flags_t dump_kind, dump_flags_t filter) const;
> +
>   private:
>    optinfo &ensure_pending_optinfo ();
>    optinfo &begin_next_optinfo (const dump_location_t &loc);
> diff --git a/gcc/dumpfile.c b/gcc/dumpfile.c
> index d359e41..e15edc7 100644
> --- a/gcc/dumpfile.c
> +++ b/gcc/dumpfile.c
> @@ -141,7 +141,7 @@ static const kv_pair<dump_flags_t> dump_options[] =
>    {"optimized", MSG_OPTIMIZED_LOCATIONS},
>    {"missed", MSG_MISSED_OPTIMIZATION},
>    {"note", MSG_NOTE},
> -  {"optall", MSG_ALL},
> +  {"optall", MSG_ALL_KINDS},
>    {"all", dump_flags_t (TDF_ALL_VALUES
>  			& ~(TDF_RAW | TDF_SLIM | TDF_LINENO | TDF_GRAPH
>  			    | TDF_STMTADDR | TDF_RHS_ONLY | TDF_NOUID
> @@ -157,7 +157,8 @@ static const kv_pair<dump_flags_t> optinfo_verbosity_options[] =
>    {"optimized", MSG_OPTIMIZED_LOCATIONS},
>    {"missed", MSG_MISSED_OPTIMIZATION},
>    {"note", MSG_NOTE},
> -  {"all", MSG_ALL},
> +  {"all", MSG_ALL_KINDS},
> +  {"internals", MSG_PRIORITY_INTERNALS},
>    {NULL, TDF_NONE}
>  };
>  
> @@ -449,7 +450,7 @@ dump_user_location_t::from_function_decl (tree fndecl)
>  static const char *
>  kind_as_string (dump_flags_t dump_kind)
>  {
> -  switch (dump_kind & MSG_ALL)
> +  switch (dump_kind & MSG_ALL_KINDS)
>      {
>      default:
>        gcc_unreachable ();
> @@ -524,6 +525,35 @@ dump_context::refresh_dumps_are_enabled ()
>  		       || m_test_pp);
>  }
>  
> +/* Determine if a message of kind DUMP_KIND and at the current scope depth
> +   should be printed.
> +
> +   Only show messages that match FILTER both on their kind *and*
> +   their priority.  */
> +
> +bool
> +dump_context::apply_dump_filter_p (dump_flags_t dump_kind,
> +				   dump_flags_t filter) const
> +{
> +  /* Few messages, if any, have an explicit MSG_PRIORITY.
> +     If DUMP_KIND does, we'll use it.
> +     Otherwise, generate an implicit priority value for the message based
> +     on the current scope depth.
> +     Messages at the top-level scope are MSG_PRIORITY_USER_FACING,
> +     whereas those in nested scopes are MSG_PRIORITY_INTERNALS.  */
> +  if (!(dump_kind & MSG_ALL_PRIORITIES))
> +    {
> +      dump_flags_t implicit_priority
> +	=  (m_scope_depth > 0
> +	    ? MSG_PRIORITY_INTERNALS
> +	    : MSG_PRIORITY_USER_FACING);
> +      dump_kind |= implicit_priority;
> +    }
> +
> +  return (dump_kind & (filter & MSG_ALL_KINDS)
> +	  && dump_kind & (filter & MSG_ALL_PRIORITIES));
> +}
> +
>  /* Print LOC to the appropriate dump destinations, given DUMP_KIND.
>     If optinfos are enabled, begin a new optinfo.  */
>  
> @@ -534,14 +564,14 @@ dump_context::dump_loc (dump_flags_t dump_kind, const dump_location_t &loc)
>  
>    location_t srcloc = loc.get_location_t ();
>  
> -  if (dump_file && (dump_kind & pflags))
> +  if (dump_file && apply_dump_filter_p (dump_kind, pflags))
>      ::dump_loc (dump_kind, dump_file, srcloc);
>  
> -  if (alt_dump_file && (dump_kind & alt_flags))
> +  if (alt_dump_file && apply_dump_filter_p (dump_kind, alt_flags))
>      ::dump_loc (dump_kind, alt_dump_file, srcloc);
>  
>    /* Support for temp_dump_context in selftests.  */
> -  if (m_test_pp && (dump_kind & m_test_pp_flags))
> +  if (m_test_pp && apply_dump_filter_p (dump_kind, m_test_pp_flags))
>      ::dump_loc (dump_kind, m_test_pp, srcloc);
>  
>    if (optinfo_enabled_p ())
> @@ -1067,22 +1097,24 @@ dump_context::get_scope_depth () const
>  }
>  
>  /* Push a nested dump scope.
> +   Increment the scope depth.
>     Print "=== NAME ===\n" to the dumpfile, if any, and to the -fopt-info
>     destination, if any.
> -   Emit a "scope" optinfo if optinfos are enabled.
> -   Increment the scope depth.  */
> +   Emit a "scope" optinfo if optinfos are enabled.  */
>  
>  void
>  dump_context::begin_scope (const char *name, const dump_location_t &loc)
>  {
> -  if (dump_file && (MSG_NOTE & pflags))
> +  m_scope_depth++;
> +
> +  if (dump_file && apply_dump_filter_p (MSG_NOTE, pflags))
>      ::dump_loc (MSG_NOTE, dump_file, loc.get_location_t ());
>  
> -  if (alt_dump_file && (MSG_NOTE & alt_flags))
> +  if (alt_dump_file && apply_dump_filter_p (MSG_NOTE, alt_flags))
>      ::dump_loc (MSG_NOTE, alt_dump_file, loc.get_location_t ());
>  
>    /* Support for temp_dump_context in selftests.  */
> -  if (m_test_pp && (MSG_NOTE & m_test_pp_flags))
> +  if (m_test_pp && apply_dump_filter_p (MSG_NOTE, m_test_pp_flags))
>      ::dump_loc (MSG_NOTE, m_test_pp, loc.get_location_t ());
>  
>    pretty_printer pp;
> @@ -1100,8 +1132,6 @@ dump_context::begin_scope (const char *name, const dump_location_t &loc)
>      }
>    else
>      delete item;
> -
> -  m_scope_depth++;
>  }
>  
>  /* Pop a nested dump scope.  */
> @@ -1155,14 +1185,14 @@ dump_context::end_any_optinfo ()
>  void
>  dump_context::emit_item (optinfo_item *item, dump_flags_t dump_kind)
>  {
> -  if (dump_file && (dump_kind & pflags))
> +  if (dump_file && apply_dump_filter_p (dump_kind, pflags))
>      fprintf (dump_file, "%s", item->get_text ());
>  
> -  if (alt_dump_file && (dump_kind & alt_flags))
> +  if (alt_dump_file && apply_dump_filter_p (dump_kind, alt_flags))
>      fprintf (alt_dump_file, "%s", item->get_text ());
>  
>    /* Support for temp_dump_context in selftests.  */
> -  if (m_test_pp && (dump_kind & m_test_pp_flags))
> +  if (m_test_pp && apply_dump_filter_p (dump_kind, m_test_pp_flags))
>      pp_string (m_test_pp, item->get_text ());
>  }
>  
> @@ -1278,10 +1308,12 @@ template void dump_dec (dump_flags_t, const poly_widest_int &);
>  void
>  dump_dec (dump_flags_t dump_kind, const poly_wide_int &value, signop sgn)
>  {
> -  if (dump_file && (dump_kind & pflags))
> +  if (dump_file
> +      && dump_context::get ().apply_dump_filter_p (dump_kind, pflags))
>      print_dec (value, dump_file, sgn);
>  
> -  if (alt_dump_file && (dump_kind & alt_flags))
> +  if (alt_dump_file
> +      && dump_context::get ().apply_dump_filter_p (dump_kind, alt_flags))
>      print_dec (value, alt_dump_file, sgn);
>  }
>  
> @@ -1290,10 +1322,12 @@ dump_dec (dump_flags_t dump_kind, const poly_wide_int &value, signop sgn)
>  void
>  dump_hex (dump_flags_t dump_kind, const poly_wide_int &value)
>  {
> -  if (dump_file && (dump_kind & pflags))
> +  if (dump_file
> +      && dump_context::get ().apply_dump_filter_p (dump_kind, pflags))
>      print_hex (value, dump_file);
>  
> -  if (alt_dump_file && (dump_kind & alt_flags))
> +  if (alt_dump_file
> +      && dump_context::get ().apply_dump_filter_p (dump_kind, alt_flags))
>      print_hex (value, alt_dump_file);
>  }
>  
> @@ -1698,7 +1732,7 @@ dump_switch_p_1 (const char *arg, struct dump_file_info *dfi, bool doglob)
>      return 0;
>  
>    ptr = option_value;
> -  flags = TDF_NONE;
> +  flags = MSG_ALL_PRIORITIES;
>  
>    while (*ptr)
>      {
> @@ -1794,7 +1828,11 @@ opt_info_switch_p_1 (const char *arg, dump_flags_t *flags,
>    ptr = option_value;
>  
>    *filename = NULL;
> -  *flags = TDF_NONE;
> +
> +  /* Default to filtering out "internals" messages, and retaining
> +     "user-facing" messages.  */
> +  *flags = MSG_PRIORITY_USER_FACING;
> +
>    *optgroup_flags = OPTGROUP_NONE;
>  
>    if (!ptr)
> @@ -1883,8 +1921,8 @@ opt_info_switch_p (const char *arg)
>      }
>  
>    file_seen = xstrdup (filename);
> -  if (!flags)
> -    flags = MSG_OPTIMIZED_LOCATIONS;
> +  if (!(flags & MSG_ALL_KINDS))
> +    flags |= MSG_OPTIMIZED_LOCATIONS;
>    if (!optgroup_flags)
>      optgroup_flags = OPTGROUP_ALL;
>  
> @@ -1896,9 +1934,11 @@ opt_info_switch_p (const char *arg)
>  void
>  dump_basic_block (dump_flags_t dump_kind, basic_block bb, int indent)
>  {
> -  if (dump_file && (dump_kind & pflags))
> +  if (dump_file
> +      && dump_context::get ().apply_dump_filter_p (dump_kind, pflags))
>      dump_bb (dump_file, bb, indent, TDF_DETAILS);
> -  if (alt_dump_file && (dump_kind & alt_flags))
> +  if (alt_dump_file
> +      && dump_context::get ().apply_dump_filter_p (dump_kind, alt_flags))
>      dump_bb (alt_dump_file, bb, indent, TDF_DETAILS);
>  }
>  
> @@ -2104,7 +2144,8 @@ test_capture_of_dump_calls (const line_table_case &case_)
>  
>        /* Test of dump_printf.  */
>        {
> -	temp_dump_context tmp (with_optinfo, MSG_ALL);
> +	temp_dump_context tmp (with_optinfo,
> +			       MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
>  	dump_printf (MSG_NOTE, "int: %i str: %s", 42, "foo");
>  
>  	ASSERT_DUMPED_TEXT_EQ (tmp, "int: 42 str: foo");
> @@ -2120,7 +2161,8 @@ test_capture_of_dump_calls (const line_table_case &case_)
>  
>        /* Test of dump_printf with %T.  */
>        {
> -	temp_dump_context tmp (with_optinfo, MSG_ALL);
> +	temp_dump_context tmp (with_optinfo,
> +			       MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
>  	dump_printf (MSG_NOTE, "tree: %T", integer_zero_node);
>  
>  	ASSERT_DUMPED_TEXT_EQ (tmp, "tree: 0");
> @@ -2137,7 +2179,8 @@ test_capture_of_dump_calls (const line_table_case &case_)
>  
>        /* Test of dump_printf with %E.  */
>        {
> -	temp_dump_context tmp (with_optinfo, MSG_ALL);
> +	temp_dump_context tmp (with_optinfo,
> +			       MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
>  	dump_printf (MSG_NOTE, "gimple: %E", stmt);
>  
>  	ASSERT_DUMPED_TEXT_EQ (tmp, "gimple: return;");
> @@ -2154,7 +2197,8 @@ test_capture_of_dump_calls (const line_table_case &case_)
>  
>        /* Test of dump_printf with %G.  */
>        {
> -	temp_dump_context tmp (with_optinfo, MSG_ALL);
> +	temp_dump_context tmp (with_optinfo,
> +			       MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
>  	dump_printf (MSG_NOTE, "gimple: %G", stmt);
>  
>  	ASSERT_DUMPED_TEXT_EQ (tmp, "gimple: return;\n");
> @@ -2176,7 +2220,8 @@ test_capture_of_dump_calls (const line_table_case &case_)
>  	 - multiple dump-specific format codes: some consecutive, others
>  	 separated by text, trailing text after the final one.  */
>        {
> -	temp_dump_context tmp (with_optinfo, MSG_ALL);
> +	temp_dump_context tmp (with_optinfo,
> +			       MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
>  	dump_printf_loc (MSG_NOTE, loc, "before %T and %T"
>  			 " %i consecutive %E%E after\n",
>  			 integer_zero_node, test_decl, 42, stmt, stmt);
> @@ -2203,7 +2248,8 @@ test_capture_of_dump_calls (const line_table_case &case_)
>  
>        /* Tree, via dump_generic_expr.  */
>        {
> -	temp_dump_context tmp (with_optinfo, MSG_ALL);
> +	temp_dump_context tmp (with_optinfo,
> +			       MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
>  	dump_printf_loc (MSG_NOTE, loc, "test of tree: ");
>  	dump_generic_expr (MSG_NOTE, TDF_SLIM, integer_zero_node);
>  
> @@ -2222,7 +2268,8 @@ test_capture_of_dump_calls (const line_table_case &case_)
>  
>        /* Tree, via dump_generic_expr_loc.  */
>        {
> -	temp_dump_context tmp (with_optinfo, MSG_ALL);
> +	temp_dump_context tmp (with_optinfo,
> +			       MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
>  	dump_generic_expr_loc (MSG_NOTE, loc, TDF_SLIM, integer_one_node);
>  
>  	ASSERT_DUMPED_TEXT_EQ (tmp, "test.txt:5:10: note: 1");
> @@ -2241,7 +2288,8 @@ test_capture_of_dump_calls (const line_table_case &case_)
>        {
>  	/* dump_gimple_stmt_loc.  */
>  	{
> -	  temp_dump_context tmp (with_optinfo, MSG_ALL);
> +	  temp_dump_context tmp (with_optinfo,
> +				 MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
>  	  dump_gimple_stmt_loc (MSG_NOTE, loc, TDF_SLIM, stmt, 2);
>  
>  	  ASSERT_DUMPED_TEXT_EQ (tmp, "test.txt:5:10: note: return;\n");
> @@ -2256,7 +2304,8 @@ test_capture_of_dump_calls (const line_table_case &case_)
>  
>  	/* dump_gimple_stmt.  */
>  	{
> -	  temp_dump_context tmp (with_optinfo, MSG_ALL);
> +	  temp_dump_context tmp (with_optinfo,
> +				 MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
>  	  dump_gimple_stmt (MSG_NOTE, TDF_SLIM, stmt, 2);
>  
>  	  ASSERT_DUMPED_TEXT_EQ (tmp, "return;\n");
> @@ -2271,7 +2320,8 @@ test_capture_of_dump_calls (const line_table_case &case_)
>  
>  	/* dump_gimple_expr_loc.  */
>  	{
> -	  temp_dump_context tmp (with_optinfo, MSG_ALL);
> +	  temp_dump_context tmp (with_optinfo,
> +				 MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
>  	  dump_gimple_expr_loc (MSG_NOTE, loc, TDF_SLIM, stmt, 2);
>  
>  	  ASSERT_DUMPED_TEXT_EQ (tmp, "test.txt:5:10: note: return;");
> @@ -2286,7 +2336,8 @@ test_capture_of_dump_calls (const line_table_case &case_)
>  
>  	/* dump_gimple_expr.  */
>  	{
> -	  temp_dump_context tmp (with_optinfo, MSG_ALL);
> +	  temp_dump_context tmp (with_optinfo,
> +				 MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
>  	  dump_gimple_expr (MSG_NOTE, TDF_SLIM, stmt, 2);
>  
>  	  ASSERT_DUMPED_TEXT_EQ (tmp, "return;");
> @@ -2302,7 +2353,8 @@ test_capture_of_dump_calls (const line_table_case &case_)
>  
>        /* poly_int.  */
>        {
> -	temp_dump_context tmp (with_optinfo, MSG_ALL);
> +	temp_dump_context tmp (with_optinfo,
> +			       MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
>  	dump_dec (MSG_NOTE, poly_int64 (42));
>  
>  	ASSERT_DUMPED_TEXT_EQ (tmp, "42");
> @@ -2315,45 +2367,92 @@ test_capture_of_dump_calls (const line_table_case &case_)
>  	  }
>        }
>  
> -      /* scopes.  */
> -      {
> -	temp_dump_context tmp (with_optinfo, MSG_ALL);
> -	dump_printf_loc (MSG_NOTE, stmt, "msg 1\n");
> +      /* Scopes.  Test with all 4 combinations of
> +	 filtering by MSG_PRIORITY_USER_FACING
> +	 and/or filtering by MSG_PRIORITY_INTERNALS.  */
> +      for (int j = 0; j < 3; j++)
>  	{
> -	  AUTO_DUMP_SCOPE ("outer scope", stmt);
> -	  dump_printf_loc (MSG_NOTE, stmt, "msg 2\n");
> +	  dump_flags_t dump_filter = MSG_ALL_KINDS;
> +	  if (j % 2)
> +	    dump_filter |= MSG_PRIORITY_USER_FACING;
> +	  if (j / 2)
> +	    dump_filter |= MSG_PRIORITY_INTERNALS;
> +
> +	  temp_dump_context tmp (with_optinfo, dump_filter);
> +	  /* Emit various messages, mostly with implicit priority.  */
> +	  dump_printf_loc (MSG_NOTE, stmt, "msg 1\n");
> +	  dump_printf_loc (MSG_NOTE | MSG_PRIORITY_INTERNALS, stmt,
> +			   "explicitly internal msg\n");
>  	  {
> -	    AUTO_DUMP_SCOPE ("middle scope", stmt);
> -	    dump_printf_loc (MSG_NOTE, stmt, "msg 3\n");
> +	    AUTO_DUMP_SCOPE ("outer scope", stmt);
> +	    dump_printf_loc (MSG_NOTE, stmt, "msg 2\n");
>  	    {
> -	      AUTO_DUMP_SCOPE ("inner scope", stmt);
> -	      dump_printf_loc (MSG_NOTE, stmt, "msg 4\n");
> +	      AUTO_DUMP_SCOPE ("middle scope", stmt);
> +	      dump_printf_loc (MSG_NOTE, stmt, "msg 3\n");
> +	      {
> +		AUTO_DUMP_SCOPE ("inner scope", stmt);
> +		dump_printf_loc (MSG_NOTE, stmt, "msg 4\n");
> +		dump_printf_loc (MSG_NOTE | MSG_PRIORITY_USER_FACING, stmt,
> +				 "explicitly user-facing msg\n");
> +	      }
> +	      dump_printf_loc (MSG_NOTE, stmt, "msg 5\n");
>  	    }
> -	    dump_printf_loc (MSG_NOTE, stmt, "msg 5\n");
> +	    dump_printf_loc (MSG_NOTE, stmt, "msg 6\n");
>  	  }
> -	  dump_printf_loc (MSG_NOTE, stmt, "msg 6\n");
> -	}
> -	dump_printf_loc (MSG_NOTE, stmt, "msg 7\n");
> +	  dump_printf_loc (MSG_NOTE, stmt, "msg 7\n");
>  
> -	ASSERT_DUMPED_TEXT_EQ (tmp,
> -			       "test.txt:5:10: note: msg 1\n"
> -			       "test.txt:5:10: note: === outer scope ===\n"
> -			       "test.txt:5:10: note:  msg 2\n"
> -			       "test.txt:5:10: note:  === middle scope ===\n"
> -			       "test.txt:5:10: note:   msg 3\n"
> -			       "test.txt:5:10: note:   === inner scope ===\n"
> -			       "test.txt:5:10: note:    msg 4\n"
> -			       "test.txt:5:10: note:   msg 5\n"
> -			       "test.txt:5:10: note:  msg 6\n"
> -			       "test.txt:5:10: note: msg 7\n");
> -	if (with_optinfo)
> -	  {
> -	    optinfo *info = tmp.get_pending_optinfo ();
> -	    ASSERT_TRUE (info != NULL);
> -	    ASSERT_EQ (info->num_items (), 1);
> -	    ASSERT_IS_TEXT (info->get_item (0), "msg 7\n");
> -	  }
> -      }
> +	  switch (dump_filter & MSG_ALL_PRIORITIES)
> +	    {
> +	    default:
> +	      gcc_unreachable ();
> +	    case 0:
> +	      ASSERT_DUMPED_TEXT_EQ (tmp, "");
> +	      break;
> +	    case MSG_PRIORITY_USER_FACING:
> +	      ASSERT_DUMPED_TEXT_EQ
> +		(tmp,
> +		 "test.txt:5:10: note: msg 1\n"
> +		 "test.txt:5:10: note:    explicitly user-facing msg\n"
> +		 "test.txt:5:10: note: msg 7\n");
> +	      break;
> +	    case MSG_PRIORITY_INTERNALS:
> +	      ASSERT_DUMPED_TEXT_EQ
> +		(tmp,
> +		 "test.txt:5:10: note: explicitly internal msg\n"
> +		 "test.txt:5:10: note:  === outer scope ===\n"
> +		 "test.txt:5:10: note:  msg 2\n"
> +		 "test.txt:5:10: note:   === middle scope ===\n"
> +		 "test.txt:5:10: note:   msg 3\n"
> +		 "test.txt:5:10: note:    === inner scope ===\n"
> +		 "test.txt:5:10: note:    msg 4\n"
> +		 "test.txt:5:10: note:   msg 5\n"
> +		 "test.txt:5:10: note:  msg 6\n");
> +	      break;
> +	    case MSG_ALL_PRIORITIES:
> +	      ASSERT_DUMPED_TEXT_EQ
> +		(tmp,
> +		 "test.txt:5:10: note: msg 1\n"
> +		 "test.txt:5:10: note: explicitly internal msg\n"
> +		 "test.txt:5:10: note: === outer scope ===\n"
> +		 "test.txt:5:10: note:  msg 2\n"
> +		 "test.txt:5:10: note:  === middle scope ===\n"
> +		 "test.txt:5:10: note:   msg 3\n"
> +		 "test.txt:5:10: note:   === inner scope ===\n"
> +		 "test.txt:5:10: note:    msg 4\n"
> +		 "test.txt:5:10: note:    explicitly user-facing msg\n"
> +		 "test.txt:5:10: note:   msg 5\n"
> +		 "test.txt:5:10: note:  msg 6\n"
> +		 "test.txt:5:10: note: msg 7\n");
> +	      break;
> +	    }
> +	  if (with_optinfo)
> +	    {
> +	      optinfo *info = tmp.get_pending_optinfo ();
> +	      ASSERT_TRUE (info != NULL);
> +	      ASSERT_EQ (info->num_items (), 1);
> +	      ASSERT_IS_TEXT (info->get_item (0), "msg 7\n");
> +	    }
> +	}
>      }
>  
>    /* Verify that MSG_* affects optinfo->get_kind (); we tested MSG_NOTE
> @@ -2361,7 +2460,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
>    {
>      /* MSG_OPTIMIZED_LOCATIONS.  */
>      {
> -      temp_dump_context tmp (true, MSG_ALL);
> +      temp_dump_context tmp (true, MSG_ALL_KINDS);
>        dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc, "test");
>        ASSERT_EQ (tmp.get_pending_optinfo ()->get_kind (),
>  		 OPTINFO_KIND_SUCCESS);
> @@ -2369,7 +2468,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
>  
>      /* MSG_MISSED_OPTIMIZATION.  */
>      {
> -      temp_dump_context tmp (true, MSG_ALL);
> +      temp_dump_context tmp (true, MSG_ALL_KINDS);
>        dump_printf_loc (MSG_MISSED_OPTIMIZATION, loc, "test");
>        ASSERT_EQ (tmp.get_pending_optinfo ()->get_kind (),
>  		 OPTINFO_KIND_FAILURE);
> @@ -2378,7 +2477,8 @@ test_capture_of_dump_calls (const line_table_case &case_)
>  
>    /* Verify that MSG_* affect AUTO_DUMP_SCOPE and the dump calls.  */
>    {
> -    temp_dump_context tmp (false, MSG_OPTIMIZED_LOCATIONS);
> +    temp_dump_context tmp (false,
> +			   MSG_OPTIMIZED_LOCATIONS | MSG_ALL_PRIORITIES);
>      dump_printf_loc (MSG_NOTE, stmt, "msg 1\n");
>      {
>        AUTO_DUMP_SCOPE ("outer scope", stmt);
> diff --git a/gcc/dumpfile.h b/gcc/dumpfile.h
> index 057ca46..5933905 100644
> --- a/gcc/dumpfile.h
> +++ b/gcc/dumpfile.h
> @@ -145,6 +145,9 @@ enum dump_flag
>    /* Dump folding details.  */
>    TDF_FOLDING = (1 << 21),
>  
> +  /* MSG_* flags for expressing the kinds of message to
> +     be emitted by -fopt-info.  */
> +
>    /* -fopt-info optimized sources.  */
>    MSG_OPTIMIZED_LOCATIONS = (1 << 22),
>  
> @@ -154,15 +157,37 @@ enum dump_flag
>    /* General optimization info.  */
>    MSG_NOTE = (1 << 24),
>  
> -  MSG_ALL = (MSG_OPTIMIZED_LOCATIONS
> -	     | MSG_MISSED_OPTIMIZATION
> -	     | MSG_NOTE),
> +  /* Mask for selecting MSG_-kind flags.  */
> +  MSG_ALL_KINDS = (MSG_OPTIMIZED_LOCATIONS
> +		   | MSG_MISSED_OPTIMIZATION
> +		   | MSG_NOTE),
> +
> +  /* MSG_PRIORITY_* flags for expressing the priority levels of message
> +     to be emitted by -fopt-info, and filtering on them.
> +     By default, messages at the top-level dump scope are "user-facing",
> +     whereas those that are in nested scopes are implicitly "internals".
> +     This behavior can be overridden for a given dump message by explicitly
> +     specifying one of the MSG_PRIORITY_* flags.
> +
> +     By default, dump files show both kinds of message, whereas -fopt-info
> +     only shows "user-facing" messages, and requires the "-internals"
> +     sub-option of -fopt-info to show the internal messages.  */
> +
> +  /* Implicitly supplied for messages at the top-level dump scope.  */
> +  MSG_PRIORITY_USER_FACING = (1 << 25),
> +
> +  /* Implicitly supplied for messages within nested dump scopes.  */
> +  MSG_PRIORITY_INTERNALS = (1 << 26),
> +
> +  /* Mask for selecting MSG_PRIORITY_* flags.  */
> +  MSG_ALL_PRIORITIES = (MSG_PRIORITY_USER_FACING
> +			| MSG_PRIORITY_INTERNALS),
>  
>    /* Dumping for -fcompare-debug.  */
> -  TDF_COMPARE_DEBUG = (1 << 25),
> +  TDF_COMPARE_DEBUG = (1 << 27),
>  
>    /* All values.  */
> -  TDF_ALL_VALUES = (1 << 26) - 1
> +  TDF_ALL_VALUES = (1 << 28) - 1
>  };
>  
>  /* Dump flags type.  */
> @@ -549,7 +574,11 @@ class auto_dump_scope
>     and then calling
>       dump_end_scope ();
>     once the object goes out of scope, thus capturing the nesting of
> -   the scopes.  */
> +   the scopes.
> +
> +   These scopes affect dump messages within them: dump messages at the
> +   top level implicitly default to MSG_PRIORITY_USER_FACING, whereas those
> +   in a nested scope implicitly default to MSG_PRIORITY_INTERNALS.  */
>  
>  #define AUTO_DUMP_SCOPE(NAME, LOC) \
>    auto_dump_scope scope (NAME, LOC)
> diff --git a/gcc/testsuite/gcc.dg/plugin/dump-1.c b/gcc/testsuite/gcc.dg/plugin/dump-1.c
> index 165a9c1..95bd7a4 100644
> --- a/gcc/testsuite/gcc.dg/plugin/dump-1.c
> +++ b/gcc/testsuite/gcc.dg/plugin/dump-1.c
> @@ -18,11 +18,7 @@ void test_remarks (void)
>    test_wide_int (); /* { dg-message "test of wide int: 0" } */
>    test_poly_int (); /* { dg-message "test of poly int: 42" } */
>  
> -  test_scopes (); /* { dg-line test_scopes_line } */
> -  /* { dg-message "=== outer scope ===" "" { target *-*-* } test_scopes_line } */
> -  /* { dg-message " at outer scope" "" { target *-*-* } test_scopes_line } */
> -  /* { dg-message " === middle scope ===" "" { target *-*-* } test_scopes_line } */
> -  /* { dg-message "  at middle scope" "" { target *-*-* } test_scopes_line } */
> -  /* { dg-message "  === innermost scope ===" "" { target *-*-* } test_scopes_line } */
> -  /* { dg-message "   at innermost scope" "" { target *-*-* } test_scopes_line } */
> +  /* Dump messages in nested scopes are not printed by default, and
> +     require "-internals".  */
> +  test_scopes ();
>  }
> diff --git a/gcc/testsuite/gcc.dg/plugin/dump-2.c b/gcc/testsuite/gcc.dg/plugin/dump-2.c
> new file mode 100644
> index 0000000..961a3d3
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/plugin/dump-2.c
> @@ -0,0 +1,30 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fopt-info-note-internals" } */
> +
> +extern void test_string_literal (void);
> +extern void test_tree (void);
> +extern void test_gimple (int);
> +extern void test_cgraph_node (void);
> +extern void test_wide_int (void);
> +extern void test_poly_int (void);
> +extern void test_scopes (void);
> +
> +void test_remarks (void)
> +{
> +  test_string_literal (); /* { dg-message "test of dump for 'test_string_literal'" } */
> +  test_tree (); /* { dg-message "test of tree: 0" } */
> +  test_gimple (42); /* { dg-message "test of gimple: test_gimple \\(42\\);" } */
> +  test_cgraph_node (); /* { dg-message "test of callgraph node: test_cgraph_node/\[0-9\]+" } */
> +  test_wide_int (); /* { dg-message "test of wide int: 0" } */
> +  test_poly_int (); /* { dg-message "test of poly int: 42" } */
> +
> +  /* Dump messages in nested scopes are not printed by default, and
> +     require "-internals".  */
> +  test_scopes (); /* { dg-line test_scopes_line } */
> +  /* { dg-message "=== outer scope ===" "" { target *-*-* } test_scopes_line } */
> +  /* { dg-message " at outer scope" "" { target *-*-* } test_scopes_line } */
> +  /* { dg-message " === middle scope ===" "" { target *-*-* } test_scopes_line } */
> +  /* { dg-message "  at middle scope" "" { target *-*-* } test_scopes_line } */
> +  /* { dg-message "  === innermost scope ===" "" { target *-*-* } test_scopes_line } */
> +  /* { dg-message "   at innermost scope" "" { target *-*-* } test_scopes_line } */
> +}
> diff --git a/gcc/testsuite/gcc.dg/plugin/plugin.exp b/gcc/testsuite/gcc.dg/plugin/plugin.exp
> index 50db3ae..1d06c04 100644
> --- a/gcc/testsuite/gcc.dg/plugin/plugin.exp
> +++ b/gcc/testsuite/gcc.dg/plugin/plugin.exp
> @@ -102,7 +102,8 @@ set plugin_test_list [list \
>      { expensive_selftests_plugin.c \
>  	  expensive-selftests-1.c } \
>      { dump_plugin.c \
> -	  dump-1.c } \
> +	  dump-1.c \
> +	  dump-2.c } \
>  ]
>  
>  foreach plugin_test $plugin_test_list {
> diff --git a/gcc/tree-vect-loop-manip.c b/gcc/tree-vect-loop-manip.c
> index a93c6ee..1d1d114 100644
> --- a/gcc/tree-vect-loop-manip.c
> +++ b/gcc/tree-vect-loop-manip.c
> @@ -3068,11 +3068,13 @@ vect_loop_versioning (loop_vec_info loop_vinfo,
>        && dump_enabled_p ())
>      {
>        if (version_alias)
> -        dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, vect_location,
> +        dump_printf_loc (MSG_OPTIMIZED_LOCATIONS | MSG_PRIORITY_USER_FACING,
> +			 vect_location,
>                           "loop versioned for vectorization because of "
>  			 "possible aliasing\n");
>        if (version_align)
> -        dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, vect_location,
> +        dump_printf_loc (MSG_OPTIMIZED_LOCATIONS | MSG_PRIORITY_USER_FACING,
> +			 vect_location,
>                           "loop versioned for vectorization to enhance "
>  			 "alignment\n");
>  
> diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h
> index d91cc07..af5d5bf 100644
> --- a/gcc/tree-vectorizer.h
> +++ b/gcc/tree-vectorizer.h
> @@ -1420,7 +1420,11 @@ extern dump_user_location_t vect_location;
>     and then calling
>       dump_end_scope ();
>     once the object goes out of scope, thus capturing the nesting of
> -   the scopes.  */
> +   the scopes.
> +
> +   These scopes affect dump messages within them: dump messages at the
> +   top level implicitly default to MSG_PRIORITY_USER_FACING, whereas those
> +   in a nested scope implicitly default to MSG_PRIORITY_INTERNALS.  */
>  
>  #define DUMP_VECT_SCOPE(MSG) \
>    AUTO_DUMP_SCOPE (MSG, vect_location)
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nuernberg)

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 3/3] v3: Report vectorization problems via a new opt_problem class
  2018-09-28 18:24         ` [PATCH 3/3] v3: Report vectorization problems via a new opt_problem class David Malcolm
@ 2018-10-04 11:28           ` Richard Biener
  2018-10-04 17:37             ` Richard Sandiford
  2018-10-04 18:28             ` -fopt-info-inline and class opt_problem David Malcolm
  0 siblings, 2 replies; 24+ messages in thread
From: Richard Biener @ 2018-10-04 11:28 UTC (permalink / raw)
  To: David Malcolm; +Cc: Richard Sandiford, gcc-patches

On Fri, 28 Sep 2018, David Malcolm wrote:

> This is v3 of the patch; previous versions were:
>   v2: https://gcc.gnu.org/ml/gcc-patches/2018-07/msg00446.html
>   v1: https://gcc.gnu.org/ml/gcc-patches/2018-06/msg01462.html
> 
> This patch introduces a class opt_problem, along with wrapper
> classes for bool (opt_result) and for pointers (e.g. opt_loop_vec_info
> for loop_vec_info).
> 
> opt_problem instances are created when an optimization problem
> is encountered, but only if dump_enabled_p.  They are manually
> propagated up the callstack, and are manually reported at the
> "top level" of an optimization if dumping is enabled, to give the user
> a concise summary of the problem *after* the failure is reported.
> In particular, the location of the problematic statement is
> captured and emitted, rather than just the loop's location.
> 
> For example:
> 
> no-vfa-vect-102.c:24:3: missed: couldn't vectorize loop
> no-vfa-vect-102.c:27:7: missed: statement clobbers memory: __asm__ __volatile__("" :  :  : "memory");
> 
> Changed in v3:
> * This version bootstraps and passes regression testing (on
>   x86_64-pc-linux-gnu).
> * added selftests, to exercise the opt_problem machinery
> * removed the "bool to opt_result" ctor, so that attempts to
>   use e.g. return a bool from an opt_result-returning function
>   will fail at compile time
> * use formatted printing within opt_problem ctor to replace the
>   various dump_printf_loc calls
> * dropped i18n
> * changed the sense of vect_analyze_data_ref_dependence's return
>   value (see the ChangeLog)
> * add MSG_PRIORITY_REEMITTED, so that -fopt-info can show the
>   messages, without them messing up the counts in scan-tree-dump-times
>   in DejaGnu tests
> 
> Re Richard Sandiford's feedback on the v2 patch:
>   https://gcc.gnu.org/ml/gcc-patches/2018-07/msg00560.html
> > Since the creation of the opt_problem depends on dump_enabled_p, would
> > it make sense for the dump_printf_loc to happen automatically on
> > opt_result::failure, rather than have both?
> 
> Yes; this v3 patch does that: opt_result::failure_at is passed a format
> string with variadic args.  If dumping is enabled, it performs the
> equivalent of dump_printf_loc in a form that will reach dumpfiles
> (and -fopt-info-internals), stashing the dumped items in the opt_problem.
> When the opt_problem is emitted at the top-level, the message is re-emitted
> (but only for -fopt-info, not for dumpfiles, to avoid duplicates that mess
> up scan-tree-dump-times in DejaGnu tests)
> 
> > I guess this is bike-shedding, but personally I'd prefer an explicit
> > test for success rather than operator bool, so that:
> >
> >    opt_result foo = ...;
> >    bool bar = foo;
> >
> > is ill-formed.  The danger otherwise might be that we drop a useful
> > opt_problem and replace it with something more generic.  E.g. the
> > opt_result form of:
> >   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;
> >     }
> >
> > in vect_analyze_stmt could silently drop the information provided by
> > the subroutine if we forgot to change "ok" from "bool" to "opt_result".
> 
> I didn't make that change in v3: if the function returns an opt_result, then
> the "return false;" will be a compile-time failure, alerting us to the
> problem.
> 
> I guess this is a matter of style, whether explicit is better than
> implicit.  Dropping the operator bool would require an explicit approach,
> with something like:
> 
>     // Explicit style:
>     opt_result res = ...;
>     if (res.failed_p ())
>        return res;
> 
> and:
> 
>     // Explicit style:
>     // It's often currently called "ok":
>     opt_result ok = ...;
>     if (ok.failed_p ())
>        return ok;
> 
> as opposed to:
> 
>     // Implicit style:
>     opt_result res = ...;
>     if (!res)
>        return res;
> 
> and:
> 
>     // Implicit style:
>     opt_result ok = ...;
>     if (!ok)
>        return ok;
> 
> I think I went with the implicit style to minimize the lines touched by
> the patch, but I'm happy with either approach.  [If we're bikeshedding,
> would renaming those "ok" to "res" be acceptable also?  "ok" reads to
> me like a "success" value for a status variable, rather than the status
> variable itself; it's presumably meant to be pronounced with a rising
> interrogative as it were a question - "ok?" - but that's not visible in
> the code when reading the usage sites].
> 
> Similarly, the pointer wrappers use an implicit style:
> 
>   // Implicit style:
> 
>   opt_loop_vec_info loop_vinfo
>     = vect_analyze_loop (loop, orig_loop_vinfo, &shared);
>   loop->aux = loop_vinfo;
> 
>   if (!loop_vinfo)
>     if (dump_enabled_p ())
>       if (opt_problem *problem = loop_vinfo.get_problem ())
> 	{
> 
> but maybe an explicit style is more readable:
> 
>   // Explicit style:
> 
>   opt_loop_vec_info opt_loop_vinfo
>     = vect_analyze_loop (loop, orig_loop_vinfo, &shared);
>   loop_vec_info loop_vinfo = loop_vinfo.get_pointer ();
>   loop->aux = loop_vinfo
> 
>   if (opt_loop_vinfo.failed_p ())
>     if (dump_enabled_p ())
>       if (opt_problem *problem = loop_vinfo.get_problem ())
> 	{
> 
> 
> How would you want the code to look?
> 
> Richi: do you have an opinion here?

I wouldn't mind about the explicit variant for the bool but
the explicit for the pointer looks odd.

In general I agree that

 opt_result foo = x;
 bool bar = x;

is confusing but I also like the brevity that is possible
with the automatic conversions so I am biased towards that.

> (or is that style in the patch OK as-is?)

For me it is OK as-is.

> Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
> 
> OK for trunk?

OK.  My question on 2/3 leaves Richard time to comment.

Maybe you can tackle the issue that -fopt-info-inline does
nothing at the moment and see if opt-problems are a good fit
there as well (reporting the CIF strings).

Thanks for working on all this!
Richard.

> 
> gcc/ChangeLog:
> 	* Makefile.in (OBJS): Add opt-problem.o.
> 	* dump-context.h: Include "selftest.h.
> 	(selftest::temp_dump_context): New forward decl.
> 	(class dump_context): Make friend of class
> 	selftest::temp_dump_context.
> 	(dump_context::dump_loc_immediate): New decl.
> 	(class dump_pretty_printer): Move here from dumpfile.c.
> 	(class temp_dump_context): Move to namespace selftest.
> 	(temp_dump_context::temp_dump_context): Add param
> 	"forcibly_enable_dumping".
> 	(selftest::verify_dumped_text):
> 	(ASSERT_DUMPED_TEXT_EQ): Move here from dumpfile.c.
> 	(selftest::verify_item):
> 	(ASSERT_IS_TEXT): Move here from dumpfile.c.
> 	(ASSERT_IS_TREE): Likewise.
> 	(ASSERT_IS_GIMPLE): Likewise.
> 	* dumpfile.c (dump_context::dump_loc): Move immediate dumping
> 	to...
> 	(dump_context::dump_loc_immediate): ...this new function.
> 	(class dump_pretty_printer): Move to dump-context.h.
> 	(dump_switch_p_1): Don't enable MSG_PRIORITY_REEMITTED.
> 	(opt_info_switch_p_1): Enable MSG_PRIORITY_REEMITTED.
> 	(temp_dump_context::temp_dump_context): Move to "selftest"
> 	namespace.  Add param "forcibly_enable_dumping", and use it to
> 	conditionalize the use of m_pp;
> 	(selftest::verify_dumped_text): Make non-static.
> 	(ASSERT_DUMPED_TEXT_EQ): Move to dump-context.h.
> 	(selftest::verify_item): Make non-static.
> 	(ASSERT_IS_TEXT): Move to dump-context.h.
> 	(ASSERT_IS_TREE): Likewise.
> 	(ASSERT_IS_GIMPLE): Likewise.
> 	(selftest::test_capture_of_dump_calls): Pass "true" for new
> 	param of temp_dump_context.
> 	* dumpfile.h (enum dump_flag): Add MSG_PRIORITY_REEMITTED, adding
> 	it to MSG_ALL_PRIORITIES.  Update values of TDF_COMPARE_DEBUG and
> 	TDF_COMPARE_DEBUG.
> 	* opt-problem.cc: New file.
> 	* opt-problem.h: New file.
> 	* optinfo-emit-json.cc
> 	(selftest::test_building_json_from_dump_calls): Pass "true" for
> 	new param of temp_dump_context.
> 	* optinfo.cc (optinfo_kind_to_dump_flag): New function.
> 	(optinfo::emit_for_opt_problem): New function.
> 	(optinfo::emit): Clarity which emit_item is used.
> 	* optinfo.h (optinfo::get_dump_location): New accessor.
> 	(optinfo::emit_for_opt_problem): New decl.
> 	(optinfo::emit): Make const.
> 	* selftest-run-tests.c (selftest::run_tests): Call
> 	selftest::opt_problem_cc_tests.
> 	* selftest.h (selftest::opt_problem_cc_tests): New decl.
> 	* tree-data-ref.c (dr_analyze_innermost): Convert return type from
> 	bool to opt_result, converting fprintf messages to
> 	opt_result::failure_at calls.  Add "stmt" param for use by the
> 	failure_at calls.
> 	(create_data_ref): Pass "stmt" to the dr_analyze_innermost call.
> 	(runtime_alias_check_p): Convert return type from bool to
> 	opt_result, converting dump_printf calls to
> 	opt_result::failure_at, using the statement DDR_A for their
> 	location.
> 	(find_data_references_in_stmt): Convert return type from bool to
> 	opt_result, converting "return false" to opt_result::failure_at
> 	with a new message.
> 	* tree-data-ref.h: Include "opt-problem.h".
> 	(dr_analyze_innermost): Convert return type from bool to opt_result,
> 	and add a const gimple * param.
> 	(find_data_references_in_stmt): Convert return type from bool to
> 	opt_result.
> 	(runtime_alias_check_p): Likewise.
> 	* tree-predcom.c (find_looparound_phi): Pass "init_stmt" to
> 	dr_analyze_innermost.
> 	* tree-vect-data-refs.c (vect_mark_for_runtime_alias_test):
> 	Convert return type from bool to opt_result, adding a message for
> 	the PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS zero case.
> 	(vect_analyze_data_ref_dependence): Convert return type from bool
> 	to opt_result.  Change sense of return type from "false"
> 	effectively meaning "no problems" to "false" meaning a problem,
> 	so that "return false" becomes "return opt_result::success".
> 	Convert "return true" calls to opt_result::failure_at, using
> 	the location of statement A rather than vect_location.
> 	(vect_analyze_data_ref_dependences): Convert return type from bool
> 	to opt_result.
> 	(verify_data_ref_alignment): Likewise, converting dump_printf_loc
> 	calls to opt_result::failure_at, using the stmt location rather
> 	than vect_location.
> 	(vect_verify_datarefs_alignment): Convert return type from bool
> 	to opt_result.
> 	(vect_enhance_data_refs_alignment): Likewise.  Split local "stat"
> 	into multiple more-tightly-scoped copies.
> 	(vect_analyze_data_refs_alignment): Convert return type from bool
> 	to opt_result.
> 	(vect_analyze_data_ref_accesses): Likewise, converting a
> 	"return false" to a "return opt_result::failure_at", adding a
> 	new message.
> 	(vect_prune_runtime_alias_test_list): Convert return type from
> 	bool to opt_result, converting dump_printf_loc to
> 	opt_result::failure_at.  Add a %G to show the pertinent statement,
> 	and use the stmt's location rather than vect_location.
> 	(vect_find_stmt_data_reference): Convert return type from
> 	bool to opt_result, converting dump_printf_loc to
> 	opt_result::failure_at, using stmt's location.
> 	(vect_analyze_data_refs):  Convert return type from bool to
> 	opt_result.  Convert "return false" to "return
> 	opt_result::failure_at", adding messages as needed.
> 	* tree-vect-loop.c (vect_determine_vf_for_stmt_1): Convert return
> 	type from bool to opt_result.
> 	(vect_determine_vf_for_stmt): Likewise.
> 	(vect_determine_vectorization_factor): Likewise, converting
> 	dump_printf_loc to opt_result::failure_at, using location of phi
> 	rather than vect_location.
> 	(vect_analyze_loop_form_1): Convert return type from bool to
> 	opt_result, converting dump_printf_loc calls, retaining the use of
> 	vect_location.
> 	(vect_analyze_loop_form): Convert return type from loop_vec_info
> 	to opt_loop_vec_info.
> 	(vect_analyze_loop_operations): Convert return type from bool to
> 	opt_result, converting dump_printf_loc calls, using the location
> 	of phi/stmt rather than vect_location where available.  Convert
> 	various "return false" to "return opt_result::failure_at" with
> 	"unsupported phi" messages.
> 	(vect_get_datarefs_in_loop): Convert return type from bool to
> 	opt_result.  Add a message for the
> 	PARAM_LOOP_MAX_DATAREFS_FOR_DATADEPS failure.
> 	(vect_analyze_loop_2): Convert return type from bool to
> 	opt_result.  Ensure "ok" is set to a opt_result::failure_at before
> 	each "goto again;", adding new messages where needed.
> 	Add "unsupported grouped {store|load}" messages.
> 	(vect_analyze_loop): Convert return type from loop_vec_info to
> 	opt_loop_vec_info.
> 	* tree-vect-slp.c (vect_analyze_slp): Convert return type from
> 	bool to opt_result.
> 	* tree-vect-stmts.c (process_use): Likewise, converting
> 	dump_printf_loc call and using stmt location, rather than
> 	vect_location.
> 	(vect_mark_stmts_to_be_vectorized): Likeise.
> 	(vect_analyze_stmt): Likewise, adding a %G.
> 	(vect_get_vector_types_for_stmt): Convert return type from bool to
> 	opt_result, converting dump_printf_loc calls and using stmt
> 	location, rather than vect_location.
> 	(vect_get_mask_type_for_stmt): Convert return type from tree to
> 	opt_tree, converting dump_printf_loc calls and using stmt location.
> 	* tree-vectorizer.c: Include "opt-problem.h.
> 	(try_vectorize_loop_1): Flag "Analyzing loop at" dump message as
> 	MSG_PRIORITY_INTERNALS.  Convert local "loop_vinfo" from
> 	loop_vec_info to opt_loop_vec_info.  If if fails, and dumping is
> 	enabled, use it to report at the top level "couldn't vectorize
> 	loop" followed by the problem.
> 	* tree-vectorizer.h (opt_loop_vec_info): New typedef.
> 	(vect_mark_stmts_to_be_vectorized): Convert return type from bool
> 	to opt_result.
> 	(vect_analyze_stmt): Likewise.
> 	(vect_get_vector_types_for_stmt): Likewise.
> 	(tree vect_get_mask_type_for_stmt): Likewise.
> 	(vect_analyze_data_ref_dependences): Likewise.
> 	(vect_enhance_data_refs_alignment): Likewise.
> 	(vect_analyze_data_refs_alignment): Likewise.
> 	(vect_verify_datarefs_alignment): Likewise.
> 	(vect_analyze_data_ref_accesses): Likewise.
> 	(vect_prune_runtime_alias_test_list): Likewise.
> 	(vect_find_stmt_data_reference): Likewise.
> 	(vect_analyze_data_refs): Likewise.
> 	(vect_analyze_loop): Convert return type from loop_vec_info to
> 	opt_loop_vec_info.
> 	(vect_analyze_loop_form): Likewise.
> 	(vect_analyze_slp): Convert return type from bool to opt_result.
> 
> gcc/testsuite/ChangeLog:
> 	* gcc.dg/vect/nodump-vect-opt-info-2.c: New test.
> 	* gcc.dg/vect/vect-alias-check-4.c: Add "-fopt-info-vec-all" to
> 	dg-additional-options.  Add dg-message and dg-missed directives
> 	to verify that -fopt-info messages are written at the correct
> 	locations.
> ---
>  gcc/Makefile.in                                    |   1 +
>  gcc/dump-context.h                                 | 104 ++++-
>  gcc/dumpfile.c                                     | 160 +++-----
>  gcc/dumpfile.h                                     |  13 +-
>  gcc/opt-problem.cc                                 | 335 ++++++++++++++++
>  gcc/opt-problem.h                                  | 289 ++++++++++++++
>  gcc/optinfo-emit-json.cc                           |   2 +-
>  gcc/optinfo.cc                                     |  44 +-
>  gcc/optinfo.h                                      |   7 +-
>  gcc/selftest-run-tests.c                           |   1 +
>  gcc/selftest.h                                     |   1 +
>  gcc/testsuite/gcc.dg/vect/nodump-vect-opt-info-2.c |  12 +
>  gcc/testsuite/gcc.dg/vect/vect-alias-check-4.c     |  18 +-
>  gcc/tree-data-ref.c                                |  70 ++--
>  gcc/tree-data-ref.h                                |  10 +-
>  gcc/tree-predcom.c                                 |   3 +-
>  gcc/tree-vect-data-refs.c                          | 347 ++++++++--------
>  gcc/tree-vect-loop.c                               | 442 +++++++++------------
>  gcc/tree-vect-slp.c                                |   4 +-
>  gcc/tree-vect-stmts.c                              | 275 ++++++-------
>  gcc/tree-vectorizer.c                              |  17 +-
>  gcc/tree-vectorizer.h                              |  45 ++-
>  22 files changed, 1408 insertions(+), 792 deletions(-)
>  create mode 100644 gcc/opt-problem.cc
>  create mode 100644 gcc/opt-problem.h
>  create mode 100644 gcc/testsuite/gcc.dg/vect/nodump-vect-opt-info-2.c
> 
> diff --git a/gcc/Makefile.in b/gcc/Makefile.in
> index 4b7cec8..116ed6e 100644
> --- a/gcc/Makefile.in
> +++ b/gcc/Makefile.in
> @@ -1423,6 +1423,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/dump-context.h b/gcc/dump-context.h
> index 20b94a7..3a45f23 100644
> --- a/gcc/dump-context.h
> +++ b/gcc/dump-context.h
> @@ -24,6 +24,9 @@ along with GCC; see the file COPYING3.  If not see
>  
>  #include "dumpfile.h"
>  #include "pretty-print.h"
> +#include "selftest.h"
> +
> +namespace selftest { class temp_dump_context; }
>  
>  /* A class for handling the various dump_* calls.
>  
> @@ -36,7 +39,8 @@ along with GCC; see the file COPYING3.  If not see
>  
>  class dump_context
>  {
> -  friend class temp_dump_context;
> +  friend class selftest::temp_dump_context;
> +
>   public:
>    static dump_context &get () { return *s_current; }
>  
> @@ -45,6 +49,7 @@ class dump_context
>    void refresh_dumps_are_enabled ();
>  
>    void dump_loc (dump_flags_t dump_kind, const dump_location_t &loc);
> +  void dump_loc_immediate (dump_flags_t dump_kind, const dump_location_t &loc);
>  
>    void dump_gimple_stmt (dump_flags_t dump_kind, dump_flags_t extra_dump_flags,
>  			 gimple *gs, int spc);
> @@ -129,8 +134,53 @@ class dump_context
>    static dump_context s_default;
>  };
>  
> +/* A subclass of pretty_printer for implementing dump_context::dump_printf_va.
> +   In particular, the formatted chunks are captured as optinfo_item instances,
> +   thus retaining metadata about the entities being dumped (e.g. source
> +   locations), rather than just as plain text.  */
> +
> +class dump_pretty_printer : public pretty_printer
> +{
> +public:
> +  dump_pretty_printer (dump_context *context, dump_flags_t dump_kind);
> +
> +  void emit_items (optinfo *dest);
> +
> +private:
> +  /* Information on an optinfo_item that was generated during phase 2 of
> +     formatting.  */
> +  struct stashed_item
> +  {
> +    stashed_item (const char **buffer_ptr_, optinfo_item *item_)
> +      : buffer_ptr (buffer_ptr_), item (item_) {}
> +    const char **buffer_ptr;
> +    optinfo_item *item;
> +  };
> +
> +  static bool format_decoder_cb (pretty_printer *pp, text_info *text,
> +				 const char *spec, int /*precision*/,
> +				 bool /*wide*/, bool /*set_locus*/,
> +				 bool /*verbose*/, bool */*quoted*/,
> +				 const char **buffer_ptr);
> +
> +  bool decode_format (text_info *text, const char *spec,
> +		      const char **buffer_ptr);
> +
> +  void stash_item (const char **buffer_ptr, optinfo_item *item);
> +
> +  void emit_any_pending_textual_chunks (optinfo *dest);
> +
> +  void emit_item (optinfo_item *item, optinfo *dest);
> +
> +  dump_context *m_context;
> +  dump_flags_t m_dump_kind;
> +  auto_vec<stashed_item> m_stashed_items;
> +};
> +
>  #if CHECKING_P
>  
> +namespace selftest {
> +
>  /* An RAII-style class for use in selftests for temporarily using a different
>     dump_context.  */
>  
> @@ -138,6 +188,7 @@ class temp_dump_context
>  {
>   public:
>    temp_dump_context (bool forcibly_enable_optinfo,
> +		     bool forcibly_enable_dumping,
>  		     dump_flags_t test_pp_flags);
>    ~temp_dump_context ();
>  
> @@ -151,6 +202,57 @@ class temp_dump_context
>    dump_context *m_saved;
>  };
>  
> +/* Implementation detail of ASSERT_DUMPED_TEXT_EQ.  */
> +
> +extern void verify_dumped_text (const location &loc,
> +				temp_dump_context *context,
> +				const char *expected_text);
> +
> +/* Verify that the text dumped so far in CONTEXT equals
> +   EXPECTED_TEXT.
> +   As a side-effect, the internal buffer is 0-terminated.  */
> +
> +#define ASSERT_DUMPED_TEXT_EQ(CONTEXT, EXPECTED_TEXT)			\
> +  SELFTEST_BEGIN_STMT							\
> +    verify_dumped_text (SELFTEST_LOCATION, &(CONTEXT), (EXPECTED_TEXT)); \
> +  SELFTEST_END_STMT
> +
> +
> +/* Verify that ITEM has the expected values.  */
> +
> +void
> +verify_item (const location &loc,
> +	     const optinfo_item *item,
> +	     enum optinfo_item_kind expected_kind,
> +	     location_t expected_location,
> +	     const char *expected_text);
> +
> +/* Verify that ITEM is a text item, with EXPECTED_TEXT.  */
> +
> +#define ASSERT_IS_TEXT(ITEM, EXPECTED_TEXT) \
> +  SELFTEST_BEGIN_STMT						    \
> +    verify_item (SELFTEST_LOCATION, (ITEM), OPTINFO_ITEM_KIND_TEXT, \
> +		 UNKNOWN_LOCATION, (EXPECTED_TEXT));		    \
> +  SELFTEST_END_STMT
> +
> +/* Verify that ITEM is a tree item, with the expected values.  */
> +
> +#define ASSERT_IS_TREE(ITEM, EXPECTED_LOCATION, EXPECTED_TEXT) \
> +  SELFTEST_BEGIN_STMT						    \
> +    verify_item (SELFTEST_LOCATION, (ITEM), OPTINFO_ITEM_KIND_TREE, \
> +		 (EXPECTED_LOCATION), (EXPECTED_TEXT));	    \
> +  SELFTEST_END_STMT
> +
> +/* Verify that ITEM is a gimple item, with the expected values.  */
> +
> +#define ASSERT_IS_GIMPLE(ITEM, EXPECTED_LOCATION, EXPECTED_TEXT) \
> +  SELFTEST_BEGIN_STMT						    \
> +    verify_item (SELFTEST_LOCATION, (ITEM), OPTINFO_ITEM_KIND_GIMPLE, \
> +		 (EXPECTED_LOCATION), (EXPECTED_TEXT));	    \
> +  SELFTEST_END_STMT
> +
> +} // namespace selftest
> +
>  #endif /* CHECKING_P */
>  
>  #endif /* GCC_DUMP_CONTEXT_H */
> diff --git a/gcc/dumpfile.c b/gcc/dumpfile.c
> index e15edc7..0b140ff 100644
> --- a/gcc/dumpfile.c
> +++ b/gcc/dumpfile.c
> @@ -562,6 +562,21 @@ dump_context::dump_loc (dump_flags_t dump_kind, const dump_location_t &loc)
>  {
>    end_any_optinfo ();
>  
> +  dump_loc_immediate (dump_kind, loc);
> +
> +  if (optinfo_enabled_p ())
> +    {
> +      optinfo &info = begin_next_optinfo (loc);
> +      info.handle_dump_file_kind (dump_kind);
> +    }
> +}
> +
> +/* As dump_loc above, but without starting a new optinfo. */
> +
> +void
> +dump_context::dump_loc_immediate (dump_flags_t dump_kind,
> +				  const dump_location_t &loc)
> +{
>    location_t srcloc = loc.get_location_t ();
>  
>    if (dump_file && apply_dump_filter_p (dump_kind, pflags))
> @@ -573,12 +588,6 @@ dump_context::dump_loc (dump_flags_t dump_kind, const dump_location_t &loc)
>    /* Support for temp_dump_context in selftests.  */
>    if (m_test_pp && apply_dump_filter_p (dump_kind, m_test_pp_flags))
>      ::dump_loc (dump_kind, m_test_pp, srcloc);
> -
> -  if (optinfo_enabled_p ())
> -    {
> -      optinfo &info = begin_next_optinfo (loc);
> -      info.handle_dump_file_kind (dump_kind);
> -    }
>  }
>  
>  /* Make an item for the given dump call, equivalent to print_gimple_stmt.  */
> @@ -739,49 +748,6 @@ dump_context::dump_generic_expr_loc (dump_flags_t dump_kind,
>    dump_generic_expr (dump_kind, extra_dump_flags, t);
>  }
>  
> -/* A subclass of pretty_printer for implementing dump_context::dump_printf_va.
> -   In particular, the formatted chunks are captured as optinfo_item instances,
> -   thus retaining metadata about the entities being dumped (e.g. source
> -   locations), rather than just as plain text.  */
> -
> -class dump_pretty_printer : public pretty_printer
> -{
> -public:
> -  dump_pretty_printer (dump_context *context, dump_flags_t dump_kind);
> -
> -  void emit_items (optinfo *dest);
> -
> -private:
> -  /* Information on an optinfo_item that was generated during phase 2 of
> -     formatting.  */
> -  struct stashed_item
> -  {
> -    stashed_item (const char **buffer_ptr_, optinfo_item *item_)
> -      : buffer_ptr (buffer_ptr_), item (item_) {}
> -    const char **buffer_ptr;
> -    optinfo_item *item;
> -  };
> -
> -  static bool format_decoder_cb (pretty_printer *pp, text_info *text,
> -				 const char *spec, int /*precision*/,
> -				 bool /*wide*/, bool /*set_locus*/,
> -				 bool /*verbose*/, bool */*quoted*/,
> -				 const char **buffer_ptr);
> -
> -  bool decode_format (text_info *text, const char *spec,
> -		      const char **buffer_ptr);
> -
> -  void stash_item (const char **buffer_ptr, optinfo_item *item);
> -
> -  void emit_any_pending_textual_chunks (optinfo *dest);
> -
> -  void emit_item (optinfo_item *item, optinfo *dest);
> -
> -  dump_context *m_context;
> -  dump_flags_t m_dump_kind;
> -  auto_vec<stashed_item> m_stashed_items;
> -};
> -
>  /* dump_pretty_printer's ctor.  */
>  
>  dump_pretty_printer::dump_pretty_printer (dump_context *context,
> @@ -1732,7 +1698,12 @@ dump_switch_p_1 (const char *arg, struct dump_file_info *dfi, bool doglob)
>      return 0;
>  
>    ptr = option_value;
> -  flags = MSG_ALL_PRIORITIES;
> +
> +  /* Retain "user-facing" and "internals" messages, but filter out
> +     those from an opt_problem being re-emitted at the top level
> +     (MSG_PRIORITY_REEMITTED), so as to avoid duplicate messages
> +     messing up scan-tree-dump-times" in DejaGnu tests.  */
> +  flags = MSG_PRIORITY_USER_FACING | MSG_PRIORITY_INTERNALS;
>  
>    while (*ptr)
>      {
> @@ -1830,8 +1801,9 @@ opt_info_switch_p_1 (const char *arg, dump_flags_t *flags,
>    *filename = NULL;
>  
>    /* Default to filtering out "internals" messages, and retaining
> -     "user-facing" messages.  */
> -  *flags = MSG_PRIORITY_USER_FACING;
> +     "user-facing" messages, and those from an opt_problem being
> +     re-emitted at the top level.  */
> +  *flags = MSG_PRIORITY_USER_FACING | MSG_PRIORITY_REEMITTED;
>  
>    *optgroup_flags = OPTGROUP_NONE;
>  
> @@ -1981,19 +1953,26 @@ enable_rtl_dump_file (void)
>  
>  #if CHECKING_P
>  
> +namespace selftest {
> +
>  /* temp_dump_context's ctor.  Temporarily override the dump_context
>     (to forcibly enable optinfo-generation).  */
>  
>  temp_dump_context::temp_dump_context (bool forcibly_enable_optinfo,
> +				      bool forcibly_enable_dumping,
>  				      dump_flags_t test_pp_flags)
> -
>  : m_context (),
>    m_saved (&dump_context ().get ())
>  {
>    dump_context::s_current = &m_context;
>    m_context.m_forcibly_enable_optinfo = forcibly_enable_optinfo;
> -  m_context.m_test_pp = &m_pp;
> -  m_context.m_test_pp_flags = test_pp_flags;
> +  /* Conditionally enable the test dump, so that we can verify both the
> +     dump_enabled_p and the !dump_enabled_p cases in selftests.  */
> +  if (forcibly_enable_dumping)
> +    {
> +      m_context.m_test_pp = &m_pp;
> +      m_context.m_test_pp_flags = test_pp_flags;
> +    }
>  
>    dump_context::get ().refresh_dumps_are_enabled ();
>  }
> @@ -2015,8 +1994,6 @@ temp_dump_context::get_dumped_text ()
>    return pp_formatted_text (&m_pp);
>  }
>  
> -namespace selftest {
> -
>  /* Verify that the dump_location_t constructors capture the source location
>     at which they were called (provided that the build compiler is sufficiently
>     recent).  */
> @@ -2055,7 +2032,7 @@ test_impl_location ()
>     EXPECTED_TEXT, using LOC for the location of any failure.
>     As a side-effect, the internal buffer is 0-terminated.  */
>  
> -static void
> +void
>  verify_dumped_text (const location &loc,
>  		    temp_dump_context *context,
>  		    const char *expected_text)
> @@ -2065,18 +2042,9 @@ verify_dumped_text (const location &loc,
>  		   expected_text);
>  }
>  
> -/* Verify that the text dumped so far in CONTEXT equals
> -   EXPECTED_TEXT.
> -   As a side-effect, the internal buffer is 0-terminated.  */
> -
> -#define ASSERT_DUMPED_TEXT_EQ(CONTEXT, EXPECTED_TEXT)			\
> -  SELFTEST_BEGIN_STMT							\
> -    verify_dumped_text (SELFTEST_LOCATION, &(CONTEXT), (EXPECTED_TEXT)); \
> -  SELFTEST_END_STMT
> -
>  /* Verify that ITEM has the expected values.  */
>  
> -static void
> +void
>  verify_item (const location &loc,
>  	     const optinfo_item *item,
>  	     enum optinfo_item_kind expected_kind,
> @@ -2088,30 +2056,6 @@ verify_item (const location &loc,
>    ASSERT_STREQ_AT (loc, item->get_text (), expected_text);
>  }
>  
> -/* Verify that ITEM is a text item, with EXPECTED_TEXT.  */
> -
> -#define ASSERT_IS_TEXT(ITEM, EXPECTED_TEXT) \
> -  SELFTEST_BEGIN_STMT						    \
> -    verify_item (SELFTEST_LOCATION, (ITEM), OPTINFO_ITEM_KIND_TEXT, \
> -		 UNKNOWN_LOCATION, (EXPECTED_TEXT));		    \
> -  SELFTEST_END_STMT
> -
> -/* Verify that ITEM is a tree item, with the expected values.  */
> -
> -#define ASSERT_IS_TREE(ITEM, EXPECTED_LOCATION, EXPECTED_TEXT) \
> -  SELFTEST_BEGIN_STMT						    \
> -    verify_item (SELFTEST_LOCATION, (ITEM), OPTINFO_ITEM_KIND_TREE, \
> -		 (EXPECTED_LOCATION), (EXPECTED_TEXT));	    \
> -  SELFTEST_END_STMT
> -
> -/* Verify that ITEM is a gimple item, with the expected values.  */
> -
> -#define ASSERT_IS_GIMPLE(ITEM, EXPECTED_LOCATION, EXPECTED_TEXT) \
> -  SELFTEST_BEGIN_STMT						    \
> -    verify_item (SELFTEST_LOCATION, (ITEM), OPTINFO_ITEM_KIND_GIMPLE, \
> -		 (EXPECTED_LOCATION), (EXPECTED_TEXT));	    \
> -  SELFTEST_END_STMT
> -
>  /* Verify that calls to the dump_* API are captured and consolidated into
>     optimization records. */
>  
> @@ -2144,7 +2088,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
>  
>        /* Test of dump_printf.  */
>        {
> -	temp_dump_context tmp (with_optinfo,
> +	temp_dump_context tmp (with_optinfo, true,
>  			       MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
>  	dump_printf (MSG_NOTE, "int: %i str: %s", 42, "foo");
>  
> @@ -2161,7 +2105,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
>  
>        /* Test of dump_printf with %T.  */
>        {
> -	temp_dump_context tmp (with_optinfo,
> +	temp_dump_context tmp (with_optinfo, true,
>  			       MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
>  	dump_printf (MSG_NOTE, "tree: %T", integer_zero_node);
>  
> @@ -2179,7 +2123,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
>  
>        /* Test of dump_printf with %E.  */
>        {
> -	temp_dump_context tmp (with_optinfo,
> +	temp_dump_context tmp (with_optinfo, true,
>  			       MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
>  	dump_printf (MSG_NOTE, "gimple: %E", stmt);
>  
> @@ -2197,7 +2141,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
>  
>        /* Test of dump_printf with %G.  */
>        {
> -	temp_dump_context tmp (with_optinfo,
> +	temp_dump_context tmp (with_optinfo, true,
>  			       MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
>  	dump_printf (MSG_NOTE, "gimple: %G", stmt);
>  
> @@ -2220,7 +2164,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
>  	 - multiple dump-specific format codes: some consecutive, others
>  	 separated by text, trailing text after the final one.  */
>        {
> -	temp_dump_context tmp (with_optinfo,
> +	temp_dump_context tmp (with_optinfo, true,
>  			       MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
>  	dump_printf_loc (MSG_NOTE, loc, "before %T and %T"
>  			 " %i consecutive %E%E after\n",
> @@ -2248,7 +2192,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
>  
>        /* Tree, via dump_generic_expr.  */
>        {
> -	temp_dump_context tmp (with_optinfo,
> +	temp_dump_context tmp (with_optinfo, true,
>  			       MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
>  	dump_printf_loc (MSG_NOTE, loc, "test of tree: ");
>  	dump_generic_expr (MSG_NOTE, TDF_SLIM, integer_zero_node);
> @@ -2268,7 +2212,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
>  
>        /* Tree, via dump_generic_expr_loc.  */
>        {
> -	temp_dump_context tmp (with_optinfo,
> +	temp_dump_context tmp (with_optinfo, true,
>  			       MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
>  	dump_generic_expr_loc (MSG_NOTE, loc, TDF_SLIM, integer_one_node);
>  
> @@ -2288,7 +2232,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
>        {
>  	/* dump_gimple_stmt_loc.  */
>  	{
> -	  temp_dump_context tmp (with_optinfo,
> +	  temp_dump_context tmp (with_optinfo, true,
>  				 MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
>  	  dump_gimple_stmt_loc (MSG_NOTE, loc, TDF_SLIM, stmt, 2);
>  
> @@ -2304,7 +2248,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
>  
>  	/* dump_gimple_stmt.  */
>  	{
> -	  temp_dump_context tmp (with_optinfo,
> +	  temp_dump_context tmp (with_optinfo, true,
>  				 MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
>  	  dump_gimple_stmt (MSG_NOTE, TDF_SLIM, stmt, 2);
>  
> @@ -2320,7 +2264,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
>  
>  	/* dump_gimple_expr_loc.  */
>  	{
> -	  temp_dump_context tmp (with_optinfo,
> +	  temp_dump_context tmp (with_optinfo, true,
>  				 MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
>  	  dump_gimple_expr_loc (MSG_NOTE, loc, TDF_SLIM, stmt, 2);
>  
> @@ -2336,7 +2280,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
>  
>  	/* dump_gimple_expr.  */
>  	{
> -	  temp_dump_context tmp (with_optinfo,
> +	  temp_dump_context tmp (with_optinfo, true,
>  				 MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
>  	  dump_gimple_expr (MSG_NOTE, TDF_SLIM, stmt, 2);
>  
> @@ -2353,7 +2297,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
>  
>        /* poly_int.  */
>        {
> -	temp_dump_context tmp (with_optinfo,
> +	temp_dump_context tmp (with_optinfo, true,
>  			       MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING);
>  	dump_dec (MSG_NOTE, poly_int64 (42));
>  
> @@ -2378,7 +2322,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
>  	  if (j / 2)
>  	    dump_filter |= MSG_PRIORITY_INTERNALS;
>  
> -	  temp_dump_context tmp (with_optinfo, dump_filter);
> +	  temp_dump_context tmp (with_optinfo, true, dump_filter);
>  	  /* Emit various messages, mostly with implicit priority.  */
>  	  dump_printf_loc (MSG_NOTE, stmt, "msg 1\n");
>  	  dump_printf_loc (MSG_NOTE | MSG_PRIORITY_INTERNALS, stmt,
> @@ -2460,7 +2404,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
>    {
>      /* MSG_OPTIMIZED_LOCATIONS.  */
>      {
> -      temp_dump_context tmp (true, MSG_ALL_KINDS);
> +      temp_dump_context tmp (true, true, MSG_ALL_KINDS);
>        dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc, "test");
>        ASSERT_EQ (tmp.get_pending_optinfo ()->get_kind (),
>  		 OPTINFO_KIND_SUCCESS);
> @@ -2468,7 +2412,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
>  
>      /* MSG_MISSED_OPTIMIZATION.  */
>      {
> -      temp_dump_context tmp (true, MSG_ALL_KINDS);
> +      temp_dump_context tmp (true, true, MSG_ALL_KINDS);
>        dump_printf_loc (MSG_MISSED_OPTIMIZATION, loc, "test");
>        ASSERT_EQ (tmp.get_pending_optinfo ()->get_kind (),
>  		 OPTINFO_KIND_FAILURE);
> @@ -2477,7 +2421,7 @@ test_capture_of_dump_calls (const line_table_case &case_)
>  
>    /* Verify that MSG_* affect AUTO_DUMP_SCOPE and the dump calls.  */
>    {
> -    temp_dump_context tmp (false,
> +    temp_dump_context tmp (false, true,
>  			   MSG_OPTIMIZED_LOCATIONS | MSG_ALL_PRIORITIES);
>      dump_printf_loc (MSG_NOTE, stmt, "msg 1\n");
>      {
> diff --git a/gcc/dumpfile.h b/gcc/dumpfile.h
> index 5933905..c82157d 100644
> --- a/gcc/dumpfile.h
> +++ b/gcc/dumpfile.h
> @@ -179,15 +179,22 @@ enum dump_flag
>    /* Implicitly supplied for messages within nested dump scopes.  */
>    MSG_PRIORITY_INTERNALS = (1 << 26),
>  
> +  /* Supplied when an opt_problem generated in a nested scope is re-emitted
> +     at the top-level.   We want to default to showing these in -fopt-info
> +     output, but to *not* show them in dump files, as the message would be
> +     shown twice, messing up "scan-tree-dump-times" in DejaGnu tests.  */
> +  MSG_PRIORITY_REEMITTED = (1 << 27),
> +
>    /* Mask for selecting MSG_PRIORITY_* flags.  */
>    MSG_ALL_PRIORITIES = (MSG_PRIORITY_USER_FACING
> -			| MSG_PRIORITY_INTERNALS),
> +			| MSG_PRIORITY_INTERNALS
> +			| MSG_PRIORITY_REEMITTED),
>  
>    /* Dumping for -fcompare-debug.  */
> -  TDF_COMPARE_DEBUG = (1 << 27),
> +  TDF_COMPARE_DEBUG = (1 << 28),
>  
>    /* All values.  */
> -  TDF_ALL_VALUES = (1 << 28) - 1
> +  TDF_ALL_VALUES = (1 << 29) - 1
>  };
>  
>  /* Dump flags type.  */
> diff --git a/gcc/opt-problem.cc b/gcc/opt-problem.cc
> new file mode 100644
> index 0000000..dad3a8c
> --- /dev/null
> +++ b/gcc/opt-problem.cc
> @@ -0,0 +1,335 @@
> +/* Rich optional 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 "tree.h"
> +#include "gimple.h"
> +#include "pretty-print.h"
> +#include "opt-problem.h"
> +#include "dump-context.h"
> +#include "tree-pass.h"
> +#include "selftest.h"
> +
> +/* opt_problem's ctor.
> +
> +   Use FMT and AP to emit a message to the "immediate" dump destinations
> +   as if via:
> +     dump_printf_loc (MSG_MISSED_OPTIMIZATION, loc, ...)
> +
> +   The optinfo_item instances are not emitted yet.  Instead, they
> +   are retained internally so that the message can be replayed and
> +   emitted when this problem is handled, higher up the call stack.  */
> +
> +opt_problem::opt_problem (const dump_location_t &loc,
> +			  const char *fmt, va_list *ap)
> +: m_optinfo (loc, OPTINFO_KIND_FAILURE, current_pass)
> +{
> +  /* We shouldn't be bothering to construct these objects if
> +     dumping isn't enabled.  */
> +  gcc_assert (dump_enabled_p ());
> +
> +  /* Update the singleton.  */
> +  delete s_the_problem;
> +  s_the_problem = this;
> +
> +  /* Print the location to the "immediate" dump destinations.  */
> +  dump_context &dc = dump_context::get ();
> +  dc.dump_loc (MSG_MISSED_OPTIMIZATION, loc);
> +
> +  /* Print the formatted string to this opt_problem's optinfo, dumping
> +     the items to the "immediate" dump destinations, and storing items
> +     for later retrieval.  */
> +  {
> +    dump_pretty_printer pp (&dump_context::get (), MSG_MISSED_OPTIMIZATION);
> +
> +    text_info text;
> +    text.err_no = errno;
> +    text.args_ptr = ap;
> +    text.format_spec = fmt; /* No i18n is performed.  */
> +
> +    /* Phases 1 and 2, using pp_format.  */
> +    pp_format (&pp, &text);
> +
> +    /* Phase 3: dump the items to the "immediate" dump destinations,
> +       and storing them into m_optinfo for later retrieval.  */
> +    pp.emit_items (&m_optinfo);
> +  }
> +}
> +
> +/* Emit this problem and delete it, clearing the current opt_problem.  */
> +
> +void
> +opt_problem::emit_and_clear ()
> +{
> +  gcc_assert (this == s_the_problem);
> +
> +  m_optinfo.emit_for_opt_problem ();
> +
> +  delete this;
> +  s_the_problem = NULL;
> +}
> +
> +/* The singleton opt_problem *.  */
> +
> +opt_problem *opt_problem::s_the_problem;
> +
> +#if CHECKING_P
> +
> +namespace selftest {
> +
> +static opt_result
> +function_that_succeeds ()
> +{
> +  return opt_result::success ();
> +}
> +
> +/* Verify that opt_result::success works.  */
> +
> +static void
> +test_opt_result_success ()
> +{
> +  /* Run all tests twice, with and then without dumping enabled.  */
> +  for (int i = 0 ; i < 2; i++)
> +    {
> +      bool with_dumping = (i == 0);
> +
> +      temp_dump_context tmp (with_dumping, with_dumping,
> +			     MSG_ALL_KINDS | MSG_ALL_PRIORITIES);
> +
> +      if (with_dumping)
> +	gcc_assert (dump_enabled_p ());
> +      else
> +	gcc_assert (!dump_enabled_p ());
> +
> +      opt_result res = function_that_succeeds ();
> +
> +      /* Verify that "success" can be used as a "true" boolean.  */
> +      ASSERT_TRUE (res);
> +
> +      /* Verify the underlying opt_wrapper<bool>.  */
> +      ASSERT_TRUE (res.get_result ());
> +      ASSERT_EQ (res.get_problem (), NULL);
> +
> +      /* Nothing should have been dumped.  */
> +      ASSERT_DUMPED_TEXT_EQ (tmp, "");
> +      optinfo *info = tmp.get_pending_optinfo ();
> +      ASSERT_EQ (info, NULL);
> +    }
> +}
> +
> +/* Example of a function that fails, with a non-trivial
> +   pre-canned error message.  */
> +
> +static opt_result
> +function_that_fails (const greturn *stmt)
> +{
> +  gcc_assert (stmt);
> +  gcc_assert (gimple_return_retval (stmt));
> +
> +  AUTO_DUMP_SCOPE ("function_that_fails", stmt);
> +
> +  return opt_result::failure_at (stmt,
> +				 "can't handle return type: %T for stmt: %G",
> +				 TREE_TYPE (gimple_return_retval (stmt)),
> +				 static_cast <const gimple *> (stmt));
> +}
> +
> +/* Example of a function that indirectly fails.  */
> +
> +static opt_result
> +function_that_indirectly_fails (const greturn *stmt)
> +{
> +  AUTO_DUMP_SCOPE ("function_that_indirectly_fails", stmt);
> +
> +  opt_result res = function_that_fails (stmt);
> +  if (!res)
> +    return res;
> +  return opt_result::success ();
> +}
> +
> +/* Verify that opt_result::failure_at works.
> +   Simulate a failure handling a stmt at one location whilst considering
> +   an optimization that's notionally at another location (as a microcosm
> +   of e.g. a problematic statement within a loop that prevents loop
> +   vectorization).  */
> +
> +static void
> +test_opt_result_failure_at (const line_table_case &case_)
> +{
> +  /* Generate a location_t for testing.  */
> +  line_table_test ltt (case_);
> +  const line_map_ordinary *ord_map
> +    = linemap_check_ordinary (linemap_add (line_table, LC_ENTER, false,
> +					   "test.c", 0));
> +  linemap_line_start (line_table, 5, 100);
> +
> +  /* A test location: "test.c:5:10".  */
> +  const location_t line_5 = linemap_position_for_column (line_table, 10);
> +
> +  /* Another test location: "test.c:6:12".  */
> +  const location_t line_6
> +    = linemap_position_for_line_and_column (line_table, ord_map, 6, 12);
> +
> +  if (line_6 > LINE_MAP_MAX_LOCATION_WITH_COLS)
> +    return;
> +
> +  /* Generate statements using "line_5" and "line_6" for testing.  */
> +  greturn *stmt_at_5 = gimple_build_return (integer_one_node);
> +  gimple_set_location (stmt_at_5, line_5);
> +
> +  greturn *stmt_at_6 = gimple_build_return (integer_zero_node);
> +  gimple_set_location (stmt_at_6, line_6);
> +
> +  /* Run with and then without dumping enabled.  */
> +  for (int i = 0; i < 2; i++)
> +    {
> +      bool with_dumping = (i == 0);
> +
> +      /* Run with all 4 combinations of
> +	 with and without MSG_PRIORITY_INTERNALS and
> +	 with and without MSG_PRIORITY_REEMITTED.  */
> +      for (int j = 0; j < 4; j++)
> +	{
> +	  dump_flags_t filter = MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING;
> +	  if (j / 2)
> +	    filter |= MSG_PRIORITY_INTERNALS;
> +	  if (j % 2)
> +	    filter |= MSG_PRIORITY_REEMITTED;
> +
> +	  temp_dump_context tmp (with_dumping, with_dumping, filter);
> +
> +	  if (with_dumping)
> +	    gcc_assert (dump_enabled_p ());
> +	  else
> +	    gcc_assert (!dump_enabled_p ());
> +
> +	  /* Simulate attempting to optimize "stmt_at_6".  */
> +	  opt_result res = function_that_indirectly_fails (stmt_at_6);
> +
> +	  /* Verify that "failure" can be used as a "false" boolean.  */
> +	  ASSERT_FALSE (res);
> +
> +	  /* Verify the underlying opt_wrapper<bool>.  */
> +	  ASSERT_FALSE (res.get_result ());
> +	  opt_problem *problem = res.get_problem ();
> +
> +	  if (with_dumping)
> +	    {
> +	      ASSERT_NE (problem, NULL);
> +	      ASSERT_EQ (problem->get_dump_location ().get_location_t (),
> +			 line_6);
> +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)
> +	      /* Verify that the problem captures the implementation location
> +		 it was emitted from.  */
> +	      const dump_impl_location_t &impl_location
> +		= problem->get_dump_location ().get_impl_location ();
> +	      ASSERT_STR_CONTAINS (impl_location.m_function,
> +				   "function_that_fails");
> +#endif
> +
> +	      /* Verify that the underlying dump items are retained in the
> +		 opt_problem.  */
> +	      const optinfo &info = problem->get_optinfo ();
> +	      ASSERT_EQ (info.get_dump_location ().get_location_t (), line_6);
> +	      ASSERT_EQ (info.num_items (), 4);
> +	      ASSERT_IS_TEXT (info.get_item (0), "can't handle return type: ");
> +	      ASSERT_IS_TREE (info.get_item (1), UNKNOWN_LOCATION, "int");
> +	      ASSERT_IS_TEXT (info.get_item (2), " for stmt: ");
> +	      ASSERT_IS_GIMPLE (info.get_item (3), line_6, "return 0;\n");
> +
> +	      /* ...but not in the dump_context's pending_optinfo.  */
> +	      ASSERT_EQ (tmp.get_pending_optinfo (), NULL);
> +
> +	      /* Simulate emitting a high-level summary message, followed
> +		 by the problem.  */
> +	      dump_printf_loc (MSG_MISSED_OPTIMIZATION, stmt_at_5,
> +			       "can't optimize loop\n");
> +	      problem->emit_and_clear ();
> +	      ASSERT_EQ (res.get_problem (), NULL);
> +
> +	      /* Verify that the error message was dumped (when the failure
> +		 occurred).  We can't use a switch here as not all of the
> +		 values are const expressions (using C++98).  */
> +	      dump_flags_t effective_filter
> +		= filter & (MSG_PRIORITY_INTERNALS | MSG_PRIORITY_REEMITTED);
> +	      if (effective_filter
> +		  == (MSG_PRIORITY_INTERNALS | MSG_PRIORITY_REEMITTED))
> +		/* The -fopt-info-internals case.  */
> +		ASSERT_DUMPED_TEXT_EQ
> +		  (tmp,
> +		   "test.c:6:12: note:  === function_that_indirectly_fails"
> +		   " ===\n"
> +		   "test.c:6:12: note:   === function_that_fails ===\n"
> +		   "test.c:6:12: missed:   can't handle return type: int"
> +		   " for stmt: return 0;\n"
> +		   "test.c:5:10: missed: can't optimize loop\n"
> +		   "test.c:6:12: missed: can't handle return type: int"
> +		   " for stmt: return 0;\n");
> +	      else if (effective_filter == MSG_PRIORITY_INTERNALS)
> +		/* The default for dump files.  */
> +		ASSERT_DUMPED_TEXT_EQ
> +		  (tmp,
> +		   "test.c:6:12: note:  === function_that_indirectly_fails"
> +		   " ===\n"
> +		   "test.c:6:12: note:   === function_that_fails ===\n"
> +		   "test.c:6:12: missed:   can't handle return type: int"
> +		     " for stmt: return 0;\n"
> +		   "test.c:5:10: missed: can't optimize loop\n");
> +	      else if (effective_filter == MSG_PRIORITY_REEMITTED)
> +		/* The default when -fopt-info is enabled.  */
> +		ASSERT_DUMPED_TEXT_EQ
> +		  (tmp,
> +		   "test.c:5:10: missed: can't optimize loop\n"
> +		   "test.c:6:12: missed: can't handle return type: int"
> +		   " for stmt: return 0;\n");
> +	      else
> +		{
> +		  gcc_assert (effective_filter == 0);
> +		  ASSERT_DUMPED_TEXT_EQ
> +		    (tmp,
> +		     "test.c:5:10: missed: can't optimize loop\n");
> +		}
> +	    }
> +	  else
> +	    {
> +	      /* If dumping was disabled, then no problem should have been
> +		 created, and nothing should have been dumped.  */
> +	      ASSERT_EQ (problem, NULL);
> +	      ASSERT_DUMPED_TEXT_EQ (tmp, "");
> +	    }
> +	}
> +    }
> +}
> +
> +/* Run all of the selftests within this file.  */
> +
> +void
> +opt_problem_cc_tests ()
> +{
> +  test_opt_result_success ();
> +  for_each_line_table_case (test_opt_result_failure_at);
> +}
> +
> +} // namespace selftest
> +
> +#endif /* CHECKING_P */
> diff --git a/gcc/opt-problem.h b/gcc/opt-problem.h
> new file mode 100644
> index 0000000..68d7e4a
> --- /dev/null
> +++ b/gcc/opt-problem.h
> @@ -0,0 +1,289 @@
> +/* 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
> +
> +#include "diagnostic-core.h" /* for ATTRIBUTE_GCC_DIAG.  */
> +#include "optinfo.h" /* for optinfo.  */
> +
> +/* This header declares a family of wrapper classes for tracking a
> +   success/failure value, while optionally supporting propagating an
> +   opt_problem * describing any failure back up the call stack.
> +
> +   For instance, at the deepest point of the callstack where the failure
> +   happens, rather than:
> +
> +     if (!check_something ())
> +       {
> +         if (dump_enabled_p ())
> +           dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> +                            "foo is unsupported.\n");
> +         return false;
> +       }
> +     // [...more checks...]
> +
> +     // All checks passed:
> +     return true;
> +
> +   we can capture the cause of the failure via:
> +
> +     if (!check_something ())
> +       return opt_result::failure_at (stmt, "foo is unsupported");
> +     // [...more checks...]
> +
> +     // All checks passed:
> +     return opt_result::success ();
> +
> +   which effectively returns true or false, whilst recording any problem.
> +
> +   opt_result::success and opt_result::failure return opt_result values
> +   which "looks like" true/false respectively, via operator bool().
> +   If dump_enabled_p, then opt_result::failure also creates an opt_problem *,
> +   capturing the pertinent data (here, "foo is unsupported " and "stmt").
> +   If dumps are disabled, then opt_problem instances aren't
> +   created, and it's equivalent to just returning a bool.
> +
> +   The opt_problem can be propagated via opt_result values back up
> +   the call stack to where it makes most sense to the user.
> +   For instance, rather than:
> +
> +     bool ok = try_something_that_might_fail ();
> +     if (!ok)
> +       {
> +         if (dump_enabled_p ())
> +           dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> +                            "some message.\n");
> +         return false;
> +       }
> +
> +   we can replace the bool with an opt_result, so if dump_enabled_p, we
> +   assume that if try_something_that_might_fail, an opt_problem * will be
> +   created, and we can propagate it up the call chain:
> +
> +     opt_result ok = try_something_that_might_fail ();
> +     if (!ok)
> +       {
> +         if (dump_enabled_p ())
> +           dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> +                            "some message.\n");
> +         return ok; // propagating the opt_result
> +       }
> +
> +   opt_result is an opt_wrapper<bool>, where opt_wrapper<T> is a base
> +   class for wrapping a T, optionally propagating an opt_problem in
> +   case of failure_at (when dumps are enabled).  Similarly,
> +   opt_pointer_wrapper<T> can be used to wrap pointer types (where non-NULL
> +   signifies success, NULL signifies failure).
> +
> +   In all cases, opt_wrapper<T> acts as if the opt_problem were one of its
> +   fields, but the opt_problem is actually stored in a global, so that when
> +   compiled, an opt_wrapper<T> is effectively just a T, so that we're
> +   still just passing e.g. a bool around; the opt_wrapper<T> classes
> +   simply provide type-checking and an API to ensure that we provide
> +   error-messages deep in the callstack at the places where problems
> +   occur, and that we propagate them.  This also avoids having
> +   to manage the ownership of the opt_problem instances.
> +
> +   Using opt_result and opt_wrapper<T> documents the intent of the code
> +   for the places where we represent success values, and allows the C++ type
> +   system to track where the deepest points in the callstack are where we
> +   need to emit the failure messages from.  */
> +
> +/* A bundle of information about why an optimization failed (e.g.
> +   vectorization), and the location in both the user's code and
> +   in GCC itself where the problem occurred.
> +
> +   Instances are created by static member functions in opt_wrapper
> +   subclasses, such as opt_result::failure.
> +
> +   Instances are only created when dump_enabled_p ().  */
> +
> +class opt_problem
> +{
> + public:
> +  static opt_problem *get_singleton () { return s_the_problem; }
> +
> +  opt_problem (const dump_location_t &loc,
> +	       const char *fmt, va_list *ap)
> +    ATTRIBUTE_GCC_DUMP_PRINTF (3, 0);
> +
> +  const dump_location_t &
> +  get_dump_location () const { return m_optinfo.get_dump_location (); }
> +
> +  const optinfo & get_optinfo () const { return m_optinfo; }
> +
> +  void emit_and_clear ();
> +
> + private:
> +  optinfo m_optinfo;
> +
> +  static opt_problem *s_the_problem;
> +};
> +
> +/* A base class for wrapper classes that track a success/failure value, while
> +   optionally supporting propagating an opt_problem * describing any
> +   failure back up the call stack.  */
> +
> +template <typename T>
> +class opt_wrapper
> +{
> + public:
> +  typedef T wrapped_t;
> +
> +  /* Be accessible as the wrapped type.  */
> +  operator wrapped_t () const { return m_result; }
> +
> +  /* No public ctor.  */
> +
> +  wrapped_t get_result () const { return m_result; }
> +  opt_problem *get_problem () const { return opt_problem::get_singleton (); }
> +
> + protected:
> +  opt_wrapper (wrapped_t result, opt_problem */*problem*/)
> +  : m_result (result)
> +  {
> +    /* "problem" is ignored: although it looks like a field, we
> +       actually just use the opt_problem singleton, so that
> +       opt_wrapper<T> in memory is just a T.  */
> +  }
> +
> + private:
> +  wrapped_t m_result;
> +};
> +
> +/* Subclass of opt_wrapper<T> for bool, where
> +   - true signifies "success", and
> +   - false signifies "failure"
> +   whilst effectively propagating an opt_problem * describing any failure
> +   back up the call stack.  */
> +
> +class opt_result : public opt_wrapper <bool>
> +{
> + public:
> +  /* Generate a "success" value: a wrapper around "true".  */
> +
> +  static opt_result success () { return opt_result (true, NULL); }
> +
> +  /* Generate a "failure" value: a wrapper around "false", and,
> +     if dump_enabled_p, an opt_problem.  */
> +
> +  static opt_result failure_at (const dump_location_t &loc,
> +				const char *fmt, ...)
> +	  ATTRIBUTE_GCC_DUMP_PRINTF (2, 3)
> +  {
> +    opt_problem *problem = NULL;
> +    if (dump_enabled_p ())
> +      {
> +	va_list ap;
> +	va_start (ap, fmt);
> +	problem = new opt_problem (loc, fmt, &ap);
> +	va_end (ap);
> +      }
> +    return opt_result (false, problem);
> +  }
> +
> +  /* Given a failure wrapper of some other kind, make an opt_result failure
> +     object, for propagating the opt_problem up the call stack.  */
> +
> +  template <typename S>
> +  static opt_result
> +  propagate_failure (opt_wrapper <S> other)
> +  {
> +    return opt_result (false, other.get_problem ());
> +  }
> +
> + private:
> +  /* Private ctor.  Instances should be created by the success and failure
> +     static member functions.  */
> +  opt_result (wrapped_t result, opt_problem *problem)
> +  : opt_wrapper (result, problem)
> +  {}
> +};
> +
> +/* Subclass of opt_wrapper<T> where T is a pointer type, for tracking
> +   success/failure, where:
> +   - a non-NULL value signifies "success", and
> +   - a NULL value signifies "failure",
> +   whilst effectively propagating an opt_problem * describing any failure
> +   back up the call stack.  */
> +
> +template <typename PtrType_t>
> +class opt_pointer_wrapper : public opt_wrapper <PtrType_t>
> +{
> + public:
> +  typedef PtrType_t wrapped_pointer_t;
> +
> +  /* Given a non-NULL pointer, make a success object wrapping it.  */
> +
> +  static opt_pointer_wrapper <wrapped_pointer_t>
> +  success (wrapped_pointer_t ptr)
> +  {
> +    return opt_pointer_wrapper <wrapped_pointer_t> (ptr, NULL);
> +  }
> +
> +  /* Make a NULL pointer failure object, with the given message
> +     (if dump_enabled_p).  */
> +
> +  static opt_pointer_wrapper <wrapped_pointer_t>
> +  failure_at (const dump_location_t &loc,
> +	      const char *fmt, ...)
> +    ATTRIBUTE_GCC_DUMP_PRINTF (2, 3)
> +  {
> +    opt_problem *problem = NULL;
> +    if (dump_enabled_p ())
> +      {
> +	va_list ap;
> +	va_start (ap, fmt);
> +	problem = new opt_problem (loc, fmt, &ap);
> +	va_end (ap);
> +      }
> +    return opt_pointer_wrapper <wrapped_pointer_t> (NULL, problem);
> +  }
> +
> +  /* Given a failure wrapper of some other kind, make a NULL pointer
> +     failure object, propagating the problem.  */
> +
> +  template <typename S>
> +  static opt_pointer_wrapper <wrapped_pointer_t>
> +  propagate_failure (opt_wrapper <S> other)
> +  {
> +    return opt_pointer_wrapper <wrapped_pointer_t> (NULL,
> +						    other.get_problem ());
> +  }
> +
> +  /* Support accessing the underlying pointer via ->.  */
> +
> +  wrapped_pointer_t operator-> () const { return this->get_result (); }
> +
> + private:
> +  /* Private ctor.  Instances should be built using the static member
> +     functions "success" and "failure".  */
> +  opt_pointer_wrapper (wrapped_pointer_t result, opt_problem *problem)
> +  : opt_wrapper<PtrType_t> (result, problem)
> +  {}
> +};
> +
> +/* A typedef for wrapping "tree" so that NULL_TREE can carry an
> +   opt_problem describing the failure (if dump_enabled_p).  */
> +
> +typedef opt_pointer_wrapper<tree> opt_tree;
> +
> +#endif /* #ifndef GCC_OPT_PROBLEM_H */
> diff --git a/gcc/optinfo-emit-json.cc b/gcc/optinfo-emit-json.cc
> index efdbdb3..31029ad 100644
> --- a/gcc/optinfo-emit-json.cc
> +++ b/gcc/optinfo-emit-json.cc
> @@ -531,7 +531,7 @@ namespace selftest {
>  static void
>  test_building_json_from_dump_calls ()
>  {
> -  temp_dump_context tmp (true, MSG_NOTE);
> +  temp_dump_context tmp (true, true, MSG_NOTE);
>    dump_location_t loc;
>    dump_printf_loc (MSG_NOTE, loc, "test of tree: ");
>    dump_generic_expr (MSG_NOTE, TDF_SLIM, integer_zero_node);
> diff --git a/gcc/optinfo.cc b/gcc/optinfo.cc
> index b858c3c..de781a5 100644
> --- a/gcc/optinfo.cc
> +++ b/gcc/optinfo.cc
> @@ -89,11 +89,51 @@ optinfo::add_item (optinfo_item *item)
>    m_items.safe_push (item);
>  }
>  
> +/* Get MSG_* flags corresponding to KIND.  */
> +
> +static dump_flags_t
> +optinfo_kind_to_dump_flag (enum optinfo_kind kind)
> +{
> +  switch (kind)
> +    {
> +    default:
> +      gcc_unreachable ();
> +    case OPTINFO_KIND_SUCCESS:
> +      return MSG_OPTIMIZED_LOCATIONS;
> +    case OPTINFO_KIND_FAILURE:
> +      return MSG_MISSED_OPTIMIZATION;
> +    case OPTINFO_KIND_NOTE:
> +    case OPTINFO_KIND_SCOPE:
> +      return MSG_NOTE;
> +    }
> +}
> +
> +/* Re-emit this optinfo, both to the "non-immediate" destinations,
> +   *and* to the "immediate" destinations.  */
> +
> +void
> +optinfo::emit_for_opt_problem () const
> +{
> +  dump_flags_t dump_kind = optinfo_kind_to_dump_flag (get_kind ());
> +  dump_kind |= MSG_PRIORITY_REEMITTED;
> +
> +  /* Re-emit to "immediate" destinations, without creating a new optinfo.  */
> +  dump_context::get ().dump_loc_immediate (dump_kind, get_dump_location ());
> +  unsigned i;
> +  optinfo_item *item;
> +  FOR_EACH_VEC_ELT (m_items, i, item)
> +    dump_context::get ().emit_item (item, dump_kind);
> +
> +  /* Re-emit to "non-immediate" destinations.  */
> +  emit ();
> +}
> +
>  /* Emit the optinfo to all of the "non-immediate" destinations
> -   (emission to "immediate" destinations is done by emit_item).  */
> +   (emission to "immediate" destinations is done by
> +   dump_context::emit_item).  */
>  
>  void
> -optinfo::emit ()
> +optinfo::emit () const
>  {
>    /* -fsave-optimization-record.  */
>    optimization_records_maybe_record_optinfo (this);
> diff --git a/gcc/optinfo.h b/gcc/optinfo.h
> index 8ac961c..99bd22c 100644
> --- a/gcc/optinfo.h
> +++ b/gcc/optinfo.h
> @@ -108,6 +108,9 @@ class optinfo
>    {}
>    ~optinfo ();
>  
> +  const dump_location_t &
> +  get_dump_location () const { return m_loc; }
> +
>    const dump_user_location_t &
>    get_user_location () const { return m_loc.get_user_location (); }
>  
> @@ -124,8 +127,10 @@ class optinfo
>  
>    void add_item (optinfo_item *item);
>  
> +  void emit_for_opt_problem () const;
> +
>   private:
> -  void emit ();
> +  void emit () const;
>  
>    /* Pre-canned ways of manipulating the optinfo, for use by friend class
>       dump_context.  */
> diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c
> index 5adb033..562ada7 100644
> --- a/gcc/selftest-run-tests.c
> +++ b/gcc/selftest-run-tests.c
> @@ -74,6 +74,7 @@ selftest::run_tests ()
>    opt_proposer_c_tests ();
>    json_cc_tests ();
>    optinfo_emit_json_cc_tests ();
> +  opt_problem_cc_tests ();
>  
>    /* Mid-level data structures.  */
>    input_c_tests ();
> diff --git a/gcc/selftest.h b/gcc/selftest.h
> index ede7732..8da7c4a 100644
> --- a/gcc/selftest.h
> +++ b/gcc/selftest.h
> @@ -229,6 +229,7 @@ extern void hash_map_tests_c_tests ();
>  extern void hash_set_tests_c_tests ();
>  extern void input_c_tests ();
>  extern void json_cc_tests ();
> +extern void opt_problem_cc_tests ();
>  extern void optinfo_emit_json_cc_tests ();
>  extern void predict_c_tests ();
>  extern void pretty_print_c_tests ();
> diff --git a/gcc/testsuite/gcc.dg/vect/nodump-vect-opt-info-2.c b/gcc/testsuite/gcc.dg/vect/nodump-vect-opt-info-2.c
> new file mode 100644
> index 0000000..94c55a9
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/vect/nodump-vect-opt-info-2.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile { target vect_int } } */
> +/* { dg-additional-options "-fopt-info-vec-all -O3" } */
> +
> +extern void accumulate (int x, int *a);
> +
> +int test_missing_function_defn (int *arr, int n) /* { dg-message "vectorized 0 loops in function" } */
> +{
> +  int sum = 0;
> +  for (int i = 0; i < n; ++i) /* { dg-missed "couldn't vectorize loop" } */
> +    accumulate (arr[i], &sum); /* { dg-missed "statement clobbers memory: accumulate \\(.*\\);" } */
> +  return sum;
> +}
> diff --git a/gcc/testsuite/gcc.dg/vect/vect-alias-check-4.c b/gcc/testsuite/gcc.dg/vect/vect-alias-check-4.c
> index 1e5fc27..750193e 100644
> --- a/gcc/testsuite/gcc.dg/vect/vect-alias-check-4.c
> +++ b/gcc/testsuite/gcc.dg/vect/vect-alias-check-4.c
> @@ -1,6 +1,6 @@
>  /* { dg-do compile } */
>  /* { dg-require-effective-target vect_int } */
> -/* { dg-additional-options "--param vect-max-version-for-alias-checks=0" } */
> +/* { dg-additional-options "--param vect-max-version-for-alias-checks=0 -fopt-info-vec-all" } */
>  
>  #define N 16
>  
> @@ -12,24 +12,26 @@ union u { struct s2 f; struct s3 g; };
>  /* We allow a and b to overlap arbitrarily.  */
>  
>  void
> -f1 (int a[][N], int b[][N])
> +f1 (int a[][N], int b[][N]) /* { dg-message "vectorized 0 loops in function" } */
>  {
> -  for (int i = 0; i < N; ++i)
> +  for (int i = 0; i < N; ++i) /* { dg-missed "couldn't vectorize loop" } */
>      a[0][i] += b[0][i];
> +  /* { dg-message "will not create alias checks, as --param vect-max-version-for-alias-checks == 0" "" { target *-*-* } .-2 } */
>  }
>  
>  void
> -f2 (union u *a, union u *b)
> +f2 (union u *a, union u *b) /* { dg-message "vectorized 0 loops in function" } */
>  {
> -  for (int i = 0; i < N; ++i)
> +  for (int i = 0; i < N; ++i) /* { dg-missed "couldn't vectorize loop" } */
>      a->f.b.a[i] += b->g.e.a[i];
> +  /* { dg-message "will not create alias checks, as --param vect-max-version-for-alias-checks == 0" "" { target *-*-* } .-2 } */
>  }
>  
>  void
> -f3 (struct s1 *a, struct s1 *b)
> +f3 (struct s1 *a, struct s1 *b) /* { dg-message "vectorized 0 loops in function" } */
>  {
> -  for (int i = 0; i < N - 1; ++i)
> -    a->a[i + 1] += b->a[i];
> +  for (int i = 0; i < N - 1; ++i) /* { dg-missed "couldn't vectorize loop" } */
> +    a->a[i + 1] += b->a[i]; /* { dg-missed "possible dependence between data-refs" } */
>  }
>  
>  /* { dg-final { scan-tree-dump-not "LOOP VECTORIZED" "vect" } } */
> diff --git a/gcc/tree-data-ref.c b/gcc/tree-data-ref.c
> index bf30a61..69c5f7b 100644
> --- a/gcc/tree-data-ref.c
> +++ b/gcc/tree-data-ref.c
> @@ -807,7 +807,8 @@ canonicalize_base_object_address (tree addr)
>    return build_fold_addr_expr (TREE_OPERAND (addr, 0));
>  }
>  
> -/* Analyze the behavior of memory reference REF.  There are two modes:
> +/* Analyze the behavior of memory reference REF within STMT.
> +   There are two modes:
>  
>     - BB analysis.  In this case we simply split the address into base,
>       init and offset components, without reference to any containing loop.
> @@ -827,9 +828,9 @@ canonicalize_base_object_address (tree addr)
>     Return true if the analysis succeeded and store the results in DRB if so.
>     BB analysis can only fail for bitfield or reversed-storage accesses.  */
>  
> -bool
> +opt_result
>  dr_analyze_innermost (innermost_loop_behavior *drb, tree ref,
> -		      struct loop *loop)
> +		      struct loop *loop, const gimple *stmt)
>  {
>    poly_int64 pbitsize, pbitpos;
>    tree base, poffset;
> @@ -848,18 +849,12 @@ dr_analyze_innermost (innermost_loop_behavior *drb, tree ref,
>  
>    poly_int64 pbytepos;
>    if (!multiple_p (pbitpos, BITS_PER_UNIT, &pbytepos))
> -    {
> -      if (dump_file && (dump_flags & TDF_DETAILS))
> -	fprintf (dump_file, "failed: bit offset alignment.\n");
> -      return false;
> -    }
> +    return opt_result::failure_at (stmt,
> +				   "failed: bit offset alignment.\n");
>  
>    if (preversep)
> -    {
> -      if (dump_file && (dump_flags & TDF_DETAILS))
> -	fprintf (dump_file, "failed: reverse storage order.\n");
> -      return false;
> -    }
> +    return opt_result::failure_at (stmt,
> +				   "failed: reverse storage order.\n");
>  
>    /* Calculate the alignment and misalignment for the inner reference.  */
>    unsigned int HOST_WIDE_INT bit_base_misalignment;
> @@ -895,11 +890,8 @@ dr_analyze_innermost (innermost_loop_behavior *drb, tree ref,
>    if (in_loop)
>      {
>        if (!simple_iv (loop, loop, base, &base_iv, true))
> -        {
> -	  if (dump_file && (dump_flags & TDF_DETAILS))
> -	    fprintf (dump_file, "failed: evolution of base is not affine.\n");
> -	  return false;
> -        }
> +	return opt_result::failure_at
> +	  (stmt, "failed: evolution of base is not affine.\n");
>      }
>    else
>      {
> @@ -921,11 +913,8 @@ dr_analyze_innermost (innermost_loop_behavior *drb, tree ref,
>            offset_iv.step = ssize_int (0);
>          }
>        else if (!simple_iv (loop, loop, poffset, &offset_iv, true))
> -        {
> -	  if (dump_file && (dump_flags & TDF_DETAILS))
> -	    fprintf (dump_file, "failed: evolution of offset is not affine.\n");
> -	  return false;
> -        }
> +	return opt_result::failure_at
> +	  (stmt, "failed: evolution of offset is not affine.\n");
>      }
>  
>    init = ssize_int (pbytepos);
> @@ -981,7 +970,7 @@ dr_analyze_innermost (innermost_loop_behavior *drb, tree ref,
>    if (dump_file && (dump_flags & TDF_DETAILS))
>      fprintf (dump_file, "success.\n");
>  
> -  return true;
> +  return opt_result::success ();
>  }
>  
>  /* Return true if OP is a valid component reference for a DR access
> @@ -1205,7 +1194,7 @@ create_data_ref (edge nest, loop_p loop, tree memref, gimple *stmt,
>    DR_IS_CONDITIONAL_IN_STMT (dr) = is_conditional_in_stmt;
>  
>    dr_analyze_innermost (&DR_INNERMOST (dr), memref,
> -			nest != NULL ? loop : NULL);
> +			nest != NULL ? loop : NULL, stmt);
>    dr_analyze_indices (dr, nest, loop);
>    dr_analyze_alias (dr);
>  
> @@ -1318,7 +1307,7 @@ data_ref_compare_tree (tree t1, tree t2)
>  /* Return TRUE it's possible to resolve data dependence DDR by runtime alias
>     check.  */
>  
> -bool
> +opt_result
>  runtime_alias_check_p (ddr_p ddr, struct loop *loop, bool speed_p)
>  {
>    if (dump_enabled_p ())
> @@ -1327,25 +1316,18 @@ runtime_alias_check_p (ddr_p ddr, struct loop *loop, bool speed_p)
>  		 DR_REF (DDR_A (ddr)), DR_REF (DDR_B (ddr)));
>  
>    if (!speed_p)
> -    {
> -      if (dump_enabled_p ())
> -	dump_printf (MSG_MISSED_OPTIMIZATION,
> -		     "runtime alias check not supported when optimizing "
> -		     "for size.\n");
> -      return false;
> -    }
> +    return opt_result::failure_at (DR_STMT (DDR_A (ddr)),
> +				   "runtime alias check not supported when"
> +				   " optimizing for size.\n");
>  
>    /* FORNOW: We don't support versioning with outer-loop in either
>       vectorization or loop distribution.  */
>    if (loop != NULL && loop->inner != NULL)
> -    {
> -      if (dump_enabled_p ())
> -	dump_printf (MSG_MISSED_OPTIMIZATION,
> -		     "runtime alias check not supported for outer loop.\n");
> -      return false;
> -    }
> +    return opt_result::failure_at (DR_STMT (DDR_A (ddr)),
> +				   "runtime alias check not supported for"
> +				   " outer loop.\n");
>  
> -  return true;
> +  return opt_result::success ();
>  }
>  
>  /* Operator == between two dr_with_seg_len objects.
> @@ -5043,18 +5025,18 @@ loop_nest_has_data_refs (loop_p loop)
>     reference, returns false, otherwise returns true.  NEST is the outermost
>     loop of the loop nest in which the references should be analyzed.  */
>  
> -bool
> +opt_result
>  find_data_references_in_stmt (struct loop *nest, gimple *stmt,
>  			      vec<data_reference_p> *datarefs)
>  {
>    unsigned i;
>    auto_vec<data_ref_loc, 2> references;
>    data_ref_loc *ref;
> -  bool ret = true;
>    data_reference_p dr;
>  
>    if (get_references_in_stmt (stmt, &references))
> -    return false;
> +    return opt_result::failure_at (stmt, "statement clobbers memory: %G",
> +				   stmt);
>  
>    FOR_EACH_VEC_ELT (references, i, ref)
>      {
> @@ -5065,7 +5047,7 @@ find_data_references_in_stmt (struct loop *nest, gimple *stmt,
>        datarefs->safe_push (dr);
>      }
>  
> -  return ret;
> +  return opt_result::success ();
>  }
>  
>  /* Stores the data references in STMT to DATAREFS.  If there is an
> diff --git a/gcc/tree-data-ref.h b/gcc/tree-data-ref.h
> index 8739853..525d27f 100644
> --- a/gcc/tree-data-ref.h
> +++ b/gcc/tree-data-ref.h
> @@ -23,6 +23,7 @@ along with GCC; see the file COPYING3.  If not see
>  
>  #include "graphds.h"
>  #include "tree-chrec.h"
> +#include "opt-problem.h"
>  
>  /*
>    innermost_loop_behavior describes the evolution of the address of the memory
> @@ -421,7 +422,8 @@ typedef struct data_dependence_relation *ddr_p;
>  #define DDR_COULD_BE_INDEPENDENT_P(DDR) (DDR)->could_be_independent_p
>  
>  \f
> -bool dr_analyze_innermost (innermost_loop_behavior *, tree, struct loop *);
> +opt_result dr_analyze_innermost (innermost_loop_behavior *, tree,
> +				 struct loop *, const gimple *);
>  extern bool compute_data_dependences_for_loop (struct loop *, bool,
>  					       vec<loop_p> *,
>  					       vec<data_reference_p> *,
> @@ -443,8 +445,8 @@ extern void free_dependence_relation (struct data_dependence_relation *);
>  extern void free_dependence_relations (vec<ddr_p> );
>  extern void free_data_ref (data_reference_p);
>  extern void free_data_refs (vec<data_reference_p> );
> -extern bool find_data_references_in_stmt (struct loop *, gimple *,
> -					  vec<data_reference_p> *);
> +extern opt_result find_data_references_in_stmt (struct loop *, gimple *,
> +						vec<data_reference_p> *);
>  extern bool graphite_find_data_references_in_stmt (edge, loop_p, gimple *,
>  						   vec<data_reference_p> *);
>  tree find_data_references_in_loop (struct loop *, vec<data_reference_p> *);
> @@ -479,7 +481,7 @@ extern bool dr_may_alias_p (const struct data_reference *,
>  extern bool dr_equal_offsets_p (struct data_reference *,
>                                  struct data_reference *);
>  
> -extern bool runtime_alias_check_p (ddr_p, struct loop *, bool);
> +extern opt_result runtime_alias_check_p (ddr_p, struct loop *, bool);
>  extern int data_ref_compare_tree (tree, tree);
>  extern void prune_runtime_alias_test_list (vec<dr_with_seg_len_pair_t> *,
>  					   poly_uint64);
> diff --git a/gcc/tree-predcom.c b/gcc/tree-predcom.c
> index 2bde732..1711027 100644
> --- a/gcc/tree-predcom.c
> +++ b/gcc/tree-predcom.c
> @@ -1280,7 +1280,8 @@ find_looparound_phi (struct loop *loop, dref ref, dref root)
>    memset (&init_dr, 0, sizeof (struct data_reference));
>    DR_REF (&init_dr) = init_ref;
>    DR_STMT (&init_dr) = phi;
> -  if (!dr_analyze_innermost (&DR_INNERMOST (&init_dr), init_ref, loop))
> +  if (!dr_analyze_innermost (&DR_INNERMOST (&init_dr), init_ref, loop,
> +			     init_stmt))
>      return NULL;
>  
>    if (!valid_initializer_p (&init_dr, ref->distance + 1, root->ref))
> diff --git a/gcc/tree-vect-data-refs.c b/gcc/tree-vect-data-refs.c
> index 56b7968..c4805e7 100644
> --- a/gcc/tree-vect-data-refs.c
> +++ b/gcc/tree-vect-data-refs.c
> @@ -156,20 +156,25 @@ vect_get_smallest_scalar_type (stmt_vec_info stmt_info,
>     tested at run-time.  Return TRUE if DDR was successfully inserted.
>     Return false if versioning is not supported.  */
>  
> -static bool
> +static opt_result
>  vect_mark_for_runtime_alias_test (ddr_p ddr, loop_vec_info loop_vinfo)
>  {
>    struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
>  
>    if ((unsigned) PARAM_VALUE (PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS) == 0)
> -    return false;
> +    return opt_result::failure_at (vect_location,
> +				   "will not create alias checks, as"
> +				   " --param vect-max-version-for-alias-checks"
> +				   " == 0\n");
>  
> -  if (!runtime_alias_check_p (ddr, loop,
> -			      optimize_loop_nest_for_speed_p (loop)))
> -    return false;
> +  opt_result res
> +    = runtime_alias_check_p (ddr, loop,
> +			     optimize_loop_nest_for_speed_p (loop));
> +  if (!res)
> +    return res;
>  
>    LOOP_VINFO_MAY_ALIAS_DDRS (loop_vinfo).safe_push (ddr);
> -  return true;
> +  return opt_result::success ();
>  }
>  
>  /* Record that loop LOOP_VINFO needs to check that VALUE is nonzero.  */
> @@ -277,12 +282,14 @@ vect_analyze_possibly_independent_ddr (data_dependence_relation *ddr,
>  
>  /* Function vect_analyze_data_ref_dependence.
>  
> -   Return TRUE if there (might) exist a dependence between a memory-reference
> +   FIXME: I needed to change the sense of the returned flag.
> +
> +   Return FALSE if there (might) exist a dependence between a memory-reference
>     DRA and a memory-reference DRB.  When versioning for alias may check a
> -   dependence at run-time, return FALSE.  Adjust *MAX_VF according to
> +   dependence at run-time, return TRUE.  Adjust *MAX_VF according to
>     the data dependence.  */
>  
> -static bool
> +static opt_result
>  vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
>  				  loop_vec_info loop_vinfo,
>  				  unsigned int *max_vf)
> @@ -305,11 +312,11 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
>  
>    /* Independent data accesses.  */
>    if (DDR_ARE_DEPENDENT (ddr) == chrec_known)
> -    return false;
> +    return opt_result::success ();
>  
>    if (dra == drb
>        || (DR_IS_READ (dra) && DR_IS_READ (drb)))
> -    return false;
> +    return opt_result::success ();
>  
>    /* We do not have to consider dependences between accesses that belong
>       to the same group, unless the stride could be smaller than the
> @@ -318,7 +325,7 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
>        && (DR_GROUP_FIRST_ELEMENT (stmtinfo_a)
>  	  == DR_GROUP_FIRST_ELEMENT (stmtinfo_b))
>        && !STMT_VINFO_STRIDED_P (stmtinfo_a))
> -    return false;
> +    return opt_result::success ();
>  
>    /* Even if we have an anti-dependence then, as the vectorized loop covers at
>       least two scalar iterations, there is always also a true dependence.
> @@ -330,7 +337,7 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
>         || (DR_IS_WRITE (dra) && DR_IS_READ (drb)))
>        && !alias_sets_conflict_p (get_alias_set (DR_REF (dra)),
>  				 get_alias_set (DR_REF (drb))))
> -    return false;
> +    return opt_result::success ();
>  
>    /* Unknown data dependence.  */
>    if (DDR_ARE_DEPENDENT (ddr) == chrec_dont_know)
> @@ -342,28 +349,25 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
>  	  if ((unsigned int) loop->safelen < *max_vf)
>  	    *max_vf = loop->safelen;
>  	  LOOP_VINFO_NO_DATA_DEPENDENCIES (loop_vinfo) = false;
> -	  return false;
> +	  return opt_result::success ();
>  	}
>  
>        if (STMT_VINFO_GATHER_SCATTER_P (stmtinfo_a)
>  	  || STMT_VINFO_GATHER_SCATTER_P (stmtinfo_b))
> -	{
> -	  if (dump_enabled_p ())
> -	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			     "versioning for alias not supported for: "
> -			     "can't determine dependence between %T and %T\n",
> -			     DR_REF (dra), DR_REF (drb));
> -	  return true;
> -	}
> +	return opt_result::failure_at
> +	  (stmtinfo_a->stmt,
> +	   "versioning for alias not supported for: "
> +	   "can't determine dependence between %T and %T\n",
> +	   DR_REF (dra), DR_REF (drb));
>  
>        if (dump_enabled_p ())
> -	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> +	dump_printf_loc (MSG_MISSED_OPTIMIZATION, stmtinfo_a->stmt,
>  			 "versioning for alias required: "
>  			 "can't determine dependence between %T and %T\n",
>  			 DR_REF (dra), DR_REF (drb));
>  
>        /* Add to list of ddrs that need to be tested at run-time.  */
> -      return !vect_mark_for_runtime_alias_test (ddr, loop_vinfo);
> +      return vect_mark_for_runtime_alias_test (ddr, loop_vinfo);
>      }
>  
>    /* Known data dependence.  */
> @@ -376,27 +380,24 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
>  	  if ((unsigned int) loop->safelen < *max_vf)
>  	    *max_vf = loop->safelen;
>  	  LOOP_VINFO_NO_DATA_DEPENDENCIES (loop_vinfo) = false;
> -	  return false;
> +	  return opt_result::success ();
>  	}
>  
>        if (STMT_VINFO_GATHER_SCATTER_P (stmtinfo_a)
>  	  || STMT_VINFO_GATHER_SCATTER_P (stmtinfo_b))
> -	{
> -	  if (dump_enabled_p ())
> -	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			     "versioning for alias not supported for: "
> -			     "bad dist vector for %T and %T\n",
> -			     DR_REF (dra), DR_REF (drb));
> -	  return true;
> -	}
> +	return opt_result::failure_at
> +	  (stmtinfo_a->stmt,
> +	   "versioning for alias not supported for: "
> +	   "bad dist vector for %T and %T\n",
> +	   DR_REF (dra), DR_REF (drb));
>  
>        if (dump_enabled_p ())
> -	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> +	dump_printf_loc (MSG_MISSED_OPTIMIZATION, stmtinfo_a->stmt,
>  			 "versioning for alias required: "
>  			 "bad dist vector for %T and %T\n",
>  			 DR_REF (dra), DR_REF (drb));
>        /* Add to list of ddrs that need to be tested at run-time.  */
> -      return !vect_mark_for_runtime_alias_test (ddr, loop_vinfo);
> +      return vect_mark_for_runtime_alias_test (ddr, loop_vinfo);
>      }
>  
>    loop_depth = index_in_loop_nest (loop->num, DDR_LOOP_NEST (ddr));
> @@ -404,7 +405,7 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
>    if (DDR_COULD_BE_INDEPENDENT_P (ddr)
>        && vect_analyze_possibly_independent_ddr (ddr, loop_vinfo,
>  						loop_depth, max_vf))
> -    return false;
> +    return opt_result::success ();
>  
>    FOR_EACH_VEC_ELT (DDR_DIST_VECTS (ddr), i, dist_v)
>      {
> @@ -440,23 +441,16 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
>  		a[i+1] = ...;
>  	     where loads from the group interleave with the store.  */
>  	  if (!vect_preserves_scalar_order_p (dr_info_a, dr_info_b))
> -	    {
> -	      if (dump_enabled_p ())
> -		dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -				 "READ_WRITE dependence in interleaving.\n");
> -	      return true;
> -	    }
> +	    return opt_result::failure_at (stmtinfo_a->stmt,
> +					   "READ_WRITE dependence"
> +					   " in interleaving.\n");
>  
>  	  if (loop->safelen < 2)
>  	    {
>  	      tree indicator = dr_zero_step_indicator (dra);
>  	      if (!indicator || integer_zerop (indicator))
> -		{
> -		  if (dump_enabled_p ())
> -		    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -				 "access also has a zero step\n");
> -		  return true;
> -		}
> +		return opt_result::failure_at (stmtinfo_a->stmt,
> +					       "access also has a zero step\n");
>  	      else if (TREE_CODE (indicator) != INTEGER_CST)
>  		vect_check_nonzero_value (loop_vinfo, indicator);
>  	    }
> @@ -503,16 +497,13 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
>  	  continue;
>  	}
>  
> -      if (dump_enabled_p ())
> -	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			 "not vectorized, possible dependence "
> -			 "between data-refs %T and %T\n",
> -			 DR_REF (dra), DR_REF (drb));
> -
> -      return true;
> +      return opt_result::failure_at (stmtinfo_a->stmt,
> +				     "not vectorized, possible dependence "
> +				     "between data-refs %T and %T\n",
> +				     DR_REF (dra), DR_REF (drb));
>      }
>  
> -  return false;
> +  return opt_result::success ();
>  }
>  
>  /* Function vect_analyze_data_ref_dependences.
> @@ -521,7 +512,7 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
>     exist any data dependences between them.  Set *MAX_VF according to
>     the maximum vectorization factor the data dependences allow.  */
>  
> -bool
> +opt_result
>  vect_analyze_data_ref_dependences (loop_vec_info loop_vinfo,
>  				   unsigned int *max_vf)
>  {
> @@ -553,10 +544,14 @@ vect_analyze_data_ref_dependences (loop_vec_info loop_vinfo,
>      *max_vf = LOOP_VINFO_ORIG_MAX_VECT_FACTOR (loop_vinfo);
>    else
>      FOR_EACH_VEC_ELT (LOOP_VINFO_DDRS (loop_vinfo), i, ddr)
> -      if (vect_analyze_data_ref_dependence (ddr, loop_vinfo, max_vf))
> -	return false;
> +      {
> +	opt_result res
> +	  = vect_analyze_data_ref_dependence (ddr, loop_vinfo, max_vf);
> +	if (!res)
> +	  return res;
> +      }
>  
> -  return true;
> +  return opt_result::success ();
>  }
>  
>  
> @@ -1055,33 +1050,24 @@ vect_update_misalignment_for_peel (dr_vec_info *dr_info,
>  
>     Return TRUE if DR_INFO can be handled with respect to alignment.  */
>  
> -static bool
> +static opt_result
>  verify_data_ref_alignment (dr_vec_info *dr_info)
>  {
>    enum dr_alignment_support supportable_dr_alignment
>      = vect_supportable_dr_alignment (dr_info, false);
>    if (!supportable_dr_alignment)
> -    {
> -      if (dump_enabled_p ())
> -	{
> -	  if (DR_IS_READ (dr_info->dr))
> -	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			     "not vectorized: unsupported unaligned load.");
> -	  else
> -	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			     "not vectorized: unsupported unaligned "
> -			     "store.");
> -
> -	  dump_printf (MSG_MISSED_OPTIMIZATION, "%T\n", DR_REF (dr_info->dr));
> -	}
> -      return false;
> -    }
> +    return opt_result::failure_at
> +      (dr_info->stmt->stmt,
> +       DR_IS_READ (dr_info->dr)
> +	? "not vectorized: unsupported unaligned load: %T\n"
> +	: "not vectorized: unsupported unaligned store: %T\n",
> +       DR_REF (dr_info->dr));
>  
>    if (supportable_dr_alignment != dr_aligned && dump_enabled_p ())
>      dump_printf_loc (MSG_NOTE, vect_location,
>  		     "Vectorizing an unaligned access.\n");
>  
> -  return true;
> +  return opt_result::success ();
>  }
>  
>  /* Function vect_verify_datarefs_alignment
> @@ -1089,7 +1075,7 @@ verify_data_ref_alignment (dr_vec_info *dr_info)
>     Return TRUE if all data references in the loop can be
>     handled with respect to alignment.  */
>  
> -bool
> +opt_result
>  vect_verify_datarefs_alignment (loop_vec_info vinfo)
>  {
>    vec<data_reference_p> datarefs = vinfo->shared->datarefs;
> @@ -1115,11 +1101,12 @@ vect_verify_datarefs_alignment (loop_vec_info vinfo)
>  	  && !STMT_VINFO_GROUPED_ACCESS (stmt_info))
>  	continue;
>  
> -      if (! verify_data_ref_alignment (dr_info))
> -	return false;
> +      opt_result res = verify_data_ref_alignment (dr_info);
> +      if (!res)
> +	return res;
>      }
>  
> -  return true;
> +  return opt_result::success ();
>  }
>  
>  /* Given an memory reference EXP return whether its alignment is less
> @@ -1593,7 +1580,7 @@ vect_peeling_supportable (loop_vec_info loop_vinfo, dr_vec_info *dr0_info,
>       (whether to generate regular loads/stores, or with special handling for
>       misalignment).  */
>  
> -bool
> +opt_result
>  vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
>  {
>    vec<data_reference_p> datarefs = LOOP_VINFO_DATAREFS (loop_vinfo);
> @@ -1605,7 +1592,6 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
>    unsigned int i, j;
>    bool do_peeling = false;
>    bool do_versioning = false;
> -  bool stat;
>    unsigned int npeel = 0;
>    bool one_misalignment_known = false;
>    bool one_misalignment_unknown = false;
> @@ -1992,7 +1978,7 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
>        /* Check if all datarefs are supportable and log.  */
>        if (do_peeling && known_alignment_for_access_p (dr0_info) && npeel == 0)
>          {
> -          stat = vect_verify_datarefs_alignment (loop_vinfo);
> +          opt_result stat = vect_verify_datarefs_alignment (loop_vinfo);
>            if (!stat)
>              do_peeling = false;
>            else
> @@ -2078,7 +2064,7 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
>  	  /* The inside-loop cost will be accounted for in vectorizable_load
>  	     and vectorizable_store correctly with adjusted alignments.
>  	     Drop the body_cst_vec on the floor here.  */
> -	  stat = vect_verify_datarefs_alignment (loop_vinfo);
> +	  opt_result stat = vect_verify_datarefs_alignment (loop_vinfo);
>  	  gcc_assert (stat);
>            return stat;
>          }
> @@ -2201,7 +2187,7 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
>        /* Peeling and versioning can't be done together at this time.  */
>        gcc_assert (! (do_peeling && do_versioning));
>  
> -      stat = vect_verify_datarefs_alignment (loop_vinfo);
> +      opt_result stat = vect_verify_datarefs_alignment (loop_vinfo);
>        gcc_assert (stat);
>        return stat;
>      }
> @@ -2209,7 +2195,7 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
>    /* This point is reached if neither peeling nor versioning is being done.  */
>    gcc_assert (! (do_peeling || do_versioning));
>  
> -  stat = vect_verify_datarefs_alignment (loop_vinfo);
> +  opt_result stat = vect_verify_datarefs_alignment (loop_vinfo);
>    return stat;
>  }
>  
> @@ -2275,7 +2261,7 @@ vect_find_same_alignment_drs (vec_info *vinfo, data_dependence_relation *ddr)
>     Analyze the alignment of the data-references in the loop.
>     Return FALSE if a data reference is found that cannot be vectorized.  */
>  
> -bool
> +opt_result
>  vect_analyze_data_refs_alignment (loop_vec_info vinfo)
>  {
>    DUMP_VECT_SCOPE ("vect_analyze_data_refs_alignment");
> @@ -2300,7 +2286,7 @@ vect_analyze_data_refs_alignment (loop_vec_info vinfo)
>  	vect_compute_data_ref_alignment (dr_info);
>      }
>  
> -  return true;
> +  return opt_result::success ();
>  }
>  
>  
> @@ -2825,7 +2811,7 @@ can_group_stmts_p (stmt_vec_info stmt1_info, stmt_vec_info stmt2_info)
>  
>     FORNOW: handle only arrays and pointer accesses.  */
>  
> -bool
> +opt_result
>  vect_analyze_data_ref_accesses (vec_info *vinfo)
>  {
>    unsigned int i;
> @@ -2835,7 +2821,7 @@ vect_analyze_data_ref_accesses (vec_info *vinfo)
>    DUMP_VECT_SCOPE ("vect_analyze_data_ref_accesses");
>  
>    if (datarefs.is_empty ())
> -    return true;
> +    return opt_result::success ();
>  
>    /* Sort the array of datarefs to make building the interleaving chains
>       linear.  Don't modify the original vector's order, it is needed for
> @@ -2994,13 +2980,15 @@ vect_analyze_data_ref_accesses (vec_info *vinfo)
>  	  else
>  	    {
>  	      datarefs_copy.release ();
> -	      return false;
> +	      return opt_result::failure_at (dr_info->stmt->stmt,
> +					     "not vectorized:"
> +					     " complicated access pattern.\n");
>  	    }
>  	}
>      }
>  
>    datarefs_copy.release ();
> -  return true;
> +  return opt_result::success ();
>  }
>  
>  /* Function vect_vfa_segment_size.
> @@ -3258,7 +3246,7 @@ vectorizable_with_step_bound_p (dr_vec_info *dr_info_a, dr_vec_info *dr_info_b,
>     Return FALSE if resulting list of ddrs is longer then allowed by
>     PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS, otherwise return TRUE.  */
>  
> -bool
> +opt_result
>  vect_prune_runtime_alias_test_list (loop_vec_info loop_vinfo)
>  {
>    typedef pair_hash <tree_operand_hash, tree_operand_hash> tree_pair_hash;
> @@ -3292,7 +3280,7 @@ vect_prune_runtime_alias_test_list (loop_vec_info loop_vinfo)
>      }
>  
>    if (may_alias_ddrs.is_empty ())
> -    return true;
> +    return opt_result::success ();
>  
>    comp_alias_ddrs.create (may_alias_ddrs.length ());
>  
> @@ -3452,12 +3440,11 @@ vect_prune_runtime_alias_test_list (loop_vec_info loop_vinfo)
>  	    continue;
>  
>  	  if (res == 1)
> -	    {
> -	      if (dump_enabled_p ())
> -		dump_printf_loc (MSG_NOTE, vect_location,
> -				 "not vectorized: compilation time alias.\n");
> -	      return false;
> -	    }
> +	    return opt_result::failure_at (stmt_info_b->stmt,
> +					   "not vectorized:"
> +					   " compilation time alias: %G%G",
> +					   stmt_info_a->stmt,
> +					   stmt_info_b->stmt);
>  	}
>  
>        dr_with_seg_len_pair_t dr_with_seg_len_pair
> @@ -3482,17 +3469,14 @@ vect_prune_runtime_alias_test_list (loop_vec_info loop_vinfo)
>  		   "improved number of alias checks from %d to %d\n",
>  		   may_alias_ddrs.length (), count);
>    if ((int) count > PARAM_VALUE (PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS))
> -    {
> -      if (dump_enabled_p ())
> -	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			 "number of versioning for alias "
> -			 "run-time tests exceeds %d "
> -			 "(--param vect-max-version-for-alias-checks)\n",
> -			 PARAM_VALUE (PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS));
> -      return false;
> -    }
> -
> -  return true;
> +    return opt_result::failure_at
> +      (vect_location,
> +       "number of versioning for alias "
> +       "run-time tests exceeds %d "
> +       "(--param vect-max-version-for-alias-checks)\n",
> +       PARAM_VALUE (PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS));
> +
> +  return opt_result::success ();
>  }
>  
>  /* Check whether we can use an internal function for a gather load
> @@ -3846,7 +3830,7 @@ vect_check_gather_scatter (stmt_vec_info stmt_info, loop_vec_info loop_vinfo,
>     append them to DATAREFS.  Return false if datarefs in this stmt cannot
>     be handled.  */
>  
> -bool
> +opt_result
>  vect_find_stmt_data_reference (loop_p loop, gimple *stmt,
>  			       vec<data_reference_p> *datarefs)
>  {
> @@ -3854,72 +3838,50 @@ vect_find_stmt_data_reference (loop_p loop, gimple *stmt,
>       loop vectorization and BB vectorization checks dependences with a
>       stmt walk.  */
>    if (gimple_clobber_p (stmt))
> -    return true;
> +    return opt_result::success ();
>  
>    if (gimple_has_volatile_ops (stmt))
> -    {
> -      if (dump_enabled_p ())
> -	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			 "not vectorized: volatile type %G", stmt);
> -      return false;
> -    }
> +    return opt_result::failure_at (stmt, "not vectorized: volatile type: %G",
> +				   stmt);
>  
>    if (stmt_can_throw_internal (stmt))
> -    {
> -      if (dump_enabled_p ())
> -	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			 "not vectorized: statement can throw an exception %G",
> -			 stmt);
> -      return false;
> -    }
> +    return opt_result::failure_at (stmt,
> +				   "not vectorized:"
> +				   " statement can throw an exception: %G",
> +				   stmt);
>  
>    auto_vec<data_reference_p, 2> refs;
> -  if (!find_data_references_in_stmt (loop, stmt, &refs))
> -    return false;
> +  opt_result res = find_data_references_in_stmt (loop, stmt, &refs);
> +  if (!res)
> +    return res;
>  
>    if (refs.is_empty ())
> -    return true;
> +    return opt_result::success ();
>  
>    if (refs.length () > 1)
> -    {
> -      if (dump_enabled_p ())
> -	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			 "not vectorized: more than one data ref "
> -			 "in stmt: %G", stmt);
> -      return false;
> -    }
> +    return opt_result::failure_at (stmt,
> +				   "not vectorized:"
> +				   " more than one data ref in stmt: %G", stmt);
>  
>    if (gcall *call = dyn_cast <gcall *> (stmt))
>      if (!gimple_call_internal_p (call)
>  	|| (gimple_call_internal_fn (call) != IFN_MASK_LOAD
>  	    && gimple_call_internal_fn (call) != IFN_MASK_STORE))
> -      {
> -	if (dump_enabled_p ())
> -	  dump_printf_loc (MSG_MISSED_OPTIMIZATION,  vect_location,
> -			   "not vectorized: dr in a call %G", stmt);
> -	return false;
> -      }
> +      return opt_result::failure_at (stmt,
> +				     "not vectorized: dr in a call %G", stmt);
>  
>    data_reference_p dr = refs.pop ();
>    if (TREE_CODE (DR_REF (dr)) == COMPONENT_REF
>        && DECL_BIT_FIELD (TREE_OPERAND (DR_REF (dr), 1)))
> -    {
> -      if (dump_enabled_p ())
> -	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			 "not vectorized: statement is bitfield "
> -			 "access %G", stmt);
> -      return false;
> -    }
> +    return opt_result::failure_at (stmt,
> +				   "not vectorized:"
> +				   " statement is bitfield access %G", stmt);
>  
>    if (DR_BASE_ADDRESS (dr)
>        && TREE_CODE (DR_BASE_ADDRESS (dr)) == INTEGER_CST)
> -    {
> -      if (dump_enabled_p ())
> -	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			 "not vectorized: base addr of dr is a "
> -			 "constant\n");
> -      return false;
> -    }
> +    return opt_result::failure_at (stmt,
> +				   "not vectorized:"
> +				   " base addr of dr is a constant\n");
>  
>    /* Check whether this may be a SIMD lane access and adjust the
>       DR to make it easier for us to handle it.  */
> @@ -3976,7 +3938,7 @@ vect_find_stmt_data_reference (loop_p loop, gimple *stmt,
>  			  newdr->aux = (void *)-1;
>  			  free_data_ref (dr);
>  			  datarefs->safe_push (newdr);
> -			  return true;
> +			  return opt_result::success ();
>  			}
>  		    }
>  		}
> @@ -3986,7 +3948,7 @@ vect_find_stmt_data_reference (loop_p loop, gimple *stmt,
>      }
>  
>    datarefs->safe_push (dr);
> -  return true;
> +  return opt_result::success ();
>  }
>  
>  /* Function vect_analyze_data_refs.
> @@ -4004,7 +3966,7 @@ vect_find_stmt_data_reference (loop_p loop, gimple *stmt,
>  
>  */
>  
> -bool
> +opt_result
>  vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf)
>  {
>    struct loop *loop = NULL;
> @@ -4074,7 +4036,10 @@ vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf)
>  		  STMT_VINFO_VECTORIZABLE (stmt_info) = false;
>  		  continue;
>  		}
> -	      return false;
> +	      return opt_result::failure_at (stmt_info->stmt,
> +					     "not vectorized:"
> +					     " data ref analysis failed: %G",
> +					     stmt_info->stmt);
>  	    }
>          }
>  
> @@ -4082,13 +4047,10 @@ vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf)
>        if (dr->aux == (void *)-1)
>  	{
>  	  if (nested_in_vect_loop_p (loop, stmt_info))
> -	    {
> -	      if (dump_enabled_p ())
> -		dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -				 "not vectorized: data ref analysis "
> -				 "failed %G", stmt_info->stmt);
> -	      return false;
> -	    }
> +	    return opt_result::failure_at (stmt_info->stmt,
> +					   "not vectorized:"
> +					   " data ref analysis failed: %G",
> +					   stmt_info->stmt);
>  	  STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) = true;
>  	}
>  
> @@ -4106,7 +4068,10 @@ vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf)
>  	      STMT_VINFO_VECTORIZABLE (stmt_info) = false;
>  	      continue;
>  	    }
> -	  return false;
> +	  return opt_result::failure_at (stmt_info->stmt,
> +					 "not vectorized: base object not"
> +					 " addressable for stmt: %G",
> +					 stmt_info->stmt);
>  	}
>  
>        if (is_a <loop_vec_info> (vinfo)
> @@ -4114,13 +4079,10 @@ vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf)
>  	  && TREE_CODE (DR_STEP (dr)) != INTEGER_CST)
>  	{
>  	  if (nested_in_vect_loop_p (loop, stmt_info))
> -	    {
> -	      if (dump_enabled_p ())
> -		dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -				 "not vectorized: not suitable for strided "
> -				 "load %G", stmt_info->stmt);
> -	      return false;
> -	    }
> +	    return opt_result::failure_at (stmt_info->stmt,
> +					   "not vectorized:"
> +					   "not suitable for strided load %G",
> +					   stmt_info->stmt);
>  	  STMT_VINFO_STRIDED_P (stmt_info) = true;
>  	}
>  
> @@ -4150,10 +4112,12 @@ vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf)
>  	    dump_printf_loc (MSG_NOTE, vect_location,
>  			     "analyze in outer loop: %T\n", init_ref);
>  
> -	  if (!dr_analyze_innermost (&STMT_VINFO_DR_WRT_VEC_LOOP (stmt_info),
> -				     init_ref, loop))
> +	  opt_result res
> +	    = dr_analyze_innermost (&STMT_VINFO_DR_WRT_VEC_LOOP (stmt_info),
> +				    init_ref, loop, stmt_info->stmt);
> +	  if (!res)
>  	    /* dr_analyze_innermost already explained the failure.  */
> -	    return false;
> +	    return res;
>  
>            if (dump_enabled_p ())
>  	    dump_printf_loc (MSG_NOTE, vect_location,
> @@ -4199,7 +4163,11 @@ vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf)
>  	      STMT_VINFO_VECTORIZABLE (stmt_info) = false;
>  	      continue;
>  	    }
> -	  return false;
> +	  return opt_result::failure_at (stmt_info->stmt,
> +					 "not vectorized:"
> +					 " no vectype for stmt: %G"
> +					 " scalar_type: %T\n",
> +					 stmt_info->stmt, scalar_type);
>          }
>        else
>  	{
> @@ -4221,17 +4189,12 @@ vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf)
>  					  as_a <loop_vec_info> (vinfo),
>  					  &gs_info)
>  	      || !get_vectype_for_scalar_type (TREE_TYPE (gs_info.offset)))
> -	    {
> -	      if (dump_enabled_p ())
> -		dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -				 (gatherscatter == GATHER) ?
> -				 "not vectorized: not suitable for gather "
> -				 "load %G" :
> -				 "not vectorized: not suitable for scatter "
> -				 "store %G",
> -				 stmt_info->stmt);
> -	      return false;
> -	    }
> +	    return opt_result::failure_at
> +	      (stmt_info->stmt,
> +	       (gatherscatter == GATHER) ?
> +	       "not vectorized: not suitable for gather load %G" :
> +	       "not vectorized: not suitable for scatter store %G",
> +	       stmt_info->stmt);
>  	  STMT_VINFO_GATHER_SCATTER_P (stmt_info) = gatherscatter;
>  	}
>      }
> @@ -4240,7 +4203,7 @@ vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf)
>       longer need to.  */
>    gcc_assert (i == datarefs.length ());
>  
> -  return true;
> +  return opt_result::success ();
>  }
>  
>  
> diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c
> index fdac10b..6ea1e77 100644
> --- a/gcc/tree-vect-loop.c
> +++ b/gcc/tree-vect-loop.c
> @@ -159,7 +159,7 @@ static void vect_estimate_min_profitable_iters (loop_vec_info, int *, int *);
>     statement.  VECTYPE_MAYBE_SET_P is true if STMT_VINFO_VECTYPE
>     may already be set for general statements (not just data refs).  */
>  
> -static bool
> +static opt_result
>  vect_determine_vf_for_stmt_1 (stmt_vec_info stmt_info,
>  			      bool vectype_maybe_set_p,
>  			      poly_uint64 *vf,
> @@ -173,13 +173,14 @@ vect_determine_vf_for_stmt_1 (stmt_vec_info stmt_info,
>      {
>        if (dump_enabled_p ())
>  	dump_printf_loc (MSG_NOTE, vect_location, "skip.\n");
> -      return true;
> +      return opt_result::success ();
>      }
>  
>    tree stmt_vectype, nunits_vectype;
> -  if (!vect_get_vector_types_for_stmt (stmt_info, &stmt_vectype,
> -				       &nunits_vectype))
> -    return false;
> +  opt_result res = vect_get_vector_types_for_stmt (stmt_info, &stmt_vectype,
> +						   &nunits_vectype);
> +  if (!res)
> +    return res;
>  
>    if (stmt_vectype)
>      {
> @@ -199,7 +200,7 @@ vect_determine_vf_for_stmt_1 (stmt_vec_info stmt_info,
>    if (nunits_vectype)
>      vect_update_max_nunits (vf, nunits_vectype);
>  
> -  return true;
> +  return opt_result::success ();
>  }
>  
>  /* Subroutine of vect_determine_vectorization_factor.  Set the vector
> @@ -209,7 +210,7 @@ vect_determine_vf_for_stmt_1 (stmt_vec_info stmt_info,
>     add them to MASK_PRODUCERS.  Return true on success or false if
>     something prevented vectorization.  */
>  
> -static bool
> +static opt_result
>  vect_determine_vf_for_stmt (stmt_vec_info stmt_info, poly_uint64 *vf,
>  			    vec<stmt_vec_info > *mask_producers)
>  {
> @@ -217,8 +218,10 @@ vect_determine_vf_for_stmt (stmt_vec_info stmt_info, poly_uint64 *vf,
>    if (dump_enabled_p ())
>      dump_printf_loc (MSG_NOTE, vect_location, "==> examining statement: %G",
>  		     stmt_info->stmt);
> -  if (!vect_determine_vf_for_stmt_1 (stmt_info, false, vf, mask_producers))
> -    return false;
> +  opt_result res
> +    = vect_determine_vf_for_stmt_1 (stmt_info, false, vf, mask_producers);
> +  if (!res)
> +    return res;
>  
>    if (STMT_VINFO_IN_PATTERN_P (stmt_info)
>        && STMT_VINFO_RELATED_STMT (stmt_info))
> @@ -237,18 +240,22 @@ vect_determine_vf_for_stmt (stmt_vec_info stmt_info, poly_uint64 *vf,
>  			     def_stmt_info->stmt);
>  	  if (!vect_determine_vf_for_stmt_1 (def_stmt_info, true,
>  					     vf, mask_producers))
> -	    return false;
> +	  res = vect_determine_vf_for_stmt_1 (def_stmt_info, true,
> +					      vf, mask_producers);
> +	  if (!res)
> +	    return res;
>  	}
>  
>        if (dump_enabled_p ())
>  	dump_printf_loc (MSG_NOTE, vect_location,
>  			 "==> examining pattern statement: %G",
>  			 stmt_info->stmt);
> -      if (!vect_determine_vf_for_stmt_1 (stmt_info, true, vf, mask_producers))
> -	return false;
> +      res = vect_determine_vf_for_stmt_1 (stmt_info, true, vf, mask_producers);
> +      if (!res)
> +	return res;
>      }
>  
> -  return true;
> +  return opt_result::success ();
>  }
>  
>  /* Function vect_determine_vectorization_factor
> @@ -276,7 +283,7 @@ vect_determine_vf_for_stmt (stmt_vec_info stmt_info, poly_uint64 *vf,
>          }
>  */
>  
> -static bool
> +static opt_result
>  vect_determine_vectorization_factor (loop_vec_info loop_vinfo)
>  {
>    struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
> @@ -320,14 +327,10 @@ vect_determine_vectorization_factor (loop_vec_info loop_vinfo)
>  
>  	      vectype = get_vectype_for_scalar_type (scalar_type);
>  	      if (!vectype)
> -		{
> -		  if (dump_enabled_p ())
> -		    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -				     "not vectorized: unsupported "
> -				     "data-type %T\n",
> -				     scalar_type);
> -		  return false;
> -		}
> +		return opt_result::failure_at (phi,
> +					       "not vectorized: unsupported "
> +					       "data-type %T\n",
> +					       scalar_type);
>  	      STMT_VINFO_VECTYPE (stmt_info) = vectype;
>  
>  	      if (dump_enabled_p ())
> @@ -349,9 +352,11 @@ vect_determine_vectorization_factor (loop_vec_info loop_vinfo)
>  	   gsi_next (&si))
>  	{
>  	  stmt_info = loop_vinfo->lookup_stmt (gsi_stmt (si));
> -	  if (!vect_determine_vf_for_stmt (stmt_info, &vectorization_factor,
> -					   &mask_producers))
> -	    return false;
> +	  opt_result res
> +	    = vect_determine_vf_for_stmt (stmt_info, &vectorization_factor,
> +					  &mask_producers);
> +	  if (!res)
> +	    return res;
>          }
>      }
>  
> @@ -364,24 +369,20 @@ vect_determine_vectorization_factor (loop_vec_info loop_vinfo)
>      }
>  
>    if (known_le (vectorization_factor, 1U))
> -    {
> -      if (dump_enabled_p ())
> -        dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -                         "not vectorized: unsupported data-type\n");
> -      return false;
> -    }
> +    return opt_result::failure_at (vect_location,
> +				   "not vectorized: unsupported data-type\n");
>    LOOP_VINFO_VECT_FACTOR (loop_vinfo) = vectorization_factor;
>  
>    for (i = 0; i < mask_producers.length (); i++)
>      {
>        stmt_info = mask_producers[i];
> -      tree mask_type = vect_get_mask_type_for_stmt (stmt_info);
> +      opt_tree mask_type = vect_get_mask_type_for_stmt (stmt_info);
>        if (!mask_type)
> -	return false;
> +	return opt_result::propagate_failure (mask_type);
>        STMT_VINFO_VECTYPE (stmt_info) = mask_type;
>      }
>  
> -  return true;
> +  return opt_result::success ();
>  }
>  
>  
> @@ -1145,7 +1146,7 @@ vect_compute_single_scalar_iteration_cost (loop_vec_info loop_vinfo)
>     - the number of iterations can be analyzed, i.e, a countable loop.  The
>       niter could be analyzed under some assumptions.  */
>  
> -bool
> +opt_result
>  vect_analyze_loop_form_1 (struct loop *loop, gcond **loop_cond,
>  			  tree *assumptions, tree *number_of_iterationsm1,
>  			  tree *number_of_iterations, gcond **inner_loop_cond)
> @@ -1171,20 +1172,13 @@ vect_analyze_loop_form_1 (struct loop *loop, gcond **loop_cond,
>                          (exit-bb)  */
>  
>        if (loop->num_nodes != 2)
> -        {
> -          if (dump_enabled_p ())
> -            dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			     "not vectorized: control flow in loop.\n");
> -          return false;
> -        }
> +	return opt_result::failure_at (vect_location,
> +				       "not vectorized:"
> +				       " control flow in loop.\n");
>  
>        if (empty_block_p (loop->header))
> -	{
> -	  if (dump_enabled_p ())
> -	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			     "not vectorized: empty loop.\n");
> -	  return false;
> -	}
> +	return opt_result::failure_at (vect_location,
> +				       "not vectorized: empty loop.\n");
>      }
>    else
>      {
> @@ -1209,75 +1203,60 @@ vect_analyze_loop_form_1 (struct loop *loop, gcond **loop_cond,
>  	 as described above.  */
>  
>        if ((loop->inner)->inner || (loop->inner)->next)
> -	{
> -	  if (dump_enabled_p ())
> -	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			     "not vectorized: multiple nested loops.\n");
> -	  return false;
> -	}
> +	return opt_result::failure_at (vect_location,
> +				       "not vectorized:"
> +				       " multiple nested loops.\n");
>  
>        if (loop->num_nodes != 5)
> -        {
> -	  if (dump_enabled_p ())
> -	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			     "not vectorized: control flow in loop.\n");
> -	  return false;
> -        }
> +	return opt_result::failure_at (vect_location,
> +				       "not vectorized:"
> +				       " control flow in loop.\n");
>  
>        entryedge = loop_preheader_edge (innerloop);
>        if (entryedge->src != loop->header
>  	  || !single_exit (innerloop)
>  	  || single_exit (innerloop)->dest != EDGE_PRED (loop->latch, 0)->src)
> -	{
> -	  if (dump_enabled_p ())
> -	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			     "not vectorized: unsupported outerloop form.\n");
> -	  return false;
> -	}
> +	return opt_result::failure_at (vect_location,
> +				       "not vectorized:"
> +				       " unsupported outerloop form.\n");
>  
>        /* Analyze the inner-loop.  */
>        tree inner_niterm1, inner_niter, inner_assumptions;
> -      if (! vect_analyze_loop_form_1 (loop->inner, inner_loop_cond,
> -				      &inner_assumptions, &inner_niterm1,
> -				      &inner_niter, NULL)
> -	  /* Don't support analyzing niter under assumptions for inner
> -	     loop.  */
> -	  || !integer_onep (inner_assumptions))
> +      opt_result res
> +	= vect_analyze_loop_form_1 (loop->inner, inner_loop_cond,
> +				    &inner_assumptions, &inner_niterm1,
> +				    &inner_niter, NULL);
> +      if (!res)
>  	{
>  	  if (dump_enabled_p ())
> -            dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> +	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
>  			     "not vectorized: Bad inner loop.\n");
> -	  return false;
> +	  return res;
>  	}
>  
> +      /* Don't support analyzing niter under assumptions for inner
> +	 loop.  */
> +      if (!integer_onep (inner_assumptions))
> +	return opt_result::failure_at (vect_location,
> +				       "not vectorized: Bad inner loop.\n");
> +
>        if (!expr_invariant_in_loop_p (loop, inner_niter))
> -	{
> -	  if (dump_enabled_p ())
> -	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			     "not vectorized: inner-loop count not"
> -                             " invariant.\n");
> -	  return false;
> -	}
> +	return opt_result::failure_at (vect_location,
> +				       "not vectorized: inner-loop count not"
> +				       " invariant.\n");
>  
>        if (dump_enabled_p ())
>          dump_printf_loc (MSG_NOTE, vect_location,
>  			 "Considering outer-loop vectorization.\n");
>      }
>  
> -  if (!single_exit (loop)
> -      || EDGE_COUNT (loop->header->preds) != 2)
> -    {
> -      if (dump_enabled_p ())
> -        {
> -          if (!single_exit (loop))
> -	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			     "not vectorized: multiple exits.\n");
> -          else if (EDGE_COUNT (loop->header->preds) != 2)
> -	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			     "not vectorized: too many incoming edges.\n");
> -        }
> -      return false;
> -    }
> +  if (!single_exit (loop))
> +    return opt_result::failure_at (vect_location,
> +				   "not vectorized: multiple exits.\n");
> +  if (EDGE_COUNT (loop->header->preds) != 2)
> +    return opt_result::failure_at (vect_location,
> +				   "not vectorized:"
> +				   " too many incoming edges.\n");
>  
>    /* We assume that the loop exit condition is at the end of the loop. i.e,
>       that the loop is represented as a do-while (with a proper if-guard
> @@ -1285,67 +1264,52 @@ vect_analyze_loop_form_1 (struct loop *loop, gcond **loop_cond,
>       executable statements, and the latch is empty.  */
>    if (!empty_block_p (loop->latch)
>        || !gimple_seq_empty_p (phi_nodes (loop->latch)))
> -    {
> -      if (dump_enabled_p ())
> -	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			 "not vectorized: latch block not empty.\n");
> -      return false;
> -    }
> +    return opt_result::failure_at (vect_location,
> +				   "not vectorized: latch block not empty.\n");
>  
>    /* Make sure the exit is not abnormal.  */
>    edge e = single_exit (loop);
>    if (e->flags & EDGE_ABNORMAL)
> -    {
> -      if (dump_enabled_p ())
> -	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			 "not vectorized: abnormal loop exit edge.\n");
> -      return false;
> -    }
> +    return opt_result::failure_at (vect_location,
> +				   "not vectorized:"
> +				   " abnormal loop exit edge.\n");
>  
>    *loop_cond = vect_get_loop_niters (loop, assumptions, number_of_iterations,
>  				     number_of_iterationsm1);
>    if (!*loop_cond)
> -    {
> -      if (dump_enabled_p ())
> -	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			 "not vectorized: complicated exit condition.\n");
> -      return false;
> -    }
> +    return opt_result::failure_at
> +      (vect_location,
> +       "not vectorized: complicated exit condition.\n");
>  
>    if (integer_zerop (*assumptions)
>        || !*number_of_iterations
>        || chrec_contains_undetermined (*number_of_iterations))
> -    {
> -      if (dump_enabled_p ())
> -	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			 "not vectorized: number of iterations cannot be "
> -			 "computed.\n");
> -      return false;
> -    }
> +    return opt_result::failure_at
> +      (*loop_cond,
> +       "not vectorized: number of iterations cannot be computed.\n");
>  
>    if (integer_zerop (*number_of_iterations))
> -    {
> -      if (dump_enabled_p ())
> -	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			 "not vectorized: number of iterations = 0.\n");
> -      return false;
> -    }
> +    return opt_result::failure_at
> +      (*loop_cond,
> +       "not vectorized: number of iterations = 0.\n");
>  
> -  return true;
> +  return opt_result::success ();
>  }
>  
>  /* Analyze LOOP form and return a loop_vec_info if it is of suitable form.  */
>  
> -loop_vec_info
> +opt_loop_vec_info
>  vect_analyze_loop_form (struct loop *loop, vec_info_shared *shared)
>  {
>    tree assumptions, number_of_iterations, number_of_iterationsm1;
>    gcond *loop_cond, *inner_loop_cond = NULL;
>  
> -  if (! vect_analyze_loop_form_1 (loop, &loop_cond,
> -				  &assumptions, &number_of_iterationsm1,
> -				  &number_of_iterations, &inner_loop_cond))
> -    return NULL;
> +  opt_result res
> +    = vect_analyze_loop_form_1 (loop, &loop_cond,
> +				&assumptions, &number_of_iterationsm1,
> +				&number_of_iterations, &inner_loop_cond);
> +  if (!res)
> +    return opt_loop_vec_info::propagate_failure (res);
>  
>    loop_vec_info loop_vinfo = new _loop_vec_info (loop, shared);
>    LOOP_VINFO_NITERSM1 (loop_vinfo) = number_of_iterationsm1;
> @@ -1387,7 +1351,7 @@ vect_analyze_loop_form (struct loop *loop, vec_info_shared *shared)
>  
>    gcc_assert (!loop->aux);
>    loop->aux = loop_vinfo;
> -  return loop_vinfo;
> +  return opt_loop_vec_info::success (loop_vinfo);
>  }
>  
>  
> @@ -1489,7 +1453,7 @@ vect_active_double_reduction_p (stmt_vec_info stmt_info)
>  
>     Scan the loop stmts and make sure they are all vectorizable.  */
>  
> -static bool
> +static opt_result
>  vect_analyze_loop_operations (loop_vec_info loop_vinfo)
>  {
>    struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
> @@ -1531,13 +1495,9 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo)
>                   requires to actually do something here.  */
>                if (STMT_VINFO_LIVE_P (stmt_info)
>  		  && !vect_active_double_reduction_p (stmt_info))
> -                {
> -                  if (dump_enabled_p ())
> -		    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -				     "Unsupported loop-closed phi in "
> -				     "outer-loop.\n");
> -                  return false;
> -                }
> +		return opt_result::failure_at (phi,
> +					       "Unsupported loop-closed phi"
> +					       " in outer-loop.\n");
>  
>                /* If PHI is used in the outer loop, we check that its operand
>                   is defined in the inner loop.  */
> @@ -1546,17 +1506,17 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo)
>                    tree phi_op;
>  
>                    if (gimple_phi_num_args (phi) != 1)
> -                    return false;
> +                    return opt_result::failure_at (phi, "unsupported phi");
>  
>                    phi_op = PHI_ARG_DEF (phi, 0);
>  		  stmt_vec_info op_def_info = loop_vinfo->lookup_def (phi_op);
>  		  if (!op_def_info)
> -                    return false;
> +		    return opt_result::failure_at (phi, "unsupported phi");
>  
>  		  if (STMT_VINFO_RELEVANT (op_def_info) != vect_used_in_outer
>  		      && (STMT_VINFO_RELEVANT (op_def_info)
>  			  != vect_used_in_outer_by_reduction))
> -		    return false;
> +		    return opt_result::failure_at (phi, "unsupported phi");
>                  }
>  
>                continue;
> @@ -1567,13 +1527,10 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo)
>            if ((STMT_VINFO_RELEVANT (stmt_info) == vect_used_in_scope
>                 || STMT_VINFO_LIVE_P (stmt_info))
>                && STMT_VINFO_DEF_TYPE (stmt_info) != vect_induction_def)
> -            {
> -              /* A scalar-dependence cycle that we don't support.  */
> -              if (dump_enabled_p ())
> -		dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -				 "not vectorized: scalar dependence cycle.\n");
> -              return false;
> -            }
> +	    /* A scalar-dependence cycle that we don't support.  */
> +	    return opt_result::failure_at (phi,
> +					   "not vectorized:"
> +					   " scalar dependence cycle.\n");
>  
>            if (STMT_VINFO_RELEVANT_P (stmt_info))
>              {
> @@ -1597,24 +1554,25 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo)
>  					      &cost_vec);
>  
>            if (!ok)
> -            {
> -              if (dump_enabled_p ())
> -		dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -				 "not vectorized: relevant phi not "
> -				 "supported: %G", phi);
> -	      return false;
> -            }
> +	    return opt_result::failure_at (phi,
> +					   "not vectorized: relevant phi not "
> +					   "supported: %G",
> +					   static_cast <gimple *> (phi));
>          }
>  
>        for (gimple_stmt_iterator si = gsi_start_bb (bb); !gsi_end_p (si);
>  	   gsi_next (&si))
>          {
>  	  gimple *stmt = gsi_stmt (si);
> -	  if (!gimple_clobber_p (stmt)
> -	      && !vect_analyze_stmt (loop_vinfo->lookup_stmt (stmt),
> +	  if (!gimple_clobber_p (stmt))
> +	    {
> +	      opt_result res
> +		= vect_analyze_stmt (loop_vinfo->lookup_stmt (stmt),
>  				     &need_to_vectorize,
> -				     NULL, NULL, &cost_vec))
> -	    return false;
> +				     NULL, NULL, &cost_vec);
> +	      if (!res)
> +		return res;
> +	    }
>          }
>      } /* bbs */
>  
> @@ -1631,14 +1589,12 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo)
>        if (dump_enabled_p ())
>          dump_printf_loc (MSG_NOTE, vect_location,
>  			 "All the computation can be taken out of the loop.\n");
> -      if (dump_enabled_p ())
> -	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			 "not vectorized: redundant loop. no profit to "
> -			 "vectorize.\n");
> -      return false;
> +      return opt_result::failure_at
> +	(vect_location,
> +	 "not vectorized: redundant loop. no profit to vectorize.\n");
>      }
>  
> -  return true;
> +  return opt_result::success ();
>  }
>  
>  /* Analyze the cost of the loop described by LOOP_VINFO.  Decide if it
> @@ -1736,7 +1692,7 @@ vect_analyze_loop_costing (loop_vec_info loop_vinfo)
>    return 1;
>  }
>  
> -static bool
> +static opt_result
>  vect_get_datarefs_in_loop (loop_p loop, basic_block *bbs,
>  			   vec<data_reference_p> *datarefs,
>  			   unsigned int *n_stmts)
> @@ -1750,7 +1706,8 @@ vect_get_datarefs_in_loop (loop_p loop, basic_block *bbs,
>  	if (is_gimple_debug (stmt))
>  	  continue;
>  	++(*n_stmts);
> -	if (!vect_find_stmt_data_reference (loop, stmt, datarefs))
> +	opt_result res = vect_find_stmt_data_reference (loop, stmt, datarefs);
> +	if (!res)
>  	  {
>  	    if (is_gimple_call (stmt) && loop->safelen)
>  	      {
> @@ -1782,15 +1739,16 @@ vect_get_datarefs_in_loop (loop_p loop, basic_block *bbs,
>  		      }
>  		  }
>  	      }
> -	    return false;
> +	    return res;
>  	  }
>  	/* If dependence analysis will give up due to the limit on the
>  	   number of datarefs stop here and fail fatally.  */
>  	if (datarefs->length ()
>  	    > (unsigned)PARAM_VALUE (PARAM_LOOP_MAX_DATAREFS_FOR_DATADEPS))
> -	  return false;
> +	  return opt_result::failure_at (stmt, "exceeded param "
> +					 "loop-max-datarefs-for-datadeps\n");
>        }
> -  return true;
> +  return opt_result::success ();
>  }
>  
>  /* Function vect_analyze_loop_2.
> @@ -1798,10 +1756,10 @@ vect_get_datarefs_in_loop (loop_p loop, basic_block *bbs,
>     Apply a set of analyses on LOOP, and create a loop_vec_info struct
>     for it.  The different analyses will record information in the
>     loop_vec_info struct.  */
> -static bool
> +static opt_result
>  vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
>  {
> -  bool ok;
> +  opt_result ok = opt_result::success ();
>    int res;
>    unsigned int max_vf = MAX_VECTORIZATION_FACTOR;
>    poly_uint64 min_vf = 2;
> @@ -1817,16 +1775,18 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
>    /* Gather the data references and count stmts in the loop.  */
>    if (!LOOP_VINFO_DATAREFS (loop_vinfo).exists ())
>      {
> -      if (!vect_get_datarefs_in_loop (loop, LOOP_VINFO_BBS (loop_vinfo),
> -				      &LOOP_VINFO_DATAREFS (loop_vinfo),
> -				      n_stmts))
> +      opt_result res
> +	= vect_get_datarefs_in_loop (loop, LOOP_VINFO_BBS (loop_vinfo),
> +				     &LOOP_VINFO_DATAREFS (loop_vinfo),
> +				     n_stmts);
> +      if (!res)
>  	{
>  	  if (dump_enabled_p ())
>  	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
>  			     "not vectorized: loop contains function "
>  			     "calls or data references that cannot "
>  			     "be analyzed\n");
> -	  return false;
> +	  return res;
>  	}
>        loop_vinfo->shared->save_datarefs ();
>      }
> @@ -1842,7 +1802,7 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
>        if (dump_enabled_p ())
>  	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
>  			 "bad data references.\n");
> -      return false;
> +      return ok;
>      }
>  
>    /* Classify all cross-iteration scalar data-flow cycles.
> @@ -1862,7 +1822,7 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
>        if (dump_enabled_p ())
>  	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
>  			 "bad data access.\n");
> -      return false;
> +      return ok;
>      }
>  
>    /* Data-flow analysis to detect stmts that do not need to be vectorized.  */
> @@ -1873,7 +1833,7 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
>        if (dump_enabled_p ())
>  	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
>  			 "unexpected pattern.\n");
> -      return false;
> +      return ok;
>      }
>  
>    /* While the rest of the analysis below depends on it in some way.  */
> @@ -1885,15 +1845,16 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
>       FORNOW: fail at the first data dependence that we encounter.  */
>  
>    ok = vect_analyze_data_ref_dependences (loop_vinfo, &max_vf);
> -  if (!ok
> -      || (max_vf != MAX_VECTORIZATION_FACTOR
> -	  && maybe_lt (max_vf, min_vf)))
> +  if (!ok)
>      {
>        if (dump_enabled_p ())
> -	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			     "bad data dependence.\n");
> -      return false;
> +	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> +			 "bad data dependence.\n");
> +      return ok;
>      }
> +  if (max_vf != MAX_VECTORIZATION_FACTOR
> +      && maybe_lt (max_vf, min_vf))
> +    return opt_result::failure_at (vect_location, "bad data dependence.\n");
>    LOOP_VINFO_MAX_VECT_FACTOR (loop_vinfo) = max_vf;
>  
>    ok = vect_determine_vectorization_factor (loop_vinfo);
> @@ -1902,16 +1863,11 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
>        if (dump_enabled_p ())
>  	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
>  			 "can't determine vectorization factor.\n");
> -      return false;
> +      return ok;
>      }
>    if (max_vf != MAX_VECTORIZATION_FACTOR
>        && maybe_lt (max_vf, LOOP_VINFO_VECT_FACTOR (loop_vinfo)))
> -    {
> -      if (dump_enabled_p ())
> -	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			 "bad data dependence.\n");
> -      return false;
> -    }
> +    return opt_result::failure_at (vect_location, "bad data dependence.\n");
>  
>    /* Compute the scalar iteration cost.  */
>    vect_compute_single_scalar_iteration_cost (loop_vinfo);
> @@ -1922,7 +1878,7 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
>    /* Check the SLP opportunities in the loop, analyze and build SLP trees.  */
>    ok = vect_analyze_slp (loop_vinfo, *n_stmts);
>    if (!ok)
> -    return false;
> +    return ok;
>  
>    /* If there are any SLP instances mark them as pure_slp.  */
>    bool slp = vect_make_slp_decision (loop_vinfo);
> @@ -1969,7 +1925,7 @@ start_over:
>        if (dump_enabled_p ())
>  	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
>  			 "bad data alignment.\n");
> -      return false;
> +      return ok;
>      }
>  
>    /* Prune the list of ddrs to be tested at run-time by versioning for alias.
> @@ -1977,7 +1933,7 @@ start_over:
>       since we use grouping information gathered by interleaving analysis.  */
>    ok = vect_prune_runtime_alias_test_list (loop_vinfo);
>    if (!ok)
> -    return false;
> +    return ok;
>  
>    /* Do not invoke vect_enhance_data_refs_alignment for epilogue
>       vectorization, since we do not want to add extra peeling or
> @@ -1989,12 +1945,7 @@ start_over:
>    else
>      ok = vect_verify_datarefs_alignment (loop_vinfo);
>    if (!ok)
> -    {
> -      if (dump_enabled_p ())
> -	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			 "bad data alignment.\n");
> -      return false;
> -    }
> +    return ok;
>  
>    if (slp)
>      {
> @@ -2004,7 +1955,11 @@ start_over:
>        unsigned old_size = LOOP_VINFO_SLP_INSTANCES (loop_vinfo).length ();
>        vect_slp_analyze_operations (loop_vinfo);
>        if (LOOP_VINFO_SLP_INSTANCES (loop_vinfo).length () != old_size)
> -	goto again;
> +	{
> +	  ok = opt_result::failure_at (vect_location,
> +				       "unsupported SLP instances\n");
> +	  goto again;
> +	}
>      }
>  
>    /* Scan all the remaining operations in the loop that are not subject
> @@ -2015,7 +1970,7 @@ start_over:
>        if (dump_enabled_p ())
>  	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
>  			 "bad operation or unsupported loop bound.\n");
> -      return false;
> +      return ok;
>      }
>  
>    /* Decide whether to use a fully-masked loop for this vectorization
> @@ -2044,26 +1999,22 @@ start_over:
>        tree scalar_niters = LOOP_VINFO_NITERSM1 (loop_vinfo);
>  
>        if (known_lt (wi::to_widest (scalar_niters), vf))
> -	{
> -	  if (dump_enabled_p ())
> -	    dump_printf_loc (MSG_NOTE, vect_location,
> -			     "loop has no enough iterations to support"
> -			     " peeling for gaps.\n");
> -	  return false;
> -	}
> +	return opt_result::failure_at (vect_location,
> +				       "loop has no enough iterations to"
> +				       " support peeling for gaps.\n");
>      }
>  
>    /* Check the costings of the loop make vectorizing worthwhile.  */
>    res = vect_analyze_loop_costing (loop_vinfo);
>    if (res < 0)
> -    goto again;
> -  if (!res)
>      {
> -      if (dump_enabled_p ())
> -	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			 "Loop costings not worthwhile.\n");
> -      return false;
> +      ok = opt_result::failure_at (vect_location,
> +				   "Loop costings may not be worthwhile.\n");
> +      goto again;
>      }
> +  if (!res)
> +    return opt_result::failure_at (vect_location,
> +				   "Loop costings not worthwhile.\n");
>  
>    /* Decide whether we need to create an epilogue loop to handle
>       remaining scalar iterations.  */
> @@ -2112,10 +2063,9 @@ start_over:
>  					   single_exit (LOOP_VINFO_LOOP
>  							 (loop_vinfo))))
>          {
> -          if (dump_enabled_p ())
> -	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			     "not vectorized: can't create required "
> -			     "epilog loop\n");
> +	  ok = opt_result::failure_at (vect_location,
> +				       "not vectorized: can't create required "
> +				       "epilog loop\n");
>            goto again;
>          }
>      }
> @@ -2154,17 +2104,20 @@ start_over:
>  			LOOP_VINFO_VECT_FACTOR (loop_vinfo)));
>  
>    /* Ok to vectorize!  */
> -  return true;
> +  return opt_result::success ();
>  
>  again:
> +  /* Ensure that "ok" is false (with an opt_problem if dumping is enabled).  */
> +  gcc_assert (!ok);
> +
>    /* Try again with SLP forced off but if we didn't do any SLP there is
>       no point in re-trying.  */
>    if (!slp)
> -    return false;
> +    return ok;
>  
>    /* If there are reduction chains re-trying will fail anyway.  */
>    if (! LOOP_VINFO_REDUCTION_CHAINS (loop_vinfo).is_empty ())
> -    return false;
> +    return ok;
>  
>    /* Likewise if the grouped loads or stores in the SLP cannot be handled
>       via interleaving or lane instructions.  */
> @@ -2183,7 +2136,8 @@ again:
>        if (! vect_store_lanes_supported (vectype, size, false)
>  	 && ! known_eq (TYPE_VECTOR_SUBPARTS (vectype), 1U)
>  	 && ! vect_grouped_store_supported (vectype, size))
> -       return false;
> +	return opt_result::failure_at (vinfo->stmt,
> +				       "unsupported grouped store\n");
>        FOR_EACH_VEC_ELT (SLP_INSTANCE_LOADS (instance), j, node)
>  	{
>  	  vinfo = SLP_TREE_SCALAR_STMTS (node)[0];
> @@ -2194,7 +2148,8 @@ again:
>  	  if (! vect_load_lanes_supported (vectype, size, false)
>  	      && ! vect_grouped_load_supported (vectype, single_element_p,
>  						size))
> -	    return false;
> +	    return opt_result::failure_at (vinfo->stmt,
> +					   "unsupported grouped load\n");
>  	}
>      }
>  
> @@ -2263,11 +2218,10 @@ again:
>     for it.  The different analyses will record information in the
>     loop_vec_info struct.  If ORIG_LOOP_VINFO is not NULL epilogue must
>     be vectorized.  */
> -loop_vec_info
> +opt_loop_vec_info
>  vect_analyze_loop (struct loop *loop, loop_vec_info orig_loop_vinfo,
>  		   vec_info_shared *shared)
>  {
> -  loop_vec_info loop_vinfo;
>    auto_vector_sizes vector_sizes;
>  
>    /* Autodetect first vector size we try.  */
> @@ -2280,35 +2234,28 @@ vect_analyze_loop (struct loop *loop, loop_vec_info orig_loop_vinfo,
>    if (loop_outer (loop)
>        && loop_vec_info_for_loop (loop_outer (loop))
>        && LOOP_VINFO_VECTORIZABLE_P (loop_vec_info_for_loop (loop_outer (loop))))
> -    {
> -      if (dump_enabled_p ())
> -	dump_printf_loc (MSG_NOTE, vect_location,
> -			 "outer-loop already vectorized.\n");
> -      return NULL;
> -    }
> +    return opt_loop_vec_info::failure_at (vect_location,
> +					  "outer-loop already vectorized.\n");
>  
>    if (!find_loop_nest (loop, &shared->loop_nest))
> -    {
> -      if (dump_enabled_p ())
> -	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			 "not vectorized: loop nest containing two "
> -			 "or more consecutive inner loops cannot be "
> -			 "vectorized\n");
> -      return NULL;
> -    }
> +    return opt_loop_vec_info::failure_at
> +      (vect_location,
> +       "not vectorized: loop nest containing two or more consecutive inner"
> +       " loops cannot be vectorized\n");
>  
>    unsigned n_stmts = 0;
>    poly_uint64 autodetected_vector_size = 0;
>    while (1)
>      {
>        /* Check the CFG characteristics of the loop (nesting, entry/exit).  */
> -      loop_vinfo = vect_analyze_loop_form (loop, shared);
> +      opt_loop_vec_info loop_vinfo
> +	= vect_analyze_loop_form (loop, shared);
>        if (!loop_vinfo)
>  	{
>  	  if (dump_enabled_p ())
>  	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
>  			     "bad loop form.\n");
> -	  return NULL;
> +	  return loop_vinfo;
>  	}
>  
>        bool fatal = false;
> @@ -2316,7 +2263,8 @@ vect_analyze_loop (struct loop *loop, loop_vec_info orig_loop_vinfo,
>        if (orig_loop_vinfo)
>  	LOOP_VINFO_ORIG_LOOP_INFO (loop_vinfo) = orig_loop_vinfo;
>  
> -      if (vect_analyze_loop_2 (loop_vinfo, fatal, &n_stmts))
> +      opt_result res = vect_analyze_loop_2 (loop_vinfo, fatal, &n_stmts);
> +      if (res)
>  	{
>  	  LOOP_VINFO_VECTORIZABLE_P (loop_vinfo) = 1;
>  
> @@ -2335,7 +2283,7 @@ vect_analyze_loop (struct loop *loop, loop_vec_info orig_loop_vinfo,
>        if (fatal
>  	  || next_size == vector_sizes.length ()
>  	  || known_eq (current_vector_size, 0U))
> -	return NULL;
> +	return opt_loop_vec_info::propagate_failure (res);
>  
>        /* Try the next biggest vector size.  */
>        current_vector_size = vector_sizes[next_size++];
> diff --git a/gcc/tree-vect-slp.c b/gcc/tree-vect-slp.c
> index ae1c453..f60fea0 100644
> --- a/gcc/tree-vect-slp.c
> +++ b/gcc/tree-vect-slp.c
> @@ -2071,7 +2071,7 @@ vect_analyze_slp_instance (vec_info *vinfo,
>  /* Check if there are stmts in the loop can be vectorized using SLP.  Build SLP
>     trees of packed scalar stmts if SLP is possible.  */
>  
> -bool
> +opt_result
>  vect_analyze_slp (vec_info *vinfo, unsigned max_tree_size)
>  {
>    unsigned int i;
> @@ -2111,7 +2111,7 @@ vect_analyze_slp (vec_info *vinfo, unsigned max_tree_size)
>  				   max_tree_size);
>      }
>  
> -  return true;
> +  return opt_result::success ();
>  }
>  
>  
> diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c
> index 7a6efdb..8108d52 100644
> --- a/gcc/tree-vect-stmts.c
> +++ b/gcc/tree-vect-stmts.c
> @@ -448,7 +448,7 @@ exist_non_indexing_operands_for_use_p (tree use, stmt_vec_info stmt_info)
>  
>     Return true if everything is as expected. Return false otherwise.  */
>  
> -static bool
> +static opt_result
>  process_use (stmt_vec_info stmt_vinfo, tree use, loop_vec_info loop_vinfo,
>  	     enum vect_relevant relevant, vec<stmt_vec_info> *worklist,
>  	     bool force)
> @@ -460,18 +460,15 @@ process_use (stmt_vec_info stmt_vinfo, tree use, loop_vec_info loop_vinfo,
>    /* case 1: we are only interested in uses that need to be vectorized.  Uses
>       that are used for address computation are not considered relevant.  */
>    if (!force && !exist_non_indexing_operands_for_use_p (use, stmt_vinfo))
> -     return true;
> +    return opt_result::success ();
>  
>    if (!vect_is_simple_use (use, loop_vinfo, &dt, &dstmt_vinfo))
> -    {
> -      if (dump_enabled_p ())
> -        dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -                         "not vectorized: unsupported use in stmt.\n");
> -      return false;
> -    }
> +    return opt_result::failure_at (stmt_vinfo->stmt,
> +				   "not vectorized:"
> +				   " unsupported use in stmt.\n");
>  
>    if (!dstmt_vinfo)
> -    return true;
> +    return opt_result::success ();
>  
>    def_bb = gimple_bb (dstmt_vinfo->stmt);
>  
> @@ -493,7 +490,7 @@ process_use (stmt_vec_info stmt_vinfo, tree use, loop_vec_info loop_vinfo,
>        gcc_assert (STMT_VINFO_RELEVANT (dstmt_vinfo) < vect_used_by_reduction);
>        gcc_assert (STMT_VINFO_LIVE_P (dstmt_vinfo)
>  		  || STMT_VINFO_RELEVANT (dstmt_vinfo) > vect_unused_in_scope);
> -      return true;
> +      return opt_result::success ();
>      }
>  
>    /* case 3a: outer-loop stmt defining an inner-loop stmt:
> @@ -582,12 +579,12 @@ process_use (stmt_vec_info stmt_vinfo, tree use, loop_vec_info loop_vinfo,
>        if (dump_enabled_p ())
>  	dump_printf_loc (MSG_NOTE, vect_location,
>                           "induction value on backedge.\n");
> -      return true;
> +      return opt_result::success ();
>      }
>  
>  
>    vect_mark_relevant (worklist, dstmt_vinfo, relevant, false);
> -  return true;
> +  return opt_result::success ();
>  }
>  
>  
> @@ -607,7 +604,7 @@ process_use (stmt_vec_info stmt_vinfo, tree use, loop_vec_info loop_vinfo,
>  
>     This pass detects such stmts.  */
>  
> -bool
> +opt_result
>  vect_mark_stmts_to_be_vectorized (loop_vec_info loop_vinfo)
>  {
>    struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
> @@ -684,38 +681,24 @@ vect_mark_stmts_to_be_vectorized (loop_vec_info loop_vinfo)
>  		&& relevant != vect_used_in_scope
>  		&& relevant != vect_used_by_reduction
>  		&& relevant != vect_used_only_live)
> -	      {
> -		if (dump_enabled_p ())
> -		  dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -				   "unsupported use of reduction.\n");
> -		return false;
> -	      }
> +	      return opt_result::failure_at
> +		(stmt_vinfo->stmt, "unsupported use of reduction.\n");
>  	    break;
>  
>            case vect_nested_cycle:
>  	    if (relevant != vect_unused_in_scope
>  		&& relevant != vect_used_in_outer_by_reduction
>  		&& relevant != vect_used_in_outer)
> -              {
> -                if (dump_enabled_p ())
> -                  dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -                                   "unsupported use of nested cycle.\n");
> -
> -                return false;
> -              }
> +	      return opt_result::failure_at
> +		(stmt_vinfo->stmt, "unsupported use of nested cycle.\n");
>              break;
>  
>            case vect_double_reduction_def:
>  	    if (relevant != vect_unused_in_scope
>  		&& relevant != vect_used_by_reduction
>  		&& relevant != vect_used_only_live)
> -              {
> -                if (dump_enabled_p ())
> -                  dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -                                   "unsupported use of double reduction.\n");
> -
> -                return false;
> -              }
> +	      return opt_result::failure_at
> +		(stmt_vinfo->stmt, "unsupported use of double reduction.\n");
>              break;
>  
>            default:
> @@ -735,20 +718,28 @@ vect_mark_stmts_to_be_vectorized (loop_vec_info loop_vinfo)
>  	      i = 1;
>  	      if (rhs_code == COND_EXPR && COMPARISON_CLASS_P (op))
>  		{
> -		  if (!process_use (stmt_vinfo, TREE_OPERAND (op, 0),
> -				    loop_vinfo, relevant, &worklist, false)
> -		      || !process_use (stmt_vinfo, TREE_OPERAND (op, 1),
> -				       loop_vinfo, relevant, &worklist, false))
> -		    return false;
> +		  opt_result res
> +		    = process_use (stmt_vinfo, TREE_OPERAND (op, 0),
> +				   loop_vinfo, relevant, &worklist, false);
> +		  if (!res)
> +		    return res;
> +		  res = process_use (stmt_vinfo, TREE_OPERAND (op, 1),
> +				     loop_vinfo, relevant, &worklist, false);
> +		  if (!res)
> +		    return res;
>  		  i = 2;
>  		}
>  	      for (; i < gimple_num_ops (assign); i++)
>  		{
>  		  op = gimple_op (assign, i);
> -                  if (TREE_CODE (op) == SSA_NAME
> -		      && !process_use (stmt_vinfo, op, loop_vinfo, relevant,
> -				       &worklist, false))
> -                    return false;
> +                  if (TREE_CODE (op) == SSA_NAME)
> +		    {
> +		      opt_result res
> +			= process_use (stmt_vinfo, op, loop_vinfo, relevant,
> +				       &worklist, false);
> +		      if (!res)
> +			return res;
> +		    }
>                   }
>              }
>  	  else if (gcall *call = dyn_cast <gcall *> (stmt_vinfo->stmt))
> @@ -756,9 +747,11 @@ vect_mark_stmts_to_be_vectorized (loop_vec_info loop_vinfo)
>  	      for (i = 0; i < gimple_call_num_args (call); i++)
>  		{
>  		  tree arg = gimple_call_arg (call, i);
> -		  if (!process_use (stmt_vinfo, arg, loop_vinfo, relevant,
> -				    &worklist, false))
> -                    return false;
> +		  opt_result res
> +		    = process_use (stmt_vinfo, arg, loop_vinfo, relevant,
> +				   &worklist, false);
> +		  if (!res)
> +		    return res;
>  		}
>  	    }
>          }
> @@ -766,9 +759,11 @@ vect_mark_stmts_to_be_vectorized (loop_vec_info loop_vinfo)
>  	FOR_EACH_PHI_OR_STMT_USE (use_p, stmt_vinfo->stmt, iter, SSA_OP_USE)
>            {
>              tree op = USE_FROM_PTR (use_p);
> -	    if (!process_use (stmt_vinfo, op, loop_vinfo, relevant,
> -			      &worklist, false))
> -              return false;
> +	    opt_result res
> +	      = process_use (stmt_vinfo, op, loop_vinfo, relevant,
> +			     &worklist, false);
> +	    if (!res)
> +	      return res;
>            }
>  
>        if (STMT_VINFO_GATHER_SCATTER_P (stmt_vinfo))
> @@ -776,13 +771,15 @@ vect_mark_stmts_to_be_vectorized (loop_vec_info loop_vinfo)
>  	  gather_scatter_info gs_info;
>  	  if (!vect_check_gather_scatter (stmt_vinfo, loop_vinfo, &gs_info))
>  	    gcc_unreachable ();
> -	  if (!process_use (stmt_vinfo, gs_info.offset, loop_vinfo, relevant,
> -			    &worklist, true))
> -	    return false;
> +	  opt_result res
> +	    = process_use (stmt_vinfo, gs_info.offset, loop_vinfo, relevant,
> +			   &worklist, true);
> +	  if (!res)
> +	    return res;
>  	}
>      } /* while worklist */
>  
> -  return true;
> +  return opt_result::success ();
>  }
>  
>  /* Compute the prologue cost for invariant or constant operands.  */
> @@ -9382,7 +9379,7 @@ can_vectorize_live_stmts (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
>  
>  /* Make sure the statement is vectorizable.  */
>  
> -bool
> +opt_result
>  vect_analyze_stmt (stmt_vec_info stmt_info, bool *need_to_vectorize,
>  		   slp_tree node, slp_instance node_instance,
>  		   stmt_vector_for_cost *cost_vec)
> @@ -9398,13 +9395,10 @@ vect_analyze_stmt (stmt_vec_info stmt_info, bool *need_to_vectorize,
>  		     stmt_info->stmt);
>  
>    if (gimple_has_volatile_ops (stmt_info->stmt))
> -    {
> -      if (dump_enabled_p ())
> -        dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -                         "not vectorized: stmt has volatile operands\n");
> -
> -      return false;
> -    }
> +    return opt_result::failure_at (stmt_info->stmt,
> +				   "not vectorized:"
> +				   " stmt has volatile operands: %G\n",
> +				   stmt_info->stmt);
>  
>    if (STMT_VINFO_IN_PATTERN_P (stmt_info)
>        && node == NULL
> @@ -9425,10 +9419,12 @@ vect_analyze_stmt (stmt_vec_info stmt_info, bool *need_to_vectorize,
>  				 "==> examining pattern def statement: %G",
>  				 pattern_def_stmt_info->stmt);
>  
> -	      if (!vect_analyze_stmt (pattern_def_stmt_info,
> -				      need_to_vectorize, node, node_instance,
> -				      cost_vec))
> -		return false;
> +	      opt_result res
> +		= vect_analyze_stmt (pattern_def_stmt_info,
> +				     need_to_vectorize, node, node_instance,
> +				     cost_vec);
> +	      if (!res)
> +		return res;
>  	    }
>  	}
>      }
> @@ -9468,7 +9464,7 @@ vect_analyze_stmt (stmt_vec_info stmt_info, bool *need_to_vectorize,
>            if (dump_enabled_p ())
>              dump_printf_loc (MSG_NOTE, vect_location, "irrelevant.\n");
>  
> -          return true;
> +          return opt_result::success ();
>          }
>      }
>    else if (STMT_VINFO_IN_PATTERN_P (stmt_info)
> @@ -9483,9 +9479,11 @@ vect_analyze_stmt (stmt_vec_info stmt_info, bool *need_to_vectorize,
>  			 "==> examining pattern statement: %G",
>  			 pattern_stmt_info->stmt);
>  
> -      if (!vect_analyze_stmt (pattern_stmt_info, need_to_vectorize, node,
> -			      node_instance, cost_vec))
> -        return false;
> +      opt_result res
> +	= vect_analyze_stmt (pattern_stmt_info, need_to_vectorize, node,
> +			     node_instance, cost_vec);
> +      if (!res)
> +	return res;
>     }
>  
>    switch (STMT_VINFO_DEF_TYPE (stmt_info))
> @@ -9528,7 +9526,7 @@ vect_analyze_stmt (stmt_vec_info stmt_info, bool *need_to_vectorize,
>      {
>        dump_printf_loc (MSG_NOTE, vect_location,
>  		       "handled only by SLP analysis\n");
> -      return true;
> +      return opt_result::success ();
>      }
>  
>    ok = true;
> @@ -9573,30 +9571,22 @@ vect_analyze_stmt (stmt_vec_info stmt_info, bool *need_to_vectorize,
>      }
>  
>    if (!ok)
> -    {
> -      if (dump_enabled_p ())
> -	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			 "not vectorized: relevant stmt not supported: %G",
> -			 stmt_info->stmt);
> -
> -      return false;
> -    }
> +    return opt_result::failure_at (stmt_info->stmt,
> +				   "not vectorized:"
> +				   " relevant stmt not supported: %G",
> +				   stmt_info->stmt);
>  
>    /* Stmts that are (also) "live" (i.e. - that are used out of the loop)
>        need extra handling, except for vectorizable reductions.  */
>    if (!bb_vinfo
>        && STMT_VINFO_TYPE (stmt_info) != reduc_vec_info_type
>        && !can_vectorize_live_stmts (stmt_info, NULL, node, NULL, cost_vec))
> -    {
> -      if (dump_enabled_p ())
> -	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			 "not vectorized: live stmt not supported: %G",
> -			 stmt_info->stmt);
> +    return opt_result::failure_at (stmt_info->stmt,
> +				   "not vectorized:"
> +				   " live stmt not supported: %G",
> +				   stmt_info->stmt);
>  
> -       return false;
> -    }
> -
> -  return true;
> +  return opt_result::success ();
>  }
>  
>  
> @@ -10537,7 +10527,7 @@ vect_gen_while_not (gimple_seq *seq, tree mask_type, tree start_index,
>       number of units needed to vectorize STMT_INFO, or NULL_TREE if the
>       statement does not help to determine the overall number of units.  */
>  
> -bool
> +opt_result
>  vect_get_vector_types_for_stmt (stmt_vec_info stmt_info,
>  				tree *stmt_vectype_out,
>  				tree *nunits_vectype_out)
> @@ -10560,22 +10550,17 @@ vect_get_vector_types_for_stmt (stmt_vec_info stmt_info,
>  	  if (dump_enabled_p ())
>  	    dump_printf_loc (MSG_NOTE, vect_location,
>  			     "defer to SIMD clone analysis.\n");
> -	  return true;
> +	  return opt_result::success ();
>  	}
>  
> -      if (dump_enabled_p ())
> -	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			 "not vectorized: irregular stmt.%G", stmt);
> -      return false;
> +      return opt_result::failure_at (stmt,
> +				     "not vectorized: irregular stmt.%G", stmt);
>      }
>  
>    if (VECTOR_MODE_P (TYPE_MODE (gimple_expr_type (stmt))))
> -    {
> -      if (dump_enabled_p ())
> -	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			 "not vectorized: vector stmt in loop:%G", stmt);
> -      return false;
> -    }
> +    return opt_result::failure_at (stmt,
> +				   "not vectorized: vector stmt in loop:%G",
> +				   stmt);
>  
>    tree vectype;
>    tree scalar_type = NULL_TREE;
> @@ -10606,7 +10591,7 @@ vect_get_vector_types_for_stmt (stmt_vec_info stmt_info,
>  	      if (dump_enabled_p ())
>  		dump_printf_loc (MSG_NOTE, vect_location,
>  				 "pure bool operation.\n");
> -	      return true;
> +	      return opt_result::success ();
>  	    }
>  	}
>  
> @@ -10615,13 +10600,10 @@ vect_get_vector_types_for_stmt (stmt_vec_info stmt_info,
>  			 "get vectype for scalar type:  %T\n", scalar_type);
>        vectype = get_vectype_for_scalar_type (scalar_type);
>        if (!vectype)
> -	{
> -	  if (dump_enabled_p ())
> -	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			     "not vectorized: unsupported data-type %T\n",
> -			     scalar_type);
> -	  return false;
> -	}
> +	return opt_result::failure_at (stmt,
> +				       "not vectorized:"
> +				       " unsupported data-type %T\n",
> +				       scalar_type);
>  
>        if (!*stmt_vectype_out)
>  	*stmt_vectype_out = vectype;
> @@ -10652,24 +10634,16 @@ vect_get_vector_types_for_stmt (stmt_vec_info stmt_info,
>        nunits_vectype = get_vectype_for_scalar_type (scalar_type);
>      }
>    if (!nunits_vectype)
> -    {
> -      if (dump_enabled_p ())
> -	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			 "not vectorized: unsupported data-type %T\n",
> -			 scalar_type);
> -      return false;
> -    }
> +    return opt_result::failure_at (stmt,
> +				   "not vectorized: unsupported data-type %T\n",
> +				   scalar_type);
>  
>    if (maybe_ne (GET_MODE_SIZE (TYPE_MODE (vectype)),
>  		GET_MODE_SIZE (TYPE_MODE (nunits_vectype))))
> -    {
> -      if (dump_enabled_p ())
> -	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			 "not vectorized: different sized vector "
> -			 "types in statement, %T and %T\n",
> -			 vectype, nunits_vectype);
> -      return false;
> -    }
> +    return opt_result::failure_at (stmt,
> +				   "not vectorized: different sized vector "
> +				   "types in statement, %T and %T\n",
> +				   vectype, nunits_vectype);
>  
>    if (dump_enabled_p ())
>      {
> @@ -10682,14 +10656,14 @@ vect_get_vector_types_for_stmt (stmt_vec_info stmt_info,
>      }
>  
>    *nunits_vectype_out = nunits_vectype;
> -  return true;
> +  return opt_result::success ();
>  }
>  
>  /* Try to determine the correct vector type for STMT_INFO, which is a
>     statement that produces a scalar boolean result.  Return the vector
>     type on success, otherwise return NULL_TREE.  */
>  
> -tree
> +opt_tree
>  vect_get_mask_type_for_stmt (stmt_vec_info stmt_info)
>  {
>    gimple *stmt = stmt_info->stmt;
> @@ -10704,12 +10678,8 @@ vect_get_mask_type_for_stmt (stmt_vec_info stmt_info)
>        mask_type = get_mask_type_for_scalar_type (scalar_type);
>  
>        if (!mask_type)
> -	{
> -	  if (dump_enabled_p ())
> -	    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -			     "not vectorized: unsupported mask\n");
> -	  return NULL_TREE;
> -	}
> +	return opt_tree::failure_at (stmt,
> +				     "not vectorized: unsupported mask\n");
>      }
>    else
>      {
> @@ -10720,13 +10690,9 @@ vect_get_mask_type_for_stmt (stmt_vec_info stmt_info)
>        FOR_EACH_SSA_TREE_OPERAND (rhs, stmt, iter, SSA_OP_USE)
>  	{
>  	  if (!vect_is_simple_use (rhs, stmt_info->vinfo, &dt, &vectype))
> -	    {
> -	      if (dump_enabled_p ())
> -		dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -				 "not vectorized: can't compute mask type "
> -				 "for statement, %G", stmt);
> -	      return NULL_TREE;
> -	    }
> +	    return opt_tree::failure_at (stmt,
> +					 "not vectorized:can't compute mask"
> +					 " type for statement, %G", stmt);
>  
>  	  /* No vectype probably means external definition.
>  	     Allow it in case there is another operand which
> @@ -10738,25 +10704,17 @@ vect_get_mask_type_for_stmt (stmt_vec_info stmt_info)
>  	    mask_type = vectype;
>  	  else if (maybe_ne (TYPE_VECTOR_SUBPARTS (mask_type),
>  			     TYPE_VECTOR_SUBPARTS (vectype)))
> -	    {
> -	      if (dump_enabled_p ())
> -		dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -				 "not vectorized: different sized masks "
> -				 "types in statement, %T and %T\n",
> -				 mask_type, vectype);
> -	      return NULL_TREE;
> -	    }
> +	    return opt_tree::failure_at (stmt,
> +					 "not vectorized: different sized mask"
> +					 " types in statement, %T and %T\n",
> +					 mask_type, vectype);
>  	  else if (VECTOR_BOOLEAN_TYPE_P (mask_type)
>  		   != VECTOR_BOOLEAN_TYPE_P (vectype))
> -	    {
> -	      if (dump_enabled_p ())
> -		dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -				 "not vectorized: mixed mask and "
> -				 "nonmask vector types in statement, "
> -				 "%T and %T\n",
> -				 mask_type, vectype);
> -	      return NULL_TREE;
> -	    }
> +	    return opt_tree::failure_at (stmt,
> +					 "not vectorized: mixed mask and "
> +					 "nonmask vector types in statement, "
> +					 "%T and %T\n",
> +					 mask_type, vectype);
>  	}
>  
>        /* We may compare boolean value loaded as vector of integers.
> @@ -10770,9 +10728,10 @@ vect_get_mask_type_for_stmt (stmt_vec_info stmt_info)
>  
>    /* No mask_type should mean loop invariant predicate.
>       This is probably a subject for optimization in if-conversion.  */
> -  if (!mask_type && dump_enabled_p ())
> -    dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> -		     "not vectorized: can't compute mask type "
> -		     "for statement, %G", stmt);
> -  return mask_type;
> +  if (!mask_type)
> +    return opt_tree::failure_at (stmt,
> +				 "not vectorized: can't compute mask type "
> +				 "for statement: %G", stmt);
> +
> +  return opt_tree::success (mask_type);
>  }
> diff --git a/gcc/tree-vectorizer.c b/gcc/tree-vectorizer.c
> index 23bddf3..747fb67 100644
> --- a/gcc/tree-vectorizer.c
> +++ b/gcc/tree-vectorizer.c
> @@ -79,6 +79,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "stringpool.h"
>  #include "attribs.h"
>  #include "gimple-pretty-print.h"
> +#include "opt-problem.h"
>  
>  
>  /* Loop or bb location, with hotness information.  */
> @@ -860,13 +861,25 @@ try_vectorize_loop_1 (hash_table<simduid_to_vf> *&simduid_to_vf_htab,
>    vect_location = find_loop_location (loop);
>    if (LOCATION_LOCUS (vect_location.get_location_t ()) != UNKNOWN_LOCATION
>        && dump_enabled_p ())
> -    dump_printf (MSG_NOTE, "\nAnalyzing loop at %s:%d\n",
> +    dump_printf (MSG_NOTE | MSG_PRIORITY_INTERNALS,
> +		 "\nAnalyzing loop at %s:%d\n",
>  		 LOCATION_FILE (vect_location.get_location_t ()),
>  		 LOCATION_LINE (vect_location.get_location_t ()));
>  
> -  loop_vec_info loop_vinfo = vect_analyze_loop (loop, orig_loop_vinfo, &shared);
> +  /* Try to analyze the loop, retaining an opt_problem if dump_enabled_p.  */
> +  opt_loop_vec_info loop_vinfo
> +    = vect_analyze_loop (loop, orig_loop_vinfo, &shared);
>    loop->aux = loop_vinfo;
>  
> +  if (!loop_vinfo)
> +    if (dump_enabled_p ())
> +      if (opt_problem *problem = loop_vinfo.get_problem ())
> +	{
> +	  dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
> +			   "couldn't vectorize loop\n");
> +	  problem->emit_and_clear ();
> +	}
> +
>    if (!loop_vinfo || !LOOP_VINFO_VECTORIZABLE_P (loop_vinfo))
>      {
>        /* Free existing information if loop is analyzed with some
> diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h
> index af5d5bf..63cff79 100644
> --- a/gcc/tree-vectorizer.h
> +++ b/gcc/tree-vectorizer.h
> @@ -612,6 +612,12 @@ typedef struct _loop_vec_info : public vec_info {
>  #define LOOP_VINFO_ORIG_MAX_VECT_FACTOR(L) \
>    (LOOP_VINFO_MAX_VECT_FACTOR (LOOP_VINFO_ORIG_LOOP_INFO (L)))
>  
> +/* Wrapper for loop_vec_info, for tracking success/failure, where a non-NULL
> +   value signifies success, and a NULL value signifies failure, supporting
> +   propagating an opt_problem * describing the failure back up the call
> +   stack.  */
> +typedef opt_pointer_wrapper <loop_vec_info> opt_loop_vec_info;
> +
>  static inline loop_vec_info
>  loop_vec_info_for_loop (struct loop *loop)
>  {
> @@ -1473,7 +1479,7 @@ extern unsigned record_stmt_cost (stmt_vector_for_cost *, int,
>  extern stmt_vec_info vect_finish_replace_stmt (stmt_vec_info, gimple *);
>  extern stmt_vec_info vect_finish_stmt_generation (stmt_vec_info, gimple *,
>  						  gimple_stmt_iterator *);
> -extern bool vect_mark_stmts_to_be_vectorized (loop_vec_info);
> +extern opt_result vect_mark_stmts_to_be_vectorized (loop_vec_info);
>  extern tree vect_get_store_rhs (stmt_vec_info);
>  extern tree vect_get_vec_def_for_operand_1 (stmt_vec_info, enum vect_def_type);
>  extern tree vect_get_vec_def_for_operand (tree, stmt_vec_info, tree = NULL);
> @@ -1487,8 +1493,8 @@ extern tree vect_get_vec_def_for_stmt_copy (vec_info *, tree);
>  extern bool vect_transform_stmt (stmt_vec_info, gimple_stmt_iterator *,
>  				 slp_tree, slp_instance);
>  extern void vect_remove_stores (stmt_vec_info);
> -extern bool vect_analyze_stmt (stmt_vec_info, bool *, slp_tree, slp_instance,
> -			       stmt_vector_for_cost *);
> +extern opt_result vect_analyze_stmt (stmt_vec_info, bool *, slp_tree,
> +				     slp_instance, stmt_vector_for_cost *);
>  extern bool vectorizable_condition (stmt_vec_info, gimple_stmt_iterator *,
>  				    stmt_vec_info *, tree, int, slp_tree,
>  				    stmt_vector_for_cost *);
> @@ -1504,8 +1510,9 @@ extern tree vect_gen_perm_mask_checked (tree, const vec_perm_indices &);
>  extern void optimize_mask_stores (struct loop*);
>  extern gcall *vect_gen_while (tree, tree, tree);
>  extern tree vect_gen_while_not (gimple_seq *, tree, tree, tree);
> -extern bool vect_get_vector_types_for_stmt (stmt_vec_info, tree *, tree *);
> -extern tree vect_get_mask_type_for_stmt (stmt_vec_info);
> +extern opt_result vect_get_vector_types_for_stmt (stmt_vec_info, tree *,
> +						  tree *);
> +extern opt_tree vect_get_mask_type_for_stmt (stmt_vec_info);
>  
>  /* In tree-vect-data-refs.c.  */
>  extern bool vect_can_force_dr_alignment_p (const_tree, unsigned int);
> @@ -1513,21 +1520,21 @@ extern enum dr_alignment_support vect_supportable_dr_alignment
>                                             (dr_vec_info *, bool);
>  extern tree vect_get_smallest_scalar_type (stmt_vec_info, HOST_WIDE_INT *,
>                                             HOST_WIDE_INT *);
> -extern bool vect_analyze_data_ref_dependences (loop_vec_info, unsigned int *);
> +extern opt_result vect_analyze_data_ref_dependences (loop_vec_info, unsigned int *);
>  extern bool vect_slp_analyze_instance_dependence (slp_instance);
> -extern bool vect_enhance_data_refs_alignment (loop_vec_info);
> -extern bool vect_analyze_data_refs_alignment (loop_vec_info);
> -extern bool vect_verify_datarefs_alignment (loop_vec_info);
> +extern opt_result vect_enhance_data_refs_alignment (loop_vec_info);
> +extern opt_result vect_analyze_data_refs_alignment (loop_vec_info);
> +extern opt_result vect_verify_datarefs_alignment (loop_vec_info);
>  extern bool vect_slp_analyze_and_verify_instance_alignment (slp_instance);
> -extern bool vect_analyze_data_ref_accesses (vec_info *);
> -extern bool vect_prune_runtime_alias_test_list (loop_vec_info);
> +extern opt_result vect_analyze_data_ref_accesses (vec_info *);
> +extern opt_result vect_prune_runtime_alias_test_list (loop_vec_info);
>  extern bool vect_gather_scatter_fn_p (bool, bool, tree, tree, unsigned int,
>  				      signop, int, internal_fn *, tree *);
>  extern bool vect_check_gather_scatter (stmt_vec_info, loop_vec_info,
>  				       gather_scatter_info *);
> -extern bool vect_find_stmt_data_reference (loop_p, gimple *,
> -					   vec<data_reference_p> *);
> -extern bool vect_analyze_data_refs (vec_info *, poly_uint64 *);
> +extern opt_result vect_find_stmt_data_reference (loop_p, gimple *,
> +						 vec<data_reference_p> *);
> +extern opt_result vect_analyze_data_refs (vec_info *, poly_uint64 *);
>  extern void vect_record_base_alignments (vec_info *);
>  extern tree vect_create_data_ref_ptr (stmt_vec_info, tree, struct loop *, tree,
>  				      tree *, gimple_stmt_iterator *,
> @@ -1563,8 +1570,9 @@ extern stmt_vec_info vect_force_simple_reduction (loop_vec_info, stmt_vec_info,
>  extern bool check_reduction_path (dump_user_location_t, loop_p, gphi *, tree,
>  				  enum tree_code);
>  /* Drive for loop analysis stage.  */
> -extern loop_vec_info vect_analyze_loop (struct loop *, loop_vec_info,
> -					vec_info_shared *);
> +extern opt_loop_vec_info vect_analyze_loop (struct loop *,
> +					    loop_vec_info,
> +					    vec_info_shared *);
>  extern tree vect_build_loop_niters (loop_vec_info, bool * = NULL);
>  extern void vect_gen_vector_loop_niters (loop_vec_info, tree, tree *,
>  					 tree *, bool);
> @@ -1577,7 +1585,8 @@ extern tree vect_get_loop_mask (gimple_stmt_iterator *, vec_loop_masks *,
>  
>  /* Drive for loop transformation stage.  */
>  extern struct loop *vect_transform_loop (loop_vec_info);
> -extern loop_vec_info vect_analyze_loop_form (struct loop *, vec_info_shared *);
> +extern opt_loop_vec_info vect_analyze_loop_form (struct loop *,
> +						 vec_info_shared *);
>  extern bool vectorizable_live_operation (stmt_vec_info, gimple_stmt_iterator *,
>  					 slp_tree, int, stmt_vec_info *,
>  					 stmt_vector_for_cost *);
> @@ -1602,7 +1611,7 @@ extern bool vect_transform_slp_perm_load (slp_tree, vec<tree> ,
>  					  slp_instance, bool, unsigned *);
>  extern bool vect_slp_analyze_operations (vec_info *);
>  extern void vect_schedule_slp (vec_info *);
> -extern bool vect_analyze_slp (vec_info *, unsigned);
> +extern opt_result vect_analyze_slp (vec_info *, unsigned);
>  extern bool vect_make_slp_decision (loop_vec_info);
>  extern void vect_detect_hybrid_slp (loop_vec_info);
>  extern void vect_get_slp_defs (vec<tree> , slp_tree, vec<vec<tree> > *);
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nuernberg)

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 2/3] Add -fopt-info-internals
  2018-10-04 11:09           ` Richard Biener
@ 2018-10-04 17:12             ` David Malcolm
  2018-10-04 17:29               ` Richard Biener
  0 siblings, 1 reply; 24+ messages in thread
From: David Malcolm @ 2018-10-04 17:12 UTC (permalink / raw)
  To: Richard Biener; +Cc: Richard Sandiford, gcc-patches

On Thu, 2018-10-04 at 12:45 +0200, Richard Biener wrote:
> On Fri, 28 Sep 2018, David Malcolm wrote:
> 
> > This patch introduces a verbosity level to dump messages:
> > "user-facing" vs "internals".
> > 
> > By default, messages at the top-level dump scope are "user-facing",
> > whereas those that are in nested scopes are implicitly "internals",
> > and are filtered out by -fopt-info unless a new "-internals" sub-
> > option
> > of "-fopt-info" is supplied (intended purely for use by GCC
> > developers).
> > Dumpfiles are unaffected by the change.
> > 
> > Given that the vectorizer is the only subsystem using
> > AUTO_DUMP_SCOPE
> > (via DUMP_VECT_SCOPE), this only affects the vectorizer.
> > 
> > Filtering out these implementation-detail messages goes a long way
> > towards making -fopt-info-vec-all more accessible to advanced end-
> > users;
> > the follow-up patch restores the most pertinent missing details.
> > 
> > Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
> > 
> > OK for trunk?
> 
> What happens for flags & MSG_ALL_PRIORITIES == 0?  That is,
> do we require two bits for the priority at all?

I didn't want to go through every dump_* call, adding explicit
priorities, hence I went with the implicit priority scheme.
In the patch,
  flags & MSG_ALL_PRIORITIES == 0
is the case for almost all dump_* calls, and indicates "use implicit
priority", making use of the nesting.  This is implemented in the patch
in dump_context::apply_dump_filter_p.

In a few places, some dump_* calls *do* have an explicit priority, in
which case dump_context::apply_dump_filter_p uses it.

Hence in some ways it's a tri-state:

(a) implicit
      (flags & MSG_ALL_PRIORITIES == 0)

(b) explicitly "user-facing"
      (flags & MSG_ALL_PRIORITIES == MSG_PRIORITY_USER_FACING)

(b) explicitly "internals"
      (flags & MSG_ALL_PRIORITIES == MSG_PRIORITY_INTERNALS)

...and so needs 2 bits.  This scheme also supports messages that are
both "user-facing" *and* "internals", though I don't know if that's
useful. selftest::test_capture_of_dump_calls has test coverage for all
4 combinations of the bits.

I went with the bits scheme for similarity with the existing MSG_ kinds
(MSG_OPTIMIZED_LOCATIONS, MSG_MISSED_OPTIMIZATION, MSG_NOTE), and the
way it allows filtering based on masking.

Dave

> It's an implementation detail of course, generally I like this
> (maybe not so much conflating with nesting, but ...).


> Richard.
> 
> > gcc/ChangeLog:
> > 	* doc/invoke.texi (-fopt-info): Document new "internals"
> > 	sub-option.
> > 	* dump-context.h (dump_context::apply_dump_filter_p): New decl.
> > 	* dumpfile.c (dump_options): Update for renaming of MSG_ALL to
> > 	MSG_ALL_KINDS.
> > 	(optinfo_verbosity_options): Add "internals".
> > 	(kind_as_string): Update for renaming of MSG_ALL to
> > MSG_ALL_KINDS.
> > 	(dump_context::apply_dump_filter_p): New member function.
> > 	(dump_context::dump_loc): Use apply_dump_filter_p rather than
> > 	explicitly masking the dump_kind.
> > 	(dump_context::begin_scope): Increment the scope depth
> > first.  Use
> > 	apply_dump_filter_p rather than explicitly masking the
> > dump_kind.
> > 	(dump_context::emit_item): Use apply_dump_filter_p rather than
> > 	explicitly masking the dump_kind.
> > 	(dump_dec): Likewise.
> > 	(dump_hex): Likewise.
> > 	(dump_switch_p_1): Default to MSG_ALL_PRIORITIES.
> > 	(opt_info_switch_p_1): Default to MSG_PRIORITY_USER_FACING.
> > 	(opt_info_switch_p): Update handling of default
> > 	MSG_OPTIMIZED_LOCATIONS to cope with default of
> > 	MSG_PRIORITY_USER_FACING.
> > 	(dump_basic_block): Use apply_dump_filter_p rather than
> > explicitly
> > 	masking the dump_kind.
> > 	(selftest::test_capture_of_dump_calls): Update
> > test_dump_context
> > 	instances to use MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING
> > rather
> > 	than MSG_ALL.  Generalize scope test to be run at all four
> > 	combinations of with/without MSG_PRIORITY_USER_FACING and
> > 	MSG_PRIORITY_INTERNALS, adding examples of explicit priority
> > 	for each of the two values.
> > 	* dumpfile.h (enum dump_flag): Add comment about the MSG_*
> > flags.
> > 	Rename MSG_ALL to MSG_ALL_KINDS.  Add MSG_PRIORITY_USER_FACING,
> > 	MSG_PRIORITY_INTERNALS, and MSG_ALL_PRIORITIES, updating the
> > 	values for TDF_COMPARE_DEBUG and TDF_ALL_VALUES.
> > 	(AUTO_DUMP_SCOPE): Add a note to the comment about the
> > interaction
> > 	with MSG_PRIORITY_*.
> > 	* tree-vect-loop-manip.c (vect_loop_versioning): Mark
> > versioning
> > 	dump messages as MSG_PRIORITY_USER_FACING.
> > 	* tree-vectorizer.h (DUMP_VECT_SCOPE): Add a note to the
> > comment
> > 	about the interaction with MSG_PRIORITY_*.
> > 
> > gcc/testsuite/ChangeLog:
> > 	* gcc.dg/plugin/dump-1.c: Update expected output for
> > test_scopes
> > 	due to "-internals" not being selected.
> > 	* gcc.dg/plugin/dump-2.c: New test, based on dump-1.c, with
> > 	"-internals" added to re-enable the output from test_scopes.
> > 	* gcc.dg/plugin/plugin.exp (plugin_test_list): Add dump-2.c.
> > ---
> >  gcc/doc/invoke.texi                    |  31 ++++-
> >  gcc/dump-context.h                     |   2 +
> >  gcc/dumpfile.c                         | 248
> > +++++++++++++++++++++++----------
> >  gcc/dumpfile.h                         |  41 +++++-
> >  gcc/testsuite/gcc.dg/plugin/dump-1.c   |  10 +-
> >  gcc/testsuite/gcc.dg/plugin/dump-2.c   |  30 ++++
> >  gcc/testsuite/gcc.dg/plugin/plugin.exp |   3 +-
> >  gcc/tree-vect-loop-manip.c             |   6 +-
> >  gcc/tree-vectorizer.h                  |   6 +-
> >  9 files changed, 279 insertions(+), 98 deletions(-)
> >  create mode 100644 gcc/testsuite/gcc.dg/plugin/dump-2.c
> > 
> > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> > index 5c95f67..ab8d9b7e8 100644
> > --- a/gcc/doc/invoke.texi
> > +++ b/gcc/doc/invoke.texi
> > @@ -14207,14 +14207,21 @@ Controls optimization dumps from various
> > optimization passes. If the
> >  @samp{-} separated option keywords to select the dump details and
> >  optimizations.  
> >  
> > -The @var{options} can be divided into two groups: options
> > describing the
> > -verbosity of the dump, and options describing which optimizations
> > -should be included. The options from both the groups can be freely
> > -mixed as they are non-overlapping. However, in case of any
> > conflicts,
> > +The @var{options} can be divided into three groups:
> > +@enumerate
> > +@item
> > +options describing what kinds of messages should be emitted,
> > +@item
> > +options describing the verbosity of the dump, and
> > +@item
> > +options describing which optimizations should be included.
> > +@end enumerate
> > +The options from each group can be freely mixed as they are
> > +non-overlapping. However, in case of any conflicts,
> >  the later options override the earlier options on the command
> >  line. 
> >  
> > -The following options control the dump verbosity:
> > +The following options control which kinds of messages should be
> > emitted:
> >  
> >  @table @samp
> >  @item optimized
> > @@ -14233,6 +14240,15 @@ Print detailed optimization information.
> > This includes
> >  @samp{optimized}, @samp{missed}, and @samp{note}.
> >  @end table
> >  
> > +The following option controls the dump verbosity:
> > +
> > +@table @samp
> > +@item internals
> > +By default, only ``high-level'' messages are emitted. This option
> > enables
> > +additional, more detailed, messages, which are likely to only be
> > of interest
> > +to GCC developers.
> > +@end table
> > +
> >  One or more of the following option keywords can be used to
> > describe a
> >  group of optimizations:
> >  
> > @@ -14253,8 +14269,9 @@ the optimization groups listed above.
> >  @end table
> >  
> >  If @var{options} is
> > -omitted, it defaults to @samp{optimized-optall}, which means to
> > dump all
> > -info about successful optimizations from all the passes.  
> > +omitted, it defaults to @samp{optimized-optall}, which means to
> > dump messages
> > +about successful optimizations from all the passes, omitting
> > messages
> > +that are treated as ``internals''.
> >  
> >  If the @var{filename} is provided, then the dumps from all the
> >  applicable optimizations are concatenated into the @var{filename}.
> > diff --git a/gcc/dump-context.h b/gcc/dump-context.h
> > index 5b20c15..20b94a7 100644
> > --- a/gcc/dump-context.h
> > +++ b/gcc/dump-context.h
> > @@ -100,6 +100,8 @@ class dump_context
> >  
> >    void emit_item (optinfo_item *item, dump_flags_t dump_kind);
> >  
> > +  bool apply_dump_filter_p (dump_flags_t dump_kind, dump_flags_t
> > filter) const;
> > +
> >   private:
> >    optinfo &ensure_pending_optinfo ();
> >    optinfo &begin_next_optinfo (const dump_location_t &loc);
> > diff --git a/gcc/dumpfile.c b/gcc/dumpfile.c
> > index d359e41..e15edc7 100644
> > --- a/gcc/dumpfile.c
> > +++ b/gcc/dumpfile.c
> > @@ -141,7 +141,7 @@ static const kv_pair<dump_flags_t>
> > dump_options[] =
> >    {"optimized", MSG_OPTIMIZED_LOCATIONS},
> >    {"missed", MSG_MISSED_OPTIMIZATION},
> >    {"note", MSG_NOTE},
> > -  {"optall", MSG_ALL},
> > +  {"optall", MSG_ALL_KINDS},
> >    {"all", dump_flags_t (TDF_ALL_VALUES
> >  			& ~(TDF_RAW | TDF_SLIM | TDF_LINENO |
> > TDF_GRAPH
> >  			    | TDF_STMTADDR | TDF_RHS_ONLY |
> > TDF_NOUID
> > @@ -157,7 +157,8 @@ static const kv_pair<dump_flags_t>
> > optinfo_verbosity_options[] =
> >    {"optimized", MSG_OPTIMIZED_LOCATIONS},
> >    {"missed", MSG_MISSED_OPTIMIZATION},
> >    {"note", MSG_NOTE},
> > -  {"all", MSG_ALL},
> > +  {"all", MSG_ALL_KINDS},
> > +  {"internals", MSG_PRIORITY_INTERNALS},
> >    {NULL, TDF_NONE}
> >  };
> >  
> > @@ -449,7 +450,7 @@ dump_user_location_t::from_function_decl (tree
> > fndecl)
> >  static const char *
> >  kind_as_string (dump_flags_t dump_kind)
> >  {
> > -  switch (dump_kind & MSG_ALL)
> > +  switch (dump_kind & MSG_ALL_KINDS)
> >      {
> >      default:
> >        gcc_unreachable ();
> > @@ -524,6 +525,35 @@ dump_context::refresh_dumps_are_enabled ()
> >  		       || m_test_pp);
> >  }
> >  
> > +/* Determine if a message of kind DUMP_KIND and at the current
> > scope depth
> > +   should be printed.
> > +
> > +   Only show messages that match FILTER both on their kind *and*
> > +   their priority.  */
> > +
> > +bool
> > +dump_context::apply_dump_filter_p (dump_flags_t dump_kind,
> > +				   dump_flags_t filter) const
> > +{
> > +  /* Few messages, if any, have an explicit MSG_PRIORITY.
> > +     If DUMP_KIND does, we'll use it.
> > +     Otherwise, generate an implicit priority value for the
> > message based
> > +     on the current scope depth.
> > +     Messages at the top-level scope are MSG_PRIORITY_USER_FACING,
> > +     whereas those in nested scopes are
> > MSG_PRIORITY_INTERNALS.  */
> > +  if (!(dump_kind & MSG_ALL_PRIORITIES))
> > +    {
> > +      dump_flags_t implicit_priority
> > +	=  (m_scope_depth > 0
> > +	    ? MSG_PRIORITY_INTERNALS
> > +	    : MSG_PRIORITY_USER_FACING);
> > +      dump_kind |= implicit_priority;
> > +    }
> > +
> > +  return (dump_kind & (filter & MSG_ALL_KINDS)
> > +	  && dump_kind & (filter & MSG_ALL_PRIORITIES));
> > +}
> > +
> >  /* Print LOC to the appropriate dump destinations, given
> > DUMP_KIND.
> >     If optinfos are enabled, begin a new optinfo.  */
> >  
> > @@ -534,14 +564,14 @@ dump_context::dump_loc (dump_flags_t
> > dump_kind, const dump_location_t &loc)
> >  
> >    location_t srcloc = loc.get_location_t ();
> >  
> > -  if (dump_file && (dump_kind & pflags))
> > +  if (dump_file && apply_dump_filter_p (dump_kind, pflags))
> >      ::dump_loc (dump_kind, dump_file, srcloc);
> >  
> > -  if (alt_dump_file && (dump_kind & alt_flags))
> > +  if (alt_dump_file && apply_dump_filter_p (dump_kind, alt_flags))
> >      ::dump_loc (dump_kind, alt_dump_file, srcloc);
> >  
> >    /* Support for temp_dump_context in selftests.  */
> > -  if (m_test_pp && (dump_kind & m_test_pp_flags))
> > +  if (m_test_pp && apply_dump_filter_p (dump_kind,
> > m_test_pp_flags))
> >      ::dump_loc (dump_kind, m_test_pp, srcloc);
> >  
> >    if (optinfo_enabled_p ())
> > @@ -1067,22 +1097,24 @@ dump_context::get_scope_depth () const
> >  }
> >  
> >  /* Push a nested dump scope.
> > +   Increment the scope depth.
> >     Print "=== NAME ===\n" to the dumpfile, if any, and to the
> > -fopt-info
> >     destination, if any.
> > -   Emit a "scope" optinfo if optinfos are enabled.
> > -   Increment the scope depth.  */
> > +   Emit a "scope" optinfo if optinfos are enabled.  */
> >  
> >  void
> >  dump_context::begin_scope (const char *name, const dump_location_t
> > &loc)
> >  {
> > -  if (dump_file && (MSG_NOTE & pflags))
> > +  m_scope_depth++;
> > +
> > +  if (dump_file && apply_dump_filter_p (MSG_NOTE, pflags))
> >      ::dump_loc (MSG_NOTE, dump_file, loc.get_location_t ());
> >  
> > -  if (alt_dump_file && (MSG_NOTE & alt_flags))
> > +  if (alt_dump_file && apply_dump_filter_p (MSG_NOTE, alt_flags))
> >      ::dump_loc (MSG_NOTE, alt_dump_file, loc.get_location_t ());
> >  
> >    /* Support for temp_dump_context in selftests.  */
> > -  if (m_test_pp && (MSG_NOTE & m_test_pp_flags))
> > +  if (m_test_pp && apply_dump_filter_p (MSG_NOTE,
> > m_test_pp_flags))
> >      ::dump_loc (MSG_NOTE, m_test_pp, loc.get_location_t ());
> >  
> >    pretty_printer pp;
> > @@ -1100,8 +1132,6 @@ dump_context::begin_scope (const char *name,
> > const dump_location_t &loc)
> >      }
> >    else
> >      delete item;
> > -
> > -  m_scope_depth++;
> >  }
> >  
> >  /* Pop a nested dump scope.  */
> > @@ -1155,14 +1185,14 @@ dump_context::end_any_optinfo ()
> >  void
> >  dump_context::emit_item (optinfo_item *item, dump_flags_t
> > dump_kind)
> >  {
> > -  if (dump_file && (dump_kind & pflags))
> > +  if (dump_file && apply_dump_filter_p (dump_kind, pflags))
> >      fprintf (dump_file, "%s", item->get_text ());
> >  
> > -  if (alt_dump_file && (dump_kind & alt_flags))
> > +  if (alt_dump_file && apply_dump_filter_p (dump_kind, alt_flags))
> >      fprintf (alt_dump_file, "%s", item->get_text ());
> >  
> >    /* Support for temp_dump_context in selftests.  */
> > -  if (m_test_pp && (dump_kind & m_test_pp_flags))
> > +  if (m_test_pp && apply_dump_filter_p (dump_kind,
> > m_test_pp_flags))
> >      pp_string (m_test_pp, item->get_text ());
> >  }
> >  
> > @@ -1278,10 +1308,12 @@ template void dump_dec (dump_flags_t, const
> > poly_widest_int &);
> >  void
> >  dump_dec (dump_flags_t dump_kind, const poly_wide_int &value,
> > signop sgn)
> >  {
> > -  if (dump_file && (dump_kind & pflags))
> > +  if (dump_file
> > +      && dump_context::get ().apply_dump_filter_p (dump_kind,
> > pflags))
> >      print_dec (value, dump_file, sgn);
> >  
> > -  if (alt_dump_file && (dump_kind & alt_flags))
> > +  if (alt_dump_file
> > +      && dump_context::get ().apply_dump_filter_p (dump_kind,
> > alt_flags))
> >      print_dec (value, alt_dump_file, sgn);
> >  }
> >  
> > @@ -1290,10 +1322,12 @@ dump_dec (dump_flags_t dump_kind, const
> > poly_wide_int &value, signop sgn)
> >  void
> >  dump_hex (dump_flags_t dump_kind, const poly_wide_int &value)
> >  {
> > -  if (dump_file && (dump_kind & pflags))
> > +  if (dump_file
> > +      && dump_context::get ().apply_dump_filter_p (dump_kind,
> > pflags))
> >      print_hex (value, dump_file);
> >  
> > -  if (alt_dump_file && (dump_kind & alt_flags))
> > +  if (alt_dump_file
> > +      && dump_context::get ().apply_dump_filter_p (dump_kind,
> > alt_flags))
> >      print_hex (value, alt_dump_file);
> >  }
> >  
> > @@ -1698,7 +1732,7 @@ dump_switch_p_1 (const char *arg, struct
> > dump_file_info *dfi, bool doglob)
> >      return 0;
> >  
> >    ptr = option_value;
> > -  flags = TDF_NONE;
> > +  flags = MSG_ALL_PRIORITIES;
> >  
> >    while (*ptr)
> >      {
> > @@ -1794,7 +1828,11 @@ opt_info_switch_p_1 (const char *arg,
> > dump_flags_t *flags,
> >    ptr = option_value;
> >  
> >    *filename = NULL;
> > -  *flags = TDF_NONE;
> > +
> > +  /* Default to filtering out "internals" messages, and retaining
> > +     "user-facing" messages.  */
> > +  *flags = MSG_PRIORITY_USER_FACING;
> > +
> >    *optgroup_flags = OPTGROUP_NONE;
> >  
> >    if (!ptr)
> > @@ -1883,8 +1921,8 @@ opt_info_switch_p (const char *arg)
> >      }
> >  
> >    file_seen = xstrdup (filename);
> > -  if (!flags)
> > -    flags = MSG_OPTIMIZED_LOCATIONS;
> > +  if (!(flags & MSG_ALL_KINDS))
> > +    flags |= MSG_OPTIMIZED_LOCATIONS;
> >    if (!optgroup_flags)
> >      optgroup_flags = OPTGROUP_ALL;
> >  
> > @@ -1896,9 +1934,11 @@ opt_info_switch_p (const char *arg)
> >  void
> >  dump_basic_block (dump_flags_t dump_kind, basic_block bb, int
> > indent)
> >  {
> > -  if (dump_file && (dump_kind & pflags))
> > +  if (dump_file
> > +      && dump_context::get ().apply_dump_filter_p (dump_kind,
> > pflags))
> >      dump_bb (dump_file, bb, indent, TDF_DETAILS);
> > -  if (alt_dump_file && (dump_kind & alt_flags))
> > +  if (alt_dump_file
> > +      && dump_context::get ().apply_dump_filter_p (dump_kind,
> > alt_flags))
> >      dump_bb (alt_dump_file, bb, indent, TDF_DETAILS);
> >  }
> >  
> > @@ -2104,7 +2144,8 @@ test_capture_of_dump_calls (const
> > line_table_case &case_)
> >  
> >        /* Test of dump_printf.  */
> >        {
> > -	temp_dump_context tmp (with_optinfo, MSG_ALL);
> > +	temp_dump_context tmp (with_optinfo,
> > +			       MSG_ALL_KINDS |
> > MSG_PRIORITY_USER_FACING);
> >  	dump_printf (MSG_NOTE, "int: %i str: %s", 42, "foo");
> >  
> >  	ASSERT_DUMPED_TEXT_EQ (tmp, "int: 42 str: foo");
> > @@ -2120,7 +2161,8 @@ test_capture_of_dump_calls (const
> > line_table_case &case_)
> >  
> >        /* Test of dump_printf with %T.  */
> >        {
> > -	temp_dump_context tmp (with_optinfo, MSG_ALL);
> > +	temp_dump_context tmp (with_optinfo,
> > +			       MSG_ALL_KINDS |
> > MSG_PRIORITY_USER_FACING);
> >  	dump_printf (MSG_NOTE, "tree: %T", integer_zero_node);
> >  
> >  	ASSERT_DUMPED_TEXT_EQ (tmp, "tree: 0");
> > @@ -2137,7 +2179,8 @@ test_capture_of_dump_calls (const
> > line_table_case &case_)
> >  
> >        /* Test of dump_printf with %E.  */
> >        {
> > -	temp_dump_context tmp (with_optinfo, MSG_ALL);
> > +	temp_dump_context tmp (with_optinfo,
> > +			       MSG_ALL_KINDS |
> > MSG_PRIORITY_USER_FACING);
> >  	dump_printf (MSG_NOTE, "gimple: %E", stmt);
> >  
> >  	ASSERT_DUMPED_TEXT_EQ (tmp, "gimple: return;");
> > @@ -2154,7 +2197,8 @@ test_capture_of_dump_calls (const
> > line_table_case &case_)
> >  
> >        /* Test of dump_printf with %G.  */
> >        {
> > -	temp_dump_context tmp (with_optinfo, MSG_ALL);
> > +	temp_dump_context tmp (with_optinfo,
> > +			       MSG_ALL_KINDS |
> > MSG_PRIORITY_USER_FACING);
> >  	dump_printf (MSG_NOTE, "gimple: %G", stmt);
> >  
> >  	ASSERT_DUMPED_TEXT_EQ (tmp, "gimple: return;\n");
> > @@ -2176,7 +2220,8 @@ test_capture_of_dump_calls (const
> > line_table_case &case_)
> >  	 - multiple dump-specific format codes: some consecutive,
> > others
> >  	 separated by text, trailing text after the final one.  */
> >        {
> > -	temp_dump_context tmp (with_optinfo, MSG_ALL);
> > +	temp_dump_context tmp (with_optinfo,
> > +			       MSG_ALL_KINDS |
> > MSG_PRIORITY_USER_FACING);
> >  	dump_printf_loc (MSG_NOTE, loc, "before %T and %T"
> >  			 " %i consecutive %E%E after\n",
> >  			 integer_zero_node, test_decl, 42, stmt,
> > stmt);
> > @@ -2203,7 +2248,8 @@ test_capture_of_dump_calls (const
> > line_table_case &case_)
> >  
> >        /* Tree, via dump_generic_expr.  */
> >        {
> > -	temp_dump_context tmp (with_optinfo, MSG_ALL);
> > +	temp_dump_context tmp (with_optinfo,
> > +			       MSG_ALL_KINDS |
> > MSG_PRIORITY_USER_FACING);
> >  	dump_printf_loc (MSG_NOTE, loc, "test of tree: ");
> >  	dump_generic_expr (MSG_NOTE, TDF_SLIM, integer_zero_node);
> >  
> > @@ -2222,7 +2268,8 @@ test_capture_of_dump_calls (const
> > line_table_case &case_)
> >  
> >        /* Tree, via dump_generic_expr_loc.  */
> >        {
> > -	temp_dump_context tmp (with_optinfo, MSG_ALL);
> > +	temp_dump_context tmp (with_optinfo,
> > +			       MSG_ALL_KINDS |
> > MSG_PRIORITY_USER_FACING);
> >  	dump_generic_expr_loc (MSG_NOTE, loc, TDF_SLIM,
> > integer_one_node);
> >  
> >  	ASSERT_DUMPED_TEXT_EQ (tmp, "test.txt:5:10: note: 1");
> > @@ -2241,7 +2288,8 @@ test_capture_of_dump_calls (const
> > line_table_case &case_)
> >        {
> >  	/* dump_gimple_stmt_loc.  */
> >  	{
> > -	  temp_dump_context tmp (with_optinfo, MSG_ALL);
> > +	  temp_dump_context tmp (with_optinfo,
> > +				 MSG_ALL_KINDS |
> > MSG_PRIORITY_USER_FACING);
> >  	  dump_gimple_stmt_loc (MSG_NOTE, loc, TDF_SLIM, stmt, 2);
> >  
> >  	  ASSERT_DUMPED_TEXT_EQ (tmp, "test.txt:5:10: note:
> > return;\n");
> > @@ -2256,7 +2304,8 @@ test_capture_of_dump_calls (const
> > line_table_case &case_)
> >  
> >  	/* dump_gimple_stmt.  */
> >  	{
> > -	  temp_dump_context tmp (with_optinfo, MSG_ALL);
> > +	  temp_dump_context tmp (with_optinfo,
> > +				 MSG_ALL_KINDS |
> > MSG_PRIORITY_USER_FACING);
> >  	  dump_gimple_stmt (MSG_NOTE, TDF_SLIM, stmt, 2);
> >  
> >  	  ASSERT_DUMPED_TEXT_EQ (tmp, "return;\n");
> > @@ -2271,7 +2320,8 @@ test_capture_of_dump_calls (const
> > line_table_case &case_)
> >  
> >  	/* dump_gimple_expr_loc.  */
> >  	{
> > -	  temp_dump_context tmp (with_optinfo, MSG_ALL);
> > +	  temp_dump_context tmp (with_optinfo,
> > +				 MSG_ALL_KINDS |
> > MSG_PRIORITY_USER_FACING);
> >  	  dump_gimple_expr_loc (MSG_NOTE, loc, TDF_SLIM, stmt, 2);
> >  
> >  	  ASSERT_DUMPED_TEXT_EQ (tmp, "test.txt:5:10: note:
> > return;");
> > @@ -2286,7 +2336,8 @@ test_capture_of_dump_calls (const
> > line_table_case &case_)
> >  
> >  	/* dump_gimple_expr.  */
> >  	{
> > -	  temp_dump_context tmp (with_optinfo, MSG_ALL);
> > +	  temp_dump_context tmp (with_optinfo,
> > +				 MSG_ALL_KINDS |
> > MSG_PRIORITY_USER_FACING);
> >  	  dump_gimple_expr (MSG_NOTE, TDF_SLIM, stmt, 2);
> >  
> >  	  ASSERT_DUMPED_TEXT_EQ (tmp, "return;");
> > @@ -2302,7 +2353,8 @@ test_capture_of_dump_calls (const
> > line_table_case &case_)
> >  
> >        /* poly_int.  */
> >        {
> > -	temp_dump_context tmp (with_optinfo, MSG_ALL);
> > +	temp_dump_context tmp (with_optinfo,
> > +			       MSG_ALL_KINDS |
> > MSG_PRIORITY_USER_FACING);
> >  	dump_dec (MSG_NOTE, poly_int64 (42));
> >  
> >  	ASSERT_DUMPED_TEXT_EQ (tmp, "42");
> > @@ -2315,45 +2367,92 @@ test_capture_of_dump_calls (const
> > line_table_case &case_)
> >  	  }
> >        }
> >  
> > -      /* scopes.  */
> > -      {
> > -	temp_dump_context tmp (with_optinfo, MSG_ALL);
> > -	dump_printf_loc (MSG_NOTE, stmt, "msg 1\n");
> > +      /* Scopes.  Test with all 4 combinations of
> > +	 filtering by MSG_PRIORITY_USER_FACING
> > +	 and/or filtering by MSG_PRIORITY_INTERNALS.  */
> > +      for (int j = 0; j < 3; j++)
> >  	{
> > -	  AUTO_DUMP_SCOPE ("outer scope", stmt);
> > -	  dump_printf_loc (MSG_NOTE, stmt, "msg 2\n");
> > +	  dump_flags_t dump_filter = MSG_ALL_KINDS;
> > +	  if (j % 2)
> > +	    dump_filter |= MSG_PRIORITY_USER_FACING;
> > +	  if (j / 2)
> > +	    dump_filter |= MSG_PRIORITY_INTERNALS;
> > +
> > +	  temp_dump_context tmp (with_optinfo, dump_filter);
> > +	  /* Emit various messages, mostly with implicit
> > priority.  */
> > +	  dump_printf_loc (MSG_NOTE, stmt, "msg 1\n");
> > +	  dump_printf_loc (MSG_NOTE | MSG_PRIORITY_INTERNALS,
> > stmt,
> > +			   "explicitly internal msg\n");
> >  	  {
> > -	    AUTO_DUMP_SCOPE ("middle scope", stmt);
> > -	    dump_printf_loc (MSG_NOTE, stmt, "msg 3\n");
> > +	    AUTO_DUMP_SCOPE ("outer scope", stmt);
> > +	    dump_printf_loc (MSG_NOTE, stmt, "msg 2\n");
> >  	    {
> > -	      AUTO_DUMP_SCOPE ("inner scope", stmt);
> > -	      dump_printf_loc (MSG_NOTE, stmt, "msg 4\n");
> > +	      AUTO_DUMP_SCOPE ("middle scope", stmt);
> > +	      dump_printf_loc (MSG_NOTE, stmt, "msg 3\n");
> > +	      {
> > +		AUTO_DUMP_SCOPE ("inner scope", stmt);
> > +		dump_printf_loc (MSG_NOTE, stmt, "msg 4\n");
> > +		dump_printf_loc (MSG_NOTE |
> > MSG_PRIORITY_USER_FACING, stmt,
> > +				 "explicitly user-facing msg\n");
> > +	      }
> > +	      dump_printf_loc (MSG_NOTE, stmt, "msg 5\n");
> >  	    }
> > -	    dump_printf_loc (MSG_NOTE, stmt, "msg 5\n");
> > +	    dump_printf_loc (MSG_NOTE, stmt, "msg 6\n");
> >  	  }
> > -	  dump_printf_loc (MSG_NOTE, stmt, "msg 6\n");
> > -	}
> > -	dump_printf_loc (MSG_NOTE, stmt, "msg 7\n");
> > +	  dump_printf_loc (MSG_NOTE, stmt, "msg 7\n");
> >  
> > -	ASSERT_DUMPED_TEXT_EQ (tmp,
> > -			       "test.txt:5:10: note: msg 1\n"
> > -			       "test.txt:5:10: note: === outer
> > scope ===\n"
> > -			       "test.txt:5:10: note:  msg 2\n"
> > -			       "test.txt:5:10: note:  === middle
> > scope ===\n"
> > -			       "test.txt:5:10: note:   msg 3\n"
> > -			       "test.txt:5:10: note:   === inner
> > scope ===\n"
> > -			       "test.txt:5:10: note:    msg 4\n"
> > -			       "test.txt:5:10: note:   msg 5\n"
> > -			       "test.txt:5:10: note:  msg 6\n"
> > -			       "test.txt:5:10: note: msg 7\n");
> > -	if (with_optinfo)
> > -	  {
> > -	    optinfo *info = tmp.get_pending_optinfo ();
> > -	    ASSERT_TRUE (info != NULL);
> > -	    ASSERT_EQ (info->num_items (), 1);
> > -	    ASSERT_IS_TEXT (info->get_item (0), "msg 7\n");
> > -	  }
> > -      }
> > +	  switch (dump_filter & MSG_ALL_PRIORITIES)
> > +	    {
> > +	    default:
> > +	      gcc_unreachable ();
> > +	    case 0:
> > +	      ASSERT_DUMPED_TEXT_EQ (tmp, "");
> > +	      break;
> > +	    case MSG_PRIORITY_USER_FACING:
> > +	      ASSERT_DUMPED_TEXT_EQ
> > +		(tmp,
> > +		 "test.txt:5:10: note: msg 1\n"
> > +		 "test.txt:5:10: note:    explicitly user-facing
> > msg\n"
> > +		 "test.txt:5:10: note: msg 7\n");
> > +	      break;
> > +	    case MSG_PRIORITY_INTERNALS:
> > +	      ASSERT_DUMPED_TEXT_EQ
> > +		(tmp,
> > +		 "test.txt:5:10: note: explicitly internal msg\n"
> > +		 "test.txt:5:10: note:  === outer scope ===\n"
> > +		 "test.txt:5:10: note:  msg 2\n"
> > +		 "test.txt:5:10: note:   === middle scope ===\n"
> > +		 "test.txt:5:10: note:   msg 3\n"
> > +		 "test.txt:5:10: note:    === inner scope ===\n"
> > +		 "test.txt:5:10: note:    msg 4\n"
> > +		 "test.txt:5:10: note:   msg 5\n"
> > +		 "test.txt:5:10: note:  msg 6\n");
> > +	      break;
> > +	    case MSG_ALL_PRIORITIES:
> > +	      ASSERT_DUMPED_TEXT_EQ
> > +		(tmp,
> > +		 "test.txt:5:10: note: msg 1\n"
> > +		 "test.txt:5:10: note: explicitly internal msg\n"
> > +		 "test.txt:5:10: note: === outer scope ===\n"
> > +		 "test.txt:5:10: note:  msg 2\n"
> > +		 "test.txt:5:10: note:  === middle scope ===\n"
> > +		 "test.txt:5:10: note:   msg 3\n"
> > +		 "test.txt:5:10: note:   === inner scope ===\n"
> > +		 "test.txt:5:10: note:    msg 4\n"
> > +		 "test.txt:5:10: note:    explicitly user-facing
> > msg\n"
> > +		 "test.txt:5:10: note:   msg 5\n"
> > +		 "test.txt:5:10: note:  msg 6\n"
> > +		 "test.txt:5:10: note: msg 7\n");
> > +	      break;
> > +	    }
> > +	  if (with_optinfo)
> > +	    {
> > +	      optinfo *info = tmp.get_pending_optinfo ();
> > +	      ASSERT_TRUE (info != NULL);
> > +	      ASSERT_EQ (info->num_items (), 1);
> > +	      ASSERT_IS_TEXT (info->get_item (0), "msg 7\n");
> > +	    }
> > +	}
> >      }
> >  
> >    /* Verify that MSG_* affects optinfo->get_kind (); we tested
> > MSG_NOTE
> > @@ -2361,7 +2460,7 @@ test_capture_of_dump_calls (const
> > line_table_case &case_)
> >    {
> >      /* MSG_OPTIMIZED_LOCATIONS.  */
> >      {
> > -      temp_dump_context tmp (true, MSG_ALL);
> > +      temp_dump_context tmp (true, MSG_ALL_KINDS);
> >        dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc, "test");
> >        ASSERT_EQ (tmp.get_pending_optinfo ()->get_kind (),
> >  		 OPTINFO_KIND_SUCCESS);
> > @@ -2369,7 +2468,7 @@ test_capture_of_dump_calls (const
> > line_table_case &case_)
> >  
> >      /* MSG_MISSED_OPTIMIZATION.  */
> >      {
> > -      temp_dump_context tmp (true, MSG_ALL);
> > +      temp_dump_context tmp (true, MSG_ALL_KINDS);
> >        dump_printf_loc (MSG_MISSED_OPTIMIZATION, loc, "test");
> >        ASSERT_EQ (tmp.get_pending_optinfo ()->get_kind (),
> >  		 OPTINFO_KIND_FAILURE);
> > @@ -2378,7 +2477,8 @@ test_capture_of_dump_calls (const
> > line_table_case &case_)
> >  
> >    /* Verify that MSG_* affect AUTO_DUMP_SCOPE and the dump
> > calls.  */
> >    {
> > -    temp_dump_context tmp (false, MSG_OPTIMIZED_LOCATIONS);
> > +    temp_dump_context tmp (false,
> > +			   MSG_OPTIMIZED_LOCATIONS |
> > MSG_ALL_PRIORITIES);
> >      dump_printf_loc (MSG_NOTE, stmt, "msg 1\n");
> >      {
> >        AUTO_DUMP_SCOPE ("outer scope", stmt);
> > diff --git a/gcc/dumpfile.h b/gcc/dumpfile.h
> > index 057ca46..5933905 100644
> > --- a/gcc/dumpfile.h
> > +++ b/gcc/dumpfile.h
> > @@ -145,6 +145,9 @@ enum dump_flag
> >    /* Dump folding details.  */
> >    TDF_FOLDING = (1 << 21),
> >  
> > +  /* MSG_* flags for expressing the kinds of message to
> > +     be emitted by -fopt-info.  */
> > +
> >    /* -fopt-info optimized sources.  */
> >    MSG_OPTIMIZED_LOCATIONS = (1 << 22),
> >  
> > @@ -154,15 +157,37 @@ enum dump_flag
> >    /* General optimization info.  */
> >    MSG_NOTE = (1 << 24),
> >  
> > -  MSG_ALL = (MSG_OPTIMIZED_LOCATIONS
> > -	     | MSG_MISSED_OPTIMIZATION
> > -	     | MSG_NOTE),
> > +  /* Mask for selecting MSG_-kind flags.  */
> > +  MSG_ALL_KINDS = (MSG_OPTIMIZED_LOCATIONS
> > +		   | MSG_MISSED_OPTIMIZATION
> > +		   | MSG_NOTE),
> > +
> > +  /* MSG_PRIORITY_* flags for expressing the priority levels of
> > message
> > +     to be emitted by -fopt-info, and filtering on them.
> > +     By default, messages at the top-level dump scope are "user-
> > facing",
> > +     whereas those that are in nested scopes are implicitly
> > "internals".
> > +     This behavior can be overridden for a given dump message by
> > explicitly
> > +     specifying one of the MSG_PRIORITY_* flags.
> > +
> > +     By default, dump files show both kinds of message, whereas
> > -fopt-info
> > +     only shows "user-facing" messages, and requires the "-
> > internals"
> > +     sub-option of -fopt-info to show the internal messages.  */
> > +
> > +  /* Implicitly supplied for messages at the top-level dump
> > scope.  */
> > +  MSG_PRIORITY_USER_FACING = (1 << 25),
> > +
> > +  /* Implicitly supplied for messages within nested dump
> > scopes.  */
> > +  MSG_PRIORITY_INTERNALS = (1 << 26),
> > +
> > +  /* Mask for selecting MSG_PRIORITY_* flags.  */
> > +  MSG_ALL_PRIORITIES = (MSG_PRIORITY_USER_FACING
> > +			| MSG_PRIORITY_INTERNALS),
> >  
> >    /* Dumping for -fcompare-debug.  */
> > -  TDF_COMPARE_DEBUG = (1 << 25),
> > +  TDF_COMPARE_DEBUG = (1 << 27),
> >  
> >    /* All values.  */
> > -  TDF_ALL_VALUES = (1 << 26) - 1
> > +  TDF_ALL_VALUES = (1 << 28) - 1
> >  };
> >  
> >  /* Dump flags type.  */
> > @@ -549,7 +574,11 @@ class auto_dump_scope
> >     and then calling
> >       dump_end_scope ();
> >     once the object goes out of scope, thus capturing the nesting
> > of
> > -   the scopes.  */
> > +   the scopes.
> > +
> > +   These scopes affect dump messages within them: dump messages at
> > the
> > +   top level implicitly default to MSG_PRIORITY_USER_FACING,
> > whereas those
> > +   in a nested scope implicitly default to
> > MSG_PRIORITY_INTERNALS.  */
> >  
> >  #define AUTO_DUMP_SCOPE(NAME, LOC) \
> >    auto_dump_scope scope (NAME, LOC)
> > diff --git a/gcc/testsuite/gcc.dg/plugin/dump-1.c
> > b/gcc/testsuite/gcc.dg/plugin/dump-1.c
> > index 165a9c1..95bd7a4 100644
> > --- a/gcc/testsuite/gcc.dg/plugin/dump-1.c
> > +++ b/gcc/testsuite/gcc.dg/plugin/dump-1.c
> > @@ -18,11 +18,7 @@ void test_remarks (void)
> >    test_wide_int (); /* { dg-message "test of wide int: 0" } */
> >    test_poly_int (); /* { dg-message "test of poly int: 42" } */
> >  
> > -  test_scopes (); /* { dg-line test_scopes_line } */
> > -  /* { dg-message "=== outer scope ===" "" { target *-*-* }
> > test_scopes_line } */
> > -  /* { dg-message " at outer scope" "" { target *-*-* }
> > test_scopes_line } */
> > -  /* { dg-message " === middle scope ===" "" { target *-*-* }
> > test_scopes_line } */
> > -  /* { dg-message "  at middle scope" "" { target *-*-* }
> > test_scopes_line } */
> > -  /* { dg-message "  === innermost scope ===" "" { target *-*-* }
> > test_scopes_line } */
> > -  /* { dg-message "   at innermost scope" "" { target *-*-* }
> > test_scopes_line } */
> > +  /* Dump messages in nested scopes are not printed by default,
> > and
> > +     require "-internals".  */
> > +  test_scopes ();
> >  }
> > diff --git a/gcc/testsuite/gcc.dg/plugin/dump-2.c
> > b/gcc/testsuite/gcc.dg/plugin/dump-2.c
> > new file mode 100644
> > index 0000000..961a3d3
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/plugin/dump-2.c
> > @@ -0,0 +1,30 @@
> > +/* { dg-do compile } */
> > +/* { dg-options "-fopt-info-note-internals" } */
> > +
> > +extern void test_string_literal (void);
> > +extern void test_tree (void);
> > +extern void test_gimple (int);
> > +extern void test_cgraph_node (void);
> > +extern void test_wide_int (void);
> > +extern void test_poly_int (void);
> > +extern void test_scopes (void);
> > +
> > +void test_remarks (void)
> > +{
> > +  test_string_literal (); /* { dg-message "test of dump for
> > 'test_string_literal'" } */
> > +  test_tree (); /* { dg-message "test of tree: 0" } */
> > +  test_gimple (42); /* { dg-message "test of gimple: test_gimple
> > \\(42\\);" } */
> > +  test_cgraph_node (); /* { dg-message "test of callgraph node:
> > test_cgraph_node/\[0-9\]+" } */
> > +  test_wide_int (); /* { dg-message "test of wide int: 0" } */
> > +  test_poly_int (); /* { dg-message "test of poly int: 42" } */
> > +
> > +  /* Dump messages in nested scopes are not printed by default,
> > and
> > +     require "-internals".  */
> > +  test_scopes (); /* { dg-line test_scopes_line } */
> > +  /* { dg-message "=== outer scope ===" "" { target *-*-* }
> > test_scopes_line } */
> > +  /* { dg-message " at outer scope" "" { target *-*-* }
> > test_scopes_line } */
> > +  /* { dg-message " === middle scope ===" "" { target *-*-* }
> > test_scopes_line } */
> > +  /* { dg-message "  at middle scope" "" { target *-*-* }
> > test_scopes_line } */
> > +  /* { dg-message "  === innermost scope ===" "" { target *-*-* }
> > test_scopes_line } */
> > +  /* { dg-message "   at innermost scope" "" { target *-*-* }
> > test_scopes_line } */
> > +}
> > diff --git a/gcc/testsuite/gcc.dg/plugin/plugin.exp
> > b/gcc/testsuite/gcc.dg/plugin/plugin.exp
> > index 50db3ae..1d06c04 100644
> > --- a/gcc/testsuite/gcc.dg/plugin/plugin.exp
> > +++ b/gcc/testsuite/gcc.dg/plugin/plugin.exp
> > @@ -102,7 +102,8 @@ set plugin_test_list [list \
> >      { expensive_selftests_plugin.c \
> >  	  expensive-selftests-1.c } \
> >      { dump_plugin.c \
> > -	  dump-1.c } \
> > +	  dump-1.c \
> > +	  dump-2.c } \
> >  ]
> >  
> >  foreach plugin_test $plugin_test_list {
> > diff --git a/gcc/tree-vect-loop-manip.c b/gcc/tree-vect-loop-
> > manip.c
> > index a93c6ee..1d1d114 100644
> > --- a/gcc/tree-vect-loop-manip.c
> > +++ b/gcc/tree-vect-loop-manip.c
> > @@ -3068,11 +3068,13 @@ vect_loop_versioning (loop_vec_info
> > loop_vinfo,
> >        && dump_enabled_p ())
> >      {
> >        if (version_alias)
> > -        dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, vect_location,
> > +        dump_printf_loc (MSG_OPTIMIZED_LOCATIONS |
> > MSG_PRIORITY_USER_FACING,
> > +			 vect_location,
> >                           "loop versioned for vectorization because
> > of "
> >  			 "possible aliasing\n");
> >        if (version_align)
> > -        dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, vect_location,
> > +        dump_printf_loc (MSG_OPTIMIZED_LOCATIONS |
> > MSG_PRIORITY_USER_FACING,
> > +			 vect_location,
> >                           "loop versioned for vectorization to
> > enhance "
> >  			 "alignment\n");
> >  
> > diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h
> > index d91cc07..af5d5bf 100644
> > --- a/gcc/tree-vectorizer.h
> > +++ b/gcc/tree-vectorizer.h
> > @@ -1420,7 +1420,11 @@ extern dump_user_location_t vect_location;
> >     and then calling
> >       dump_end_scope ();
> >     once the object goes out of scope, thus capturing the nesting
> > of
> > -   the scopes.  */
> > +   the scopes.
> > +
> > +   These scopes affect dump messages within them: dump messages at
> > the
> > +   top level implicitly default to MSG_PRIORITY_USER_FACING,
> > whereas those
> > +   in a nested scope implicitly default to
> > MSG_PRIORITY_INTERNALS.  */
> >  
> >  #define DUMP_VECT_SCOPE(MSG) \
> >    AUTO_DUMP_SCOPE (MSG, vect_location)
> > 
> 
> 

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 2/3] Add -fopt-info-internals
  2018-10-04 17:12             ` David Malcolm
@ 2018-10-04 17:29               ` Richard Biener
  0 siblings, 0 replies; 24+ messages in thread
From: Richard Biener @ 2018-10-04 17:29 UTC (permalink / raw)
  To: David Malcolm, Richard Biener; +Cc: Richard Sandiford, gcc-patches

On October 4, 2018 6:35:57 PM GMT+02:00, David Malcolm <dmalcolm@redhat.com> wrote:
>On Thu, 2018-10-04 at 12:45 +0200, Richard Biener wrote:
>> On Fri, 28 Sep 2018, David Malcolm wrote:
>> 
>> > This patch introduces a verbosity level to dump messages:
>> > "user-facing" vs "internals".
>> > 
>> > By default, messages at the top-level dump scope are "user-facing",
>> > whereas those that are in nested scopes are implicitly "internals",
>> > and are filtered out by -fopt-info unless a new "-internals" sub-
>> > option
>> > of "-fopt-info" is supplied (intended purely for use by GCC
>> > developers).
>> > Dumpfiles are unaffected by the change.
>> > 
>> > Given that the vectorizer is the only subsystem using
>> > AUTO_DUMP_SCOPE
>> > (via DUMP_VECT_SCOPE), this only affects the vectorizer.
>> > 
>> > Filtering out these implementation-detail messages goes a long way
>> > towards making -fopt-info-vec-all more accessible to advanced end-
>> > users;
>> > the follow-up patch restores the most pertinent missing details.
>> > 
>> > Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
>> > 
>> > OK for trunk?
>> 
>> What happens for flags & MSG_ALL_PRIORITIES == 0?  That is,
>> do we require two bits for the priority at all?
>
>I didn't want to go through every dump_* call, adding explicit
>priorities, hence I went with the implicit priority scheme.
>In the patch,
>  flags & MSG_ALL_PRIORITIES == 0
>is the case for almost all dump_* calls, and indicates "use implicit
>priority", making use of the nesting.  This is implemented in the patch
>in dump_context::apply_dump_filter_p.
>
>In a few places, some dump_* calls *do* have an explicit priority, in
>which case dump_context::apply_dump_filter_p uses it.
>
>Hence in some ways it's a tri-state:
>
>(a) implicit
>      (flags & MSG_ALL_PRIORITIES == 0)
>
>(b) explicitly "user-facing"
>      (flags & MSG_ALL_PRIORITIES == MSG_PRIORITY_USER_FACING)
>
>(b) explicitly "internals"
>      (flags & MSG_ALL_PRIORITIES == MSG_PRIORITY_INTERNALS)
>
>...and so needs 2 bits.  This scheme also supports messages that are
>both "user-facing" *and* "internals", though I don't know if that's
>useful. selftest::test_capture_of_dump_calls has test coverage for all
>4 combinations of the bits.
>
>I went with the bits scheme for similarity with the existing MSG_ kinds
>(MSG_OPTIMIZED_LOCATIONS, MSG_MISSED_OPTIMIZATION, MSG_NOTE), and the
>way it allows filtering based on masking.

Ah, OK, that makes sense. 

Patch is OK. 

Richard. 

>Dave
>
>> It's an implementation detail of course, generally I like this
>> (maybe not so much conflating with nesting, but ...).
>
>
>> Richard.
>> 
>> > gcc/ChangeLog:
>> > 	* doc/invoke.texi (-fopt-info): Document new "internals"
>> > 	sub-option.
>> > 	* dump-context.h (dump_context::apply_dump_filter_p): New decl.
>> > 	* dumpfile.c (dump_options): Update for renaming of MSG_ALL to
>> > 	MSG_ALL_KINDS.
>> > 	(optinfo_verbosity_options): Add "internals".
>> > 	(kind_as_string): Update for renaming of MSG_ALL to
>> > MSG_ALL_KINDS.
>> > 	(dump_context::apply_dump_filter_p): New member function.
>> > 	(dump_context::dump_loc): Use apply_dump_filter_p rather than
>> > 	explicitly masking the dump_kind.
>> > 	(dump_context::begin_scope): Increment the scope depth
>> > first.  Use
>> > 	apply_dump_filter_p rather than explicitly masking the
>> > dump_kind.
>> > 	(dump_context::emit_item): Use apply_dump_filter_p rather than
>> > 	explicitly masking the dump_kind.
>> > 	(dump_dec): Likewise.
>> > 	(dump_hex): Likewise.
>> > 	(dump_switch_p_1): Default to MSG_ALL_PRIORITIES.
>> > 	(opt_info_switch_p_1): Default to MSG_PRIORITY_USER_FACING.
>> > 	(opt_info_switch_p): Update handling of default
>> > 	MSG_OPTIMIZED_LOCATIONS to cope with default of
>> > 	MSG_PRIORITY_USER_FACING.
>> > 	(dump_basic_block): Use apply_dump_filter_p rather than
>> > explicitly
>> > 	masking the dump_kind.
>> > 	(selftest::test_capture_of_dump_calls): Update
>> > test_dump_context
>> > 	instances to use MSG_ALL_KINDS | MSG_PRIORITY_USER_FACING
>> > rather
>> > 	than MSG_ALL.  Generalize scope test to be run at all four
>> > 	combinations of with/without MSG_PRIORITY_USER_FACING and
>> > 	MSG_PRIORITY_INTERNALS, adding examples of explicit priority
>> > 	for each of the two values.
>> > 	* dumpfile.h (enum dump_flag): Add comment about the MSG_*
>> > flags.
>> > 	Rename MSG_ALL to MSG_ALL_KINDS.  Add MSG_PRIORITY_USER_FACING,
>> > 	MSG_PRIORITY_INTERNALS, and MSG_ALL_PRIORITIES, updating the
>> > 	values for TDF_COMPARE_DEBUG and TDF_ALL_VALUES.
>> > 	(AUTO_DUMP_SCOPE): Add a note to the comment about the
>> > interaction
>> > 	with MSG_PRIORITY_*.
>> > 	* tree-vect-loop-manip.c (vect_loop_versioning): Mark
>> > versioning
>> > 	dump messages as MSG_PRIORITY_USER_FACING.
>> > 	* tree-vectorizer.h (DUMP_VECT_SCOPE): Add a note to the
>> > comment
>> > 	about the interaction with MSG_PRIORITY_*.
>> > 
>> > gcc/testsuite/ChangeLog:
>> > 	* gcc.dg/plugin/dump-1.c: Update expected output for
>> > test_scopes
>> > 	due to "-internals" not being selected.
>> > 	* gcc.dg/plugin/dump-2.c: New test, based on dump-1.c, with
>> > 	"-internals" added to re-enable the output from test_scopes.
>> > 	* gcc.dg/plugin/plugin.exp (plugin_test_list): Add dump-2.c.
>> > ---
>> >  gcc/doc/invoke.texi                    |  31 ++++-
>> >  gcc/dump-context.h                     |   2 +
>> >  gcc/dumpfile.c                         | 248
>> > +++++++++++++++++++++++----------
>> >  gcc/dumpfile.h                         |  41 +++++-
>> >  gcc/testsuite/gcc.dg/plugin/dump-1.c   |  10 +-
>> >  gcc/testsuite/gcc.dg/plugin/dump-2.c   |  30 ++++
>> >  gcc/testsuite/gcc.dg/plugin/plugin.exp |   3 +-
>> >  gcc/tree-vect-loop-manip.c             |   6 +-
>> >  gcc/tree-vectorizer.h                  |   6 +-
>> >  9 files changed, 279 insertions(+), 98 deletions(-)
>> >  create mode 100644 gcc/testsuite/gcc.dg/plugin/dump-2.c
>> > 
>> > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
>> > index 5c95f67..ab8d9b7e8 100644
>> > --- a/gcc/doc/invoke.texi
>> > +++ b/gcc/doc/invoke.texi
>> > @@ -14207,14 +14207,21 @@ Controls optimization dumps from various
>> > optimization passes. If the
>> >  @samp{-} separated option keywords to select the dump details and
>> >  optimizations.  
>> >  
>> > -The @var{options} can be divided into two groups: options
>> > describing the
>> > -verbosity of the dump, and options describing which optimizations
>> > -should be included. The options from both the groups can be freely
>> > -mixed as they are non-overlapping. However, in case of any
>> > conflicts,
>> > +The @var{options} can be divided into three groups:
>> > +@enumerate
>> > +@item
>> > +options describing what kinds of messages should be emitted,
>> > +@item
>> > +options describing the verbosity of the dump, and
>> > +@item
>> > +options describing which optimizations should be included.
>> > +@end enumerate
>> > +The options from each group can be freely mixed as they are
>> > +non-overlapping. However, in case of any conflicts,
>> >  the later options override the earlier options on the command
>> >  line. 
>> >  
>> > -The following options control the dump verbosity:
>> > +The following options control which kinds of messages should be
>> > emitted:
>> >  
>> >  @table @samp
>> >  @item optimized
>> > @@ -14233,6 +14240,15 @@ Print detailed optimization information.
>> > This includes
>> >  @samp{optimized}, @samp{missed}, and @samp{note}.
>> >  @end table
>> >  
>> > +The following option controls the dump verbosity:
>> > +
>> > +@table @samp
>> > +@item internals
>> > +By default, only ``high-level'' messages are emitted. This option
>> > enables
>> > +additional, more detailed, messages, which are likely to only be
>> > of interest
>> > +to GCC developers.
>> > +@end table
>> > +
>> >  One or more of the following option keywords can be used to
>> > describe a
>> >  group of optimizations:
>> >  
>> > @@ -14253,8 +14269,9 @@ the optimization groups listed above.
>> >  @end table
>> >  
>> >  If @var{options} is
>> > -omitted, it defaults to @samp{optimized-optall}, which means to
>> > dump all
>> > -info about successful optimizations from all the passes.  
>> > +omitted, it defaults to @samp{optimized-optall}, which means to
>> > dump messages
>> > +about successful optimizations from all the passes, omitting
>> > messages
>> > +that are treated as ``internals''.
>> >  
>> >  If the @var{filename} is provided, then the dumps from all the
>> >  applicable optimizations are concatenated into the @var{filename}.
>> > diff --git a/gcc/dump-context.h b/gcc/dump-context.h
>> > index 5b20c15..20b94a7 100644
>> > --- a/gcc/dump-context.h
>> > +++ b/gcc/dump-context.h
>> > @@ -100,6 +100,8 @@ class dump_context
>> >  
>> >    void emit_item (optinfo_item *item, dump_flags_t dump_kind);
>> >  
>> > +  bool apply_dump_filter_p (dump_flags_t dump_kind, dump_flags_t
>> > filter) const;
>> > +
>> >   private:
>> >    optinfo &ensure_pending_optinfo ();
>> >    optinfo &begin_next_optinfo (const dump_location_t &loc);
>> > diff --git a/gcc/dumpfile.c b/gcc/dumpfile.c
>> > index d359e41..e15edc7 100644
>> > --- a/gcc/dumpfile.c
>> > +++ b/gcc/dumpfile.c
>> > @@ -141,7 +141,7 @@ static const kv_pair<dump_flags_t>
>> > dump_options[] =
>> >    {"optimized", MSG_OPTIMIZED_LOCATIONS},
>> >    {"missed", MSG_MISSED_OPTIMIZATION},
>> >    {"note", MSG_NOTE},
>> > -  {"optall", MSG_ALL},
>> > +  {"optall", MSG_ALL_KINDS},
>> >    {"all", dump_flags_t (TDF_ALL_VALUES
>> >  			& ~(TDF_RAW | TDF_SLIM | TDF_LINENO |
>> > TDF_GRAPH
>> >  			    | TDF_STMTADDR | TDF_RHS_ONLY |
>> > TDF_NOUID
>> > @@ -157,7 +157,8 @@ static const kv_pair<dump_flags_t>
>> > optinfo_verbosity_options[] =
>> >    {"optimized", MSG_OPTIMIZED_LOCATIONS},
>> >    {"missed", MSG_MISSED_OPTIMIZATION},
>> >    {"note", MSG_NOTE},
>> > -  {"all", MSG_ALL},
>> > +  {"all", MSG_ALL_KINDS},
>> > +  {"internals", MSG_PRIORITY_INTERNALS},
>> >    {NULL, TDF_NONE}
>> >  };
>> >  
>> > @@ -449,7 +450,7 @@ dump_user_location_t::from_function_decl (tree
>> > fndecl)
>> >  static const char *
>> >  kind_as_string (dump_flags_t dump_kind)
>> >  {
>> > -  switch (dump_kind & MSG_ALL)
>> > +  switch (dump_kind & MSG_ALL_KINDS)
>> >      {
>> >      default:
>> >        gcc_unreachable ();
>> > @@ -524,6 +525,35 @@ dump_context::refresh_dumps_are_enabled ()
>> >  		       || m_test_pp);
>> >  }
>> >  
>> > +/* Determine if a message of kind DUMP_KIND and at the current
>> > scope depth
>> > +   should be printed.
>> > +
>> > +   Only show messages that match FILTER both on their kind *and*
>> > +   their priority.  */
>> > +
>> > +bool
>> > +dump_context::apply_dump_filter_p (dump_flags_t dump_kind,
>> > +				   dump_flags_t filter) const
>> > +{
>> > +  /* Few messages, if any, have an explicit MSG_PRIORITY.
>> > +     If DUMP_KIND does, we'll use it.
>> > +     Otherwise, generate an implicit priority value for the
>> > message based
>> > +     on the current scope depth.
>> > +     Messages at the top-level scope are MSG_PRIORITY_USER_FACING,
>> > +     whereas those in nested scopes are
>> > MSG_PRIORITY_INTERNALS.  */
>> > +  if (!(dump_kind & MSG_ALL_PRIORITIES))
>> > +    {
>> > +      dump_flags_t implicit_priority
>> > +	=  (m_scope_depth > 0
>> > +	    ? MSG_PRIORITY_INTERNALS
>> > +	    : MSG_PRIORITY_USER_FACING);
>> > +      dump_kind |= implicit_priority;
>> > +    }
>> > +
>> > +  return (dump_kind & (filter & MSG_ALL_KINDS)
>> > +	  && dump_kind & (filter & MSG_ALL_PRIORITIES));
>> > +}
>> > +
>> >  /* Print LOC to the appropriate dump destinations, given
>> > DUMP_KIND.
>> >     If optinfos are enabled, begin a new optinfo.  */
>> >  
>> > @@ -534,14 +564,14 @@ dump_context::dump_loc (dump_flags_t
>> > dump_kind, const dump_location_t &loc)
>> >  
>> >    location_t srcloc = loc.get_location_t ();
>> >  
>> > -  if (dump_file && (dump_kind & pflags))
>> > +  if (dump_file && apply_dump_filter_p (dump_kind, pflags))
>> >      ::dump_loc (dump_kind, dump_file, srcloc);
>> >  
>> > -  if (alt_dump_file && (dump_kind & alt_flags))
>> > +  if (alt_dump_file && apply_dump_filter_p (dump_kind, alt_flags))
>> >      ::dump_loc (dump_kind, alt_dump_file, srcloc);
>> >  
>> >    /* Support for temp_dump_context in selftests.  */
>> > -  if (m_test_pp && (dump_kind & m_test_pp_flags))
>> > +  if (m_test_pp && apply_dump_filter_p (dump_kind,
>> > m_test_pp_flags))
>> >      ::dump_loc (dump_kind, m_test_pp, srcloc);
>> >  
>> >    if (optinfo_enabled_p ())
>> > @@ -1067,22 +1097,24 @@ dump_context::get_scope_depth () const
>> >  }
>> >  
>> >  /* Push a nested dump scope.
>> > +   Increment the scope depth.
>> >     Print "=== NAME ===\n" to the dumpfile, if any, and to the
>> > -fopt-info
>> >     destination, if any.
>> > -   Emit a "scope" optinfo if optinfos are enabled.
>> > -   Increment the scope depth.  */
>> > +   Emit a "scope" optinfo if optinfos are enabled.  */
>> >  
>> >  void
>> >  dump_context::begin_scope (const char *name, const dump_location_t
>> > &loc)
>> >  {
>> > -  if (dump_file && (MSG_NOTE & pflags))
>> > +  m_scope_depth++;
>> > +
>> > +  if (dump_file && apply_dump_filter_p (MSG_NOTE, pflags))
>> >      ::dump_loc (MSG_NOTE, dump_file, loc.get_location_t ());
>> >  
>> > -  if (alt_dump_file && (MSG_NOTE & alt_flags))
>> > +  if (alt_dump_file && apply_dump_filter_p (MSG_NOTE, alt_flags))
>> >      ::dump_loc (MSG_NOTE, alt_dump_file, loc.get_location_t ());
>> >  
>> >    /* Support for temp_dump_context in selftests.  */
>> > -  if (m_test_pp && (MSG_NOTE & m_test_pp_flags))
>> > +  if (m_test_pp && apply_dump_filter_p (MSG_NOTE,
>> > m_test_pp_flags))
>> >      ::dump_loc (MSG_NOTE, m_test_pp, loc.get_location_t ());
>> >  
>> >    pretty_printer pp;
>> > @@ -1100,8 +1132,6 @@ dump_context::begin_scope (const char *name,
>> > const dump_location_t &loc)
>> >      }
>> >    else
>> >      delete item;
>> > -
>> > -  m_scope_depth++;
>> >  }
>> >  
>> >  /* Pop a nested dump scope.  */
>> > @@ -1155,14 +1185,14 @@ dump_context::end_any_optinfo ()
>> >  void
>> >  dump_context::emit_item (optinfo_item *item, dump_flags_t
>> > dump_kind)
>> >  {
>> > -  if (dump_file && (dump_kind & pflags))
>> > +  if (dump_file && apply_dump_filter_p (dump_kind, pflags))
>> >      fprintf (dump_file, "%s", item->get_text ());
>> >  
>> > -  if (alt_dump_file && (dump_kind & alt_flags))
>> > +  if (alt_dump_file && apply_dump_filter_p (dump_kind, alt_flags))
>> >      fprintf (alt_dump_file, "%s", item->get_text ());
>> >  
>> >    /* Support for temp_dump_context in selftests.  */
>> > -  if (m_test_pp && (dump_kind & m_test_pp_flags))
>> > +  if (m_test_pp && apply_dump_filter_p (dump_kind,
>> > m_test_pp_flags))
>> >      pp_string (m_test_pp, item->get_text ());
>> >  }
>> >  
>> > @@ -1278,10 +1308,12 @@ template void dump_dec (dump_flags_t, const
>> > poly_widest_int &);
>> >  void
>> >  dump_dec (dump_flags_t dump_kind, const poly_wide_int &value,
>> > signop sgn)
>> >  {
>> > -  if (dump_file && (dump_kind & pflags))
>> > +  if (dump_file
>> > +      && dump_context::get ().apply_dump_filter_p (dump_kind,
>> > pflags))
>> >      print_dec (value, dump_file, sgn);
>> >  
>> > -  if (alt_dump_file && (dump_kind & alt_flags))
>> > +  if (alt_dump_file
>> > +      && dump_context::get ().apply_dump_filter_p (dump_kind,
>> > alt_flags))
>> >      print_dec (value, alt_dump_file, sgn);
>> >  }
>> >  
>> > @@ -1290,10 +1322,12 @@ dump_dec (dump_flags_t dump_kind, const
>> > poly_wide_int &value, signop sgn)
>> >  void
>> >  dump_hex (dump_flags_t dump_kind, const poly_wide_int &value)
>> >  {
>> > -  if (dump_file && (dump_kind & pflags))
>> > +  if (dump_file
>> > +      && dump_context::get ().apply_dump_filter_p (dump_kind,
>> > pflags))
>> >      print_hex (value, dump_file);
>> >  
>> > -  if (alt_dump_file && (dump_kind & alt_flags))
>> > +  if (alt_dump_file
>> > +      && dump_context::get ().apply_dump_filter_p (dump_kind,
>> > alt_flags))
>> >      print_hex (value, alt_dump_file);
>> >  }
>> >  
>> > @@ -1698,7 +1732,7 @@ dump_switch_p_1 (const char *arg, struct
>> > dump_file_info *dfi, bool doglob)
>> >      return 0;
>> >  
>> >    ptr = option_value;
>> > -  flags = TDF_NONE;
>> > +  flags = MSG_ALL_PRIORITIES;
>> >  
>> >    while (*ptr)
>> >      {
>> > @@ -1794,7 +1828,11 @@ opt_info_switch_p_1 (const char *arg,
>> > dump_flags_t *flags,
>> >    ptr = option_value;
>> >  
>> >    *filename = NULL;
>> > -  *flags = TDF_NONE;
>> > +
>> > +  /* Default to filtering out "internals" messages, and retaining
>> > +     "user-facing" messages.  */
>> > +  *flags = MSG_PRIORITY_USER_FACING;
>> > +
>> >    *optgroup_flags = OPTGROUP_NONE;
>> >  
>> >    if (!ptr)
>> > @@ -1883,8 +1921,8 @@ opt_info_switch_p (const char *arg)
>> >      }
>> >  
>> >    file_seen = xstrdup (filename);
>> > -  if (!flags)
>> > -    flags = MSG_OPTIMIZED_LOCATIONS;
>> > +  if (!(flags & MSG_ALL_KINDS))
>> > +    flags |= MSG_OPTIMIZED_LOCATIONS;
>> >    if (!optgroup_flags)
>> >      optgroup_flags = OPTGROUP_ALL;
>> >  
>> > @@ -1896,9 +1934,11 @@ opt_info_switch_p (const char *arg)
>> >  void
>> >  dump_basic_block (dump_flags_t dump_kind, basic_block bb, int
>> > indent)
>> >  {
>> > -  if (dump_file && (dump_kind & pflags))
>> > +  if (dump_file
>> > +      && dump_context::get ().apply_dump_filter_p (dump_kind,
>> > pflags))
>> >      dump_bb (dump_file, bb, indent, TDF_DETAILS);
>> > -  if (alt_dump_file && (dump_kind & alt_flags))
>> > +  if (alt_dump_file
>> > +      && dump_context::get ().apply_dump_filter_p (dump_kind,
>> > alt_flags))
>> >      dump_bb (alt_dump_file, bb, indent, TDF_DETAILS);
>> >  }
>> >  
>> > @@ -2104,7 +2144,8 @@ test_capture_of_dump_calls (const
>> > line_table_case &case_)
>> >  
>> >        /* Test of dump_printf.  */
>> >        {
>> > -	temp_dump_context tmp (with_optinfo, MSG_ALL);
>> > +	temp_dump_context tmp (with_optinfo,
>> > +			       MSG_ALL_KINDS |
>> > MSG_PRIORITY_USER_FACING);
>> >  	dump_printf (MSG_NOTE, "int: %i str: %s", 42, "foo");
>> >  
>> >  	ASSERT_DUMPED_TEXT_EQ (tmp, "int: 42 str: foo");
>> > @@ -2120,7 +2161,8 @@ test_capture_of_dump_calls (const
>> > line_table_case &case_)
>> >  
>> >        /* Test of dump_printf with %T.  */
>> >        {
>> > -	temp_dump_context tmp (with_optinfo, MSG_ALL);
>> > +	temp_dump_context tmp (with_optinfo,
>> > +			       MSG_ALL_KINDS |
>> > MSG_PRIORITY_USER_FACING);
>> >  	dump_printf (MSG_NOTE, "tree: %T", integer_zero_node);
>> >  
>> >  	ASSERT_DUMPED_TEXT_EQ (tmp, "tree: 0");
>> > @@ -2137,7 +2179,8 @@ test_capture_of_dump_calls (const
>> > line_table_case &case_)
>> >  
>> >        /* Test of dump_printf with %E.  */
>> >        {
>> > -	temp_dump_context tmp (with_optinfo, MSG_ALL);
>> > +	temp_dump_context tmp (with_optinfo,
>> > +			       MSG_ALL_KINDS |
>> > MSG_PRIORITY_USER_FACING);
>> >  	dump_printf (MSG_NOTE, "gimple: %E", stmt);
>> >  
>> >  	ASSERT_DUMPED_TEXT_EQ (tmp, "gimple: return;");
>> > @@ -2154,7 +2197,8 @@ test_capture_of_dump_calls (const
>> > line_table_case &case_)
>> >  
>> >        /* Test of dump_printf with %G.  */
>> >        {
>> > -	temp_dump_context tmp (with_optinfo, MSG_ALL);
>> > +	temp_dump_context tmp (with_optinfo,
>> > +			       MSG_ALL_KINDS |
>> > MSG_PRIORITY_USER_FACING);
>> >  	dump_printf (MSG_NOTE, "gimple: %G", stmt);
>> >  
>> >  	ASSERT_DUMPED_TEXT_EQ (tmp, "gimple: return;\n");
>> > @@ -2176,7 +2220,8 @@ test_capture_of_dump_calls (const
>> > line_table_case &case_)
>> >  	 - multiple dump-specific format codes: some consecutive,
>> > others
>> >  	 separated by text, trailing text after the final one.  */
>> >        {
>> > -	temp_dump_context tmp (with_optinfo, MSG_ALL);
>> > +	temp_dump_context tmp (with_optinfo,
>> > +			       MSG_ALL_KINDS |
>> > MSG_PRIORITY_USER_FACING);
>> >  	dump_printf_loc (MSG_NOTE, loc, "before %T and %T"
>> >  			 " %i consecutive %E%E after\n",
>> >  			 integer_zero_node, test_decl, 42, stmt,
>> > stmt);
>> > @@ -2203,7 +2248,8 @@ test_capture_of_dump_calls (const
>> > line_table_case &case_)
>> >  
>> >        /* Tree, via dump_generic_expr.  */
>> >        {
>> > -	temp_dump_context tmp (with_optinfo, MSG_ALL);
>> > +	temp_dump_context tmp (with_optinfo,
>> > +			       MSG_ALL_KINDS |
>> > MSG_PRIORITY_USER_FACING);
>> >  	dump_printf_loc (MSG_NOTE, loc, "test of tree: ");
>> >  	dump_generic_expr (MSG_NOTE, TDF_SLIM, integer_zero_node);
>> >  
>> > @@ -2222,7 +2268,8 @@ test_capture_of_dump_calls (const
>> > line_table_case &case_)
>> >  
>> >        /* Tree, via dump_generic_expr_loc.  */
>> >        {
>> > -	temp_dump_context tmp (with_optinfo, MSG_ALL);
>> > +	temp_dump_context tmp (with_optinfo,
>> > +			       MSG_ALL_KINDS |
>> > MSG_PRIORITY_USER_FACING);
>> >  	dump_generic_expr_loc (MSG_NOTE, loc, TDF_SLIM,
>> > integer_one_node);
>> >  
>> >  	ASSERT_DUMPED_TEXT_EQ (tmp, "test.txt:5:10: note: 1");
>> > @@ -2241,7 +2288,8 @@ test_capture_of_dump_calls (const
>> > line_table_case &case_)
>> >        {
>> >  	/* dump_gimple_stmt_loc.  */
>> >  	{
>> > -	  temp_dump_context tmp (with_optinfo, MSG_ALL);
>> > +	  temp_dump_context tmp (with_optinfo,
>> > +				 MSG_ALL_KINDS |
>> > MSG_PRIORITY_USER_FACING);
>> >  	  dump_gimple_stmt_loc (MSG_NOTE, loc, TDF_SLIM, stmt, 2);
>> >  
>> >  	  ASSERT_DUMPED_TEXT_EQ (tmp, "test.txt:5:10: note:
>> > return;\n");
>> > @@ -2256,7 +2304,8 @@ test_capture_of_dump_calls (const
>> > line_table_case &case_)
>> >  
>> >  	/* dump_gimple_stmt.  */
>> >  	{
>> > -	  temp_dump_context tmp (with_optinfo, MSG_ALL);
>> > +	  temp_dump_context tmp (with_optinfo,
>> > +				 MSG_ALL_KINDS |
>> > MSG_PRIORITY_USER_FACING);
>> >  	  dump_gimple_stmt (MSG_NOTE, TDF_SLIM, stmt, 2);
>> >  
>> >  	  ASSERT_DUMPED_TEXT_EQ (tmp, "return;\n");
>> > @@ -2271,7 +2320,8 @@ test_capture_of_dump_calls (const
>> > line_table_case &case_)
>> >  
>> >  	/* dump_gimple_expr_loc.  */
>> >  	{
>> > -	  temp_dump_context tmp (with_optinfo, MSG_ALL);
>> > +	  temp_dump_context tmp (with_optinfo,
>> > +				 MSG_ALL_KINDS |
>> > MSG_PRIORITY_USER_FACING);
>> >  	  dump_gimple_expr_loc (MSG_NOTE, loc, TDF_SLIM, stmt, 2);
>> >  
>> >  	  ASSERT_DUMPED_TEXT_EQ (tmp, "test.txt:5:10: note:
>> > return;");
>> > @@ -2286,7 +2336,8 @@ test_capture_of_dump_calls (const
>> > line_table_case &case_)
>> >  
>> >  	/* dump_gimple_expr.  */
>> >  	{
>> > -	  temp_dump_context tmp (with_optinfo, MSG_ALL);
>> > +	  temp_dump_context tmp (with_optinfo,
>> > +				 MSG_ALL_KINDS |
>> > MSG_PRIORITY_USER_FACING);
>> >  	  dump_gimple_expr (MSG_NOTE, TDF_SLIM, stmt, 2);
>> >  
>> >  	  ASSERT_DUMPED_TEXT_EQ (tmp, "return;");
>> > @@ -2302,7 +2353,8 @@ test_capture_of_dump_calls (const
>> > line_table_case &case_)
>> >  
>> >        /* poly_int.  */
>> >        {
>> > -	temp_dump_context tmp (with_optinfo, MSG_ALL);
>> > +	temp_dump_context tmp (with_optinfo,
>> > +			       MSG_ALL_KINDS |
>> > MSG_PRIORITY_USER_FACING);
>> >  	dump_dec (MSG_NOTE, poly_int64 (42));
>> >  
>> >  	ASSERT_DUMPED_TEXT_EQ (tmp, "42");
>> > @@ -2315,45 +2367,92 @@ test_capture_of_dump_calls (const
>> > line_table_case &case_)
>> >  	  }
>> >        }
>> >  
>> > -      /* scopes.  */
>> > -      {
>> > -	temp_dump_context tmp (with_optinfo, MSG_ALL);
>> > -	dump_printf_loc (MSG_NOTE, stmt, "msg 1\n");
>> > +      /* Scopes.  Test with all 4 combinations of
>> > +	 filtering by MSG_PRIORITY_USER_FACING
>> > +	 and/or filtering by MSG_PRIORITY_INTERNALS.  */
>> > +      for (int j = 0; j < 3; j++)
>> >  	{
>> > -	  AUTO_DUMP_SCOPE ("outer scope", stmt);
>> > -	  dump_printf_loc (MSG_NOTE, stmt, "msg 2\n");
>> > +	  dump_flags_t dump_filter = MSG_ALL_KINDS;
>> > +	  if (j % 2)
>> > +	    dump_filter |= MSG_PRIORITY_USER_FACING;
>> > +	  if (j / 2)
>> > +	    dump_filter |= MSG_PRIORITY_INTERNALS;
>> > +
>> > +	  temp_dump_context tmp (with_optinfo, dump_filter);
>> > +	  /* Emit various messages, mostly with implicit
>> > priority.  */
>> > +	  dump_printf_loc (MSG_NOTE, stmt, "msg 1\n");
>> > +	  dump_printf_loc (MSG_NOTE | MSG_PRIORITY_INTERNALS,
>> > stmt,
>> > +			   "explicitly internal msg\n");
>> >  	  {
>> > -	    AUTO_DUMP_SCOPE ("middle scope", stmt);
>> > -	    dump_printf_loc (MSG_NOTE, stmt, "msg 3\n");
>> > +	    AUTO_DUMP_SCOPE ("outer scope", stmt);
>> > +	    dump_printf_loc (MSG_NOTE, stmt, "msg 2\n");
>> >  	    {
>> > -	      AUTO_DUMP_SCOPE ("inner scope", stmt);
>> > -	      dump_printf_loc (MSG_NOTE, stmt, "msg 4\n");
>> > +	      AUTO_DUMP_SCOPE ("middle scope", stmt);
>> > +	      dump_printf_loc (MSG_NOTE, stmt, "msg 3\n");
>> > +	      {
>> > +		AUTO_DUMP_SCOPE ("inner scope", stmt);
>> > +		dump_printf_loc (MSG_NOTE, stmt, "msg 4\n");
>> > +		dump_printf_loc (MSG_NOTE |
>> > MSG_PRIORITY_USER_FACING, stmt,
>> > +				 "explicitly user-facing msg\n");
>> > +	      }
>> > +	      dump_printf_loc (MSG_NOTE, stmt, "msg 5\n");
>> >  	    }
>> > -	    dump_printf_loc (MSG_NOTE, stmt, "msg 5\n");
>> > +	    dump_printf_loc (MSG_NOTE, stmt, "msg 6\n");
>> >  	  }
>> > -	  dump_printf_loc (MSG_NOTE, stmt, "msg 6\n");
>> > -	}
>> > -	dump_printf_loc (MSG_NOTE, stmt, "msg 7\n");
>> > +	  dump_printf_loc (MSG_NOTE, stmt, "msg 7\n");
>> >  
>> > -	ASSERT_DUMPED_TEXT_EQ (tmp,
>> > -			       "test.txt:5:10: note: msg 1\n"
>> > -			       "test.txt:5:10: note: === outer
>> > scope ===\n"
>> > -			       "test.txt:5:10: note:  msg 2\n"
>> > -			       "test.txt:5:10: note:  === middle
>> > scope ===\n"
>> > -			       "test.txt:5:10: note:   msg 3\n"
>> > -			       "test.txt:5:10: note:   === inner
>> > scope ===\n"
>> > -			       "test.txt:5:10: note:    msg 4\n"
>> > -			       "test.txt:5:10: note:   msg 5\n"
>> > -			       "test.txt:5:10: note:  msg 6\n"
>> > -			       "test.txt:5:10: note: msg 7\n");
>> > -	if (with_optinfo)
>> > -	  {
>> > -	    optinfo *info = tmp.get_pending_optinfo ();
>> > -	    ASSERT_TRUE (info != NULL);
>> > -	    ASSERT_EQ (info->num_items (), 1);
>> > -	    ASSERT_IS_TEXT (info->get_item (0), "msg 7\n");
>> > -	  }
>> > -      }
>> > +	  switch (dump_filter & MSG_ALL_PRIORITIES)
>> > +	    {
>> > +	    default:
>> > +	      gcc_unreachable ();
>> > +	    case 0:
>> > +	      ASSERT_DUMPED_TEXT_EQ (tmp, "");
>> > +	      break;
>> > +	    case MSG_PRIORITY_USER_FACING:
>> > +	      ASSERT_DUMPED_TEXT_EQ
>> > +		(tmp,
>> > +		 "test.txt:5:10: note: msg 1\n"
>> > +		 "test.txt:5:10: note:    explicitly user-facing
>> > msg\n"
>> > +		 "test.txt:5:10: note: msg 7\n");
>> > +	      break;
>> > +	    case MSG_PRIORITY_INTERNALS:
>> > +	      ASSERT_DUMPED_TEXT_EQ
>> > +		(tmp,
>> > +		 "test.txt:5:10: note: explicitly internal msg\n"
>> > +		 "test.txt:5:10: note:  === outer scope ===\n"
>> > +		 "test.txt:5:10: note:  msg 2\n"
>> > +		 "test.txt:5:10: note:   === middle scope ===\n"
>> > +		 "test.txt:5:10: note:   msg 3\n"
>> > +		 "test.txt:5:10: note:    === inner scope ===\n"
>> > +		 "test.txt:5:10: note:    msg 4\n"
>> > +		 "test.txt:5:10: note:   msg 5\n"
>> > +		 "test.txt:5:10: note:  msg 6\n");
>> > +	      break;
>> > +	    case MSG_ALL_PRIORITIES:
>> > +	      ASSERT_DUMPED_TEXT_EQ
>> > +		(tmp,
>> > +		 "test.txt:5:10: note: msg 1\n"
>> > +		 "test.txt:5:10: note: explicitly internal msg\n"
>> > +		 "test.txt:5:10: note: === outer scope ===\n"
>> > +		 "test.txt:5:10: note:  msg 2\n"
>> > +		 "test.txt:5:10: note:  === middle scope ===\n"
>> > +		 "test.txt:5:10: note:   msg 3\n"
>> > +		 "test.txt:5:10: note:   === inner scope ===\n"
>> > +		 "test.txt:5:10: note:    msg 4\n"
>> > +		 "test.txt:5:10: note:    explicitly user-facing
>> > msg\n"
>> > +		 "test.txt:5:10: note:   msg 5\n"
>> > +		 "test.txt:5:10: note:  msg 6\n"
>> > +		 "test.txt:5:10: note: msg 7\n");
>> > +	      break;
>> > +	    }
>> > +	  if (with_optinfo)
>> > +	    {
>> > +	      optinfo *info = tmp.get_pending_optinfo ();
>> > +	      ASSERT_TRUE (info != NULL);
>> > +	      ASSERT_EQ (info->num_items (), 1);
>> > +	      ASSERT_IS_TEXT (info->get_item (0), "msg 7\n");
>> > +	    }
>> > +	}
>> >      }
>> >  
>> >    /* Verify that MSG_* affects optinfo->get_kind (); we tested
>> > MSG_NOTE
>> > @@ -2361,7 +2460,7 @@ test_capture_of_dump_calls (const
>> > line_table_case &case_)
>> >    {
>> >      /* MSG_OPTIMIZED_LOCATIONS.  */
>> >      {
>> > -      temp_dump_context tmp (true, MSG_ALL);
>> > +      temp_dump_context tmp (true, MSG_ALL_KINDS);
>> >        dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc, "test");
>> >        ASSERT_EQ (tmp.get_pending_optinfo ()->get_kind (),
>> >  		 OPTINFO_KIND_SUCCESS);
>> > @@ -2369,7 +2468,7 @@ test_capture_of_dump_calls (const
>> > line_table_case &case_)
>> >  
>> >      /* MSG_MISSED_OPTIMIZATION.  */
>> >      {
>> > -      temp_dump_context tmp (true, MSG_ALL);
>> > +      temp_dump_context tmp (true, MSG_ALL_KINDS);
>> >        dump_printf_loc (MSG_MISSED_OPTIMIZATION, loc, "test");
>> >        ASSERT_EQ (tmp.get_pending_optinfo ()->get_kind (),
>> >  		 OPTINFO_KIND_FAILURE);
>> > @@ -2378,7 +2477,8 @@ test_capture_of_dump_calls (const
>> > line_table_case &case_)
>> >  
>> >    /* Verify that MSG_* affect AUTO_DUMP_SCOPE and the dump
>> > calls.  */
>> >    {
>> > -    temp_dump_context tmp (false, MSG_OPTIMIZED_LOCATIONS);
>> > +    temp_dump_context tmp (false,
>> > +			   MSG_OPTIMIZED_LOCATIONS |
>> > MSG_ALL_PRIORITIES);
>> >      dump_printf_loc (MSG_NOTE, stmt, "msg 1\n");
>> >      {
>> >        AUTO_DUMP_SCOPE ("outer scope", stmt);
>> > diff --git a/gcc/dumpfile.h b/gcc/dumpfile.h
>> > index 057ca46..5933905 100644
>> > --- a/gcc/dumpfile.h
>> > +++ b/gcc/dumpfile.h
>> > @@ -145,6 +145,9 @@ enum dump_flag
>> >    /* Dump folding details.  */
>> >    TDF_FOLDING = (1 << 21),
>> >  
>> > +  /* MSG_* flags for expressing the kinds of message to
>> > +     be emitted by -fopt-info.  */
>> > +
>> >    /* -fopt-info optimized sources.  */
>> >    MSG_OPTIMIZED_LOCATIONS = (1 << 22),
>> >  
>> > @@ -154,15 +157,37 @@ enum dump_flag
>> >    /* General optimization info.  */
>> >    MSG_NOTE = (1 << 24),
>> >  
>> > -  MSG_ALL = (MSG_OPTIMIZED_LOCATIONS
>> > -	     | MSG_MISSED_OPTIMIZATION
>> > -	     | MSG_NOTE),
>> > +  /* Mask for selecting MSG_-kind flags.  */
>> > +  MSG_ALL_KINDS = (MSG_OPTIMIZED_LOCATIONS
>> > +		   | MSG_MISSED_OPTIMIZATION
>> > +		   | MSG_NOTE),
>> > +
>> > +  /* MSG_PRIORITY_* flags for expressing the priority levels of
>> > message
>> > +     to be emitted by -fopt-info, and filtering on them.
>> > +     By default, messages at the top-level dump scope are "user-
>> > facing",
>> > +     whereas those that are in nested scopes are implicitly
>> > "internals".
>> > +     This behavior can be overridden for a given dump message by
>> > explicitly
>> > +     specifying one of the MSG_PRIORITY_* flags.
>> > +
>> > +     By default, dump files show both kinds of message, whereas
>> > -fopt-info
>> > +     only shows "user-facing" messages, and requires the "-
>> > internals"
>> > +     sub-option of -fopt-info to show the internal messages.  */
>> > +
>> > +  /* Implicitly supplied for messages at the top-level dump
>> > scope.  */
>> > +  MSG_PRIORITY_USER_FACING = (1 << 25),
>> > +
>> > +  /* Implicitly supplied for messages within nested dump
>> > scopes.  */
>> > +  MSG_PRIORITY_INTERNALS = (1 << 26),
>> > +
>> > +  /* Mask for selecting MSG_PRIORITY_* flags.  */
>> > +  MSG_ALL_PRIORITIES = (MSG_PRIORITY_USER_FACING
>> > +			| MSG_PRIORITY_INTERNALS),
>> >  
>> >    /* Dumping for -fcompare-debug.  */
>> > -  TDF_COMPARE_DEBUG = (1 << 25),
>> > +  TDF_COMPARE_DEBUG = (1 << 27),
>> >  
>> >    /* All values.  */
>> > -  TDF_ALL_VALUES = (1 << 26) - 1
>> > +  TDF_ALL_VALUES = (1 << 28) - 1
>> >  };
>> >  
>> >  /* Dump flags type.  */
>> > @@ -549,7 +574,11 @@ class auto_dump_scope
>> >     and then calling
>> >       dump_end_scope ();
>> >     once the object goes out of scope, thus capturing the nesting
>> > of
>> > -   the scopes.  */
>> > +   the scopes.
>> > +
>> > +   These scopes affect dump messages within them: dump messages at
>> > the
>> > +   top level implicitly default to MSG_PRIORITY_USER_FACING,
>> > whereas those
>> > +   in a nested scope implicitly default to
>> > MSG_PRIORITY_INTERNALS.  */
>> >  
>> >  #define AUTO_DUMP_SCOPE(NAME, LOC) \
>> >    auto_dump_scope scope (NAME, LOC)
>> > diff --git a/gcc/testsuite/gcc.dg/plugin/dump-1.c
>> > b/gcc/testsuite/gcc.dg/plugin/dump-1.c
>> > index 165a9c1..95bd7a4 100644
>> > --- a/gcc/testsuite/gcc.dg/plugin/dump-1.c
>> > +++ b/gcc/testsuite/gcc.dg/plugin/dump-1.c
>> > @@ -18,11 +18,7 @@ void test_remarks (void)
>> >    test_wide_int (); /* { dg-message "test of wide int: 0" } */
>> >    test_poly_int (); /* { dg-message "test of poly int: 42" } */
>> >  
>> > -  test_scopes (); /* { dg-line test_scopes_line } */
>> > -  /* { dg-message "=== outer scope ===" "" { target *-*-* }
>> > test_scopes_line } */
>> > - 

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 3/3] v3: Report vectorization problems via a new opt_problem class
  2018-10-04 11:28           ` Richard Biener
@ 2018-10-04 17:37             ` Richard Sandiford
  2018-10-04 18:28             ` -fopt-info-inline and class opt_problem David Malcolm
  1 sibling, 0 replies; 24+ messages in thread
From: Richard Sandiford @ 2018-10-04 17:37 UTC (permalink / raw)
  To: Richard Biener; +Cc: David Malcolm, gcc-patches

Richard Biener <rguenther@suse.de> writes:
> On Fri, 28 Sep 2018, David Malcolm wrote:
>> This is v3 of the patch; previous versions were:
>>   v2: https://gcc.gnu.org/ml/gcc-patches/2018-07/msg00446.html
>>   v1: https://gcc.gnu.org/ml/gcc-patches/2018-06/msg01462.html
>> 
>> This patch introduces a class opt_problem, along with wrapper
>> classes for bool (opt_result) and for pointers (e.g. opt_loop_vec_info
>> for loop_vec_info).
>> 
>> opt_problem instances are created when an optimization problem
>> is encountered, but only if dump_enabled_p.  They are manually
>> propagated up the callstack, and are manually reported at the
>> "top level" of an optimization if dumping is enabled, to give the user
>> a concise summary of the problem *after* the failure is reported.
>> In particular, the location of the problematic statement is
>> captured and emitted, rather than just the loop's location.
>> 
>> For example:
>> 
>> no-vfa-vect-102.c:24:3: missed: couldn't vectorize loop
>> no-vfa-vect-102.c:27:7: missed: statement clobbers memory: __asm__
> __volatile__("" : : : "memory");
>> 
>> Changed in v3:
>> * This version bootstraps and passes regression testing (on
>>   x86_64-pc-linux-gnu).
>> * added selftests, to exercise the opt_problem machinery
>> * removed the "bool to opt_result" ctor, so that attempts to
>>   use e.g. return a bool from an opt_result-returning function
>>   will fail at compile time
>> * use formatted printing within opt_problem ctor to replace the
>>   various dump_printf_loc calls
>> * dropped i18n
>> * changed the sense of vect_analyze_data_ref_dependence's return
>>   value (see the ChangeLog)
>> * add MSG_PRIORITY_REEMITTED, so that -fopt-info can show the
>>   messages, without them messing up the counts in scan-tree-dump-times
>>   in DejaGnu tests
>> 
>> Re Richard Sandiford's feedback on the v2 patch:
>>   https://gcc.gnu.org/ml/gcc-patches/2018-07/msg00560.html
>> > Since the creation of the opt_problem depends on dump_enabled_p, would
>> > it make sense for the dump_printf_loc to happen automatically on
>> > opt_result::failure, rather than have both?
>> 
>> Yes; this v3 patch does that: opt_result::failure_at is passed a format
>> string with variadic args.  If dumping is enabled, it performs the
>> equivalent of dump_printf_loc in a form that will reach dumpfiles
>> (and -fopt-info-internals), stashing the dumped items in the opt_problem.
>> When the opt_problem is emitted at the top-level, the message is re-emitted
>> (but only for -fopt-info, not for dumpfiles, to avoid duplicates that mess
>> up scan-tree-dump-times in DejaGnu tests)
>> 
>> > I guess this is bike-shedding, but personally I'd prefer an explicit
>> > test for success rather than operator bool, so that:
>> >
>> >    opt_result foo = ...;
>> >    bool bar = foo;
>> >
>> > is ill-formed.  The danger otherwise might be that we drop a useful
>> > opt_problem and replace it with something more generic.  E.g. the
>> > opt_result form of:
>> >   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;
>> >     }
>> >
>> > in vect_analyze_stmt could silently drop the information provided by
>> > the subroutine if we forgot to change "ok" from "bool" to "opt_result".
>> 
>> I didn't make that change in v3: if the function returns an opt_result, then
>> the "return false;" will be a compile-time failure, alerting us to the
>> problem.
>> 
>> I guess this is a matter of style, whether explicit is better than
>> implicit.  Dropping the operator bool would require an explicit approach,
>> with something like:
>> 
>>     // Explicit style:
>>     opt_result res = ...;
>>     if (res.failed_p ())
>>        return res;
>> 
>> and:
>> 
>>     // Explicit style:
>>     // It's often currently called "ok":
>>     opt_result ok = ...;
>>     if (ok.failed_p ())
>>        return ok;
>> 
>> as opposed to:
>> 
>>     // Implicit style:
>>     opt_result res = ...;
>>     if (!res)
>>        return res;
>> 
>> and:
>> 
>>     // Implicit style:
>>     opt_result ok = ...;
>>     if (!ok)
>>        return ok;
>> 
>> I think I went with the implicit style to minimize the lines touched by
>> the patch, but I'm happy with either approach.  [If we're bikeshedding,
>> would renaming those "ok" to "res" be acceptable also?  "ok" reads to
>> me like a "success" value for a status variable, rather than the status
>> variable itself; it's presumably meant to be pronounced with a rising
>> interrogative as it were a question - "ok?" - but that's not visible in
>> the code when reading the usage sites].
>> 
>> Similarly, the pointer wrappers use an implicit style:
>> 
>>   // Implicit style:
>> 
>>   opt_loop_vec_info loop_vinfo
>>     = vect_analyze_loop (loop, orig_loop_vinfo, &shared);
>>   loop->aux = loop_vinfo;
>> 
>>   if (!loop_vinfo)
>>     if (dump_enabled_p ())
>>       if (opt_problem *problem = loop_vinfo.get_problem ())
>> 	{
>> 
>> but maybe an explicit style is more readable:
>> 
>>   // Explicit style:
>> 
>>   opt_loop_vec_info opt_loop_vinfo
>>     = vect_analyze_loop (loop, orig_loop_vinfo, &shared);
>>   loop_vec_info loop_vinfo = loop_vinfo.get_pointer ();
>>   loop->aux = loop_vinfo
>> 
>>   if (opt_loop_vinfo.failed_p ())
>>     if (dump_enabled_p ())
>>       if (opt_problem *problem = loop_vinfo.get_problem ())
>> 	{
>> 
>> 
>> How would you want the code to look?
>> 
>> Richi: do you have an opinion here?
>
> I wouldn't mind about the explicit variant for the bool but
> the explicit for the pointer looks odd.
>
> In general I agree that
>
>  opt_result foo = x;
>  bool bar = x;
>
> is confusing but I also like the brevity that is possible
> with the automatic conversions so I am biased towards that.
>
>> (or is that style in the patch OK as-is?)
>
> For me it is OK as-is.
>
>> Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
>> 
>> OK for trunk?
>
> OK.  My question on 2/3 leaves Richard time to comment.

No objection from me.

Thanks,
Richard

^ permalink raw reply	[flat|nested] 24+ messages in thread

* -fopt-info-inline and class opt_problem
  2018-10-04 11:28           ` Richard Biener
  2018-10-04 17:37             ` Richard Sandiford
@ 2018-10-04 18:28             ` David Malcolm
  2018-10-05  7:16               ` Richard Biener
  1 sibling, 1 reply; 24+ messages in thread
From: David Malcolm @ 2018-10-04 18:28 UTC (permalink / raw)
  To: Richard Biener; +Cc: Richard Sandiford, gcc-patches, Jan Hubicka

On Thu, 2018-10-04 at 12:52 +0200, Richard Biener wrote:
> On Fri, 28 Sep 2018, David Malcolm wrote:

[...snip...]

> > 
> > OK for trunk?
> 
> OK.  My question on 2/3 leaves Richard time to comment.
> 
> Maybe you can tackle the issue that -fopt-info-inline does
> nothing at the moment and see if opt-problems are a good fit
> there as well (reporting the CIF strings).

Thanks.  I've committed the patch kit.

[CCing Honza]

I'm looking at -fopt-info-inline now (PR ipa/86395).  I might look at
loop optimizations also (there are some fprintfs there also).

Presumably the user-experience for -fopt-info-inline should be
something like:

  <CALLSITE-LOCATION>: missed: can't inline foo into bar
  <REASON-LOCATION>: missed: because of <REASON>

or:

  <CALLSITE-LOCATION>: missed: not inlining foo into bar
  <REASON-LOCATION>: missed: because of <REASON>

and:

  <CALLSITE-LOCATION>: optimized: inlined foo into bar

(gathering all pertinent data into the -fsave-optimization-record
output).

I suspect that the opt_problem class from the above patch kit [1] isn't
a good fit for inlining: the loop vectorizer runs one outer loop at a
time, with a deep callstack, needing to bubble up a single "problem" at
at time.

In contrast, assuming I'm reading the code right, the inliner stores a
status in each cgraph_edge, and walks the cgraph to decide what to do
with all of the edges, with a fairly shallow callstack: I believe
decisions made for one edge can affect other edges etc.

It might still be possible to store and/or emit a bit more per-edge
detail other than the plain enum cgraph_inline_failed_t, if that's
desirable.

Brainstorming:

(a) replace the "inline_failed" enum with a pointer to a class that can
contain more details (perhaps an opt_problem subclass): in a normal
dump-disabled setting, these would point to global constant singletons
(so no allocation is needed); in a dump-enabled setting, these could be
allocated objects containing additional details describing *exactly*
why an edge wasn't inlined (but this adds lots of indirections, ugh)

(b) add a map of cgraph_edge to opt_problem instances; this would only
be populated if dumping is enabled.

(c) if dumping is enabled, generate an opt_problem when an edge
transitions to CIF_FINAL_ERROR, and emit it... somewhere.

I'm not sure if the above are good ideas or not.  (b) and (c) feel more
credible than (a).


Dave

[1] https://gcc.gnu.org/ml/gcc-patches/2018-09/msg01747.html

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: -fopt-info-inline and class opt_problem
  2018-10-04 18:28             ` -fopt-info-inline and class opt_problem David Malcolm
@ 2018-10-05  7:16               ` Richard Biener
  0 siblings, 0 replies; 24+ messages in thread
From: Richard Biener @ 2018-10-05  7:16 UTC (permalink / raw)
  To: David Malcolm; +Cc: Richard Sandiford, gcc-patches, Jan Hubicka

On Thu, 4 Oct 2018, David Malcolm wrote:

> On Thu, 2018-10-04 at 12:52 +0200, Richard Biener wrote:
> > On Fri, 28 Sep 2018, David Malcolm wrote:
> 
> [...snip...]
> 
> > > 
> > > OK for trunk?
> > 
> > OK.  My question on 2/3 leaves Richard time to comment.
> > 
> > Maybe you can tackle the issue that -fopt-info-inline does
> > nothing at the moment and see if opt-problems are a good fit
> > there as well (reporting the CIF strings).
> 
> Thanks.  I've committed the patch kit.
> 
> [CCing Honza]
> 
> I'm looking at -fopt-info-inline now (PR ipa/86395).  I might look at
> loop optimizations also (there are some fprintfs there also).
> 
> Presumably the user-experience for -fopt-info-inline should be
> something like:
> 
>   <CALLSITE-LOCATION>: missed: can't inline foo into bar
>   <REASON-LOCATION>: missed: because of <REASON>
> 
> or:
> 
>   <CALLSITE-LOCATION>: missed: not inlining foo into bar
>   <REASON-LOCATION>: missed: because of <REASON>
> 
> and:
> 
>   <CALLSITE-LOCATION>: optimized: inlined foo into bar
> 
> (gathering all pertinent data into the -fsave-optimization-record
> output).
> 
> I suspect that the opt_problem class from the above patch kit [1] isn't
> a good fit for inlining: the loop vectorizer runs one outer loop at a
> time, with a deep callstack, needing to bubble up a single "problem" at
> at time.
> 
> In contrast, assuming I'm reading the code right, the inliner stores a
> status in each cgraph_edge, and walks the cgraph to decide what to do
> with all of the edges, with a fairly shallow callstack: I believe
> decisions made for one edge can affect other edges etc.
> 
> It might still be possible to store and/or emit a bit more per-edge
> detail other than the plain enum cgraph_inline_failed_t, if that's
> desirable.
> 
> Brainstorming:
> 
> (a) replace the "inline_failed" enum with a pointer to a class that can
> contain more details (perhaps an opt_problem subclass): in a normal
> dump-disabled setting, these would point to global constant singletons
> (so no allocation is needed); in a dump-enabled setting, these could be
> allocated objects containing additional details describing *exactly*
> why an edge wasn't inlined (but this adds lots of indirections, ugh)
> 
> (b) add a map of cgraph_edge to opt_problem instances; this would only
> be populated if dumping is enabled.
> 
> (c) if dumping is enabled, generate an opt_problem when an edge
> transitions to CIF_FINAL_ERROR, and emit it... somewhere.
> 
> I'm not sure if the above are good ideas or not.  (b) and (c) feel more
> credible than (a).

I guess I'd try a classical top-down approach - start by simply
adding some dump_printf to where inline failed/succeeded and see
if that's enough to do the job.  Back to square one if it isn't ;)

Richard.

> 
> Dave
> 
> [1] https://gcc.gnu.org/ml/gcc-patches/2018-09/msg01747.html
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nuernberg)

^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2018-10-05  6:48 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-06-22 20:26 [PATCH] [RFC] Higher-level reporting of vectorization problems David Malcolm
2018-06-25  9:15 ` Richard Biener
2018-07-02 16:35   ` Richard Sandiford
2018-07-03  7:14     ` Richard Biener
2018-07-10  0:27   ` [PATCH 0/5] [RFC v2] " David Malcolm
2018-07-10  0:27     ` [PATCH 4/5] Use opt_result throughout vectorizer David Malcolm
2018-07-10  0:27     ` [PATCH 3/5] Add some test coverage David Malcolm
2018-07-10  0:27     ` [PATCH 1/5] Add opt-problem.h David Malcolm
2018-07-10  0:27     ` [PATCH 2/5] Use opt-problem.h in try_vectorize_loop_1 David Malcolm
2018-07-10  0:27     ` [PATCH 5/5] Add opt-problem.cc David Malcolm
2018-07-11 15:56     ` [PATCH 0/5] [RFC v2] Higher-level reporting of vectorization problems Richard Sandiford
2018-07-11 18:28       ` David Malcolm
2018-09-28 18:23       ` [PATCH 0/3] Higher-level reporting of vectorization problems (v3) David Malcolm
2018-09-28 18:24         ` [PATCH 2/3] Add -fopt-info-internals David Malcolm
2018-10-04 11:09           ` Richard Biener
2018-10-04 17:12             ` David Malcolm
2018-10-04 17:29               ` Richard Biener
2018-09-28 18:24         ` [PATCH 3/3] v3: Report vectorization problems via a new opt_problem class David Malcolm
2018-10-04 11:28           ` Richard Biener
2018-10-04 17:37             ` Richard Sandiford
2018-10-04 18:28             ` -fopt-info-inline and class opt_problem David Malcolm
2018-10-05  7:16               ` Richard Biener
2018-09-28 18:25         ` [PATCH 1/3] Fix -fopt-info for plugin passes David Malcolm
2018-10-04 10:52           ` Richard Biener

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).