diff mbox series

[RFC] Higher-level reporting of vectorization problems

Message ID 1529701789-40263-1-git-send-email-dmalcolm@redhat.com
State New
Headers show
Series [RFC] Higher-level reporting of vectorization problems | expand

Commit Message

David Malcolm June 22, 2018, 9:09 p.m. UTC
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

Comments

Richard Biener June 25, 2018, 9:10 a.m. UTC | #1
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 Sandiford July 2, 2018, 4:35 p.m. UTC | #2
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
Richard Biener July 3, 2018, 7:14 a.m. UTC | #3
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
diff mbox series

Patch

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  */