diff mbox series

predcom: Refactor more by encapsulating global states

Message ID 2b1c6017-08b4-e96e-cc0d-b229e912ea0e@linux.ibm.com
State New
Headers show
Series predcom: Refactor more by encapsulating global states | expand

Commit Message

Kewen.Lin June 22, 2021, 2:35 a.m. UTC
Hi Richi and Martin,

>>
>> Thanks Richi!  One draft (not ready for review) is attached for the further
>> discussion.  It follows the idea of RAII-style cleanup.  I noticed that
>> Martin suggested stepping forward to make tree_predictive_commoning_loop
>> and its callees into one class (Thanks Martin), since there are not many
>> this kind of C++-style work functions, I want to double confirm which option
>> do you guys prefer?
>>
> 
> Such general cleanup is of course desired - Giuliano started some of it within
> GSoC two years ago in the attempt to thread the compilation process.  The
> cleanup then helps to get rid of global state which of course interferes here
> (and avoids unnecessary use of TLS vars).
> 
> So yes, encapsulating global state into a class and making accessors
> member functions is something that is desired (but a lot of mechanical
> work).
> 
> Thanks
> Richard.
> 
> I meant that not necessarily as something to include in this patch
> but as a suggestion for a future improvement.  If you'd like to
> tackle it at any point that would be great of course   In any
> event, thanks for double-checking!
>
> The attached patch looks good to me as well (more for the sake of
> style than anything else, declaring the class copy ctor and copy assignment = delete would > make it clear it's not meant to be
> copied, although in this case it's unlikely to make a practical
> difference). 
> 
> Martin.


Thanks for your explanation!  Sorry for the late response.
As the way to encapsulate global state into a class and making accessors
member functions looks more complete, I gave up the RAII draft and
switched onto this way.

This patch is to encapsulate global states into a class and
making their accessors as member functions, remove some
consequent useless clean up code, and do some clean up with
RAII.

Bootstrapped/regtested on powerpc64le-linux-gnu P9,
x86_64-redhat-linux and aarch64-linux-gnu, also
bootstrapped on ppc64le P9 with bootstrap-O3 config.

Is it ok for trunk?

BR,
Kewen
-----
gcc/ChangeLog:

	* tree-predcom.c (class pcom_worker): New class.
	(release_chain): Renamed to...
	(pcom_worker::release_chain): ...this.
	(release_chains): Renamed to...
	(pcom_worker::release_chains): ...this.
	(aff_combination_dr_offset): Renamed to...
	(pcom_worker::aff_combination_dr_offset): ...this.
	(determine_offset): Renamed to...
	(pcom_worker::determine_offset): ...this.
	(class comp_ptrs): New class.
	(split_data_refs_to_components): Renamed to...
	(pcom_worker::split_data_refs_to_components): ...this,
	and update with class comp_ptrs.
	(suitable_component_p): Renamed to...
	(pcom_worker::suitable_component_p): ...this.
	(filter_suitable_components): Renamed to...
	(pcom_worker::filter_suitable_components): ...this.
	(valid_initializer_p): Renamed to...
	(pcom_worker::valid_initializer_p): ...this.
	(find_looparound_phi): Renamed to...
	(pcom_worker::find_looparound_phi): ...this.
	(add_looparound_copies): Renamed to...
	(pcom_worker::add_looparound_copies): ...this.
	(determine_roots_comp): Renamed to...
	(pcom_worker::determine_roots_comp): ...this.
	(determine_roots): Renamed to...
	(pcom_worker::determine_roots): ...this.
	(single_nonlooparound_use): Renamed to...
	(pcom_worker::single_nonlooparound_use): ...this.
	(remove_stmt): Renamed to...
	(pcom_worker::remove_stmt): ...this.
	(execute_pred_commoning_chain): Renamed to...
	(pcom_worker::execute_pred_commoning_chain): ...this.
	(execute_pred_commoning): Renamed to...
	(pcom_worker::execute_pred_commoning): ...this.
	(struct epcc_data): New member worker.
	(execute_pred_commoning_cbck): Call execute_pred_commoning
	with pcom_worker pointer.
	(find_use_stmt): Renamed to...
	(pcom_worker::find_use_stmt): ...this.
	(find_associative_operation_root): Renamed to...
	(pcom_worker::find_associative_operation_root): ...this.
	(find_common_use_stmt): Renamed to...
	(pcom_worker::find_common_use_stmt): ...this.
	(combinable_refs_p): Renamed to...
	(pcom_worker::combinable_refs_p): ...this.
	(reassociate_to_the_same_stmt): Renamed to...
	(pcom_worker::reassociate_to_the_same_stmt): ...this.
	(stmt_combining_refs): Renamed to...
	(pcom_worker::stmt_combining_refs): ...this.
	(combine_chains): Renamed to...
	(pcom_worker::combine_chains): ...this.
	(try_combine_chains): Renamed to...
	(pcom_worker::try_combine_chains): ...this.
	(prepare_initializers_chain): Renamed to...
	(pcom_worker::prepare_initializers_chain): ...this.
	(prepare_initializers): Renamed to...
	(pcom_worker::prepare_initializers): ...this.
	(prepare_finalizers_chain): Renamed to...
	(pcom_worker::prepare_finalizers_chain): ...this.
	(prepare_finalizers): Renamed to...
	(pcom_worker::prepare_finalizers): ...this.
	(tree_predictive_commoning_loop): Renamed to...
	(pcom_worker::tree_predictive_commoning_loop): ...this, adjust
	some calls and remove some cleanup code.
	(tree_predictive_commoning): Adjusted to use pcom_worker instance.
	(static variable looparound_phis): Remove.
	(static variable name_expansions): Remove.
gcc/tree-predcom.c | 483 +++++++++++++++++++++++++++++----------------
 1 file changed, 309 insertions(+), 174 deletions(-)

Comments

Martin Sebor June 22, 2021, 4:14 p.m. UTC | #1
On 6/21/21 8:35 PM, Kewen.Lin wrote:
> Hi Richi and Martin,
> 
>>>
>>> Thanks Richi!  One draft (not ready for review) is attached for the further
>>> discussion.  It follows the idea of RAII-style cleanup.  I noticed that
>>> Martin suggested stepping forward to make tree_predictive_commoning_loop
>>> and its callees into one class (Thanks Martin), since there are not many
>>> this kind of C++-style work functions, I want to double confirm which option
>>> do you guys prefer?
>>>
>>
>> Such general cleanup is of course desired - Giuliano started some of it within
>> GSoC two years ago in the attempt to thread the compilation process.  The
>> cleanup then helps to get rid of global state which of course interferes here
>> (and avoids unnecessary use of TLS vars).
>>
>> So yes, encapsulating global state into a class and making accessors
>> member functions is something that is desired (but a lot of mechanical
>> work).
>>
>> Thanks
>> Richard.
>>
>> I meant that not necessarily as something to include in this patch
>> but as a suggestion for a future improvement.  If you'd like to
>> tackle it at any point that would be great of course   In any
>> event, thanks for double-checking!
>>
>> The attached patch looks good to me as well (more for the sake of
>> style than anything else, declaring the class copy ctor and copy assignment = delete would > make it clear it's not meant to be
>> copied, although in this case it's unlikely to make a practical
>> difference).
>>
>> Martin.
> 
> 
> Thanks for your explanation!  Sorry for the late response.
> As the way to encapsulate global state into a class and making accessors
> member functions looks more complete, I gave up the RAII draft and
> switched onto this way.
> 
> This patch is to encapsulate global states into a class and
> making their accessors as member functions, remove some
> consequent useless clean up code, and do some clean up with
> RAII.

Nice!

