1 /* Analyze RTL for GNU compiler.
2 Copyright (C) 2020-2023 Free Software Foundation, Inc.
4 This file is part of GCC.
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
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
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/>. */
20 /* Note that for historical reasons, many rtlanal.cc functions are
21 declared in rtl.h rather than here. */
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;
31 /* Bitmasks of flags describing an rtx_obj_reference. See the accessors
32 in the class for details. */
33 namespace rtx_obj_flags
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;
45 /* Flags that apply to all subrtxes of the rtx they were originally
47 static const uint16_t STICKY_FLAGS
= IN_NOTE
;
50 /* Contains information about a reference to a register or variable memory. */
51 class rtx_obj_reference
54 rtx_obj_reference () = default;
55 rtx_obj_reference (unsigned int regno
, uint16_t flags
,
56 machine_mode mode
, unsigned int multireg_offset
= 0);
58 bool is_reg () const { return regno
!= MEM_REGNO
; }
59 bool is_mem () const { return regno
== MEM_REGNO
; }
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
; }
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
; }
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
74 return flags
& rtx_obj_flags::IS_PRE_POST_MODIFY
;
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
; }
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
; }
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
; }
86 /* True if the reference occurs in any kind of MEM address. */
87 bool in_address () const { return in_mem_load () || in_mem_store (); }
89 /* True if the reference occurs in a SUBREG. */
90 bool in_subreg () const { return flags
& rtx_obj_flags::IN_SUBREG
; }
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
; }
95 /* The referenced register, or MEM_REGNO for variable memory. */
98 /* A bitmask of rtx_obj_flags. */
99 unsigned int flags
: 16;
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
;
105 /* If IS_MULTIREG, the offset of REGNO from the start of the register. */
106 unsigned int multireg_offset
: 8;
109 /* Construct a reference with the given fields. */
111 inline rtx_obj_reference::rtx_obj_reference (unsigned int regno
, uint16_t flags
,
113 unsigned int multireg_offset
)
117 multireg_offset (multireg_offset
)
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. */
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
);
137 iterator_range
<rtx_obj_reference
*> refs () const;
139 /* Return the number of rtx_obj_references that have been recorded. */
140 size_t num_refs () const { return ref_iter
- ref_begin
; }
142 bool has_side_effects () const;
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
;
150 /* True if the rtx includes an asm. */
151 unsigned int has_asm
: 1;
153 /* True if the rtx includes a call. */
154 unsigned int has_call
: 1;
156 /* True if the rtx includes an RTX_AUTOINC expression. */
157 unsigned int has_pre_post_modify
: 1;
159 /* True if the rtx contains volatile references, in the sense of
161 unsigned int has_volatile_refs
: 1;
163 /* For future expansion. */
164 unsigned int spare
: 28;
167 inline rtx_properties::rtx_properties ()
168 : ref_begin (nullptr),
173 has_pre_post_modify (false),
174 has_volatile_refs (false),
179 /* Like add_src, but treat X has being part of a REG_EQUAL or
183 rtx_properties::try_to_add_note (const_rtx x
)
185 try_to_add_src (x
, rtx_obj_flags::IN_NOTE
);
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). */
193 rtx_properties::has_side_effects () const
195 return has_volatile_refs
|| has_pre_post_modify
|| has_call
;
198 /* Return an iterator range for all the references, suitable for
199 range-based for loops. */
201 inline iterator_range
<rtx_obj_reference
*>
202 rtx_properties::refs () const
204 return { ref_begin
, ref_iter
};
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. */
211 template<typename Base
>
212 class growing_rtx_properties
: public Base
215 template<typename
... Args
>
216 growing_rtx_properties (Args
...);
218 template<typename AddFn
>
219 void repeat (AddFn add
);
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
);
229 template<typename Base
>
230 template<typename
... Args
>
231 growing_rtx_properties
<Base
>::growing_rtx_properties (Args
... args
)
232 : Base (std::forward
<Args
> (args
)...)
236 /* Perform ADD until there is enough room to hold the result. */
238 template<typename Base
>
239 template<typename AddFn
>
241 growing_rtx_properties
<Base
>::repeat (AddFn add
)
243 ptrdiff_t count
= this->num_refs ();
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
250 if (LIKELY (this->ref_iter
!= this->ref_end
))
256 template<typename Base
>
258 growing_rtx_properties
<Base
>::add_dest (const_rtx x
, unsigned int flags
)
260 repeat ([&]() { this->try_to_add_dest (x
, flags
); });
263 template<typename Base
>
265 growing_rtx_properties
<Base
>::add_src (const_rtx x
, unsigned int flags
)
267 repeat ([&]() { this->try_to_add_src (x
, flags
); });
270 template<typename Base
>
272 growing_rtx_properties
<Base
>::add_pattern (const_rtx pat
)
274 repeat ([&]() { this->try_to_add_pattern (pat
); });
277 template<typename Base
>
279 growing_rtx_properties
<Base
>::add_note (const_rtx x
)
281 repeat ([&]() { this->try_to_add_note (x
); });
284 template<typename Base
>
286 growing_rtx_properties
<Base
>::add_insn (const rtx_insn
*insn
, bool include_notes
)
288 repeat ([&]() { this->try_to_add_insn (insn
, include_notes
); });
291 /* A base class for vec_rtx_properties; see there for details. */
293 class vec_rtx_properties_base
: public rtx_properties
295 static const size_t SIZE
= 32;
298 vec_rtx_properties_base ();
299 ~vec_rtx_properties_base ();
302 void grow (ptrdiff_t);
305 rtx_obj_reference m_storage
[SIZE
];
308 inline vec_rtx_properties_base::vec_rtx_properties_base ()
310 ref_begin
= ref_iter
= m_storage
;
311 ref_end
= m_storage
+ SIZE
;
314 inline vec_rtx_properties_base::~vec_rtx_properties_base ()
316 if (UNLIKELY (ref_begin
!= m_storage
))
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.
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
>;
335 vec_series_highpart_p (machine_mode result_mode
, machine_mode op_mode
,
339 vec_series_lowpart_p (machine_mode result_mode
, machine_mode op_mode
, rtx sel
);