Line data Source code
1 : /* Analyze RTL for GNU compiler.
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 : /* Note that for historical reasons, many rtlanal.cc 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 68604161 : 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 1412242525 : bool is_read () const { return flags & rtx_obj_flags::IS_READ; }
65 1648453753 : 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 13078248 : 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 461021675 : bool is_pre_post_modify () const
73 : {
74 461021675 : 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 1059901908 : 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 585648422 : 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 648233987 : bool in_address () const { return in_mem_load () || in_mem_store (); }
88 :
89 : /* True if the reference occurs in a SUBREG. */
90 1059901908 : 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 648056568 : 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 : MACHINE_MODE_BITSIZE;
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 213055791 : 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 18500 : mode (mode),
117 837862244 : 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 673995793 : 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 673995793 : inline rtx_properties::rtx_properties ()
168 : : ref_begin (nullptr),
169 : ref_iter (nullptr),
170 : ref_end (nullptr),
171 673995793 : has_asm (false),
172 673995793 : has_call (false),
173 673995793 : has_pre_post_modify (false),
174 673995793 : has_volatile_refs (false),
175 673995793 : 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 22399230 : rtx_properties::try_to_add_note (const_rtx x)
184 : {
185 22399230 : try_to_add_src (x, rtx_obj_flags::IN_NOTE);
186 22399230 : }
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.cc clobbers). */
191 :
192 : inline bool
193 370 : rtx_properties::has_side_effects () const
194 : {
195 370 : 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 1330741077 : rtx_properties::refs () const
203 : {
204 1330741077 : 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 1293788477 : 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 673995793 : growing_rtx_properties<Base>::growing_rtx_properties (Args... args)
232 673995793 : : 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 673995793 : growing_rtx_properties<Base>::repeat (AddFn add)
242 : {
243 673995793 : ptrdiff_t count = this->num_refs ();
244 28516 : for (;;)
245 : {
246 674024309 : 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 674024309 : if (LIKELY (this->ref_iter != this->ref_end))
251 : break;
252 28516 : this->grow (count);
253 : }
254 673995793 : }
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 17250059 : growing_rtx_properties<Base>::add_pattern (const_rtx pat)
273 : {
274 34500273 : 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 656745734 : growing_rtx_properties<Base>::add_insn (const rtx_insn *insn, bool include_notes)
287 : {
288 1313519829 : 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 673995793 : inline vec_rtx_properties_base::vec_rtx_properties_base ()
309 : {
310 673995793 : ref_begin = ref_iter = m_storage;
311 673995793 : ref_end = m_storage + SIZE;
312 : }
313 :
314 673995793 : inline vec_rtx_properties_base::~vec_rtx_properties_base ()
315 : {
316 673995793 : if (UNLIKELY (ref_begin != m_storage))
317 24416 : 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 :
334 : bool
335 : vec_series_highpart_p (machine_mode result_mode, machine_mode op_mode,
336 : rtx sel);
337 :
338 : bool
339 : vec_series_lowpart_p (machine_mode result_mode, machine_mode op_mode, rtx sel);
340 :
341 : bool
342 : contains_paradoxical_subreg_p (rtx x);
343 : #endif
|