]>
Commit | Line | Data |
---|---|---|
73b75827 | 1 | // RTL SSA utility functions for changing instructions -*- C++ -*- |
83ffe9cd | 2 | // Copyright (C) 2020-2023 Free Software Foundation, Inc. |
73b75827 RS |
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 | // 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. | |
37 | // | |
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) | |
42 | { | |
43 | return insn_is_changing_closure (changes); | |
44 | } | |
45 | ||
46 | // Restrict CHANGE.move_range so that the changed instruction can perform | |
47 | // all its definitions and uses. Assume that if: | |
48 | // | |
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 | |
52 | // | |
53 | // then either: | |
54 | // | |
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. | |
58 | // | |
59 | // IGNORE should return true for CHANGE.insn (). | |
60 | // | |
61 | // Return true on success, otherwise leave CHANGE.move_range in an invalid | |
62 | // state. | |
63 | // | |
64 | // This function only works correctly for instructions that remain within | |
65 | // the same extended basic block. | |
66 | template<typename IgnorePredicate> | |
67 | bool | |
68 | restrict_movement_ignoring (insn_change &change, IgnorePredicate ignore) | |
69 | { | |
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 ())); | |
76 | } | |
77 | ||
78 | // Like restrict_movement_ignoring, but ignore only the instruction | |
79 | // that is being changed. | |
80 | inline bool | |
81 | restrict_movement (insn_change &change) | |
82 | { | |
83 | return restrict_movement_ignoring (change, insn_is (change.insn ())); | |
84 | } | |
85 | ||
86 | using add_regno_clobber_fn = std::function<bool (insn_change &, | |
87 | unsigned int)>; | |
88 | bool recog_internal (insn_change &, add_regno_clobber_fn); | |
89 | ||
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. | |
92 | // | |
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. | |
98 | // | |
99 | // IGNORE should return true for CHANGE.insn (). | |
100 | // | |
101 | // Return true on success. Leave CHANGE unmodified on failure. | |
102 | template<typename IgnorePredicate> | |
103 | inline bool | |
104 | recog_ignoring (obstack_watermark &watermark, insn_change &change, | |
105 | IgnorePredicate ignore) | |
106 | { | |
107 | auto add_regno_clobber = [&](insn_change &change, unsigned int regno) | |
108 | { | |
109 | return crtl->ssa->add_regno_clobber (watermark, change, regno, ignore); | |
110 | }; | |
111 | return recog_internal (change, add_regno_clobber); | |
112 | } | |
113 | ||
114 | // As for recog_ignoring, but ignore only the instruction that is being | |
115 | // changed. | |
116 | inline bool | |
117 | recog (obstack_watermark &watermark, insn_change &change) | |
118 | { | |
119 | return recog_ignoring (watermark, change, insn_is (change.insn ())); | |
120 | } | |
121 | ||
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 | |
125 | // instructions. | |
126 | bool changes_are_worthwhile (array_slice<insn_change *const> changes, | |
127 | bool strict_p = false); | |
128 | ||
129 | // Like changes_are_worthwhile, but for a single change. | |
130 | inline bool | |
131 | change_is_worthwhile (insn_change &change, bool strict_p = false) | |
132 | { | |
133 | insn_change *changes[] = { &change }; | |
134 | return changes_are_worthwhile (changes, strict_p); | |
135 | } | |
136 | ||
137 | } |