1 // RTL SSA utility functions for changing instructions -*- C++ -*-
2 // Copyright (C) 2020-2025 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 // Restrict CHANGE.move_range so that the changed instruction can perform
34 // all its definitions and uses.
36 // IGNORE is an object that provides the same interface as ignore_nothing.
39 // - CHANGE contains an access A1 of resource R;
40 // - an instruction I2 contains another access A2 to R; and
41 // - IGNORE says that I2 should be ignored
45 // - A2 will be removed; or
46 // - something will ensure that A1 and A2 maintain their current order,
47 // without this having to be enforced by CHANGE's move range.
49 // Assume the same thing about a definition D of R, and about all uses of D,
50 // if IGNORE says that D should be ignored.
52 // IGNORE should ignore CHANGE.insn ().
54 // Return true on success, otherwise leave CHANGE.move_range in an invalid
57 // This function only works correctly for instructions that remain within
58 // the same extended basic block.
59 template<typename IgnorePredicates
>
61 restrict_movement (insn_change
&change
, IgnorePredicates ignore
)
63 // Uses generally lead to failure quicker, so test those first.
64 return (restrict_movement_for_uses (change
.move_range
,
65 change
.new_uses
, ignore
)
66 && restrict_movement_for_defs (change
.move_range
,
67 change
.new_defs
, ignore
)
68 && canonicalize_move_range (change
.move_range
, change
.insn ()));
71 // As above, but ignore only the instruction that is being changed.
73 restrict_movement (insn_change
&change
)
75 return restrict_movement (change
, ignore_insn (change
.insn ()));
78 using add_regno_clobber_fn
= std::function
<bool (insn_change
&,
80 bool recog_internal (insn_change
&, add_regno_clobber_fn
);
82 // Try to recognize the new instruction pattern for CHANGE, potentially
83 // tweaking the pattern or adding extra clobbers in order to make it match.
85 // When adding an extra clobber for register R, restrict CHANGE.move_range
86 // to a range of instructions for which R is not live. Use IGNORE to guide
87 // this process, where IGNORE is an object that provides the same interface
88 // as ignore_nothing. When determining whether R is live, ignore accesses
89 // made by an instruction I if IGNORE says that I should be ignored.
90 // The caller then assumes the responsibility of ensuring that CHANGE
91 // and I are placed in a valid order. Similarly, ignore live ranges
92 // associated with a definition of R if IGNORE says that that definition
95 // IGNORE should ignore CHANGE.insn ().
97 // Return true on success. Leave CHANGE unmodified on failure.
98 template<typename IgnorePredicates
>
100 recog (obstack_watermark
&watermark
, insn_change
&change
,
101 IgnorePredicates ignore
)
103 auto add_regno_clobber
= [&](insn_change
&change
, unsigned int regno
)
105 return crtl
->ssa
->add_regno_clobber (watermark
, change
, regno
, ignore
);
107 return recog_internal (change
, add_regno_clobber
);
110 // As above, but ignore only the instruction that is being changed.
112 recog (obstack_watermark
&watermark
, insn_change
&change
)
114 return recog (watermark
, change
, ignore_insn (change
.insn ()));
117 // Check whether insn costs indicate that the net effect of the changes
118 // in CHANGES is worthwhile. Require a strict improvement if STRICT_P,
119 // otherwise allow the new instructions to be the same cost as the old
121 bool changes_are_worthwhile (array_slice
<insn_change
*const> changes
,
122 bool strict_p
= false);
124 // Like changes_are_worthwhile, but for a single change.
126 change_is_worthwhile (insn_change
&change
, bool strict_p
= false)
128 insn_change
*changes
[] = { &change
};
129 return changes_are_worthwhile (changes
, strict_p
);