From 3ed5325259dfeea9187daf083a411854407d81f7 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Thu, 5 Jul 2018 15:17:20 -0400
Subject: [PATCH 42/58] FIXME: add opt_result

---
 gcc/opt-problem.h         | 57 ++++++++++++++++++++++++++++++++++-
 gcc/tree-data-ref.c       |  8 ++---
 gcc/tree-data-ref.h       |  8 +++--
 gcc/tree-vect-data-refs.c | 74 +++++++++++++++++++++++++--------------------
 gcc/tree-vect-loop.c      | 77 ++++++++++++++++++++++++++---------------------
 gcc/tree-vect-slp.c       |  2 +-
 gcc/tree-vect-stmts.c     | 29 +++++++++---------
 gcc/tree-vectorizer.h     | 20 ++++++------
 8 files changed, 176 insertions(+), 99 deletions(-)

diff --git a/gcc/opt-problem.h b/gcc/opt-problem.h
index 05d0e11..0f0ea0c 100644
--- a/gcc/opt-problem.h
+++ b/gcc/opt-problem.h
@@ -21,11 +21,12 @@ along with GCC; see the file COPYING3.  If not see
 #ifndef GCC_OPT_PROBLEM_H
 #define GCC_OPT_PROBLEM_H
 
+#include "diagnostic-core.h"
+
 /* High-level optimization reporting API.
    User-facing, i18n, etc.
    FIXME: this exists so that the underlying optrecords can be grouped
    together, if we're doing optrecords.  */
-
 class opt_report
 {
 public:
@@ -56,4 +57,58 @@ class GTY(()) opt_problem
   dump_impl_location_t m_impl_location;
 };
 
+/* FIXME.  */
+
+class opt_result
+{
+ public:
+  // No public ctor
+
+#if 1
+  /* FIXME: during transition, allow construction from bool.
+     We want to eliminate this, as it doesn't capture the reason.  */
+  opt_result (bool result,
+	      const dump_impl_location_t &impl_location
+		= dump_impl_location_t ())
+    : m_result (result),
+      m_problem (new opt_problem ("UNKNOWN", NULL, impl_location))
+  {
+  }
+#endif
+
+  // FIXME: what about discarding the opt_problem in the dtor?
+  // it feels more like a shared_ptr
+  // or maybe have it write to a global, rather than have the field
+  // inline?
+
+  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 ())
+  {
+    if (dump_enabled_p ())
+      return opt_result (false,
+			 new opt_problem (gmsgid, stmt, impl_location));
+    else
+      return opt_result (false, NULL);
+  }
+
+  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
+  }
+
+  operator bool () const { return m_result; }
+
+ private:
+  opt_result (bool result, opt_problem *problem)
+  : m_result (result), m_problem (problem)
+  {}
+
+  bool m_result;
+  opt_problem *m_problem;
+};
+
 #endif /* #ifndef GCC_OPT_PROBLEM_H */
diff --git a/gcc/tree-data-ref.c b/gcc/tree-data-ref.c
index b163eaf..1ab2621 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)
 {
@@ -5067,18 +5067,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;
+  opt_result ret = opt_result::success ();
   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)
     {
diff --git a/gcc/tree-data-ref.h b/gcc/tree-data-ref.h
index 8739853..dbb912a 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
 
 
-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> *);
diff --git a/gcc/tree-vect-data-refs.c b/gcc/tree-vect-data-refs.c
index 63429a3..ed860ab 100644
--- a/gcc/tree-vect-data-refs.c
+++ b/gcc/tree-vect-data-refs.c
@@ -559,7 +559,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)
 {
@@ -594,7 +594,7 @@ vect_analyze_data_ref_dependences (loop_vec_info loop_vinfo,
       if (vect_analyze_data_ref_dependence (ddr, loop_vinfo, max_vf))
 	return false;
 
-  return true;
+  return opt_result::success ();
 }
 
 
@@ -1666,7 +1666,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);
@@ -2352,7 +2352,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 +2377,7 @@ vect_analyze_data_refs_alignment (loop_vec_info vinfo)
 	vect_compute_data_ref_alignment (dr);
     }
 
-  return true;
+  return opt_result::success ();
 }
 
 
@@ -2916,7 +2916,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 +2926,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 +3088,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 +3352,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 +3386,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 ());
 
