]>
Commit | Line | Data |
---|---|---|
04ee46ed | 1 | /* Analyze RTL for GNU compiler. |
99dee823 | 2 | Copyright (C) 2020-2021 Free Software Foundation, Inc. |
04ee46ed 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 | /* Note that for historical reasons, many rtlanal.c functions are | |
21 | declared in rtl.h rather than here. */ | |
22 | ||
23 | #ifndef GCC_RTLANAL_H | |
24 | #define GCC_RTLANAL_H | |
25 | ||
26 | /* A dummy register value that represents the whole of variable memory. | |
27 | Using ~0U means that arrays that track both registers and memory can | |
28 | be indexed by regno + 1. */ | |
29 | const unsigned int MEM_REGNO = ~0U; | |
30 | ||
31 | /* Bitmasks of flags describing an rtx_obj_reference. See the accessors | |
32 | in the class for details. */ | |
33 | namespace rtx_obj_flags | |
34 | { | |
35 | const uint16_t IS_READ = 1U << 0; | |
36 | const uint16_t IS_WRITE = 1U << 1; | |
37 | const uint16_t IS_CLOBBER = 1U << 2; | |
38 | const uint16_t IS_PRE_POST_MODIFY = 1U << 3; | |
39 | const uint16_t IS_MULTIREG = 1U << 4; | |
40 | const uint16_t IN_MEM_LOAD = 1U << 5; | |
41 | const uint16_t IN_MEM_STORE = 1U << 6; | |
42 | const uint16_t IN_SUBREG = 1U << 7; | |
43 | const uint16_t IN_NOTE = 1U << 8; | |
44 | ||
45 | /* Flags that apply to all subrtxes of the rtx they were originally | |
46 | added for. */ | |
47 | static const uint16_t STICKY_FLAGS = IN_NOTE; | |
48 | } | |
49 | ||
50 | /* Contains information about a reference to a register or variable memory. */ | |
51 | class rtx_obj_reference | |
52 | { | |
53 | public: | |
54 | rtx_obj_reference () = default; | |
55 | rtx_obj_reference (unsigned int regno, uint16_t flags, | |
56 | machine_mode mode, unsigned int multireg_offset = 0); | |
57 | ||
58 | bool is_reg () const { return regno != MEM_REGNO; } | |
59 | bool is_mem () const { return regno == MEM_REGNO; } | |
60 | ||
61 | /* True if the reference is a read or a write respectively. | |
62 | Both flags are set in a read-modify-write context, such as | |
63 | for read_modify_subreg_p. */ | |
64 | bool is_read () const { return flags & rtx_obj_flags::IS_READ; } | |
65 | bool is_write () const { return flags & rtx_obj_flags::IS_WRITE; } | |
66 | ||
67 | /* True if IS_WRITE and if the write is a clobber rather than a set. */ | |
68 | bool is_clobber () const { return flags & rtx_obj_flags::IS_CLOBBER; } | |
69 | ||
70 | /* True if the reference is updated by an RTX_AUTOINC. Both IS_READ | |
71 | and IS_WRITE are also true if so. */ | |
72 | bool is_pre_post_modify () const | |
73 | { | |
74 | return flags & rtx_obj_flags::IS_PRE_POST_MODIFY; | |
75 | } | |
76 | ||
77 | /* True if the register is part of a multi-register hard REG. */ | |
78 | bool is_multireg () const { return flags & rtx_obj_flags::IS_MULTIREG; } | |
79 | ||
80 | /* True if the reference occurs in the address of a load MEM. */ | |
81 | bool in_mem_load () const { return flags & rtx_obj_flags::IN_MEM_LOAD; } | |
82 | ||
83 | /* True if the reference occurs in the address of a store MEM. */ | |
84 | bool in_mem_store () const { return flags & rtx_obj_flags::IN_MEM_STORE; } | |
85 | ||
86 | /* True if the reference occurs in any kind of MEM address. */ | |
87 | bool in_address () const { return in_mem_load () || in_mem_store (); } | |
88 | ||
89 | /* True if the reference occurs in a SUBREG. */ | |
90 | bool in_subreg () const { return flags & rtx_obj_flags::IN_SUBREG; } | |
91 | ||
92 | /* True if the reference occurs in a REG_EQUAL or REG_EQUIV note. */ | |
93 | bool in_note () const { return flags & rtx_obj_flags::IN_NOTE; } | |
94 | ||
95 | /* The referenced register, or MEM_REGNO for variable memory. */ | |
96 | unsigned int regno; | |
97 | ||
98 | /* A bitmask of rtx_obj_flags. */ | |
99 | unsigned int flags : 16; | |
100 | ||
101 | /* The mode of the reference. If IS_MULTIREG, this is the mode of | |
102 | REGNO - MULTIREG_OFFSET. */ | |
103 | machine_mode mode : 8; | |
104 | ||
105 | /* If IS_MULTIREG, the offset of REGNO from the start of the register. */ | |
106 | unsigned int multireg_offset : 8; | |
107 | }; | |
108 | ||
109 | /* Construct a reference with the given fields. */ | |
110 | ||
111 | inline rtx_obj_reference::rtx_obj_reference (unsigned int regno, uint16_t flags, | |
112 | machine_mode mode, | |
113 | unsigned int multireg_offset) | |
114 | : regno (regno), | |
115 | flags (flags), | |
116 | mode (mode), | |
117 | multireg_offset (multireg_offset) | |
118 | { | |
119 | } | |
120 | ||
121 | /* Contains information about an rtx or an instruction, including a | |
122 | list of rtx_obj_references. The storage backing the list needs | |
123 | to be filled in by assigning to REF_BEGIN and REF_END. */ | |
124 | ||
125 | class rtx_properties | |
126 | { | |
127 | public: | |
128 | rtx_properties (); | |
129 | ||
130 | void try_to_add_reg (const_rtx x, unsigned int flags = 0); | |
131 | void try_to_add_dest (const_rtx x, unsigned int flags = 0); | |
132 | void try_to_add_src (const_rtx x, unsigned int flags = 0); | |
133 | void try_to_add_pattern (const_rtx pat); | |
134 | void try_to_add_note (const_rtx x); | |
135 | void try_to_add_insn (const rtx_insn *insn, bool include_notes); | |
136 | ||
137 | iterator_range<rtx_obj_reference *> refs () const; | |
138 | ||
139 | /* Return the number of rtx_obj_references that have been recorded. */ | |
140 | size_t num_refs () const { return ref_iter - ref_begin; } | |
141 | ||
142 | bool has_side_effects () const; | |
143 | ||
144 | /* [REF_BEGIN, REF_END) is the maximum extent of the memory available | |
145 | for recording references. REG_ITER is the first unused entry. */ | |
146 | rtx_obj_reference *ref_begin; | |
147 | rtx_obj_reference *ref_iter; | |
148 | rtx_obj_reference *ref_end; | |
149 | ||
150 | /* True if the rtx includes an asm. */ | |
151 | unsigned int has_asm : 1; | |
152 | ||
153 | /* True if the rtx includes a call. */ | |
154 | unsigned int has_call : 1; | |
155 | ||
156 | /* True if the rtx includes an RTX_AUTOINC expression. */ | |
157 | unsigned int has_pre_post_modify : 1; | |
158 | ||
159 | /* True if the rtx contains volatile references, in the sense of | |
160 | volatile_refs_p. */ | |
161 | unsigned int has_volatile_refs : 1; | |
162 | ||
163 | /* For future expansion. */ | |
164 | unsigned int spare : 28; | |
165 | }; | |
166 | ||
167 | inline rtx_properties::rtx_properties () | |
168 | : ref_begin (nullptr), | |
169 | ref_iter (nullptr), | |
170 | ref_end (nullptr), | |
171 | has_asm (false), | |
172 | has_call (false), | |
173 | has_pre_post_modify (false), | |
174 | has_volatile_refs (false), | |
175 | spare (0) | |
176 | { | |
177 | } | |
178 | ||
179 | /* Like add_src, but treat X has being part of a REG_EQUAL or | |
180 | REG_EQUIV note. */ | |
181 | ||
182 | inline void | |
183 | rtx_properties::try_to_add_note (const_rtx x) | |
184 | { | |
185 | try_to_add_src (x, rtx_obj_flags::IN_NOTE); | |
186 | } | |
187 | ||
188 | /* Return true if the rtx has side effects, in the sense of | |
189 | side_effects_p (except for side_effects_p's special handling | |
190 | of combine.c clobbers). */ | |
191 | ||
192 | inline bool | |
193 | rtx_properties::has_side_effects () const | |
194 | { | |
195 | return has_volatile_refs || has_pre_post_modify || has_call; | |
196 | } | |
197 | ||
198 | /* Return an iterator range for all the references, suitable for | |
199 | range-based for loops. */ | |
200 | ||
201 | inline iterator_range<rtx_obj_reference *> | |
202 | rtx_properties::refs () const | |
203 | { | |
204 | return { ref_begin, ref_iter }; | |
205 | } | |
206 | ||
207 | /* BASE is derived from rtx_properties and provides backing storage | |
208 | for REF_BEGIN. It has a grow () method that increases the amount | |
209 | of memory available if the initial allocation was too small. */ | |
210 | ||
211 | template<typename Base> | |
212 | class growing_rtx_properties : public Base | |
213 | { | |
214 | public: | |
215 | template<typename... Args> | |
216 | growing_rtx_properties (Args...); | |
217 | ||
218 | template<typename AddFn> | |
219 | void repeat (AddFn add); | |
220 | ||
221 | /* Wrappers around the try_to_* functions that always succeed. */ | |
222 | void add_dest (const_rtx x, unsigned int flags = 0); | |
223 | void add_src (const_rtx x, unsigned int flags = 0); | |
224 | void add_pattern (const_rtx pat); | |
225 | void add_note (const_rtx x); | |
226 | void add_insn (const rtx_insn *insn, bool include_notes); | |
227 | }; | |
228 | ||
229 | template<typename Base> | |
230 | template<typename... Args> | |
231 | growing_rtx_properties<Base>::growing_rtx_properties (Args... args) | |
232 | : Base (std::forward<Args> (args)...) | |
233 | { | |
234 | } | |
235 | ||
236 | /* Perform ADD until there is enough room to hold the result. */ | |
237 | ||
238 | template<typename Base> | |
239 | template<typename AddFn> | |
240 | inline void | |
241 | growing_rtx_properties<Base>::repeat (AddFn add) | |
242 | { | |
243 | ptrdiff_t count = this->num_refs (); | |
244 | for (;;) | |
245 | { | |
246 | add (); | |
247 | /* This retries if the storage happened to be exactly the right size, | |
248 | but that's expected to be a rare case and so isn't worth | |
249 | optimizing for. */ | |
250 | if (__builtin_expect (this->ref_iter != this->ref_end, 1)) | |
251 | break; | |
252 | this->grow (count); | |
253 | } | |
254 | } | |
255 | ||
256 | template<typename Base> | |
257 | inline void | |
258 | growing_rtx_properties<Base>::add_dest (const_rtx x, unsigned int flags) | |
259 | { | |
260 | repeat ([&]() { this->try_to_add_dest (x, flags); }); | |
261 | } | |
262 | ||
263 | template<typename Base> | |
264 | inline void | |
265 | growing_rtx_properties<Base>::add_src (const_rtx x, unsigned int flags) | |
266 | { | |
267 | repeat ([&]() { this->try_to_add_src (x, flags); }); | |
268 | } | |
269 | ||
270 | template<typename Base> | |
271 | inline void | |
272 | growing_rtx_properties<Base>::add_pattern (const_rtx pat) | |
273 | { | |
274 | repeat ([&]() { this->try_to_add_pattern (pat); }); | |
275 | } | |
276 | ||
277 | template<typename Base> | |
278 | inline void | |
279 | growing_rtx_properties<Base>::add_note (const_rtx x) | |
280 | { | |
281 | repeat ([&]() { this->try_to_add_note (x); }); | |
282 | } | |
283 | ||
284 | template<typename Base> | |
285 | inline void | |
286 | growing_rtx_properties<Base>::add_insn (const rtx_insn *insn, bool include_notes) | |
287 | { | |
288 | repeat ([&]() { this->try_to_add_insn (insn, include_notes); }); | |
289 | } | |
290 | ||
291 | /* A base class for vec_rtx_properties; see there for details. */ | |
292 | ||
293 | class vec_rtx_properties_base : public rtx_properties | |
294 | { | |
295 | static const size_t SIZE = 32; | |
296 | ||
297 | public: | |
298 | vec_rtx_properties_base (); | |
299 | ~vec_rtx_properties_base (); | |
300 | ||
301 | protected: | |
302 | void grow (ptrdiff_t); | |
303 | ||
304 | private: | |
305 | rtx_obj_reference m_storage[SIZE]; | |
306 | }; | |
307 | ||
308 | inline vec_rtx_properties_base::vec_rtx_properties_base () | |
309 | { | |
310 | ref_begin = ref_iter = m_storage; | |
311 | ref_end = m_storage + SIZE; | |
312 | } | |
313 | ||
314 | inline vec_rtx_properties_base::~vec_rtx_properties_base () | |
315 | { | |
316 | if (__builtin_expect (ref_begin != m_storage, 0)) | |
317 | free (ref_begin); | |
318 | } | |
319 | ||
320 | /* A rtx_properties that stores its references in a temporary array. | |
321 | Like auto_vec, the array is initially on the stack, but can switch | |
322 | to the heap if necessary. | |
323 | ||
324 | The reason for implementing this as a derived class is that the | |
325 | default on-stack size should be enough for the vast majority of | |
326 | expressions and instructions. It's therefore not worth paying | |
327 | the cost of conditionally calling grow code at every site that | |
328 | records a new reference. Instead, the rtx_properties code can use | |
329 | trivial iterator updates for the common case, and in the rare case | |
330 | that the vector needs to be resized, we can pay the cost of | |
331 | collecting the references a second time. */ | |
332 | using vec_rtx_properties = growing_rtx_properties<vec_rtx_properties_base>; | |
333 | ||
63834c84 JW |
334 | bool |
335 | vec_series_highpart_p (machine_mode result_mode, machine_mode op_mode, | |
336 | rtx sel); | |
337 | ||
8695bf78 JW |
338 | bool |
339 | vec_series_lowpart_p (machine_mode result_mode, machine_mode op_mode, rtx sel); | |
340 | ||
04ee46ed | 341 | #endif |