diff mbox series

[1/6] rtl-ssa: Rework _ignoring interfaces

Message ID 20240620133418.350772-2-richard.sandiford@arm.com
State New
Headers show
Series Add a late-combine pass | expand

Commit Message

Richard Sandiford June 20, 2024, 1:34 p.m. UTC
rtl-ssa has routines for scanning forwards or backwards for something
under the control of an exclusion set.  These searches are currently
used for two main things:

- to work out where an instruction can be moved within its EBB
- to work out whether recog can add a new hard register clobber

The exclusion set was originally a callback function that returned
true for insns that should be ignored.  However, for the late-combine
work, I'd also like to be able to skip an entire definition, along
with all its uses.

This patch prepares for that by turning the exclusion set into an
object that provides predicate member functions.  Currently the
only two member functions are:

- should_ignore_insn: what the old callback did
- should_ignore_def: the new functionality

but more could be added later.

Doing this also makes it easy to remove some assymmetry that I think
in hindsight was a mistake: in forward scans, ignoring an insn meant
ignoring all definitions in that insn (ok) and all uses of those
definitions (non-obvious).  The new interface makes it possible
to select the required behaviour, with that behaviour being applied
consistently in both directions.

Now that the exclusion set is a dedicated object, rather than
just a "random" function, I think it makes sense to remove the
_ignoring suffix from the function names.  The suffix was originally
there to describe the callback, and in particular to emphasise that
a true return meant "ignore" rather than "heed".

gcc/
	* rtl-ssa.h: Include predicates.h.
	* rtl-ssa/predicates.h: New file.
	* rtl-ssa/access-utils.h (prev_call_clobbers_ignoring): Rename to...
	(prev_call_clobbers): ...this and treat the ignore parameter as an
	object with the same interface as ignore_nothing.
	(next_call_clobbers_ignoring): Rename to...
	(next_call_clobbers): ...this and treat the ignore parameter as an
	object with the same interface as ignore_nothing.
	(first_nondebug_insn_use_ignoring): Rename to...
	(first_nondebug_insn_use): ...this and treat the ignore parameter as
	an object with the same interface as ignore_nothing.
	(last_nondebug_insn_use_ignoring): Rename to...
	(last_nondebug_insn_use): ...this and treat the ignore parameter as
	an object with the same interface as ignore_nothing.
	(last_access_ignoring): Rename to...
	(last_access): ...this and treat the ignore parameter as an object
	with the same interface as ignore_nothing.  Conditionally skip
	definitions.
	(prev_access_ignoring): Rename to...
	(prev_access): ...this and treat the ignore parameter as an object
	with the same interface as ignore_nothing.
	(first_def_ignoring): Replace with...
	(first_access): ...this new function.
	(next_access_ignoring): Rename to...
	(next_access): ...this and treat the ignore parameter as an object
	with the same interface as ignore_nothing.  Conditionally skip
	definitions.
	* rtl-ssa/change-utils.h (insn_is_changing): Delete.
	(restrict_movement_ignoring): Rename to...
	(restrict_movement): ...this and treat the ignore parameter as an
	object with the same interface as ignore_nothing.
	(recog_ignoring): Rename to...
	(recog): ...this and treat the ignore parameter as an object with
	the same interface as ignore_nothing.
	* rtl-ssa/changes.h (insn_is_changing_closure): Delete.
	* rtl-ssa/functions.h (function_info::add_regno_clobber): Treat
	the ignore parameter as an object with the same interface as
	ignore_nothing.
	* rtl-ssa/insn-utils.h (insn_is): Delete.
	* rtl-ssa/insns.h (insn_is_closure): Delete.
	* rtl-ssa/member-fns.inl
	(insn_is_changing_closure::insn_is_changing_closure): Delete.
	(insn_is_changing_closure::operator()): Likewise.
	(function_info::add_regno_clobber): Treat the ignore parameter
	as an object with the same interface as ignore_nothing.
	(ignore_changing_insns::ignore_changing_insns): New function.
	(ignore_changing_insns::should_ignore_insn): Likewise.
	* rtl-ssa/movement.h (restrict_movement_for_dead_range): Treat
	the ignore parameter as an object with the same interface as
	ignore_nothing.
	(restrict_movement_for_defs_ignoring): Rename to...
	(restrict_movement_for_defs): ...this and treat the ignore parameter
	as an object with the same interface as ignore_nothing.
	(restrict_movement_for_uses_ignoring): Rename to...
	(restrict_movement_for_uses): ...this and treat the ignore parameter
	as an object with the same interface as ignore_nothing.  Conditionally
	skip definitions.
	* doc/rtl.texi: Update for above name changes.  Use
	ignore_changing_insns instead of insn_is_changing.
	* config/aarch64/aarch64-cc-fusion.cc (cc_fusion::parallelize_insns):
	Likewise.
	* pair-fusion.cc (no_ignore): Delete.
	(latest_hazard_before, first_hazard_after): Update for above name
	changes.  Use ignore_nothing instead of no_ignore.
	(pair_fusion_bb_info::fuse_pair): Update for above name changes.
	Use ignore_changing_insns instead of insn_is_changing.
	(pair_fusion::try_promote_writeback): Likewise.
---
 gcc/config/aarch64/aarch64-cc-fusion.cc |   4 +-
 gcc/doc/rtl.texi                        |  14 +--
 gcc/pair-fusion.cc                      |  34 +++---
 gcc/rtl-ssa.h                           |   1 +
 gcc/rtl-ssa/access-utils.h              | 145 +++++++++++++-----------
 gcc/rtl-ssa/change-utils.h              |  67 +++++------
 gcc/rtl-ssa/changes.h                   |  13 ---
 gcc/rtl-ssa/functions.h                 |  16 ++-
 gcc/rtl-ssa/insn-utils.h                |   8 --
 gcc/rtl-ssa/insns.h                     |  12 --
 gcc/rtl-ssa/member-fns.inl              |  35 +++---
 gcc/rtl-ssa/movement.h                  | 118 +++++++++----------
 gcc/rtl-ssa/predicates.h                |  58 ++++++++++
 13 files changed, 275 insertions(+), 250 deletions(-)
 create mode 100644 gcc/rtl-ssa/predicates.h

Comments

Alex Coplan June 20, 2024, 9:22 p.m. UTC | #1
Hi Richard,

I had a quick look through the patch and noticed a couple of minor typos.
Otherwise looks like a nice cleanup!

On 20/06/2024 14:34, Richard Sandiford wrote:
> rtl-ssa has routines for scanning forwards or backwards for something
> under the control of an exclusion set.  These searches are currently
> used for two main things:
> 
> - to work out where an instruction can be moved within its EBB
> - to work out whether recog can add a new hard register clobber
> 
> The exclusion set was originally a callback function that returned
> true for insns that should be ignored.  However, for the late-combine
> work, I'd also like to be able to skip an entire definition, along
> with all its uses.
> 
> This patch prepares for that by turning the exclusion set into an
> object that provides predicate member functions.  Currently the
> only two member functions are:
> 
> - should_ignore_insn: what the old callback did
> - should_ignore_def: the new functionality
> 
> but more could be added later.
> 
> Doing this also makes it easy to remove some assymmetry that I think

s/assymmetry/asymmetry/