@@ -3948,7 +3949,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 +3957,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 +3967,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 +3979,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 +4000,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 +4014,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 +4028,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 +4038,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 +4096,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 +4106,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 +4124,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;
@@ -4248,7 +4251,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 +4287,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 +4348,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 +4386,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 +4399,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 19c7c30..6f364b9 100644
--- a/gcc/tree-vect-loop.c
+++ b/gcc/tree-vect-loop.c
@@ -282,7 +282,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 +341,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;
 
@@ -399,7 +400,7 @@ vect_determine_vectorization_factor (loop_vec_info loop_vinfo)
       STMT_VINFO_VECTYPE (stmt_info) = mask_type;
     }
 
-  return true;
+  return opt_result::success ();
 }
 
 
@@ -1506,7 +1507,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);
@@ -1764,7 +1765,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 +1779,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)
 	      {
@@ -1788,8 +1790,10 @@ vect_get_datarefs_in_loop (loop_p loop, basic_block *bbs,
 		    cgraph_node *node = cgraph_node::get (fndecl);
 		    if (node == NULL)
 		      {
-			push_vect_problem ("FIXME 1", stmt);
-			return false;
+			// FIXME: should we return something else?
+			return res;
+			//push_vect_problem ("FIXME 1", stmt);
+			//return false;
 		      }
 		    if (node->simd_clones != NULL)
 		      {
@@ -1815,19 +1819,18 @@ vect_get_datarefs_in_loop (loop_p loop, basic_block *bbs,
 		      }
 		  }
 	      }
-	    push_vect_problem ("FIXME 2", stmt);
-	    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))
-	  {
-	    push_vect_problem ("FIXME: exceeded PARAM_LOOP_MAX_DATAREFS_FOR_DATADEPS", stmt);
-	    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.
@@ -1835,10 +1838,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;
@@ -1854,9 +1857,11 @@ 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 ())
@@ -1864,7 +1869,7 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts)
 			     "not vectorized: loop contains function "
 			     "calls or data references that cannot "
 			     "be analyzed\n");
-	  return false;
+	  return res;
 	}
       loop_vinfo->shared->save_datarefs ();
     }
@@ -1880,7 +1885,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.
@@ -1900,7 +1905,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.  */
@@ -1911,7 +1916,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.  */
@@ -1940,7 +1945,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)))
@@ -1948,7 +1953,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.  */
@@ -1960,7 +1965,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);
@@ -2007,7 +2012,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.
@@ -2015,7 +2020,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.  */
@@ -2029,7 +2034,7 @@ start_over:
 	if (dump_enabled_p ())
 	  dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 			   "bad data alignment.\n");
-        return false;
+        return ok;
       }
     }
 
@@ -2052,7 +2057,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
@@ -2099,7 +2104,7 @@ start_over:
       if (dump_enabled_p ())
 	dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
 			 "Loop costings not worthwhile.\n");
-      return false;
+      return res;
     }
 
   /* Decide whether we need to create an epilogue loop to handle
@@ -2184,7 +2189,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
@@ -2349,13 +2354,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)
diff --git a/gcc/tree-vect-slp.c b/gcc/tree-vect-slp.c
index 528e1d5..e3bdd8d 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;
diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c
index 7d0fc9b..368aa6a 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,7 +469,7 @@ 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))
     {
@@ -480,14 +480,14 @@ process_use (gimple *stmt, tree use, loop_vec_info loop_vinfo,
     }
 
   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 +509,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 +597,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 +622,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 +713,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 +726,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 +739,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;
 
@@ -807,7 +808,7 @@ vect_mark_stmts_to_be_vectorized (loop_vec_info loop_vinfo)
 	}
     } /* while worklist */
 
-  return true;
+  return opt_result::success ();
 }
 
 /* Compute the prologue cost for invariant or constant operands.  */
diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h
index 62061de..1a28657 100644
--- a/gcc/tree-vectorizer.h
+++ b/gcc/tree-vectorizer.h
@@ -1511,7 +1511,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);
@@ -1551,21 +1551,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 opt_result vect_enhance_data_refs_alignment (loop_vec_info);
+extern opt_result vect_analyze_data_refs_alignment (loop_vec_info);
 extern bool 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 *,
@@ -1640,7 +1640,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

