The vect_build_slp_instance function has a lot of parameters.
Hitherto, it was undocumented whether it took ownership of the
vectors named scalar_stmts, root_stmt_infos and remain.
The calling code in vect_analyze_slp was written in such a way
as to assume that vect_build_slp_instance always took ownership
of the caller's reference to the passed-in scalar_stmts (i.e.
that the vector need not be released by the caller on failure).
That contract might have been alright in principle (albeit
inconsistent with the treatment of root_stmt_infos) except that
vect_build_slp_tree can succeed when called within
vect_build_slp_instance before vect_build_slp_instance fails.
vect_build_slp_tree puts a reference to the stmts into the
bst_map, but does not undo that on the failure recovery path.
Consequently, the destructor for the _bb_vec_info later
crashed upon trying to release the stmts of one of its roots
because the stmts had already been released by the destructor
of the _slp_tree created by vect_build_slp_tree (when
invoked via release_scalar_stmts_to_slp_tree_map).
There was also a potential leak in the case where *limit is 0
(which causes false to be returned without releasing anything).
Another broken failure recovery path occurred if
vect_build_slp_instance detected that unrolling could have
been required for BB SLP and the maximum number of vector
elements for the tree was a known constant not greater than
the group size. In this case, the tree node was freed *and*
scalar_stmts was released (despite ownership having passed
to the tree).
Simplified the implementation of vect_build_slp_instance by
not calling vect_build_slp_tree until after all other
checks are completed. Simplified the contract with its
callers by requiring them to release scalar_stmts on
failure.
The "Save for re-processing on failure" code was brittle because if
the length of scalar_stmts was greater than one and
vect_build_slp_instance failed then the length of scalar_stmts would
have been queried again, despite ownership of scalar_stmts having
already passed to vect_build_slp_instance. We now avoid querying the
length a second time.
---
gcc/tree-vect-slp.cc | 127 ++++++++++++++++++++++++-------------------
1 file changed, 72 insertions(+), 55 deletions(-)
diff --git a/gcc/tree-vect-slp.cc b/gcc/tree-vect-slp.cc
index 89bbd13fcb9..8b66751a8a9 100644
--- a/gcc/tree-vect-slp.cc
+++ b/gcc/tree-vect-slp.cc
@@ -4062,7 +4062,9 @@ vect_build_slp_store_interleaving (vec<slp_tree>
&rhs_nodes,
}
/* Analyze an SLP instance starting from SCALAR_STMTS which are a group
- of KIND. Return true if successful. */
+ of KIND. Return true if successful. VEC_INFO and BST_MAP take joint
+ ownership of SCALAR_STMTS if successful. VEC_INFO takes ownership of
+ ROOT_STMT_INFOS and REMAIN if successful. */
static bool
vect_build_slp_instance (vec_info *vinfo,
@@ -4115,10 +4117,6 @@ vect_build_slp_instance (vec_info *vinfo,
matches[1] = false;
}
else
- node = vect_build_slp_tree (vinfo, scalar_stmts, group_size,
- &nunits, matches, limit,
- &tree_size, bst_map);
- if (node != NULL)
{
/* Calculate the unrolling factor based on the smallest type. */
poly_uint64 unrolling_factor
@@ -4136,7 +4134,6 @@ vect_build_slp_instance (vec_info *vinfo,
"Build SLP failed: store group "
"size not a multiple of the vector size "
"in basic block SLP\n");
- vect_free_slp_tree (node);
return false;
}
/* Fatal mismatch. */
@@ -4146,46 +4143,52 @@ vect_build_slp_instance (vec_info *vinfo,
"splitting\n");
memset (matches, true, group_size);
matches[group_size / const_max_nunits * const_max_nunits] = false;
- vect_free_slp_tree (node);
}
- else
+ else
{
- /* Create a new SLP instance. */
- slp_instance new_instance = XNEW (class _slp_instance);
- SLP_INSTANCE_TREE (new_instance) = node;
- SLP_INSTANCE_LOADS (new_instance) = vNULL;
- SLP_INSTANCE_ROOT_STMTS (new_instance) = root_stmt_infos;
- SLP_INSTANCE_REMAIN_DEFS (new_instance) = remain;
- SLP_INSTANCE_KIND (new_instance) = kind;
- new_instance->reduc_phis = NULL;
- new_instance->cost_vec = vNULL;
- new_instance->subgraph_entries = vNULL;
+ node = vect_build_slp_tree (vinfo, scalar_stmts, group_size, &nunits,
+ matches, limit, &tree_size, bst_map);
+ }
+ }
- if (dump_enabled_p ())
- dump_printf_loc (MSG_NOTE, vect_location,
- "SLP size %u vs. limit %u.\n",
- tree_size, max_tree_size);
+ if (node != NULL)
+ {
+ /* Create a new SLP instance. */
+ slp_instance new_instance = XNEW (class _slp_instance);
+ SLP_INSTANCE_TREE (new_instance) = node;
+ SLP_INSTANCE_LOADS (new_instance) = vNULL;
+ SLP_INSTANCE_ROOT_STMTS (new_instance) = root_stmt_infos;
+ SLP_INSTANCE_REMAIN_DEFS (new_instance) = remain;
+ SLP_INSTANCE_KIND (new_instance) = kind;
+ new_instance->reduc_phis = NULL;
+ new_instance->cost_vec = vNULL;
+ new_instance->subgraph_entries = vNULL;
- vinfo->slp_instances.safe_push (new_instance);
+ if (dump_enabled_p ())
+ dump_printf_loc (MSG_NOTE, vect_location, "SLP size %u vs limit %u.\n",
+ tree_size, max_tree_size);
- /* ??? We've replaced the old SLP_INSTANCE_GROUP_SIZE with
- the number of scalar stmts in the root in a few places.
- Verify that assumption holds. */
- gcc_assert (SLP_TREE_SCALAR_STMTS (SLP_INSTANCE_TREE (new_instance))
- .length () == group_size);
+ vinfo->slp_instances.safe_push (new_instance);
- if (dump_enabled_p ())
- {
- dump_printf_loc (MSG_NOTE, vect_location,
- "Final SLP tree for instance %p:\n",
- (void *) new_instance);
- vect_print_slp_graph (MSG_NOTE, vect_location,
- SLP_INSTANCE_TREE (new_instance));
- }
+ /* ??? We've replaced the old SLP_INSTANCE_GROUP_SIZE with
+ the number of scalar stmts in the root in a few places.
+ Verify that assumption holds. */
+ gcc_assert (
+ SLP_TREE_SCALAR_STMTS (SLP_INSTANCE_TREE (new_instance)).length ()
+ == group_size);
- return true;
+ if (dump_enabled_p ())
+ {
+ dump_printf_loc (MSG_NOTE, vect_location,
+ "Final SLP tree for instance %p:\n",
+ (void *) new_instance);
+ vect_print_slp_graph (MSG_NOTE, vect_location,
+ SLP_INSTANCE_TREE (new_instance));
}
+
+ return true;
}
+
/* Failed to SLP. */
/* While we arrive here even with slp_inst_kind_store we should only
@@ -4193,9 +4196,6 @@ vect_build_slp_instance (vec_info *vinfo,
vect_analyze_slp_instance now. */
gcc_assert (kind != slp_inst_kind_store || group_size == 1);
- /* Free the allocated memory. */
- scalar_stmts.release ();
-
/* Failed to SLP. */
if (dump_enabled_p ())
dump_printf_loc (MSG_NOTE, vect_location, "SLP discovery failed\n");
@@ -4699,7 +4699,6 @@ vect_analyze_slp_reduction (loop_vec_info vinfo,
return true;
}
/* Failed to SLP. */
-
/* Free the allocated memory. */
scalar_stmts.release ();
@@ -5560,8 +5559,11 @@ vect_analyze_slp (vec_info *vinfo, unsigned
max_tree_size,
if (! vect_build_slp_instance (vinfo, slp_inst_kind_store,
stmts, roots, remain, max_tree_size,
&limit, bst_map, force_single_lane))
- return opt_result::failure_at (vect_location,
- "SLP build failed.\n");
+ {
+ stmts.release ();
+ return opt_result::failure_at (vect_location,
+ "SLP build failed.\n");
+ }
}
stmt_vec_info stmt_info;
@@ -5575,8 +5577,11 @@ vect_analyze_slp (vec_info *vinfo, unsigned
max_tree_size,
if (! vect_build_slp_instance (vinfo, slp_inst_kind_store,
stmts, roots, remain, max_tree_size,
&limit, bst_map, force_single_lane))
- return opt_result::failure_at (vect_location,
- "SLP build failed.\n");
+ {
+ stmts.release ();
+ return opt_result::failure_at (vect_location,
+ "SLP build failed.\n");
+ }
}
}
@@ -5634,8 +5639,11 @@ vect_analyze_slp (vec_info *vinfo, unsigned
max_tree_size,
max_tree_size, &limit,
bst_map,
force_single_lane))
- return opt_result::failure_at (vect_location,
- "SLP build failed.\n");
+ {
+ scalar_stmts.release ();
+ return opt_result::failure_at (vect_location,
+ "SLP build failed.\n");
+ }
}
}
/* Save for re-processing on failure. */
@@ -5649,8 +5657,7 @@ vect_analyze_slp (vec_info *vinfo, unsigned max_tree_size,
max_tree_size, &limit, bst_map,
force_single_lane))
{
- if (scalar_stmts.length () <= 1)
- scalar_stmts.release ();
+ scalar_stmts.release ();
/* Do SLP discovery for single-lane reductions. */
for (auto stmt_info : saved_stmts)
if (! vect_analyze_slp_reduction (loop_vinfo,
@@ -5691,8 +5698,11 @@ vect_analyze_slp (vec_info *vinfo, unsigned
max_tree_size,
stmts, roots, remain,
max_tree_size, &limit,
bst_map, force_single_lane))
- return opt_result::failure_at (vect_location,
- "SLP build failed.\n");
+ {
+ stmts.release ();
+ return opt_result::failure_at (vect_location,
+ "SLP build failed.\n");
+ }
}
}
@@ -5736,6 +5746,7 @@ vect_analyze_slp (vec_info *vinfo, unsigned max_tree_size,
bst_map, force_single_lane))
{
roots.release ();
+ stmts.release ();
return opt_result::failure_at (vect_location,
"SLP build failed.\n");
}
@@ -5760,8 +5771,11 @@ vect_analyze_slp (vec_info *vinfo, unsigned
max_tree_size,
stmts, roots, remain,
max_tree_size, &limit,
bst_map, force_single_lane))
- return opt_result::failure_at (vect_location,
- "SLP build failed.\n");
+ {
+ stmts.release ();
+ return opt_result::failure_at (vect_location,
+ "SLP build failed.\n");
+ }
}
/* When the latch def is from a different cycle this can only
be a induction. Build a simple instance for this.
@@ -5778,8 +5792,11 @@ vect_analyze_slp (vec_info *vinfo, unsigned
max_tree_size,
stmts, roots, remain,
max_tree_size, &limit,
bst_map, force_single_lane))
- return opt_result::failure_at (vect_location,
- "SLP build failed.\n");
+ {
+ stmts.release ();
+ return opt_result::failure_at (vect_location,
+ "SLP build failed.\n");
+ }
}
}
}
--
2.43.0