> in hindsight was a mistake: in forward scans, ignoring an insn meant
> ignoring all definitions in that insn (ok) and all uses of those
> definitions (non-obvious).  The new interface makes it possible
> to select the required behaviour, with that behaviour being applied
> consistently in both directions.
> 
> Now that the exclusion set is a dedicated object, rather than
> just a "random" function, I think it makes sense to remove the
> _ignoring suffix from the function names.  The suffix was originally
> there to describe the callback, and in particular to emphasise that
> a true return meant "ignore" rather than "heed".
> 
> gcc/
> 	* rtl-ssa.h: Include predicates.h.
> 	* rtl-ssa/predicates.h: New file.
> 	* rtl-ssa/access-utils.h (prev_call_clobbers_ignoring): Rename to...
> 	(prev_call_clobbers): ...this and treat the ignore parameter as an
> 	object with the same interface as ignore_nothing.
> 	(next_call_clobbers_ignoring): Rename to...
> 	(next_call_clobbers): ...this and treat the ignore parameter as an
> 	object with the same interface as ignore_nothing.
> 	(first_nondebug_insn_use_ignoring): Rename to...
> 	(first_nondebug_insn_use): ...this and treat the ignore parameter as
> 	an object with the same interface as ignore_nothing.
> 	(last_nondebug_insn_use_ignoring): Rename to...
> 	(last_nondebug_insn_use): ...this and treat the ignore parameter as
> 	an object with the same interface as ignore_nothing.
> 	(last_access_ignoring): Rename to...
> 	(last_access): ...this and treat the ignore parameter as an object
> 	with the same interface as ignore_nothing.  Conditionally skip
> 	definitions.
> 	(prev_access_ignoring): Rename to...
> 	(prev_access): ...this and treat the ignore parameter as an object
> 	with the same interface as ignore_nothing.
> 	(first_def_ignoring): Replace with...
> 	(first_access): ...this new function.
> 	(next_access_ignoring): Rename to...
> 	(next_access): ...this and treat the ignore parameter as an object
> 	with the same interface as ignore_nothing.  Conditionally skip
> 	definitions.
> 	* rtl-ssa/change-utils.h (insn_is_changing): Delete.
> 	(restrict_movement_ignoring): Rename to...
> 	(restrict_movement): ...this and treat the ignore parameter as an
> 	object with the same interface as ignore_nothing.
> 	(recog_ignoring): Rename to...
> 	(recog): ...this and treat the ignore parameter as an object with
> 	the same interface as ignore_nothing.
> 	* rtl-ssa/changes.h (insn_is_changing_closure): Delete.
> 	* rtl-ssa/functions.h (function_info::add_regno_clobber): Treat
> 	the ignore parameter as an object with the same interface as
> 	ignore_nothing.
> 	* rtl-ssa/insn-utils.h (insn_is): Delete.
> 	* rtl-ssa/insns.h (insn_is_closure): Delete.
> 	* rtl-ssa/member-fns.inl
> 	(insn_is_changing_closure::insn_is_changing_closure): Delete.
> 	(insn_is_changing_closure::operator()): Likewise.
> 	(function_info::add_regno_clobber): Treat the ignore parameter
> 	as an object with the same interface as ignore_nothing.
> 	(ignore_changing_insns::ignore_changing_insns): New function.
> 	(ignore_changing_insns::should_ignore_insn): Likewise.
> 	* rtl-ssa/movement.h (restrict_movement_for_dead_range): Treat
> 	the ignore parameter as an object with the same interface as
> 	ignore_nothing.
> 	(restrict_movement_for_defs_ignoring): Rename to...
> 	(restrict_movement_for_defs): ...this and treat the ignore parameter
> 	as an object with the same interface as ignore_nothing.
> 	(restrict_movement_for_uses_ignoring): Rename to...
> 	(restrict_movement_for_uses): ...this and treat the ignore parameter
> 	as an object with the same interface as ignore_nothing.  Conditionally
> 	skip definitions.
> 	* doc/rtl.texi: Update for above name changes.  Use
> 	ignore_changing_insns instead of insn_is_changing.
> 	* config/aarch64/aarch64-cc-fusion.cc (cc_fusion::parallelize_insns):
> 	Likewise.
> 	* pair-fusion.cc (no_ignore): Delete.
> 	(latest_hazard_before, first_hazard_after): Update for above name
> 	changes.  Use ignore_nothing instead of no_ignore.
> 	(pair_fusion_bb_info::fuse_pair): Update for above name changes.
> 	Use ignore_changing_insns instead of insn_is_changing.
> 	(pair_fusion::try_promote_writeback): Likewise.
> ---
>  gcc/config/aarch64/aarch64-cc-fusion.cc |   4 +-
>  gcc/doc/rtl.texi                        |  14 +--
>  gcc/pair-fusion.cc                      |  34 +++---
>  gcc/rtl-ssa.h                           |   1 +
>  gcc/rtl-ssa/access-utils.h              | 145 +++++++++++++-----------
>  gcc/rtl-ssa/change-utils.h              |  67 +++++------
>  gcc/rtl-ssa/changes.h                   |  13 ---
>  gcc/rtl-ssa/functions.h                 |  16 ++-
>  gcc/rtl-ssa/insn-utils.h                |   8 --
>  gcc/rtl-ssa/insns.h                     |  12 --
>  gcc/rtl-ssa/member-fns.inl              |  35 +++---
>  gcc/rtl-ssa/movement.h                  | 118 +++++++++----------
>  gcc/rtl-ssa/predicates.h                |  58 ++++++++++
>  13 files changed, 275 insertions(+), 250 deletions(-)
>  create mode 100644 gcc/rtl-ssa/predicates.h
> 
<snip>
> diff --git a/gcc/rtl-ssa/functions.h b/gcc/rtl-ssa/functions.h
> index f5aca643beb..479c6992e97 100644
> --- a/gcc/rtl-ssa/functions.h
> +++ b/gcc/rtl-ssa/functions.h
> @@ -165,16 +165,22 @@ public:
>  
>    // If CHANGE doesn't already clobber REGNO, try to add such a clobber,
>    // limiting the movement range in order to make the clobber valid.
> -  // When determining whether REGNO is live, ignore accesses made by an
> -  // instruction I if IGNORE (I) is true.  The caller then assumes the
> -  // responsibility of ensuring that CHANGE and I are placed in a valid order.
> +  // Use IGNORE to guide this process, where IGNORE is an object that
> +  // provides the same interface as ignore_nothing.
> +  //
> +  // That is, when determining whether REGNO is live, ignore accesses made
> +  // by an instruction I if IGNORE says that I should be ignored.  The caller
> +  // then assumes the responsibility of ensuring that CHANGE and I are placed
> +  // in a valid order.  Similarly, ignore live ranges associated/ with a

Stray '/' after associated?

Thanks,
Alex

> +  // definition of REGNO if IGNORE says that that definition should be
> +  // ignored.
>    //
>    // Return true on success.  Leave CHANGE unmodified when returning false.
>    //
>    // WATERMARK is a watermark returned by new_change_attempt ().
> -  template<typename IgnorePredicate>
> +  template<typename IgnorePredicates>
>    bool add_regno_clobber (obstack_watermark &watermark, insn_change &change,
> -			  unsigned int regno, IgnorePredicate ignore);
> +			  unsigned int regno, IgnorePredicates ignore);
>  
>    // Return true if change_insns will be able to perform the changes
>    // described by CHANGES.
<snip>
Richard Sandiford June 21, 2024, 8:11 a.m. UTC | #2
Alex Coplan <alex.coplan@arm.com> writes:
> Hi Richard,
>
> I had a quick look through the patch and noticed a couple of minor typos.
> Otherwise looks like a nice cleanup!

Thanks for the review!  I've fixed the typos in my local copy.

Richard

