1 // RTL SSA utility functions for changing instructions -*- C++ -*-
2 // Copyright (C) 2020-2023 Free Software Foundation, Inc.
4 // This file is part of GCC.
6 // GCC is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU General Public License as published by the Free
8 // Software Foundation; either version 3, or (at your option) any later
11 // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 // You should have received a copy of the GNU General Public License
17 // along with GCC; see the file COPYING3. If not see
18 // <http://www.gnu.org/licenses/>.
22 // Return true if INSN is one of the instructions being changed by CHANGES.
24 insn_is_changing (array_slice
<insn_change
*const> changes
,
25 const insn_info
*insn
)
27 for (const insn_change
*change
: changes
)
28 if (change
->insn () == insn
)
33 // Return a closure of insn_is_changing, for use as a predicate.
34 // This could be done using local lambdas instead, but the predicate is
35 // used often enough that having a class should be more convenient and allow
36 // reuse of template instantiations.
38 // We don't use std::bind because it would involve an indirect function call,
39 // whereas this function is used in relatively performance-critical code.
40 inline insn_is_changing_closure
41 insn_is_changing (array_slice
<insn_change
*const> changes
)
43 return insn_is_changing_closure (changes
);
46 // Restrict CHANGE.move_range so that the changed instruction can perform
47 // all its definitions and uses. Assume that if:
49 // - CHANGE contains an access A1 of resource R;
50 // - an instruction I2 contains another access A2 to R; and
51 // - IGNORE (I2) is true
55 // - A2 will be removed; or
56 // - something will ensure that A1 and A2 maintain their current order,
57 // without this having to be enforced by CHANGE's move range.
59 // IGNORE should return true for CHANGE.insn ().
61 // Return true on success, otherwise leave CHANGE.move_range in an invalid
64 // This function only works correctly for instructions that remain within
65 // the same extended basic block.
66 template<typename IgnorePredicate
>
68 restrict_movement_ignoring (insn_change
&change
, IgnorePredicate ignore
)
70 // Uses generally lead to failure quicker, so test those first.
71 return (restrict_movement_for_uses_ignoring (change
.move_range
,
72 change
.new_uses
, ignore
)
73 && restrict_movement_for_defs_ignoring (change
.move_range
,
74 change
.new_defs
, ignore
)
75 && canonicalize_move_range (change
.move_range
, change
.insn ()));
78 // Like restrict_movement_ignoring, but ignore only the instruction
79 // that is being changed.
81 restrict_movement (insn_change
&change
)
83 return restrict_movement_ignoring (change
, insn_is (change
.insn ()));
86 using add_regno_clobber_fn
= std::function
<bool (insn_change
&,
88 bool recog_internal (insn_change
&, add_regno_clobber_fn
);
90 // Try to recognize the new instruction pattern for CHANGE, potentially
91 // tweaking the pattern or adding extra clobbers in order to make it match.
93 // When adding an extra clobber for register R, restrict CHANGE.move_range
94 // to a range of instructions for which R is not live. When determining
95 // whether R is live, ignore accesses made by an instruction I if
96 // IGNORE (I) is true. The caller then assumes the responsibility
97 // of ensuring that CHANGE and I are placed in a valid order.
99 // IGNORE should return true for CHANGE.insn ().
101 // Return true on success. Leave CHANGE unmodified on failure.
102 template<typename IgnorePredicate
>
104 recog_ignoring (obstack_watermark
&watermark
, insn_change
&change
,
105 IgnorePredicate ignore
)
107 auto add_regno_clobber
= [&](insn_change
&change
, unsigned int regno
)
109 return crtl
->ssa
->add_regno_clobber (watermark
, change
, regno
, ignore
);
111 return recog_internal (change
, add_regno_clobber
);
114 // As for recog_ignoring, but ignore only the instruction that is being
117 recog (obstack_watermark
&watermark
, insn_change
&change
)
119 return recog_ignoring (watermark
, change
, insn_is (change
.insn ()));
122 // Check whether insn costs indicate that the net effect of the changes
123 // in CHANGES is worthwhile. Require a strict improvement if STRICT_P,
124 // otherwise allow the new instructions to be the same cost as the old
126 bool changes_are_worthwhile (array_slice
<insn_change
*const> changes
,
127 bool strict_p
= false);
129 // Like changes_are_worthwhile, but for a single change.
131 change_is_worthwhile (insn_change
&change
, bool strict_p
= false)
133 insn_change
*changes
[] = { &change
};
134 return changes_are_worthwhile (changes
, strict_p
);