@@ -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;
@@ -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;
@@ -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",
@@ -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"
@@ -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.
@@ -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
@@ -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 &);
}
@@ -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.
@@ -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);
-}
-
}
@@ -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 *);
}
@@ -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;
+}
+
}
@@ -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);
}
new file mode 100644
@@ -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;
+};
+
+}