> On 20/06/2024 14:34, Richard Sandiford wrote:
>> rtl-ssa has routines for scanning forwards or backwards for something
>> under the control of an exclusion set.  These searches are currently
>> used for two main things:
>> 
>> - to work out where an instruction can be moved within its EBB
>> - to work out whether recog can add a new hard register clobber
>> 
>> The exclusion set was originally a callback function that returned
>> true for insns that should be ignored.  However, for the late-combine
>> work, I'd also like to be able to skip an entire definition, along
>> with all its uses.
>> 
>> This patch prepares for that by turning the exclusion set into an
>> object that provides predicate member functions.  Currently the
>> only two member functions are:
>> 
>> - should_ignore_insn: what the old callback did
>> - should_ignore_def: the new functionality
>> 
>> but more could be added later.
>> 
>> Doing this also makes it easy to remove some assymmetry that I think
>
> s/assymmetry/asymmetry/
>
>> in hindsight was a mistake: in forward scans, ignoring an insn meant
>> ignoring all definitions in that insn (ok) and all uses of those
>> definitions (non-obvious).  The new interface makes it possible
>> to select the required behaviour, with that behaviour being applied
>> consistently in both directions.
>> 
>> Now that the exclusion set is a dedicated object, rather than
>> just a "random" function, I think it makes sense to remove the
>> _ignoring suffix from the function names.  The suffix was originally
>> there to describe the callback, and in particular to emphasise that
>> a true return meant "ignore" rather than "heed".
>> 
>> gcc/
>> 	* rtl-ssa.h: Include predicates.h.
>> 	* rtl-ssa/predicates.h: New file.
>> 	* rtl-ssa/access-utils.h (prev_call_clobbers_ignoring): Rename to...
>> 	(prev_call_clobbers): ...this and treat the ignore parameter as an
>> 	object with the same interface as ignore_nothing.
>> 	(next_call_clobbers_ignoring): Rename to...
>> 	(next_call_clobbers): ...this and treat the ignore parameter as an
>> 	object with the same interface as ignore_nothing.
>> 	(first_nondebug_insn_use_ignoring): Rename to...
>> 	(first_nondebug_insn_use): ...this and treat the ignore parameter as
>> 	an object with the same interface as ignore_nothing.
>> 	(last_nondebug_insn_use_ignoring): Rename to...
>> 	(last_nondebug_insn_use): ...this and treat the ignore parameter as
>> 	an object with the same interface as ignore_nothing.
>> 	(last_access_ignoring): Rename to...
>> 	(last_access): ...this and treat the ignore parameter as an object
>> 	with the same interface as ignore_nothing.  Conditionally skip
>> 	definitions.
>> 	(prev_access_ignoring): Rename to...
>> 	(prev_access): ...this and treat the ignore parameter as an object
>> 	with the same interface as ignore_nothing.
>> 	(first_def_ignoring): Replace with...
>> 	(first_access): ...this new function.
>> 	(next_access_ignoring): Rename to...
>> 	(next_access): ...this and treat the ignore parameter as an object
>> 	with the same interface as ignore_nothing.  Conditionally skip
>> 	definitions.
>> 	* rtl-ssa/change-utils.h (insn_is_changing): Delete.
>> 	(restrict_movement_ignoring): Rename to...
>> 	(restrict_movement): ...this and treat the ignore parameter as an
>> 	object with the same interface as ignore_nothing.
>> 	(recog_ignoring): Rename to...
>> 	(recog): ...this and treat the ignore parameter as an object with
>> 	the same interface as ignore_nothing.
>> 	* rtl-ssa/changes.h (insn_is_changing_closure): Delete.
>> 	* rtl-ssa/functions.h (function_info::add_regno_clobber): Treat
>> 	the ignore parameter as an object with the same interface as
>> 	ignore_nothing.
>> 	* rtl-ssa/insn-utils.h (insn_is): Delete.
>> 	* rtl-ssa/insns.h (insn_is_closure): Delete.
>> 	* rtl-ssa/member-fns.inl
>> 	(insn_is_changing_closure::insn_is_changing_closure): Delete.
>> 	(insn_is_changing_closure::operator()): Likewise.
>> 	(function_info::add_regno_clobber): Treat the ignore parameter
>> 	as an object with the same interface as ignore_nothing.
>> 	(ignore_changing_insns::ignore_changing_insns): New function.
>> 	(ignore_changing_insns::should_ignore_insn): Likewise.
>> 	* rtl-ssa/movement.h (restrict_movement_for_dead_range): Treat
>> 	the ignore parameter as an object with the same interface as
>> 	ignore_nothing.
>> 	(restrict_movement_for_defs_ignoring): Rename to...
>> 	(restrict_movement_for_defs): ...this and treat the ignore parameter
>> 	as an object with the same interface as ignore_nothing.
>> 	(restrict_movement_for_uses_ignoring): Rename to...
>> 	(restrict_movement_for_uses): ...this and treat the ignore parameter
>> 	as an object with the same interface as ignore_nothing.  Conditionally
>> 	skip definitions.
>> 	* doc/rtl.texi: Update for above name changes.  Use
>> 	ignore_changing_insns instead of insn_is_changing.
>> 	* config/aarch64/aarch64-cc-fusion.cc (cc_fusion::parallelize_insns):
>> 	Likewise.
>> 	* pair-fusion.cc (no_ignore): Delete.
>> 	(latest_hazard_before, first_hazard_after): Update for above name
>> 	changes.  Use ignore_nothing instead of no_ignore.
>> 	(pair_fusion_bb_info::fuse_pair): Update for above name changes.
>> 	Use ignore_changing_insns instead of insn_is_changing.
>> 	(pair_fusion::try_promote_writeback): Likewise.
>> ---
>>  gcc/config/aarch64/aarch64-cc-fusion.cc |   4 +-
>>  gcc/doc/rtl.texi                        |  14 +--
>>  gcc/pair-fusion.cc                      |  34 +++---
>>  gcc/rtl-ssa.h                           |   1 +
>>  gcc/rtl-ssa/access-utils.h              | 145 +++++++++++++-----------
>>  gcc/rtl-ssa/change-utils.h              |  67 +++++------
>>  gcc/rtl-ssa/changes.h                   |  13 ---
>>  gcc/rtl-ssa/functions.h                 |  16 ++-
>>  gcc/rtl-ssa/insn-utils.h                |   8 --
>>  gcc/rtl-ssa/insns.h                     |  12 --
>>  gcc/rtl-ssa/member-fns.inl              |  35 +++---
>>  gcc/rtl-ssa/movement.h                  | 118 +++++++++----------
>>  gcc/rtl-ssa/predicates.h                |  58 ++++++++++
>>  13 files changed, 275 insertions(+), 250 deletions(-)
>>  create mode 100644 gcc/rtl-ssa/predicates.h
>> 
> <snip>
>> diff --git a/gcc/rtl-ssa/functions.h b/gcc/rtl-ssa/functions.h
>> index f5aca643beb..479c6992e97 100644
>> --- a/gcc/rtl-ssa/functions.h
>> +++ b/gcc/rtl-ssa/functions.h
>> @@ -165,16 +165,22 @@ public:
>>  
>>    // If CHANGE doesn't already clobber REGNO, try to add such a clobber,
>>    // limiting the movement range in order to make the clobber valid.
>> -  // When determining whether REGNO is live, ignore accesses made by an
>> -  // instruction I if IGNORE (I) is true.  The caller then assumes the
>> -  // responsibility of ensuring that CHANGE and I are placed in a valid order.
>> +  // Use IGNORE to guide this process, where IGNORE is an object that
>> +  // provides the same interface as ignore_nothing.
>> +  //
>> +  // That is, when determining whether REGNO is live, ignore accesses made
>> +  // by an instruction I if IGNORE says that I should be ignored.  The caller
>> +  // then assumes the responsibility of ensuring that CHANGE and I are placed
>> +  // in a valid order.  Similarly, ignore live ranges associated/ with a
>
> Stray '/' after associated?
>
> Thanks,
> Alex
>
>> +  // definition of REGNO if IGNORE says that that definition should be
>> +  // ignored.
>>    //
>>    // Return true on success.  Leave CHANGE unmodified when returning false.
>>    //
>>    // WATERMARK is a watermark returned by new_change_attempt ().
>> -  template<typename IgnorePredicate>
>> +  template<typename IgnorePredicates>
>>    bool add_regno_clobber (obstack_watermark &watermark, insn_change &change,
>> -			  unsigned int regno, IgnorePredicate ignore);
>> +			  unsigned int regno, IgnorePredicates ignore);
>>  
>>    // Return true if change_insns will be able to perform the changes
>>    // described by CHANGES.
> <snip>
Jeff Law June 21, 2024, 2:40 p.m. UTC | #3
On 6/20/24 7:34 AM, Richard Sandiford wrote:
> rtl-ssa has routines for scanning forwards or backwards for something
> under the control of an exclusion set.  These searches are currently
> used for two main things:
> 
> - to work out where an instruction can be moved within its EBB
> - to work out whether recog can add a new hard register clobber
> 
> The exclusion set was originally a callback function that returned
> true for insns that should be ignored.  However, for the late-combine
> work, I'd also like to be able to skip an entire definition, along
> with all its uses.
> 
> This patch prepares for that by turning the exclusion set into an
> object that provides predicate member functions.  Currently the
> only two member functions are:
> 
> - should_ignore_insn: what the old callback did
> - should_ignore_def: the new functionality
> 
> but more could be added later.
> 
> Doing this also makes it easy to remove some assymmetry that I think
> in hindsight was a mistake: in forward scans, ignoring an insn meant
> ignoring all definitions in that insn (ok) and all uses of those
> definitions (non-obvious).  The new interface makes it possible
> to select the required behaviour, with that behaviour being applied
> consistently in both directions.
> 
> Now that the exclusion set is a dedicated object, rather than
> just a "random" function, I think it makes sense to remove the
> _ignoring suffix from the function names.  The suffix was originally
> there to describe the callback, and in particular to emphasise that
> a true return meant "ignore" rather than "heed".
> 
> gcc/
> 	* rtl-ssa.h: Include predicates.h.
> 	* rtl-ssa/predicates.h: New file.
> 	* rtl-ssa/access-utils.h (prev_call_clobbers_ignoring): Rename to...
> 	(prev_call_clobbers): ...this and treat the ignore parameter as an
> 	object with the same interface as ignore_nothing.
> 	(next_call_clobbers_ignoring): Rename to...
> 	(next_call_clobbers): ...this and treat the ignore parameter as an
> 	object with the same interface as ignore_nothing.
> 	(first_nondebug_insn_use_ignoring): Rename to...
> 	(first_nondebug_insn_use): ...this and treat the ignore parameter as
> 	an object with the same interface as ignore_nothing.
> 	(last_nondebug_insn_use_ignoring): Rename to...
> 	(last_nondebug_insn_use): ...this and treat the ignore parameter as
> 	an object with the same interface as ignore_nothing.
> 	(last_access_ignoring): Rename to...
> 	(last_access): ...this and treat the ignore parameter as an object
> 	with the same interface as ignore_nothing.  Conditionally skip
> 	definitions.
> 	(prev_access_ignoring): Rename to...
> 	(prev_access): ...this and treat the ignore parameter as an object
> 	with the same interface as ignore_nothing.
> 	(first_def_ignoring): Replace with...
> 	(first_access): ...this new function.
> 	(next_access_ignoring): Rename to...
> 	(next_access): ...this and treat the ignore parameter as an object
> 	with the same interface as ignore_nothing.  Conditionally skip
> 	definitions.
> 	* rtl-ssa/change-utils.h (insn_is_changing): Delete.
> 	(restrict_movement_ignoring): Rename to...
> 	(restrict_movement): ...this and treat the ignore parameter as an
> 	object with the same interface as ignore_nothing.
> 	(recog_ignoring): Rename to...
> 	(recog): ...this and treat the ignore parameter as an object with
> 	the same interface as ignore_nothing.
> 	* rtl-ssa/changes.h (insn_is_changing_closure): Delete.
> 	* rtl-ssa/functions.h (function_info::add_regno_clobber): Treat
> 	the ignore parameter as an object with the same interface as
> 	ignore_nothing.
> 	* rtl-ssa/insn-utils.h (insn_is): Delete.
> 	* rtl-ssa/insns.h (insn_is_closure): Delete.
> 	* rtl-ssa/member-fns.inl
> 	(insn_is_changing_closure::insn_is_changing_closure): Delete.
> 	(insn_is_changing_closure::operator()): Likewise.
> 	(function_info::add_regno_clobber): Treat the ignore parameter
> 	as an object with the same interface as ignore_nothing.
> 	(ignore_changing_insns::ignore_changing_insns): New function.
> 	(ignore_changing_insns::should_ignore_insn): Likewise.
> 	* rtl-ssa/movement.h (restrict_movement_for_dead_range): Treat
> 	the ignore parameter as an object with the same interface as
> 	ignore_nothing.
> 	(restrict_movement_for_defs_ignoring): Rename to...
> 	(restrict_movement_for_defs): ...this and treat the ignore parameter
> 	as an object with the same interface as ignore_nothing.
> 	(restrict_movement_for_uses_ignoring): Rename to...
> 	(restrict_movement_for_uses): ...this and treat the ignore parameter
> 	as an object with the same interface as ignore_nothing.  Conditionally
> 	skip definitions.
> 	* doc/rtl.texi: Update for above name changes.  Use
> 	ignore_changing_insns instead of insn_is_changing.
> 	* config/aarch64/aarch64-cc-fusion.cc (cc_fusion::parallelize_insns):
> 	Likewise.
> 	* pair-fusion.cc (no_ignore): Delete.
> 	(latest_hazard_before, first_hazard_after): Update for above name
> 	changes.  Use ignore_nothing instead of no_ignore.
> 	(pair_fusion_bb_info::fuse_pair): Update for above name changes.
> 	Use ignore_changing_insns instead of insn_is_changing.
> 	(pair_fusion::try_promote_writeback): Likewise.
> ---