A further improvement worth considering (if you're so inclined :)
is replacing the pcom_worker vec members with auto_vec (obviating
having to explicitly release them) and for the same reason also
replacing the comp_ptrs bare pointer members with auto_vecs.
There may be other opportunities to do the same in individual
functions (I'd look to get rid of as many calls to functions
like XNEW()/XNEWVEC() and free() use auto_vec instead).

An unrelated but worthwhile change is to replace the FOR_EACH_
loops with C++ 11 range loops, analogously to:
https://gcc.gnu.org/pipermail/gcc-patches/2021-June/572315.html

Finally, the only loosely followed naming convention for member
variables is to start them with the m_ prefix.

These just suggestions that could be done in a followup, not
something I would consider prerequisite for accepting the patch
as is if I were in a position to make such a decision.

Martin

> 
> Bootstrapped/regtested on powerpc64le-linux-gnu P9,
> x86_64-redhat-linux and aarch64-linux-gnu, also
> bootstrapped on ppc64le P9 with bootstrap-O3 config.
> 
> Is it ok for trunk?
> 
> BR,
> Kewen
> -----
> gcc/ChangeLog:
> 
> 	* tree-predcom.c (class pcom_worker): New class.
> 	(release_chain): Renamed to...
> 	(pcom_worker::release_chain): ...this.
> 	(release_chains): Renamed to...
> 	(pcom_worker::release_chains): ...this.
> 	(aff_combination_dr_offset): Renamed to...
> 	(pcom_worker::aff_combination_dr_offset): ...this.
> 	(determine_offset): Renamed to...
> 	(pcom_worker::determine_offset): ...this.
> 	(class comp_ptrs): New class.
> 	(split_data_refs_to_components): Renamed to...
> 	(pcom_worker::split_data_refs_to_components): ...this,
> 	and update with class comp_ptrs.
> 	(suitable_component_p): Renamed to...
> 	(pcom_worker::suitable_component_p): ...this.
> 	(filter_suitable_components): Renamed to...
> 	(pcom_worker::filter_suitable_components): ...this.
> 	(valid_initializer_p): Renamed to...
> 	(pcom_worker::valid_initializer_p): ...this.
> 	(find_looparound_phi): Renamed to...
> 	(pcom_worker::find_looparound_phi): ...this.
> 	(add_looparound_copies): Renamed to...
> 	(pcom_worker::add_looparound_copies): ...this.
> 	(determine_roots_comp): Renamed to...
> 	(pcom_worker::determine_roots_comp): ...this.
> 	(determine_roots): Renamed to...
> 	(pcom_worker::determine_roots): ...this.
> 	(single_nonlooparound_use): Renamed to...
> 	(pcom_worker::single_nonlooparound_use): ...this.
> 	(remove_stmt): Renamed to...
> 	(pcom_worker::remove_stmt): ...this.
> 	(execute_pred_commoning_chain): Renamed to...
> 	(pcom_worker::execute_pred_commoning_chain): ...this.
> 	(execute_pred_commoning): Renamed to...
> 	(pcom_worker::execute_pred_commoning): ...this.
> 	(struct epcc_data): New member worker.
> 	(execute_pred_commoning_cbck): Call execute_pred_commoning
> 	with pcom_worker pointer.
> 	(find_use_stmt): Renamed to...
> 	(pcom_worker::find_use_stmt): ...this.
> 	(find_associative_operation_root): Renamed to...
> 	(pcom_worker::find_associative_operation_root): ...this.
> 	(find_common_use_stmt): Renamed to...
> 	(pcom_worker::find_common_use_stmt): ...this.
> 	(combinable_refs_p): Renamed to...
> 	(pcom_worker::combinable_refs_p): ...this.
> 	(reassociate_to_the_same_stmt): Renamed to...
> 	(pcom_worker::reassociate_to_the_same_stmt): ...this.
> 	(stmt_combining_refs): Renamed to...
> 	(pcom_worker::stmt_combining_refs): ...this.
> 	(combine_chains): Renamed to...
> 	(pcom_worker::combine_chains): ...this.
> 	(try_combine_chains): Renamed to...
> 	(pcom_worker::try_combine_chains): ...this.
> 	(prepare_initializers_chain): Renamed to...
> 	(pcom_worker::prepare_initializers_chain): ...this.
> 	(prepare_initializers): Renamed to...
> 	(pcom_worker::prepare_initializers): ...this.
> 	(prepare_finalizers_chain): Renamed to...
> 	(pcom_worker::prepare_finalizers_chain): ...this.
> 	(prepare_finalizers): Renamed to...
> 	(pcom_worker::prepare_finalizers): ...this.
> 	(tree_predictive_commoning_loop): Renamed to...
> 	(pcom_worker::tree_predictive_commoning_loop): ...this, adjust
> 	some calls and remove some cleanup code.
> 	(tree_predictive_commoning): Adjusted to use pcom_worker instance.
> 	(static variable looparound_phis): Remove.
> 	(static variable name_expansions): Remove.
>
Richard Biener June 23, 2021, 7:22 a.m. UTC | #2
On Tue, Jun 22, 2021 at 4:35 AM Kewen.Lin <linkw@linux.ibm.com> wrote:
>
> Hi Richi and Martin,
>
> >>
> >> Thanks Richi!  One draft (not ready for review) is attached for the further
> >> discussion.  It follows the idea of RAII-style cleanup.  I noticed that
> >> Martin suggested stepping forward to make tree_predictive_commoning_loop
> >> and its callees into one class (Thanks Martin), since there are not many
> >> this kind of C++-style work functions, I want to double confirm which option
> >> do you guys prefer?
> >>
> >
> > Such general cleanup is of course desired - Giuliano started some of it within
> > GSoC two years ago in the attempt to thread the compilation process.  The
> > cleanup then helps to get rid of global state which of course interferes here
> > (and avoids unnecessary use of TLS vars).
> >
> > So yes, encapsulating global state into a class and making accessors
> > member functions is something that is desired (but a lot of mechanical
> > work).
> >
> > Thanks
> > Richard.
> >
> > I meant that not necessarily as something to include in this patch
> > but as a suggestion for a future improvement.  If you'd like to
> > tackle it at any point that would be great of course   In any
> > event, thanks for double-checking!
> >
> > The attached patch looks good to me as well (more for the sake of
> > style than anything else, declaring the class copy ctor and copy assignment = delete would > make it clear it's not meant to be
> > copied, although in this case it's unlikely to make a practical
> > difference).
> >
> > Martin.
>
>
> Thanks for your explanation!  Sorry for the late response.
> As the way to encapsulate global state into a class and making accessors
> member functions looks more complete, I gave up the RAII draft and
> switched onto this way.
>
> This patch is to encapsulate global states into a class and
> making their accessors as member functions, remove some
> consequent useless clean up code, and do some clean up with
> RAII.
>
> Bootstrapped/regtested on powerpc64le-linux-gnu P9,
> x86_64-redhat-linux and aarch64-linux-gnu, also
> bootstrapped on ppc64le P9 with bootstrap-O3 config.
>
> Is it ok for trunk?

OK, thanks for the work - Martins suggestions are good but indeed can be
handled as followup.

Richard.

> BR,
> Kewen
> -----
> gcc/ChangeLog:
>
>         * tree-predcom.c (class pcom_worker): New class.
>         (release_chain): Renamed to...
>         (pcom_worker::release_chain): ...this.
>         (release_chains): Renamed to...
>         (pcom_worker::release_chains): ...this.
>         (aff_combination_dr_offset): Renamed to...
>         (pcom_worker::aff_combination_dr_offset): ...this.
>         (determine_offset): Renamed to...
>         (pcom_worker::determine_offset): ...this.
>         (class comp_ptrs): New class.
>         (split_data_refs_to_components): Renamed to...
>         (pcom_worker::split_data_refs_to_components): ...this,
>         and update with class comp_ptrs.
>         (suitable_component_p): Renamed to...
>         (pcom_worker::suitable_component_p): ...this.
>         (filter_suitable_components): Renamed to...
>         (pcom_worker::filter_suitable_components): ...this.
>         (valid_initializer_p): Renamed to...
>         (pcom_worker::valid_initializer_p): ...this.
>         (find_looparound_phi): Renamed to...
>         (pcom_worker::find_looparound_phi): ...this.
>         (add_looparound_copies): Renamed to...
>         (pcom_worker::add_looparound_copies): ...this.
>         (determine_roots_comp): Renamed to...
>         (pcom_worker::determine_roots_comp): ...this.
>         (determine_roots): Renamed to...
>         (pcom_worker::determine_roots): ...this.
>         (single_nonlooparound_use): Renamed to...
>         (pcom_worker::single_nonlooparound_use): ...this.
>         (remove_stmt): Renamed to...
>         (pcom_worker::remove_stmt): ...this.
>         (execute_pred_commoning_chain): Renamed to...
>         (pcom_worker::execute_pred_commoning_chain): ...this.
>         (execute_pred_commoning): Renamed to...
>         (pcom_worker::execute_pred_commoning): ...this.
>         (struct epcc_data): New member worker.
>         (execute_pred_commoning_cbck): Call execute_pred_commoning
>         with pcom_worker pointer.
>         (find_use_stmt): Renamed to...
>         (pcom_worker::find_use_stmt): ...this.
>         (find_associative_operation_root): Renamed to...
>         (pcom_worker::find_associative_operation_root): ...this.
>         (find_common_use_stmt): Renamed to...
>         (pcom_worker::find_common_use_stmt): ...this.
>         (combinable_refs_p): Renamed to...
>         (pcom_worker::combinable_refs_p): ...this.
>         (reassociate_to_the_same_stmt): Renamed to...
>         (pcom_worker::reassociate_to_the_same_stmt): ...this.
>         (stmt_combining_refs): Renamed to...
>         (pcom_worker::stmt_combining_refs): ...this.
>         (combine_chains): Renamed to...
>         (pcom_worker::combine_chains): ...this.
>         (try_combine_chains): Renamed to...
>         (pcom_worker::try_combine_chains): ...this.
>         (prepare_initializers_chain): Renamed to...
>         (pcom_worker::prepare_initializers_chain): ...this.
>         (prepare_initializers): Renamed to...
>         (pcom_worker::prepare_initializers): ...this.
>         (prepare_finalizers_chain): Renamed to...
>         (pcom_worker::prepare_finalizers_chain): ...this.
>         (prepare_finalizers): Renamed to...
>         (pcom_worker::prepare_finalizers): ...this.
>         (tree_predictive_commoning_loop): Renamed to...
>         (pcom_worker::tree_predictive_commoning_loop): ...this, adjust
>         some calls and remove some cleanup code.
>         (tree_predictive_commoning): Adjusted to use pcom_worker instance.
>         (static variable looparound_phis): Remove.
>         (static variable name_expansions): Remove.
Kewen.Lin June 24, 2021, 9:26 a.m. UTC | #3
Hi Martin,

on 2021/6/23 上午12:14, Martin Sebor wrote:
> On 6/21/21 8:35 PM, Kewen.Lin wrote:
>> Hi Richi and Martin,
>>
>>>>
>>>> Thanks Richi!  One draft (not ready for review) is attached for the further
>>>> discussion.  It follows the idea of RAII-style cleanup.  I noticed that
>>>> Martin suggested stepping forward to make tree_predictive_commoning_loop
>>>> and its callees into one class (Thanks Martin), since there are not many
>>>> this kind of C++-style work functions, I want to double confirm which option
>>>> do you guys prefer?
>>>>
>>>
>>> Such general cleanup is of course desired - Giuliano started some of it within
>>> GSoC two years ago in the attempt to thread the compilation process.  The
>>> cleanup then helps to get rid of global state which of course interferes here
>>> (and avoids unnecessary use of TLS vars).
>>>
>>> So yes, encapsulating global state into a class and making accessors
>>> member functions is something that is desired (but a lot of mechanical
>>> work).
>>>
>>> Thanks
>>> Richard.
>>>
>>> I meant that not necessarily as something to include in this patch
>>> but as a suggestion for a future improvement.  If you'd like to
>>> tackle it at any point that would be great of course   In any
>>> event, thanks for double-checking!
>>>
>>> The attached patch looks good to me as well (more for the sake of
>>> style than anything else, declaring the class copy ctor and copy assignment = delete would > make it clear it's not meant to be
>>> copied, although in this case it's unlikely to make a practical
>>> difference).
>>>
>>> Martin.
>>
>>
>> Thanks for your explanation!  Sorry for the late response.
>> As the way to encapsulate global state into a class and making accessors
>> member functions looks more complete, I gave up the RAII draft and
>> switched onto this way.
>>
>> This patch is to encapsulate global states into a class and
>> making their accessors as member functions, remove some
>> consequent useless clean up code, and do some clean up with
>> RAII.
> 
> Nice!
> 
> A further improvement worth considering (if you're so inclined :)
> is replacing the pcom_worker vec members with auto_vec (obviating
> having to explicitly release them) and for the same reason also
> replacing the comp_ptrs bare pointer members with auto_vecs.
> There may be other opportunities to do the same in individual
> functions (I'd look to get rid of as many calls to functions
> like XNEW()/XNEWVEC() and free() use auto_vec instead).
> 
> An unrelated but worthwhile change is to replace the FOR_EACH_
> loops with C++ 11 range loops, analogously to:
> https://gcc.gnu.org/pipermail/gcc-patches/2021-June/572315.html
> 
> Finally, the only loosely followed naming convention for member
> variables is to start them with the m_ prefix.
> 
> These just suggestions that could be done in a followup, not
> something I would consider prerequisite for accepting the patch
> as is if I were in a position to make such a decision.
> 

Many thanks for all the great suggestions!  I'll deal with them
in a follow up patch.


BR,
Kewen
Kewen.Lin June 24, 2021, 9:28 a.m. UTC | #4
on 2021/6/23 下午3:22, Richard Biener wrote:
> On Tue, Jun 22, 2021 at 4:35 AM Kewen.Lin <linkw@linux.ibm.com> wrote:
>>
>> Hi Richi and Martin,
>>
>>>>
>>>> Thanks Richi!  One draft (not ready for review) is attached for the further
>>>> discussion.  It follows the idea of RAII-style cleanup.  I noticed that
>>>> Martin suggested stepping forward to make tree_predictive_commoning_loop
>>>> and its callees into one class (Thanks Martin), since there are not many
>>>> this kind of C++-style work functions, I want to double confirm which option
>>>> do you guys prefer?
>>>>
>>>
>>> Such general cleanup is of course desired - Giuliano started some of it within
>>> GSoC two years ago in the attempt to thread the compilation process.  The
>>> cleanup then helps to get rid of global state which of course interferes here
>>> (and avoids unnecessary use of TLS vars).
>>>
>>> So yes, encapsulating global state into a class and making accessors
>>> member functions is something that is desired (but a lot of mechanical
>>> work).
>>>
>>> Thanks
>>> Richard.
>>>
>>> I meant that not necessarily as something to include in this patch
>>> but as a suggestion for a future improvement.  If you'd like to
>>> tackle it at any point that would be great of course   In any
>>> event, thanks for double-checking!
>>>
>>> The attached patch looks good to me as well (more for the sake of
>>> style than anything else, declaring the class copy ctor and copy assignment = delete would > make it clear it's not meant to be
>>> copied, although in this case it's unlikely to make a practical
>>> difference).
>>>
>>> Martin.
>>
>>
>> Thanks for your explanation!  Sorry for the late response.
>> As the way to encapsulate global state into a class and making accessors
>> member functions looks more complete, I gave up the RAII draft and
>> switched onto this way.
>>
>> This patch is to encapsulate global states into a class and
>> making their accessors as member functions, remove some
>> consequent useless clean up code, and do some clean up with
>> RAII.
>>
>> Bootstrapped/regtested on powerpc64le-linux-gnu P9,
>> x86_64-redhat-linux and aarch64-linux-gnu, also
>> bootstrapped on ppc64le P9 with bootstrap-O3 config.
>>
>> Is it ok for trunk?
> 
> OK, thanks for the work - Martins suggestions are good but indeed can be
> handled as followup.
> 

Thanks Richi!  Re-tested and committed in r12-1767, I will make up a
follow up patch for Martin's suggestions.

BR,
Kewen
diff mbox series

Patch

diff --git a/gcc/tree-predcom.c b/gcc/tree-predcom.c
index ac1674d5486..a4ebf2261b0 100644
--- a/gcc/tree-predcom.c
+++ b/gcc/tree-predcom.c
@@ -375,13 +375,156 @@  struct component
   struct component *next;
 };
 
-/* Bitmap of ssa names defined by looparound phi nodes covered by chains.  */
+/* A class to encapsulate the global states used for predictive
+   commoning work on top of one given LOOP.  */
 
-static bitmap looparound_phis;
+class pcom_worker
+{
+public:
+  pcom_worker (loop_p l) : loop (l), chains (vNULL), cache (NULL)
+  {
+    dependences.create (10);
+    datarefs.create (10);
+  }
+
+  ~pcom_worker ()
+  {
+    free_data_refs (datarefs);
+    free_dependence_relations (dependences);
+    free_affine_expand_cache (&cache);
+    release_chains ();
+  }
+
+  pcom_worker (const pcom_worker &) = delete;
+  pcom_worker &operator= (const pcom_worker &) = delete;
+
+  /* Performs predictive commoning.  */
+  unsigned tree_predictive_commoning_loop (bool allow_unroll_p);
+
+  /* Perform the predictive commoning optimization for chains, make this
+     public for being called in callback execute_pred_commoning_cbck.  */
+  void execute_pred_commoning (bitmap tmp_vars);
+
+private:
+  /* The pointer to the given loop.  */
+  loop_p loop;
+
+  /* All data references.  */
+  vec<data_reference_p> datarefs;
+
+  /* All data dependences.  */
+  vec<ddr_p> dependences;
+
+  /* All chains.  */
+  vec<chain_p> chains;
+
+  /* Bitmap of ssa names defined by looparound phi nodes covered by chains.  */
+  auto_bitmap looparound_phis;
+
+  typedef hash_map<tree, name_expansion *> tree_expand_map_t;
+  /* Cache used by tree_to_aff_combination_expand.  */
+  tree_expand_map_t *cache;
+  /* Splits dependence graph to components.  */
+  struct component *split_data_refs_to_components ();
+
+  /* Check the conditions on references inside each of components COMPS,
+     and remove the unsuitable components from the list.  */
+  struct component *filter_suitable_components (struct component *comps);
+
+  /* Find roots of the values and determine distances in components COMPS,
+     and separates the references to chains.  */
+  void determine_roots (struct component *comps);
+
+  /* Prepare initializers for chains, and free chains that cannot
+     be used because the initializers might trap.  */
+  void prepare_initializers ();
+
+  /* Generates finalizer memory reference for chains.  Returns true if
+     finalizer code generation for chains breaks loop closed ssa form.  */
+  bool prepare_finalizers ();
+
+  /* Try to combine the chains.  */
+  void try_combine_chains ();
+
+  /* Frees CHAINS.  */
+  void release_chains ();
+
+  /* Frees a chain CHAIN.  */
+  void release_chain (chain_p chain);
 
-/* Cache used by tree_to_aff_combination_expand.  */
+  /* Prepare initializers for CHAIN.  Returns false if this is impossible
+     because one of these initializers may trap, true otherwise.  */
+  bool prepare_initializers_chain (chain_p chain);
 
-static hash_map<tree, name_expansion *> *name_expansions;
+  /* Generates finalizer memory references for CHAIN.  Returns true
+     if finalizer code for CHAIN can be generated, otherwise false.  */
+  bool prepare_finalizers_chain (chain_p chain);
+
+  /* Stores DR_OFFSET (DR) + DR_INIT (DR) to OFFSET.  */
+  void aff_combination_dr_offset (struct data_reference *dr, aff_tree *offset);
+
+  /* Determines number of iterations of the innermost enclosing loop before
+     B refers to exactly the same location as A and stores it to OFF.  */
+  bool determine_offset (struct data_reference *a, struct data_reference *b,
+			 poly_widest_int *off);
+
+  /* Returns true if the component COMP satisfies the conditions
+     described in 2) at the beginning of this file.  */
+  bool suitable_component_p (struct component *comp);
+
+  /* Returns true if REF is a valid initializer for ROOT with given
+     DISTANCE (in iterations of the innermost enclosing loop).  */
+  bool valid_initializer_p (struct data_reference *ref, unsigned distance,
+			    struct data_reference *root);
+
+  /* Finds looparound phi node of loop that copies the value of REF.  */
+  gphi *find_looparound_phi (dref ref, dref root);
+
+  /* Find roots of the values and determine distances in the component
+     COMP.  The references are redistributed into chains.  */
+  void determine_roots_comp (struct component *comp);
+
+  /* For references in CHAIN that are copied around the loop, add the
+     results of such copies to the chain.  */
+  void add_looparound_copies (chain_p chain);
+
+  /* Returns the single statement in that NAME is used, excepting
+     the looparound phi nodes contained in one of the chains.  */
+  gimple *single_nonlooparound_use (tree name);
+
+  /* Remove statement STMT, as well as the chain of assignments in that
+     it is used.  */
+  void remove_stmt (gimple *stmt);
+
+  /* Perform the predictive commoning optimization for a chain CHAIN.  */
+  void execute_pred_commoning_chain (chain_p chain, bitmap tmp_vars);
+
+  /* Returns the modify statement that uses NAME.  */
+  gimple *find_use_stmt (tree *name);
+
+  /* If the operation used in STMT is associative and commutative, go
+     through the tree of the same operations and returns its root.  */
+  gimple *find_associative_operation_root (gimple *stmt, unsigned *distance);
+
+  /* Returns the common statement in that NAME1 and NAME2 have a use.  */
+  gimple *find_common_use_stmt (tree *name1, tree *name2);
+
+  /* Checks whether R1 and R2 are combined together using CODE, with the
+     result in RSLT_TYPE, in order R1 CODE R2 if SWAP is false and in order
+     R2 CODE R1 if it is true.  */
+  bool combinable_refs_p (dref r1, dref r2, enum tree_code *code, bool *swap,
+			  tree *rslt_type);
+
+  /* Reassociates the expression in that NAME1 and NAME2 are used so that
+     they are combined in a single statement, and returns this statement.  */
+  gimple *reassociate_to_the_same_stmt (tree name1, tree name2);
+
+  /* Returns the statement that combines references R1 and R2.  */
+  gimple *stmt_combining_refs (dref r1, dref r2);
+
+  /* Tries to combine chains CH1 and CH2 together.  */
+  chain_p combine_chains (chain_p ch1, chain_p ch2);
+};
 
 /* Dumps data reference REF to FILE.  */
 
@@ -540,8 +683,8 @@  dump_components (FILE *file, struct component *comps)
 
 /* Frees a chain CHAIN.  */
 
-static void
-release_chain (chain_p chain)
+void
+pcom_worker::release_chain (chain_p chain)
 {
   dref ref;
   unsigned i;
@@ -567,8 +710,8 @@  release_chain (chain_p chain)
 
 /* Frees CHAINS.  */
 
-static void
-release_chains (vec<chain_p> chains)
+void
+pcom_worker::release_chains ()
 {
   unsigned i;
   chain_p chain;
@@ -672,14 +815,14 @@  suitable_reference_p (struct data_reference *a, enum ref_step_type *ref_step)
 
 /* Stores DR_OFFSET (DR) + DR_INIT (DR) to OFFSET.  */
 
-static void
-aff_combination_dr_offset (struct data_reference *dr, aff_tree *offset)
+void
+pcom_worker::aff_combination_dr_offset (struct data_reference *dr,
+					aff_tree *offset)
 {
   tree type = TREE_TYPE (DR_OFFSET (dr));
   aff_tree delta;
 
-  tree_to_aff_combination_expand (DR_OFFSET (dr), type, offset,
-				  &name_expansions);
+  tree_to_aff_combination_expand (DR_OFFSET (dr), type, offset, &cache);
   aff_combination_const (&delta, type, wi::to_poly_widest (DR_INIT (dr)));
   aff_combination_add (offset, &delta);
 }
@@ -690,9 +833,9 @@  aff_combination_dr_offset (struct data_reference *dr, aff_tree *offset)
    returns false, otherwise returns true.  Both A and B are assumed to
    satisfy suitable_reference_p.  */
 
-static bool
-determine_offset (struct data_reference *a, struct data_reference *b,
-		  poly_widest_int *off)
+bool
+pcom_worker::determine_offset (struct data_reference *a,
+			       struct data_reference *b, poly_widest_int *off)
 {
   aff_tree diff, baseb, step;
   tree typea, typeb;
@@ -726,7 +869,7 @@  determine_offset (struct data_reference *a, struct data_reference *b,
   aff_combination_add (&diff, &baseb);
 
   tree_to_aff_combination_expand (DR_STEP (a), TREE_TYPE (DR_STEP (a)),
-				  &step, &name_expansions);
+				  &step, &cache);
   return aff_combination_constant_multiple_p (&diff, &step, off);
 }
 
@@ -747,17 +890,39 @@  last_always_executed_block (class loop *loop)
   return last;
 }
 
-/* Splits dependence graph on DATAREFS described by DEPENDS to components.  */
+/* RAII class for comp_father and comp_size usage.  */
+
+class comp_ptrs
+{
+public:
+  unsigned *comp_father;
+  unsigned *comp_size;
+
+  comp_ptrs (unsigned n)
+  {
+    comp_father = XNEWVEC (unsigned, n + 1);
+    comp_size = XNEWVEC (unsigned, n + 1);
+  }
+
+  ~comp_ptrs ()
+  {
+    free (comp_father);
+    free (comp_size);
+  }
+
+  comp_ptrs (const comp_ptrs &) = delete;
+  comp_ptrs &operator= (const comp_ptrs &) = delete;
+};
+
+/* Splits dependence graph on DATAREFS described by DEPENDENCES to
+   components.  */
 
-static struct component *
-split_data_refs_to_components (class loop *loop,
-			       vec<data_reference_p> datarefs,
-			       vec<ddr_p> depends)
+struct component *
+pcom_worker::split_data_refs_to_components ()
 {
   unsigned i, n = datarefs.length ();
   unsigned ca, ia, ib, bad;
-  unsigned *comp_father = XNEWVEC (unsigned, n + 1);
-  unsigned *comp_size = XNEWVEC (unsigned, n + 1);
+  comp_ptrs ptrs (n);
   struct component **comps;
   struct data_reference *dr, *dra, *drb;
   struct data_dependence_relation *ddr;
@@ -771,22 +936,20 @@  split_data_refs_to_components (class loop *loop,
   FOR_EACH_VEC_ELT (datarefs, i, dr)
     {
       if (!DR_REF (dr))
-	{
 	  /* A fake reference for call or asm_expr that may clobber memory;
 	     just fail.  */
-	  goto end;
-	}
+	  return NULL;
       /* predcom pass isn't prepared to handle calls with data references.  */
       if (is_gimple_call (DR_STMT (dr)))
-	goto end;
+	return NULL;
       dr->aux = (void *) (size_t) i;
-      comp_father[i] = i;
-      comp_size[i] = 1;
+      ptrs.comp_father[i] = i;
+      ptrs.comp_size[i] = 1;
     }
 
   /* A component reserved for the "bad" data references.  */
-  comp_father[n] = n;
-  comp_size[n] = 1;
+  ptrs.comp_father[n] = n;
+  ptrs.comp_size[n] = 1;
 
   FOR_EACH_VEC_ELT (datarefs, i, dr)
     {
@@ -795,11 +958,11 @@  split_data_refs_to_components (class loop *loop,
       if (!suitable_reference_p (dr, &dummy))
 	{
 	  ia = (unsigned) (size_t) dr->aux;
-	  merge_comps (comp_father, comp_size, n, ia);
+	  merge_comps (ptrs.comp_father, ptrs.comp_size, n, ia);
 	}
     }
 
-  FOR_EACH_VEC_ELT (depends, i, ddr)
+  FOR_EACH_VEC_ELT (dependences, i, ddr)
     {
       poly_widest_int dummy_off;
 
@@ -816,12 +979,12 @@  split_data_refs_to_components (class loop *loop,
 	      || DDR_NUM_DIST_VECTS (ddr) == 0))
 	eliminate_store_p = false;
 
-      ia = component_of (comp_father, (unsigned) (size_t) dra->aux);
-      ib = component_of (comp_father, (unsigned) (size_t) drb->aux);
+      ia = component_of (ptrs.comp_father, (unsigned) (size_t) dra->aux);
+      ib = component_of (ptrs.comp_father, (unsigned) (size_t) drb->aux);
       if (ia == ib)
 	continue;
 
-      bad = component_of (comp_father, n);
+      bad = component_of (ptrs.comp_father, n);
 
       /* If both A and B are reads, we may ignore unsuitable dependences.  */
       if (DR_IS_READ (dra) && DR_IS_READ (drb))
@@ -845,7 +1008,7 @@  split_data_refs_to_components (class loop *loop,
 	  else if (!determine_offset (dra, drb, &dummy_off))
 	    {
 	      bitmap_set_bit (no_store_store_comps, ib);
-	      merge_comps (comp_father, comp_size, bad, ia);
+	      merge_comps (ptrs.comp_father, ptrs.comp_size, bad, ia);
 	      continue;
 	    }
 	}
@@ -859,7 +1022,7 @@  split_data_refs_to_components (class loop *loop,
 	  else if (!determine_offset (dra, drb, &dummy_off))
 	    {
 	      bitmap_set_bit (no_store_store_comps, ia);
-	      merge_comps (comp_father, comp_size, bad, ib);
+	      merge_comps (ptrs.comp_father, ptrs.comp_size, bad, ib);
 	      continue;
 	    }
 	}
@@ -867,12 +1030,12 @@  split_data_refs_to_components (class loop *loop,
 	       && ia != bad && ib != bad
 	       && !determine_offset (dra, drb, &dummy_off))
 	{
-	  merge_comps (comp_father, comp_size, bad, ia);
-	  merge_comps (comp_father, comp_size, bad, ib);
+	  merge_comps (ptrs.comp_father, ptrs.comp_size, bad, ia);
+	  merge_comps (ptrs.comp_father, ptrs.comp_size, bad, ib);
 	  continue;
 	}
 
-      merge_comps (comp_father, comp_size, ia, ib);
+      merge_comps (ptrs.comp_father, ptrs.comp_size, ia, ib);
     }
 
   if (eliminate_store_p)
@@ -886,11 +1049,11 @@  split_data_refs_to_components (class loop *loop,
     }
 
   comps = XCNEWVEC (struct component *, n);
-  bad = component_of (comp_father, n);
+  bad = component_of (ptrs.comp_father, n);
   FOR_EACH_VEC_ELT (datarefs, i, dr)
     {
       ia = (unsigned) (size_t) dr->aux;
-      ca = component_of (comp_father, ia);
+      ca = component_of (ptrs.comp_father, ia);
       if (ca == bad)
 	continue;
 
@@ -898,7 +1061,7 @@  split_data_refs_to_components (class loop *loop,
       if (!comp)
 	{
 	  comp = XCNEW (struct component);
-	  comp->refs.create (comp_size[ca]);
+	  comp->refs.create (ptrs.comp_size[ca]);
 	  comp->eliminate_store_p = eliminate_store_p;
 	  comps[ca] = comp;
 	}
@@ -921,7 +1084,7 @@  split_data_refs_to_components (class loop *loop,
       bitmap_iterator bi;
       EXECUTE_IF_SET_IN_BITMAP (no_store_store_comps, 0, ia, bi)
 	{
-	  ca = component_of (comp_father, ia);
+	  ca = component_of (ptrs.comp_father, ia);
 	  if (ca != bad)
 	    comps[ca]->eliminate_store_p = false;
 	}
@@ -937,19 +1100,14 @@  split_data_refs_to_components (class loop *loop,
 	}
     }
   free (comps);
-
-end:
-  free (comp_father);
-  free (comp_size);
   return comp_list;
 }
 
 /* Returns true if the component COMP satisfies the conditions
-   described in 2) at the beginning of this file.  LOOP is the current
-   loop.  */
+   described in 2) at the beginning of this file.  */
 
-static bool
-suitable_component_p (class loop *loop, struct component *comp)
+bool
+pcom_worker::suitable_component_p (struct component *comp)
 {
   unsigned i;
   dref a, first;
@@ -1002,17 +1160,17 @@  suitable_component_p (class loop *loop, struct component *comp)
 /* Check the conditions on references inside each of components COMPS,
    and remove the unsuitable components from the list.  The new list
    of components is returned.  The conditions are described in 2) at
-   the beginning of this file.  LOOP is the current loop.  */
+   the beginning of this file.  */
 
-static struct component *
-filter_suitable_components (class loop *loop, struct component *comps)
+struct component *
+pcom_worker::filter_suitable_components (struct component *comps)
 {
   struct component **comp, *act;
 
   for (comp = &comps; *comp; )
     {
       act = *comp;
-      if (suitable_component_p (loop, act))
+      if (suitable_component_p (act))
 	comp = &act->next;
       else
 	{
@@ -1205,9 +1363,9 @@  name_for_ref (dref ref)
 /* Returns true if REF is a valid initializer for ROOT with given DISTANCE (in
    iterations of the innermost enclosing loop).  */
 
-static bool
-valid_initializer_p (struct data_reference *ref,
-		     unsigned distance, struct data_reference *root)
+bool
+pcom_worker::valid_initializer_p (struct data_reference *ref, unsigned distance,
+				  struct data_reference *root)
 {
   aff_tree diff, base, step;
   poly_widest_int off;
@@ -1234,7 +1392,7 @@  valid_initializer_p (struct data_reference *ref,
   aff_combination_add (&diff, &base);
 
   tree_to_aff_combination_expand (DR_STEP (root), TREE_TYPE (DR_STEP (root)),
-				  &step, &name_expansions);
+				  &step, &cache);
   if (!aff_combination_constant_multiple_p (&diff, &step, &off))
     return false;
 
@@ -1244,13 +1402,13 @@  valid_initializer_p (struct data_reference *ref,
   return true;
 }
 
-/* Finds looparound phi node of LOOP that copies the value of REF, and if its
+/* Finds looparound phi node of loop that copies the value of REF, and if its
    initial value is correct (equal to initial value of REF shifted by one
    iteration), returns the phi node.  Otherwise, NULL_TREE is returned.  ROOT
    is the root of the current chain.  */
 
-static gphi *
-find_looparound_phi (class loop *loop, dref ref, dref root)
+gphi *
+pcom_worker::find_looparound_phi (dref ref, dref root)
 {
   tree name, init, init_ref;
   gphi *phi = NULL;
@@ -1333,13 +1491,13 @@  insert_looparound_copy (chain_p chain, dref ref, gphi *phi)
     }
 }
 
-/* For references in CHAIN that are copied around the LOOP (created previously
+/* For references in CHAIN that are copied around the loop (created previously
    by PRE, or by user), add the results of such copies to the chain.  This
    enables us to remove the copies by unrolling, and may need less registers
    (also, it may allow us to combine chains together).  */
 
-static void
-add_looparound_copies (class loop *loop, chain_p chain)
+void
+pcom_worker::add_looparound_copies (chain_p chain)
 {
   unsigned i;
   dref ref, root = get_chain_root (chain);
@@ -1350,7 +1508,7 @@  add_looparound_copies (class loop *loop, chain_p chain)
 
   FOR_EACH_VEC_ELT (chain->refs, i, ref)
     {
-      phi = find_looparound_phi (loop, ref, root);
+      phi = find_looparound_phi (ref, root);
       if (!phi)
 	continue;
 
@@ -1360,13 +1518,10 @@  add_looparound_copies (class loop *loop, chain_p chain)
 }
 
 /* Find roots of the values and determine distances in the component COMP.
-   The references are redistributed into CHAINS.  LOOP is the current
-   loop.  */
+   The references are redistributed into chains.  */
 
-static void
-determine_roots_comp (class loop *loop,
-		      struct component *comp,
-		      vec<chain_p> *chains)
+void
+pcom_worker::determine_roots_comp (struct component *comp)
 {
   unsigned i;
   dref a;
@@ -1378,7 +1533,7 @@  determine_roots_comp (class loop *loop,
   if (comp->comp_step == RS_INVARIANT)
     {
       chain = make_invariant_chain (comp);
-      chains->safe_push (chain);
+      chains.safe_push (chain);
       return;
     }
 
@@ -1422,8 +1577,8 @@  determine_roots_comp (class loop *loop,
 	{
 	  if (nontrivial_chain_p (chain))
 	    {
-	      add_looparound_copies (loop, chain);
-	      chains->safe_push (chain);
+	      add_looparound_copies (chain);
+	      chains.safe_push (chain);
 	    }
 	  else
 	    release_chain (chain);
@@ -1443,24 +1598,23 @@  determine_roots_comp (class loop *loop,
 
   if (nontrivial_chain_p (chain))
     {
-      add_looparound_copies (loop, chain);
-      chains->safe_push (chain);
+      add_looparound_copies (chain);
+      chains.safe_push (chain);
     }
   else
     release_chain (chain);
 }
 
 /* Find roots of the values and determine distances in components COMPS, and
-   separates the references to CHAINS.  LOOP is the current loop.  */
+   separates the references to chains.  */
 
-static void
-determine_roots (class loop *loop,
-		 struct component *comps, vec<chain_p> *chains)
+void
+pcom_worker::determine_roots (struct component *comps)
 {
   struct component *comp;
 
   for (comp = comps; comp; comp = comp->next)
-    determine_roots_comp (loop, comp, chains);
+    determine_roots_comp (comp);
 }
 
 /* Replace the reference in statement STMT with temporary variable
@@ -2027,8 +2181,8 @@  execute_load_motion (class loop *loop, chain_p chain, bitmap tmp_vars)
    the looparound phi nodes contained in one of the chains.  If there is no
    such statement, or more statements, NULL is returned.  */
 
-static gimple *
-single_nonlooparound_use (tree name)
+gimple *
+pcom_worker::single_nonlooparound_use (tree name)
 {
   use_operand_p use;
   imm_use_iterator it;
@@ -2062,8 +2216,8 @@  single_nonlooparound_use (tree name)
 /* Remove statement STMT, as well as the chain of assignments in that it is
    used.  */
 
-static void
-remove_stmt (gimple *stmt)
+void
+pcom_worker::remove_stmt (gimple *stmt)
 {
   tree name;
   gimple *next;
@@ -2120,8 +2274,8 @@  remove_stmt (gimple *stmt)
 /* Perform the predictive commoning optimization for a chain CHAIN.
    Uids of the newly created temporary variables are marked in TMP_VARS.*/
 
-static void
-execute_pred_commoning_chain (class loop *loop, chain_p chain,
+void
+pcom_worker::execute_pred_commoning_chain (chain_p chain,
 			      bitmap tmp_vars)
 {
   unsigned i;
@@ -2248,12 +2402,11 @@  determine_unroll_factor (vec<chain_p> chains)
   return factor;
 }
 
-/* Perform the predictive commoning optimization for CHAINS.
+/* Perform the predictive commoning optimization for chains.
    Uids of the newly created temporary variables are marked in TMP_VARS.  */
 
-static void
-execute_pred_commoning (class loop *loop, vec<chain_p> chains,
-			bitmap tmp_vars)
+void
+pcom_worker::execute_pred_commoning (bitmap tmp_vars)
 {
   chain_p chain;
   unsigned i;
@@ -2263,7 +2416,7 @@  execute_pred_commoning (class loop *loop, vec<chain_p> chains,
       if (chain->type == CT_INVARIANT)
 	execute_load_motion (loop, chain, tmp_vars);
       else
-	execute_pred_commoning_chain (loop, chain, tmp_vars);
+	execute_pred_commoning_chain (chain, tmp_vars);
     }
 
   FOR_EACH_VEC_ELT (chains, i, chain)
@@ -2330,18 +2483,20 @@  struct epcc_data
 {
   vec<chain_p> chains;
   bitmap tmp_vars;
+  pcom_worker *worker;
 };
 
 static void
-execute_pred_commoning_cbck (class loop *loop, void *data)
+execute_pred_commoning_cbck (class loop *loop ATTRIBUTE_UNUSED, void *data)
 {
   struct epcc_data *const dta = (struct epcc_data *) data;
+  pcom_worker *worker = dta->worker;
 
   /* Restore phi nodes that were replaced by ssa names before
      tree_transform_and_unroll_loop (see detailed description in
      tree_predictive_commoning_loop).  */
   replace_names_by_phis (dta->chains);
-  execute_pred_commoning (loop, dta->chains, dta->tmp_vars);
+  worker->execute_pred_commoning (dta->tmp_vars);
 }
 
 /* Base NAME and all the names in the chain of phi nodes that use it
@@ -2433,8 +2588,8 @@  chain_can_be_combined_p (chain_p chain)
    statements, NAME is replaced with the actual name used in the returned
    statement.  */
 
-static gimple *
-find_use_stmt (tree *name)
+gimple *
+pcom_worker::find_use_stmt (tree *name)
 {
   gimple *stmt;
   tree rhs, lhs;
@@ -2486,8 +2641,8 @@  may_reassociate_p (tree type, enum tree_code code)
    tree of the same operations and returns its root.  Distance to the root
    is stored in DISTANCE.  */
 
-static gimple *
-find_associative_operation_root (gimple *stmt, unsigned *distance)
+gimple *
+pcom_worker::find_associative_operation_root (gimple *stmt, unsigned *distance)
 {
   tree lhs;
   gimple *next;
@@ -2523,8 +2678,8 @@  find_associative_operation_root (gimple *stmt, unsigned *distance)
    tree formed by this operation instead of the statement that uses NAME1 or
    NAME2.  */
 
-static gimple *
-find_common_use_stmt (tree *name1, tree *name2)
+gimple *
+pcom_worker::find_common_use_stmt (tree *name1, tree *name2)
 {
   gimple *stmt1, *stmt2;
 
@@ -2553,8 +2708,8 @@  find_common_use_stmt (tree *name1, tree *name2)
    in RSLT_TYPE, in order R1 CODE R2 if SWAP is false and in order R2 CODE R1
    if it is true.  If CODE is ERROR_MARK, set these values instead.  */
 
-static bool
-combinable_refs_p (dref r1, dref r2,
+bool
+pcom_worker::combinable_refs_p (dref r1, dref r2,
 		   enum tree_code *code, bool *swap, tree *rslt_type)
 {
   enum tree_code acode;
@@ -2622,8 +2777,8 @@  remove_name_from_operation (gimple *stmt, tree op)
 /* Reassociates the expression in that NAME1 and NAME2 are used so that they
    are combined in a single statement, and returns this statement.  */
 
-static gimple *
-reassociate_to_the_same_stmt (tree name1, tree name2)
+gimple *
+pcom_worker::reassociate_to_the_same_stmt (tree name1, tree name2)
 {
   gimple *stmt1, *stmt2, *root1, *root2, *s1, *s2;
   gassign *new_stmt, *tmp_stmt;
@@ -2707,8 +2862,8 @@  reassociate_to_the_same_stmt (tree name1, tree name2)
    associative and commutative operation in the same expression, reassociate
    the expression so that they are used in the same statement.  */
 
-static gimple *
-stmt_combining_refs (dref r1, dref r2)
+gimple *
+pcom_worker::stmt_combining_refs (dref r1, dref r2)
 {
   gimple *stmt1, *stmt2;
   tree name1 = name_for_ref (r1);
@@ -2725,8 +2880,8 @@  stmt_combining_refs (dref r1, dref r2)
 /* Tries to combine chains CH1 and CH2 together.  If this succeeds, the
    description of the new chain is returned, otherwise we return NULL.  */
 
-static chain_p
-combine_chains (chain_p ch1, chain_p ch2)
+chain_p
+pcom_worker::combine_chains (chain_p ch1, chain_p ch2)
 {
   dref r1, r2, nw;
   enum tree_code op = ERROR_MARK;
@@ -2814,17 +2969,17 @@  pcom_stmt_dominates_stmt_p (gimple *s1, gimple *s2)
   return dominated_by_p (CDI_DOMINATORS, bb2, bb1);
 }
 
-/* Try to combine the CHAINS in LOOP.  */
+/* Try to combine the chains.  */
 
-static void
-try_combine_chains (class loop *loop, vec<chain_p> *chains)
+void
+pcom_worker::try_combine_chains ()
 {
   unsigned i, j;
   chain_p ch1, ch2, cch;
   auto_vec<chain_p> worklist;
   bool combined_p = false;
 
-  FOR_EACH_VEC_ELT (*chains, i, ch1)
+  FOR_EACH_VEC_ELT (chains, i, ch1)
     if (chain_can_be_combined_p (ch1))
       worklist.safe_push (ch1);
 
@@ -2834,7 +2989,7 @@  try_combine_chains (class loop *loop, vec<chain_p> *chains)
       if (!chain_can_be_combined_p (ch1))
 	continue;
 
-      FOR_EACH_VEC_ELT (*chains, j, ch2)
+      FOR_EACH_VEC_ELT (chains, j, ch2)
 	{
 	  if (!chain_can_be_combined_p (ch2))
 	    continue;
@@ -2843,7 +2998,7 @@  try_combine_chains (class loop *loop, vec<chain_p> *chains)
 	  if (cch)
 	    {
 	      worklist.safe_push (cch);
-	      chains->safe_push (cch);
+	      chains.safe_push (cch);
 	      combined_p = true;
 	      break;
 	    }
@@ -2867,7 +3022,7 @@  try_combine_chains (class loop *loop, vec<chain_p> *chains)
 
      We first update position information for all combined chains.  */
   dref ref;
-  for (i = 0; chains->iterate (i, &ch1); ++i)
+  for (i = 0; chains.iterate (i, &ch1); ++i)
     {
       if (ch1->type != CT_COMBINATION || ch1->combined)
 	continue;
@@ -2878,7 +3033,7 @@  try_combine_chains (class loop *loop, vec<chain_p> *chains)
       update_pos_for_combined_chains (ch1);
     }
   /* Then sort references according to newly updated position information.  */
-  for (i = 0; chains->iterate (i, &ch1); ++i)
+  for (i = 0; chains.iterate (i, &ch1); ++i)
     {
       if (ch1->type != CT_COMBINATION && !ch1->combined)
 	continue;
@@ -2990,11 +3145,11 @@  prepare_initializers_chain_store_elim (class loop *loop, chain_p chain)
   return true;
 }
 
-/* Prepare initializers for CHAIN in LOOP.  Returns false if this is
-   impossible because one of these initializers may trap, true otherwise.  */
+/* Prepare initializers for CHAIN.  Returns false if this is impossible
+   because one of these initializers may trap, true otherwise.  */
 
-static bool
-prepare_initializers_chain (class loop *loop, chain_p chain)
+bool
+pcom_worker::prepare_initializers_chain (chain_p chain)
 {
   unsigned i, n = (chain->type == CT_INVARIANT) ? 1 : chain->length;
   struct data_reference *dr = get_chain_root (chain)->ref;
@@ -3046,11 +3201,11 @@  prepare_initializers_chain (class loop *loop, chain_p chain)
   return true;
 }
 
-/* Prepare initializers for CHAINS in LOOP, and free chains that cannot
+/* Prepare initializers for chains, and free chains that cannot
    be used because the initializers might trap.  */
 
-static void
-prepare_initializers (class loop *loop, vec<chain_p> chains)
+void
+pcom_worker::prepare_initializers ()
 {
   chain_p chain;
   unsigned i;
@@ -3058,7 +3213,7 @@  prepare_initializers (class loop *loop, vec<chain_p> chains)
   for (i = 0; i < chains.length (); )
     {
       chain = chains[i];
-      if (prepare_initializers_chain (loop, chain))
+      if (prepare_initializers_chain (chain))
 	i++;
       else
 	{
@@ -3068,11 +3223,11 @@  prepare_initializers (class loop *loop, vec<chain_p> chains)
     }
 }
 
-/* Generates finalizer memory references for CHAIN in LOOP.  Returns true
+/* Generates finalizer memory references for CHAIN.  Returns true
    if finalizer code for CHAIN can be generated, otherwise false.  */
 
-static bool
-prepare_finalizers_chain (class loop *loop, chain_p chain)
+bool
+pcom_worker::prepare_finalizers_chain (chain_p chain)
 {
   unsigned i, n = chain->length;
   struct data_reference *dr = get_chain_root (chain)->ref;
@@ -3116,11 +3271,11 @@  prepare_finalizers_chain (class loop *loop, chain_p chain)
   return true;
 }
 
-/* Generates finalizer memory reference for CHAINS in LOOP.  Returns true
-   if finalizer code generation for CHAINS breaks loop closed ssa form.  */
+/* Generates finalizer memory reference for chains.  Returns true if
+   finalizer code generation for chains breaks loop closed ssa form.  */
 
-static bool
-prepare_finalizers (class loop *loop, vec<chain_p> chains)
+bool
+pcom_worker::prepare_finalizers ()
 {
   chain_p chain;
   unsigned i;
@@ -3138,7 +3293,7 @@  prepare_finalizers (class loop *loop, vec<chain_p> chains)
 	  continue;
 	}
 
-      if (prepare_finalizers_chain (loop, chain))
+      if (prepare_finalizers_chain (chain))
 	{
 	  i++;
 	  /* Be conservative, assume loop closed ssa form is corrupted
@@ -3156,7 +3311,7 @@  prepare_finalizers (class loop *loop, vec<chain_p> chains)
   return loop_closed_ssa;
 }
 
-/* Insert all initializing gimple stmts into loop's entry edge.  */
+/* Insert all initializing gimple stmts into LOOP's entry edge.  */
 
 static void
 insert_init_seqs (class loop *loop, vec<chain_p> chains)
@@ -3177,19 +3332,16 @@  insert_init_seqs (class loop *loop, vec<chain_p> chains)
    form was corrupted.  Non-zero return value indicates some changes were
    applied to this loop.  */
 
-static unsigned
-tree_predictive_commoning_loop (class loop *loop, bool allow_unroll_p)
+unsigned
+pcom_worker::tree_predictive_commoning_loop (bool allow_unroll_p)
 {
-  vec<data_reference_p> datarefs;
-  vec<ddr_p> dependences;
   struct component *components;
-  vec<chain_p> chains = vNULL;
   unsigned unroll_factor = 0;
   class tree_niter_desc desc;
   bool unroll = false, loop_closed_ssa = false;
 
   if (dump_file && (dump_flags & TDF_DETAILS))
-    fprintf (dump_file, "Processing loop %d\n",  loop->num);
+    fprintf (dump_file, "Processing loop %d\n", loop->num);
 
   /* Nothing for predicitive commoning if loop only iterates 1 time.  */
   if (get_max_loop_iterations_int (loop) == 0)
@@ -3203,30 +3355,22 @@  tree_predictive_commoning_loop (class loop *loop, bool allow_unroll_p)
   /* Find the data references and split them into components according to their
      dependence relations.  */
   auto_vec<loop_p, 3> loop_nest;
-  dependences.create (10);
-  datarefs.create (10);
-  if (! compute_data_dependences_for_loop (loop, true, &loop_nest, &datarefs,
-					   &dependences))
+  if (!compute_data_dependences_for_loop (loop, true, &loop_nest, &datarefs,
+					  &dependences))
     {
       if (dump_file && (dump_flags & TDF_DETAILS))
 	fprintf (dump_file, "Cannot analyze data dependencies\n");
-      free_data_refs (datarefs);
-      free_dependence_relations (dependences);
       return 0;
     }
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     dump_data_dependence_relations (dump_file, dependences);
 
-  components = split_data_refs_to_components (loop, datarefs, dependences);
+  components = split_data_refs_to_components ();
+
   loop_nest.release ();
-  free_dependence_relations (dependences);
   if (!components)
-    {
-      free_data_refs (datarefs);
-      free_affine_expand_cache (&name_expansions);
-      return 0;
-    }
+    return 0;
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
@@ -3235,34 +3379,25 @@  tree_predictive_commoning_loop (class loop *loop, bool allow_unroll_p)
     }
 
   /* Find the suitable components and split them into chains.  */
-  components = filter_suitable_components (loop, components);
+  components = filter_suitable_components (components);
 
   auto_bitmap tmp_vars;
-  looparound_phis = BITMAP_ALLOC (NULL);
-  determine_roots (loop, components, &chains);
+  determine_roots (components);
   release_components (components);
 
-  auto cleanup = [&]() {
-    release_chains (chains);
-    free_data_refs (datarefs);
-    BITMAP_FREE (looparound_phis);
-    free_affine_expand_cache (&name_expansions);
-  };
-
   if (!chains.exists ())
     {
       if (dump_file && (dump_flags & TDF_DETAILS))
 	fprintf (dump_file,
 		 "Predictive commoning failed: no suitable chains\n");
-      cleanup ();
       return 0;
     }
 
-  prepare_initializers (loop, chains);
-  loop_closed_ssa = prepare_finalizers (loop, chains);
+  prepare_initializers ();
+  loop_closed_ssa = prepare_finalizers ();
 
   /* Try to combine the chains that are always worked with together.  */
-  try_combine_chains (loop, &chains);
+  try_combine_chains ();
 
   insert_init_seqs (loop, chains);
 
@@ -3289,8 +3424,9 @@  tree_predictive_commoning_loop (class loop *loop, bool allow_unroll_p)
       if (dump_file && (dump_flags & TDF_DETAILS))
 	fprintf (dump_file, "Unrolling %u times.\n", unroll_factor);
 
-      dta.chains = chains;
       dta.tmp_vars = tmp_vars;
+      dta.chains = chains;
+      dta.worker = this;
 
       /* Cfg manipulations performed in tree_transform_and_unroll_loop before
 	 execute_pred_commoning_cbck is called may cause phi nodes to be
@@ -3310,11 +3446,9 @@  tree_predictive_commoning_loop (class loop *loop, bool allow_unroll_p)
       if (dump_file && (dump_flags & TDF_DETAILS))
 	fprintf (dump_file,
 		 "Executing predictive commoning without unrolling.\n");
-      execute_pred_commoning (loop, chains, tmp_vars);
+      execute_pred_commoning (tmp_vars);
     }
 
-  cleanup ();
-
   return (unroll ? 2 : 1) | (loop_closed_ssa ? 4 : 1);
 }
 
@@ -3330,7 +3464,8 @@  tree_predictive_commoning (bool allow_unroll_p)
   FOR_EACH_LOOP (loop, LI_ONLY_INNERMOST)
     if (optimize_loop_for_speed_p (loop))
       {
-	changed |= tree_predictive_commoning_loop (loop, allow_unroll_p);
+	pcom_worker w(loop);
+	changed |= w.tree_predictive_commoning_loop (allow_unroll_p);
       }
   free_original_copy_tables ();