Line data Source code
1 : // RTL SSA utility functions for changing instructions -*- C++ -*-
2 : // Copyright (C) 2020-2026 Free Software Foundation, Inc.
3 : //
4 : // This file is part of GCC.
5 : //
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
9 : // version.
10 : //
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
14 : // for more details.
15 : //
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/>.
19 :
20 : namespace rtl_ssa {
21 :
22 : // Return true if INSN is one of the instructions being changed by CHANGES.
23 : inline bool
24 : insn_is_changing (array_slice<insn_change *const> changes,
25 : const insn_info *insn)
26 : {
27 : for (const insn_change *change : changes)
28 : if (change->insn () == insn)
29 : return true;
30 : return false;
31 : }
32 :
33 : // Restrict CHANGE.move_range so that the changed instruction can perform
34 : // all its definitions and uses.
35 : //
36 : // IGNORE is an object that provides the same interface as ignore_nothing.
37 : // Assume that if:
38 : //
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
42 : //
43 : // then either:
44 : //
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.
48 : //
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.
51 : //
52 : // IGNORE should ignore CHANGE.insn ().
53 : //
54 : // Return true on success, otherwise leave CHANGE.move_range in an invalid
55 : // state.
56 : //
57 : // This function only works correctly for instructions that remain within
58 : // the same extended basic block.
59 : template<typename IgnorePredicates>
60 : bool
61 61647836 : restrict_movement (insn_change &change, IgnorePredicates ignore)
62 : {
63 : // Uses generally lead to failure quicker, so test those first.
64 61647836 : return (restrict_movement_for_uses (change.move_range,
65 : change.new_uses, ignore)
66 59681740 : && restrict_movement_for_defs (change.move_range,
67 : change.new_defs, ignore)
68 120417088 : && canonicalize_move_range (change.move_range, change.insn ()));
69 : }
70 :
71 : // As above, but ignore only the instruction that is being changed.
72 : inline bool
73 33034745 : restrict_movement (insn_change &change)
74 : {
75 33034745 : return restrict_movement (change, ignore_insn (change.insn ()));
76 : }
77 :
78 : using add_regno_clobber_fn = std::function<bool (insn_change &,
79 : unsigned int)>;
80 : bool recog_internal (insn_change &, add_regno_clobber_fn);
81 :
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.
84 : //
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
93 : // should be ignored.
94 : //
95 : // IGNORE should ignore CHANGE.insn ().
96 : //
97 : // Return true on success. Leave CHANGE unmodified on failure.
98 : template<typename IgnorePredicates>
99 : inline bool
100 43850025 : recog (obstack_watermark &watermark, insn_change &change,
101 : IgnorePredicates ignore)
102 : {
103 44555267 : auto add_regno_clobber = [&](insn_change &change, unsigned int regno)
104 : {
105 2519849 : return crtl->ssa->add_regno_clobber (watermark, change, regno, ignore);
106 : };
107 43850025 : return recog_internal (change, add_regno_clobber);
108 : }
109 :
110 : // As above, but ignore only the instruction that is being changed.
111 : inline bool
112 16867574 : recog (obstack_watermark &watermark, insn_change &change)
113 : {
114 16867574 : return recog (watermark, change, ignore_insn (change.insn ()));
115 : }
116 :
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
120 : // instructions.
121 : bool changes_are_worthwhile (array_slice<insn_change *const> changes,
122 : bool strict_p = false);
123 :
124 : // Like changes_are_worthwhile, but for a single change.
125 : inline bool
126 6204593 : change_is_worthwhile (insn_change &change, bool strict_p = false)
127 : {
128 6204593 : insn_change *changes[] = { &change };
129 6204593 : return changes_are_worthwhile (changes, strict_p);
130 : }
131 :
132 : }
|