OK.

jeff
diff mbox series

Patch

diff --git a/gcc/config/aarch64/aarch64-cc-fusion.cc b/gcc/config/aarch64/aarch64-cc-fusion.cc
index a4f43295680..e97c26682d0 100644
--- a/gcc/config/aarch64/aarch64-cc-fusion.cc
+++ b/gcc/config/aarch64/aarch64-cc-fusion.cc
@@ -183,7 +183,7 @@  cc_fusion::parallelize_insns (def_info *cc_def, rtx cc_set,
   auto other_change = insn_change::delete_insn (other_insn);
   insn_change *changes[] = { &other_change, &cc_change };
   cc_change.move_range = cc_insn->ebb ()->insn_range ();
-  if (!restrict_movement_ignoring (cc_change, insn_is_changing (changes)))
+  if (!restrict_movement (cc_change, ignore_changing_insns (changes)))
     {
       if (dump_file && (dump_flags & TDF_DETAILS))
 	fprintf (dump_file, "-- cannot satisfy all definitions and uses\n");
@@ -205,7 +205,7 @@  cc_fusion::parallelize_insns (def_info *cc_def, rtx cc_set,
   validate_change (cc_rtl, &PATTERN (cc_rtl), m_parallel, 1);
 
   // These routines report failures themselves.
-  if (!recog_ignoring (attempt, cc_change, insn_is_changing (changes))
+  if (!recog (attempt, cc_change, ignore_changing_insns (changes))
       || !changes_are_worthwhile (changes)
       || !crtl->ssa->verify_insn_changes (changes))
     return false;
diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi
index aa10b5235b5..846a043bdc7 100644
--- a/gcc/doc/rtl.texi
+++ b/gcc/doc/rtl.texi
@@ -5073,7 +5073,7 @@  in the correct order with respect to each other.
 The way to do this is:
 
 @smallexample
-if (!rtl_ssa::restrict_movement_ignoring (change, insn_is_changing (changes)))
+if (!rtl_ssa::restrict_movement (change, ignore_changing_insns (changes)))
   return false;
 @end smallexample
 
@@ -5085,7 +5085,7 @@  changing instructions (which might, for example, no longer need
 to clobber the flags register).  The way to do this is:
 
 @smallexample
-if (!rtl_ssa::recog_ignoring (attempt, change, insn_is_changing (changes)))
+if (!rtl_ssa::recog (attempt, change, ignore_changing_insns (changes)))
   return false;
 @end smallexample
 
@@ -5137,16 +5137,16 @@  change2.move_range = @dots{};
 
 rtl_ssa::insn_change *changes[] = @{ &change1, &change2 @};
 
-auto is_changing = insn_is_changing (changes);
-if (!rtl_ssa::restrict_movement_ignoring (change1, is_changing)
-    || !rtl_ssa::restrict_movement_ignoring (change2, is_changing))
+auto ignore = ignore_changing_insns (changes);
+if (!rtl_ssa::restrict_movement (change1, ignore)
+    || !rtl_ssa::restrict_movement (change2, ignore))
   return false;
 
 insn_change_watermark watermark;
 // Use validate_change etc. to change INSN1's and INSN2's patterns.
 @dots{}
-if (!rtl_ssa::recog_ignoring (attempt, change1, is_changing)
-    || !rtl_ssa::recog_ignoring (attempt, change2, is_changing)
+if (!rtl_ssa::recog (attempt, change1, ignore)
+    || !rtl_ssa::recog (attempt, change2, ignore)
     || !rtl_ssa::changes_are_worthwhile (changes)
     || !crtl->ssa->verify_insn_changes (changes))
   return false;
diff --git a/gcc/pair-fusion.cc b/gcc/pair-fusion.cc
index 26b2284ed37..31d2c21c88f 100644
--- a/gcc/pair-fusion.cc
+++ b/gcc/pair-fusion.cc
@@ -563,9 +563,6 @@  pair_fusion_bb_info::track_access (insn_info *insn, bool load_p, rtx mem)
     }
 }
 
-// Dummy predicate that never ignores any insns.
-static bool no_ignore (insn_info *) { return false; }
-
 // Return the latest dataflow hazard before INSN.
 //
 // If IGNORE is non-NULL, this points to a sub-rtx which we should ignore for
@@ -643,9 +640,8 @@  latest_hazard_before (insn_info *insn, rtx *ignore,
 	  if (!call_group->clobbers (def->resource ()))
 	    continue;
 
-	  auto clobber_insn = prev_call_clobbers_ignoring (*call_group,
-							   def->insn (),
-							   no_ignore);
+	  auto clobber_insn = prev_call_clobbers (*call_group, def->insn (),
+						  ignore_nothing ());
 	  if (clobber_insn)
 	    hazard (clobber_insn);
 	}
@@ -704,9 +700,8 @@  first_hazard_after (insn_info *insn, rtx *ignore)
 	  if (!call_group->clobbers (def->resource ()))
 	    continue;
 
-	  auto clobber_insn = next_call_clobbers_ignoring (*call_group,
-							   def->insn (),
-							   no_ignore);
+	  auto clobber_insn = next_call_clobbers (*call_group, def->insn (),
+						  ignore_nothing ());
 	  if (clobber_insn)
 	    hazard (clobber_insn);
 	}
@@ -733,16 +728,15 @@  first_hazard_after (insn_info *insn, rtx *ignore)
 
       // Also need to handle call clobbers of our uses (again WaR).
       //
-      // See restrict_movement_for_uses_ignoring for why we don't
-      // need to check backwards for call clobbers.
+      // See restrict_movement_for_uses for why we don't need to check
+      // backwards for call clobbers.
       for (auto call_group : use->ebb ()->call_clobbers ())
 	{
 	  if (!call_group->clobbers (use->resource ()))
 	    continue;
 
-	  auto clobber_insn = next_call_clobbers_ignoring (*call_group,
-							   use->insn (),
-							   no_ignore);
+	  auto clobber_insn = next_call_clobbers (*call_group, use->insn (),
+						  ignore_nothing ());
 	  if (clobber_insn)
 	    hazard (clobber_insn);
 	}
@@ -1965,12 +1959,12 @@  pair_fusion_bb_info::fuse_pair (bool load_p,
 	}
     }
 
-  auto is_changing = insn_is_changing (changes);
+  auto ignore = ignore_changing_insns (changes);
   for (unsigned i = 0; i < changes.length (); i++)
-    gcc_assert (rtl_ssa::restrict_movement_ignoring (*changes[i], is_changing));
+    gcc_assert (rtl_ssa::restrict_movement (*changes[i], ignore));
 
   // Check the pair pattern is recog'd.
-  if (!rtl_ssa::recog_ignoring (attempt, *pair_change, is_changing))
+  if (!rtl_ssa::recog (attempt, *pair_change, ignore))
     {
       if (dump_file)
 	fprintf (dump_file, "  failed to form pair, recog failed\n");
@@ -2953,11 +2947,11 @@  pair_fusion::try_promote_writeback (insn_info *insn, bool load_p)
 					pair_change.new_defs);
   gcc_assert (pair_change.new_defs.is_valid ());
 
-  auto is_changing = insn_is_changing (changes);
+  auto ignore = ignore_changing_insns (changes);
   for (unsigned i = 0; i < ARRAY_SIZE (changes); i++)
-    gcc_assert (rtl_ssa::restrict_movement_ignoring (*changes[i], is_changing));
+    gcc_assert (rtl_ssa::restrict_movement (*changes[i], ignore));
 
-  if (!rtl_ssa::recog_ignoring (attempt, pair_change, is_changing))
+  if (!rtl_ssa::recog (attempt, pair_change, ignore))
     {
       if (dump_file)
 	fprintf (dump_file, "i%d: recog failed on wb pair, bailing out\n",
diff --git a/gcc/rtl-ssa.h b/gcc/rtl-ssa.h
index 17337639ae8..2718d97b6d9 100644
--- a/gcc/rtl-ssa.h
+++ b/gcc/rtl-ssa.h
@@ -63,6 +63,7 @@ 
 #include "rtl-ssa/blocks.h"
 #include "rtl-ssa/changes.h"
 #include "rtl-ssa/functions.h"
+#include "rtl-ssa/predicates.h"
 #include "rtl-ssa/is-a.inl"
 #include "rtl-ssa/access-utils.h"
 #include "rtl-ssa/insn-utils.h"
diff --git a/gcc/rtl-ssa/access-utils.h b/gcc/rtl-ssa/access-utils.h
index f889300666d..8805eec1d7f 100644
--- a/gcc/rtl-ssa/access-utils.h
+++ b/gcc/rtl-ssa/access-utils.h
@@ -321,19 +321,22 @@  int lookup_def (def_splay_tree &, insn_info *);
 int lookup_clobber (clobber_tree &, insn_info *);
 int lookup_call_clobbers (insn_call_clobbers_tree &, insn_info *);
 
-// Search backwards from immediately before INSN for the first instruction
-// recorded in TREE, ignoring any instruction I for which IGNORE (I) is true.
-// Return null if no such instruction exists.
-template<typename IgnorePredicate>
+// Search backwards from immediately before INSN for the first "relevant"
+// instruction recorded in TREE.  IGNORE is an object that provides the same
+// interface as ignore_nothing; it defines which insns are "relevant"
+// and which should be ignored.
+//
+// Return null if no such relevant instruction exists.
+template<typename IgnorePredicates>
 insn_info *
-prev_call_clobbers_ignoring (insn_call_clobbers_tree &tree, insn_info *insn,
-			     IgnorePredicate ignore)
+prev_call_clobbers (insn_call_clobbers_tree &tree, insn_info *insn,
+		    IgnorePredicates ignore)
 {
   if (!tree)
     return nullptr;
 
   int comparison = lookup_call_clobbers (tree, insn);
-  while (comparison <= 0 || ignore (tree->insn ()))
+  while (comparison <= 0 || ignore.should_ignore_insn (tree->insn ()))
     {
       if (!tree.splay_prev_node ())
 	return nullptr;
@@ -343,19 +346,22 @@  prev_call_clobbers_ignoring (insn_call_clobbers_tree &tree, insn_info *insn,
   return tree->insn ();
 }
 
-// Search forwards from immediately after INSN for the first instruction
-// recorded in TREE, ignoring any instruction I for which IGNORE (I) is true.
-// Return null if no such instruction exists.
-template<typename IgnorePredicate>
+// Search forwards from immediately after INSN for the first "relevant"
+// instruction recorded in TREE.  IGNORE is an object that provides the
+// same interface as ignore_nothing; it defines which insns are "relevant"
+// and which should be ignored.
+//
+// Return null if no such relevant instruction exists.
+template<typename IgnorePredicates>
 insn_info *
-next_call_clobbers_ignoring (insn_call_clobbers_tree &tree, insn_info *insn,
-			     IgnorePredicate ignore)
+next_call_clobbers (insn_call_clobbers_tree &tree, insn_info *insn,
+		    IgnorePredicates ignore)
 {
   if (!tree)
     return nullptr;
 
   int comparison = lookup_call_clobbers (tree, insn);
-  while (comparison >= 0 || ignore (tree->insn ()))
+  while (comparison >= 0 || ignore.should_ignore_insn (tree->insn ()))
     {
       if (!tree.splay_next_node ())
 	return nullptr;
@@ -370,17 +376,18 @@  next_call_clobbers_ignoring (insn_call_clobbers_tree &tree, insn_info *insn,
 inline insn_info *
 next_call_clobbers (insn_call_clobbers_tree &tree, insn_info *insn)
 {
-  auto ignore = [](const insn_info *) { return false; };
-  return next_call_clobbers_ignoring (tree, insn, ignore);
+  return next_call_clobbers (tree, insn, ignore_nothing ());
 }
 
-// If ACCESS is a set, return the first use of ACCESS by a nondebug insn I
-// for which IGNORE (I) is false.  Return null if ACCESS is not a set or if
-// no such use exists.
-template<typename IgnorePredicate>
+// If ACCESS is a set, return the first "relevant" use of ACCESS by a
+// nondebug insn.  IGNORE is an object that provides the same interface
+// as ignore_nothing; it defines which accesses and insns are "relevant"
+// and which should be ignored.
+//
+// Return null if ACCESS is not a set or if no such relevant use exists.
+template<typename IgnorePredicates>
 inline use_info *
-first_nondebug_insn_use_ignoring (const access_info *access,
-				  IgnorePredicate ignore)
+first_nondebug_insn_use (const access_info *access, IgnorePredicates ignore)
 {
   if (const set_info *set = set_with_nondebug_insn_uses (access))
     {
@@ -389,7 +396,7 @@  first_nondebug_insn_use_ignoring (const access_info *access,
       use_info *use = set->first_use ();
       do
 	{
-	  if (!ignore (use->insn ()))
+	  if (!ignore.should_ignore_insn (use->insn ()))
 	    return use;
 	  use = use->next_nondebug_insn_use ();
 	}
@@ -398,13 +405,15 @@  first_nondebug_insn_use_ignoring (const access_info *access,
   return nullptr;
 }
 
-// If ACCESS is a set, return the last use of ACCESS by a nondebug insn I for
-// which IGNORE (I) is false.  Return null if ACCESS is not a set or if no
-// such use exists.
-template<typename IgnorePredicate>
+// If ACCESS is a set, return the last "relevant" use of ACCESS by a
+// nondebug insn.  IGNORE is an object that provides the same interface
+// as ignore_nothing; it defines which accesses and insns are "relevant"
+// and which should be ignored.
+//
+// Return null if ACCESS is not a set or if no such relevant use exists.
+template<typename IgnorePredicates>
 inline use_info *
-last_nondebug_insn_use_ignoring (const access_info *access,
-				 IgnorePredicate ignore)
+last_nondebug_insn_use (const access_info *access, IgnorePredicates ignore)
 {
   if (const set_info *set = set_with_nondebug_insn_uses (access))
     {
@@ -413,7 +422,7 @@  last_nondebug_insn_use_ignoring (const access_info *access,
       use_info *use = set->last_nondebug_insn_use ();
       do
 	{
-	  if (!ignore (use->insn ()))
+	  if (!ignore.should_ignore_insn (use->insn ()))
 	    return use;
 	  use = use->prev_use ();
 	}
@@ -427,7 +436,8 @@  last_nondebug_insn_use_ignoring (const access_info *access,
 // Otherwise, search backwards for an access to DEF->resource (), starting at
 // the end of DEF's live range.  Ignore clobbers if IGNORE_CLOBBERS_SETTING
 // is YES, otherwise treat them like any other access.  Also ignore any
-// access A for which IGNORE (access_insn (A)) is true.
+// accesses and insns that IGNORE says should be ignored, where IGNORE
+// is an object that provides the same interface as ignore_nothing.
 //
 // Thus if DEF is a set that is used by nondebug insns, the first access
 // that the function considers is the last such use of the set.  Otherwise,
@@ -438,23 +448,21 @@  last_nondebug_insn_use_ignoring (const access_info *access,
 //
 // Note that this function does not consider separately-recorded call clobbers,
 // although such clobbers are only relevant if IGNORE_CLOBBERS_SETTING is NO.
-template<typename IgnorePredicate>
+template<typename IgnorePredicates>
 access_info *
-last_access_ignoring (def_info *def, ignore_clobbers ignore_clobbers_setting,
-		      IgnorePredicate ignore)
+last_access (def_info *def, ignore_clobbers ignore_clobbers_setting,
+	     IgnorePredicates ignore)
 {
   while (def)
     {
       auto *clobber = dyn_cast<clobber_info *> (def);
       if (clobber && ignore_clobbers_setting == ignore_clobbers::YES)
 	def = first_clobber_in_group (clobber);
-      else
+      else if (!ignore.should_ignore_def (def))
 	{
-	  if (use_info *use = last_nondebug_insn_use_ignoring (def, ignore))
+	  if (use_info *use = last_nondebug_insn_use (def, ignore))
 	    return use;
-
-	  insn_info *insn = def->insn ();
-	  if (!ignore (insn))
+	  if (!ignore.should_ignore_insn (def->insn ()))
 	    return def;
 	}
       def = def->prev_def ();
@@ -465,8 +473,9 @@  last_access_ignoring (def_info *def, ignore_clobbers ignore_clobbers_setting,
 // Search backwards for an access to DEF->resource (), starting
 // immediately before the point at which DEF occurs.  Ignore clobbers
 // if IGNORE_CLOBBERS_SETTING is YES, otherwise treat them like any other
-// access.  Also ignore any access A for which IGNORE (access_insn (A))
-// is true.
+// access.  Also ignore any accesses and insns that IGNORE says should be
+// ignored, where IGNORE is an object that provides the same interface as
+// ignore_nothing.
 //
 // Thus if DEF->insn () uses DEF->resource (), that use is the first access
 // that the function considers, since an instruction's uses occur strictly
@@ -474,40 +483,44 @@  last_access_ignoring (def_info *def, ignore_clobbers ignore_clobbers_setting,
 //
 // Note that this function does not consider separately-recorded call clobbers,
 // although such clobbers are only relevant if IGNORE_CLOBBERS_SETTING is NO.
-template<typename IgnorePredicate>
+template<typename IgnorePredicates>
 inline access_info *
-prev_access_ignoring (def_info *def, ignore_clobbers ignore_clobbers_setting,
-		      IgnorePredicate ignore)
+prev_access (def_info *def, ignore_clobbers ignore_clobbers_setting,
+	     IgnorePredicates ignore)
 {
-  return last_access_ignoring (def->prev_def (), ignore_clobbers_setting,
-			       ignore);
+  return last_access (def->prev_def (), ignore_clobbers_setting, ignore);
 }
 
 // If DEF is null, return null.
 //
-// Otherwise, search forwards for a definition of DEF->resource (),
+// Otherwise, search forwards for an access to DEF->resource (),
 // starting at DEF itself.  Ignore clobbers if IGNORE_CLOBBERS_SETTING
 // is YES, otherwise treat them like any other access.  Also ignore any
-// definition D for which IGNORE (D->insn ()) is true.
+// accesses and insns that IGNORE says should be ignored, where IGNORE
+// is an object that provides the same interface as ignore_nothing.
 //
 // Return the definition found, or null if there is no access that meets
 // the criteria.
 //
 // Note that this function does not consider separately-recorded call clobbers,
 // although such clobbers are only relevant if IGNORE_CLOBBERS_SETTING is NO.
-template<typename IgnorePredicate>
-def_info *
-first_def_ignoring (def_info *def, ignore_clobbers ignore_clobbers_setting,
-		    IgnorePredicate ignore)
+template<typename IgnorePredicates>
+access_info *
+first_access (def_info *def, ignore_clobbers ignore_clobbers_setting,
+	      IgnorePredicates ignore)
 {
   while (def)
     {
       auto *clobber = dyn_cast<clobber_info *> (def);
       if (clobber && ignore_clobbers_setting == ignore_clobbers::YES)
 	def = last_clobber_in_group (clobber);
-      else if (!ignore (def->insn ()))
-	return def;
-
+      else if (!ignore.should_ignore_def (def))
+	{
+	  if (!ignore.should_ignore_insn (def->insn ()))
+	    return def;
+	  if (use_info *use = first_nondebug_insn_use (def, ignore))
+	    return use;
+	}
       def = def->next_def ();
     }
   return nullptr;
@@ -516,27 +529,29 @@  first_def_ignoring (def_info *def, ignore_clobbers ignore_clobbers_setting,
 // Search forwards for the next access to DEF->resource (),
 // starting immediately after DEF's instruction.  Ignore clobbers if
 // IGNORE_CLOBBERS_SETTING is YES, otherwise treat them like any other access.
-// Also ignore any access A for which IGNORE (access_insn (A)) is true;
-// in this context, ignoring a set includes ignoring all uses of the set.
+// Also ignore any accesses and insns that IGNORE says should be ignored,
+// where IGNORE is an object that provides the same interface as
+// ignore_nothing.
 //
 // Thus if DEF is a set with uses by nondebug insns, the first access that the
-// function considers is the first such use of the set.
+// function considers is the first such use of the set.  Otherwise, the first
+// access that the function considers is the definition after DEF.
 //
 // Return the access found, or null if there is no access that meets the
 // criteria.
 //
 // Note that this function does not consider separately-recorded call clobbers,
 // although such clobbers are only relevant if IGNORE_CLOBBERS_SETTING is NO.
-template<typename IgnorePredicate>
+template<typename IgnorePredicates>
 access_info *
-next_access_ignoring (def_info *def, ignore_clobbers ignore_clobbers_setting,
-		      IgnorePredicate ignore)
+next_access (def_info *def, ignore_clobbers ignore_clobbers_setting,
+	     IgnorePredicates ignore)
 {
-  if (use_info *use = first_nondebug_insn_use_ignoring (def, ignore))
-    return use;
+  if (!ignore.should_ignore_def (def))
+    if (use_info *use = first_nondebug_insn_use (def, ignore))
+      return use;
 
-  return first_def_ignoring (def->next_def (), ignore_clobbers_setting,
-			     ignore);
+  return first_access (def->next_def (), ignore_clobbers_setting, ignore);
 }
 
 // Return true if ACCESS1 should before ACCESS2 in an access_array.
diff --git a/gcc/rtl-ssa/change-utils.h b/gcc/rtl-ssa/change-utils.h
index fce41b0157a..fa27d1ad047 100644
--- a/gcc/rtl-ssa/change-utils.h
+++ b/gcc/rtl-ssa/change-utils.h
@@ -30,25 +30,15 @@  insn_is_changing (array_slice<insn_change *const> changes,
   return false;
 }
 
-// Return a closure of insn_is_changing, for use as a predicate.
-// This could be done using local lambdas instead, but the predicate is
-// used often enough that having a class should be more convenient and allow
-// reuse of template instantiations.
-//
-// We don't use std::bind because it would involve an indirect function call,
-// whereas this function is used in relatively performance-critical code.
-inline insn_is_changing_closure
-insn_is_changing (array_slice<insn_change *const> changes)
-{
-  return insn_is_changing_closure (changes);
-}
-
 // Restrict CHANGE.move_range so that the changed instruction can perform
-// all its definitions and uses.  Assume that if:
+// all its definitions and uses.
+//
+// IGNORE is an object that provides the same interface as ignore_nothing.
+// Assume that if:
 //
 // - CHANGE contains an access A1 of resource R;
 // - an instruction I2 contains another access A2 to R; and
-// - IGNORE (I2) is true
+// - IGNORE says that I2 should be ignored
 //
 // then either:
 //
@@ -56,31 +46,33 @@  insn_is_changing (array_slice<insn_change *const> changes)
 // - something will ensure that A1 and A2 maintain their current order,
 //   without this having to be enforced by CHANGE's move range.
 //
-// IGNORE should return true for CHANGE.insn ().
+// Assume the same thing about a definition D of R, and about all uses of D,
+// if IGNORE says that D should be ignored.
+//
+// IGNORE should ignore CHANGE.insn ().
 //
 // Return true on success, otherwise leave CHANGE.move_range in an invalid
 // state.
 //
 // This function only works correctly for instructions that remain within
 // the same extended basic block.
-template<typename IgnorePredicate>
+template<typename IgnorePredicates>
 bool
-restrict_movement_ignoring (insn_change &change, IgnorePredicate ignore)
+restrict_movement (insn_change &change, IgnorePredicates ignore)
 {
   // Uses generally lead to failure quicker, so test those first.
-  return (restrict_movement_for_uses_ignoring (change.move_range,
-					       change.new_uses, ignore)
-	  && restrict_movement_for_defs_ignoring (change.move_range,
-						  change.new_defs, ignore)
+  return (restrict_movement_for_uses (change.move_range,
+				      change.new_uses, ignore)
+	  && restrict_movement_for_defs (change.move_range,
+					 change.new_defs, ignore)
 	  && canonicalize_move_range (change.move_range, change.insn ()));
 }
 
-// Like restrict_movement_ignoring, but ignore only the instruction
-// that is being changed.
+// As above, but ignore only the instruction that is being changed.
 inline bool
 restrict_movement (insn_change &change)
 {
-  return restrict_movement_ignoring (change, insn_is (change.insn ()));
+  return restrict_movement (change, ignore_insn (change.insn ()));
 }
 
 using add_regno_clobber_fn = std::function<bool (insn_change &,
@@ -91,18 +83,22 @@  bool recog_internal (insn_change &, add_regno_clobber_fn);
 // tweaking the pattern or adding extra clobbers in order to make it match.
 //
 // When adding an extra clobber for register R, restrict CHANGE.move_range
-// to a range of instructions for which R is not live.  When determining
-// whether R is live, ignore accesses made by an instruction I if
-// IGNORE (I) is true.  The caller then assumes the responsibility
-// of ensuring that CHANGE and I are placed in a valid order.
+// to a range of instructions for which R is not live.  Use IGNORE to guide
+// this process, where IGNORE is an object that provides the same interface
+// as ignore_nothing.  When determining whether R is live, ignore accesses
+// made by an instruction I if IGNORE says that I should be ignored.
+// The caller then assumes the responsibility of ensuring that CHANGE
+// and I are placed in a valid order.  Similarly, ignore live ranges
+// associated with a definition of R if IGNORE says that that definition
+// should be ignored.
 //
-// IGNORE should return true for CHANGE.insn ().
+// IGNORE should ignore CHANGE.insn ().
 //
 // Return true on success.  Leave CHANGE unmodified on failure.
-template<typename IgnorePredicate>
+template<typename IgnorePredicates>
 inline bool
-recog_ignoring (obstack_watermark &watermark, insn_change &change,
-		IgnorePredicate ignore)
+recog (obstack_watermark &watermark, insn_change &change,
+       IgnorePredicates ignore)
 {
   auto add_regno_clobber = [&](insn_change &change, unsigned int regno)
     {
@@ -111,12 +107,11 @@  recog_ignoring (obstack_watermark &watermark, insn_change &change,
   return recog_internal (change, add_regno_clobber);
 }
 
-// As for recog_ignoring, but ignore only the instruction that is being
-// changed.
+// As above, but ignore only the instruction that is being changed.
 inline bool
 recog (obstack_watermark &watermark, insn_change &change)
 {
-  return recog_ignoring (watermark, change, insn_is (change.insn ()));
+  return recog (watermark, change, ignore_insn (change.insn ()));
 }
 
 // Check whether insn costs indicate that the net effect of the changes
diff --git a/gcc/rtl-ssa/changes.h b/gcc/rtl-ssa/changes.h
index 35ab02243a9..0bcd962fa77 100644
--- a/gcc/rtl-ssa/changes.h
+++ b/gcc/rtl-ssa/changes.h
@@ -98,19 +98,6 @@  private:
   bool m_is_deletion;
 };
 
-// A class that represents a closure of the two-argument form of
-// insn_is_changing.  See the comment above the one-argument form
-// for details.
-class insn_is_changing_closure
-{
-public:
-  insn_is_changing_closure (array_slice<insn_change *const> changes);
-  bool operator() (const insn_info *) const;
-
-private:
-  array_slice<insn_change *const> m_changes;
-};
-
 void pp_insn_change (pretty_printer *, const insn_change &);
 
 }
diff --git a/gcc/rtl-ssa/functions.h b/gcc/rtl-ssa/functions.h
index f5aca643beb..479c6992e97 100644
--- a/gcc/rtl-ssa/functions.h
+++ b/gcc/rtl-ssa/functions.h
@@ -165,16 +165,22 @@  public:
 
   // If CHANGE doesn't already clobber REGNO, try to add such a clobber,
   // limiting the movement range in order to make the clobber valid.
-  // When determining whether REGNO is live, ignore accesses made by an
-  // instruction I if IGNORE (I) is true.  The caller then assumes the
-  // responsibility of ensuring that CHANGE and I are placed in a valid order.
+  // Use IGNORE to guide this process, where IGNORE is an object that
+  // provides the same interface as ignore_nothing.
+  //
+  // That is, when determining whether REGNO is live, ignore accesses made
+  // by an instruction I if IGNORE says that I should be ignored.  The caller
+  // then assumes the responsibility of ensuring that CHANGE and I are placed
+  // in a valid order.  Similarly, ignore live ranges associated/ with a
+  // definition of REGNO if IGNORE says that that definition should be
+  // ignored.
   //
   // Return true on success.  Leave CHANGE unmodified when returning false.
   //
   // WATERMARK is a watermark returned by new_change_attempt ().
-  template<typename IgnorePredicate>
+  template<typename IgnorePredicates>
   bool add_regno_clobber (obstack_watermark &watermark, insn_change &change,
-			  unsigned int regno, IgnorePredicate ignore);
+			  unsigned int regno, IgnorePredicates ignore);
 
   // Return true if change_insns will be able to perform the changes
   // described by CHANGES.
diff --git a/gcc/rtl-ssa/insn-utils.h b/gcc/rtl-ssa/insn-utils.h
index bd3a4cbdcfa..1c54fe662e3 100644
--- a/gcc/rtl-ssa/insn-utils.h
+++ b/gcc/rtl-ssa/insn-utils.h
@@ -35,12 +35,4 @@  later_insn (insn_info *insn1, insn_info *insn2)
   return *insn1 < *insn2 ? insn2 : insn1;
 }
 
-// Return a closure of operator== for INSN.  See insn_is_changing for
-// the rationale for defining the function this way.
-inline insn_is_closure
-insn_is (const insn_info *insn)
-{
-  return insn_is_closure (insn);
-}
-
 }
diff --git a/gcc/rtl-ssa/insns.h b/gcc/rtl-ssa/insns.h
index 334d02888ca..1ba56abc2ca 100644
--- a/gcc/rtl-ssa/insns.h
+++ b/gcc/rtl-ssa/insns.h
@@ -493,18 +493,6 @@  public:
   insn_info *last;
 };
 
-// A class that represents a closure of operator== for instructions.
-// This is used by insn_is; see there for details.
-class insn_is_closure
-{
-public:
-  insn_is_closure (const insn_info *insn) : m_insn (insn) {}
-  bool operator() (const insn_info *other) const { return m_insn == other; }
-
-private:
-  const insn_info *m_insn;
-};
-
 void pp_insn (pretty_printer *, const insn_info *);
 
 }
diff --git a/gcc/rtl-ssa/member-fns.inl b/gcc/rtl-ssa/member-fns.inl
index e4825ad2a18..833907b62c9 100644
--- a/gcc/rtl-ssa/member-fns.inl
+++ b/gcc/rtl-ssa/member-fns.inl
@@ -870,21 +870,6 @@  inline insn_change::insn_change (insn_info *insn, delete_action)
 {
 }
 
-inline insn_is_changing_closure::
-insn_is_changing_closure (array_slice<insn_change *const> changes)
-  : m_changes (changes)
-{
-}
-
-inline bool
-insn_is_changing_closure::operator() (const insn_info *insn) const
-{
-  for (const insn_change *change : m_changes)
-    if (change->insn () == insn)
-      return true;
-  return false;
-}
-
 inline iterator_range<bb_iterator>
 function_info::bbs () const
 {
@@ -963,11 +948,11 @@  function_info::single_dominating_def (unsigned int regno) const
   return nullptr;
 }
 
-template<typename IgnorePredicate>
+template<typename IgnorePredicates>
 bool
 function_info::add_regno_clobber (obstack_watermark &watermark,
 				  insn_change &change, unsigned int regno,
-				  IgnorePredicate ignore)
+				  IgnorePredicates ignore)
 {
   // Check whether CHANGE already clobbers REGNO.
   if (find_access (change.new_defs, regno))
@@ -1003,4 +988,20 @@  function_info::change_alloc (obstack_watermark &wm, Ts... args)
   return new (addr) T (std::forward<Ts> (args)...);
 }
 
+inline
+ignore_changing_insns::
+ignore_changing_insns (array_slice<insn_change *const> changes)
+  : m_changes (changes)
+{
+}
+
+inline bool
+ignore_changing_insns::should_ignore_insn (const insn_info *insn)
+{
+  for (const insn_change *change : m_changes)
+    if (change->insn () == insn)
+      return true;
+  return false;
+}
+
 }
diff --git a/gcc/rtl-ssa/movement.h b/gcc/rtl-ssa/movement.h
index f55c234e824..17d31e0b5cb 100644
--- a/gcc/rtl-ssa/movement.h
+++ b/gcc/rtl-ssa/movement.h
@@ -83,10 +83,13 @@  canonicalize_move_range (insn_range_info &move_range, insn_info *insn)
 }
 
 // Try to restrict movement range MOVE_RANGE of INSN so that it can set
-// or clobber REGNO.  Assume that if:
+// or clobber REGNO.
+//
+// IGNORE is an object that provides the same interface as ignore_nothing.
+// Assume that if:
 //
 // - an instruction I2 contains another access A to REGNO; and
-// - IGNORE (I2) is true
+// - IGNORE says that I2 should be ignored
 //
 // then either:
 //
@@ -94,15 +97,18 @@  canonicalize_move_range (insn_range_info &move_range, insn_info *insn)
 // - something will ensure that the new definition of REGNO does not
 //   interfere with A, without this having to be enforced by I1's move range.
 //
+// If IGNORE says that a definition D of REGNO should be ignored, assume that
+// the new definition of REGNO will not conflict with D.
+//
 // Return true on success, otherwise leave MOVE_RANGE in an invalid state.
 //
 // This function only works correctly for instructions that remain within
 // the same extended basic block.
-template<typename IgnorePredicate>
+template<typename IgnorePredicates>
 bool
 restrict_movement_for_dead_range (insn_range_info &move_range,
 				  unsigned int regno, insn_info *insn,
-				  IgnorePredicate ignore)
+				  IgnorePredicates ignore)
 {
   // Find a definition at or neighboring INSN.
   resource_info resource = full_register (regno);
@@ -141,17 +147,18 @@  restrict_movement_for_dead_range (insn_range_info &move_range,
     {
       // Stop the instruction moving beyond the previous relevant access
       // to REGNO.
-      access_info *prev_access
-	= last_access_ignoring (prev, ignore_clobbers::YES, ignore);
+      access_info *prev_access = last_access (prev, ignore_clobbers::YES,
+					      ignore);
       if (prev_access)
 	move_range = move_later_than (move_range, access_insn (prev_access));
     }
 
-  // Stop the instruction moving beyond the next relevant definition of REGNO.
+  // Stop the instruction moving beyond the next relevant use or definition
+  // of REGNO.
   def_info *next = dl.matching_set_or_first_def_of_next_group ();
-  next = first_def_ignoring (next, ignore_clobbers::YES, ignore);
-  if (next)
-    move_range = move_earlier_than (move_range, next->insn ());
+  access_info *next_access = first_access (next, ignore_clobbers::YES, ignore);
+  if (next_access)
+    move_range = move_earlier_than (move_range, access_insn (next_access));
 
   return canonicalize_move_range (move_range, insn);
 }
@@ -159,11 +166,14 @@  restrict_movement_for_dead_range (insn_range_info &move_range,
 // Try to restrict movement range MOVE_RANGE so that it is possible for the
 // instruction being moved ("instruction I1") to perform all the definitions
 // in DEFS while still preserving dependencies between those definitions
-// and surrounding instructions.  Assume that if:
+// and surrounding instructions.
+//
+// IGNORE is an object that provides the same interface as ignore_nothing.
+// Assume that if:
 //
 // - DEFS contains a definition D of resource R;
 // - an instruction I2 contains another access A to R; and
-// - IGNORE (I2) is true
+// - IGNORE says that I2 should be ignored
 //
 // then either:
 //
@@ -171,14 +181,17 @@  restrict_movement_for_dead_range (insn_range_info &move_range,
 // - something will ensure that D and A maintain their current order,
 //   without this having to be enforced by I1's move range.
 //
+// Assume the same thing about a definition D and all uses of D if IGNORE
+// says that D should be ignored.
+//
 // Return true on success, otherwise leave MOVE_RANGE in an invalid state.
 //
 // This function only works correctly for instructions that remain within
 // the same extended basic block.
-template<typename IgnorePredicate>
+template<typename IgnorePredicates>
 bool
-restrict_movement_for_defs_ignoring (insn_range_info &move_range,
-				     def_array defs, IgnorePredicate ignore)
+restrict_movement_for_defs (insn_range_info &move_range, def_array defs,
+			    IgnorePredicates ignore)
 {
   for (def_info *def : defs)
     {
@@ -194,29 +207,16 @@  restrict_movement_for_defs_ignoring (insn_range_info &move_range,
       // are being moved at once.
       bool is_clobber = is_a<clobber_info *> (def);
 
-      // Search back for the first unfiltered use or definition of the
+      // Search back for the first relevant use or definition of the
       // same resource.
       access_info *access;
-      access = prev_access_ignoring (def, ignore_clobbers (is_clobber),
-				     ignore);
+      access = prev_access (def, ignore_clobbers (is_clobber), ignore);
       if (access)
 	move_range = move_later_than (move_range, access_insn (access));
 
-      // Search forward for the first unfiltered use of DEF,
-      // or the first unfiltered definition that follows DEF.
-      //
-      // We don't need to consider uses of following definitions, since
-      // if IGNORE (D->insn ()) is true for some definition D, the caller
-      // is guarantees that either
-      //
-      // - D will be removed, and thus its uses will be removed; or
-      // - D will occur after DEF, and thus D's uses will also occur
-      //   after DEF.
-      //
-      // This is purely a simplification: we could also process D's uses,
-      // but we don't need to.
-      access = next_access_ignoring (def, ignore_clobbers (is_clobber),
-				     ignore);
+      // Search forward for the next relevant use or definition of the
+      // same resource.
+      access = next_access (def, ignore_clobbers (is_clobber), ignore);
       if (access)
 	move_range = move_earlier_than (move_range, access_insn (access));
 
@@ -238,13 +238,11 @@  restrict_movement_for_defs_ignoring (insn_range_info &move_range,
 	    return false;
 
 	  insn_info *insn;
-	  insn = prev_call_clobbers_ignoring (*call_group, def->insn (),
-					      ignore);
+	  insn = prev_call_clobbers (*call_group, def->insn (), ignore);
 	  if (insn)
 	    move_range = move_later_than (move_range, insn);
 
-	  insn = next_call_clobbers_ignoring (*call_group, def->insn (),
-					      ignore);
+	  insn = next_call_clobbers (*call_group, def->insn (), ignore);
 	  if (insn)
 	    move_range = move_earlier_than (move_range, insn);
 	}
@@ -262,11 +260,11 @@  restrict_movement_for_defs_ignoring (insn_range_info &move_range,
   return bool (move_range);
 }
 
-// Like restrict_movement_for_defs_ignoring, but for the uses in USES.
-template<typename IgnorePredicate>
+// Like restrict_movement_for_defs, but for the uses in USES.
+template<typename IgnorePredicates>
 bool
-restrict_movement_for_uses_ignoring (insn_range_info &move_range,
-				     use_array uses, IgnorePredicate ignore)
+restrict_movement_for_uses (insn_range_info &move_range, use_array uses,
+			    IgnorePredicates ignore)
 {
   for (const use_info *use : uses)
     {
@@ -284,31 +282,21 @@  restrict_movement_for_uses_ignoring (insn_range_info &move_range,
       if (use->is_in_debug_insn ())
 	continue;
 
-      // If the used value is defined by an instruction I2 for which
-      // IGNORE (I2) is true, the caller guarantees that I2 will occur
-      // before change.insn ().  Otherwise, make sure that the use occurs
-      // after the definition.
+      // If the used value is defined by an ignored instruction I2,
+      // the caller guarantees that I2 will occur before change.insn ()
+      // and that its value will still be available at change.insn ().
+      // Otherwise, make sure that the use occurs after the definition.
       insn_info *insn = set->insn ();
-      if (!ignore (insn))
+      if (!ignore.should_ignore_def (set)
+	  && !ignore.should_ignore_insn (insn))
 	move_range = move_later_than (move_range, insn);
 
-      // Search forward for the first unfiltered definition that follows SET.
-      //
-      // We don't need to consider the uses of these definitions, since
-      // if IGNORE (D->insn ()) is true for some definition D, the caller
-      // is guarantees that either
-      //
-      // - D will be removed, and thus its uses will be removed; or
-      // - D will occur after USE, and thus D's uses will also occur
-      //   after USE.
-      //
-      // This is purely a simplification: we could also process D's uses,
-      // but we don't need to.
-      def_info *def;
-      def = first_def_ignoring (set->next_def (), ignore_clobbers::NO,
-				ignore);
-      if (def)
-	move_range = move_earlier_than (move_range, def->insn ());
+      // Search forward after SET's live range for the first relevant
+      // use or definition of the same resource.
+      access_info *access;
+      access = first_access (set->next_def (), ignore_clobbers::NO, ignore);
+      if (access)
+	move_range = move_earlier_than (move_range, access_insn (access));
 
       // If USE uses a hard register, take any call clobbers into account too.
       // SET will necessarily occur after any previous call clobber, so we
@@ -326,8 +314,8 @@  restrict_movement_for_uses_ignoring (insn_range_info &move_range,
 	  if (!move_range)
 	    return false;
 
-	  insn_info *insn = next_call_clobbers_ignoring (*call_group,
-							 use->insn (), ignore);
+	  insn_info *insn = next_call_clobbers (*call_group, use->insn (),
+						ignore);
 	  if (insn)
 	    move_range = move_earlier_than (move_range, insn);
 	}
diff --git a/gcc/rtl-ssa/predicates.h b/gcc/rtl-ssa/predicates.h
new file mode 100644
index 00000000000..225a8c658b4
--- /dev/null
+++ b/gcc/rtl-ssa/predicates.h
@@ -0,0 +1,58 @@ 
+// RTL SSA predicate classes                                        -*- C++ -*-
+// Copyright (C) 2024 Free Software Foundation, Inc.
+//
+// This file is part of GCC.
+//
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+//
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+namespace rtl_ssa {
+
+// Collects predicates that affect a scan over the IR, specifying what
+// (if anything) should be ignored.
+struct ignore_nothing
+{
+  // Return true if the scan should ignore the given definition
+  // and all uses of the definition.
+  bool should_ignore_def (const def_info *) { return false; }
+
+  // Return true if the scan should ignore the given instruction.
+  bool should_ignore_insn (const insn_info *) { return false; }
+};
+
+// Predicates that ignore the instruction passed to the constructor
+// (and nothing else).
+class ignore_insn : public ignore_nothing
+{
+public:
+  ignore_insn (const insn_info *insn) : m_insn (insn) {}
+  bool should_ignore_insn (const insn_info *insn) { return insn == m_insn; }
+
+private:
+  const insn_info *m_insn;
+};
+
+// Predicates that ignore all the instructions being changed by a set
+// of insn_changes.
+class ignore_changing_insns : public ignore_nothing
+{
+public:
+  ignore_changing_insns (array_slice<insn_change *const>);
+  bool should_ignore_insn (const insn_info *);
+
+private:
+  array_slice<insn_change *const> m_changes;
+};
+
+}