[4/5] Use opt_result throughout vectorizer

Message ID 1531185096-17113-5-git-send-email-dmalcolm@redhat.com
State New
Headers show
Series
  • Higher-level reporting of vectorization problems
Related show

Commit Message

David Malcolm July 10, 2018, 1:11 a.m.
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(-)

Patch

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
 
 
-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> > *);