Branch data Line data Source code
1 : : /* Analyze RTL for GNU compiler.
2 : : Copyright (C) 2020-2024 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 : 37730107 : 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 : 877655268 : bool is_read () const { return flags & rtx_obj_flags::IS_READ; }
65 : 1014628744 : 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 : 4612 : 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 : 257005288 : bool is_pre_post_modify () const
73 : : {
74 : 257005288 : 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 : 650984052 : 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 : 359298469 : 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 : 393978764 : bool in_address () const { return in_mem_load () || in_mem_store (); }
88 : :
89 : : /* True if the reference occurs in a SUBREG. */
90 : 650984052 : 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 : 393978764 : 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 : 112459544 : 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 : 12616 : mode (mode),
117 : 508622577 : 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 : 392553267 : 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 : 392553267 : inline rtx_properties::rtx_properties ()
168 : : : ref_begin (nullptr),
169 : : ref_iter (nullptr),
170 : : ref_end (nullptr),
171 : 392553267 : has_asm (false),
172 : 392553267 : has_call (false),
173 : 392553267 : has_pre_post_modify (false),
174 : 392553267 : has_volatile_refs (false),
175 : 392553267 : 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 : 15689276 : rtx_properties::try_to_add_note (const_rtx x)
184 : : {
185 : 15689276 : try_to_add_src (x, rtx_obj_flags::IN_NOTE);
186 : 15689276 : }
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 : 39 : rtx_properties::has_side_effects () const
194 : : {
195 : 39 : 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 : 785106481 : rtx_properties::refs () const
203 : : {
204 : 785106481 : 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 : 785106488 : 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 : 392553267 : growing_rtx_properties<Base>::growing_rtx_properties (Args... args)
232 : 392553267 : : 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 : 392553267 : growing_rtx_properties<Base>::repeat (AddFn add)
242 : : {
243 : 392553267 : ptrdiff_t count = this->num_refs ();
244 : 12573 : for (;;)
245 : : {
246 : 392565840 : 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 : 392565840 : if (LIKELY (this->ref_iter != this->ref_end))
251 : : break;
252 : 12573 : this->grow (count);
253 : : }
254 : 392553267 : }
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 : 392553267 : growing_rtx_properties<Base>::add_insn (const rtx_insn *insn, bool include_notes)
287 : : {
288 : 785119107 : 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 : 392553267 : inline vec_rtx_properties_base::vec_rtx_properties_base ()
309 : : {
310 : 392553267 : ref_begin = ref_iter = m_storage;
311 : 392553267 : ref_end = m_storage + SIZE;
312 : : }
313 : :
314 : 392553267 : inline vec_rtx_properties_base::~vec_rtx_properties_base ()
315 : : {
316 : 392553267 : if (UNLIKELY (ref_begin != m_storage))
317 : 10284 : 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
|