xref: /netbsd-src/external/gpl3/gcc/dist/gcc/rtlanal.h (revision 0a3071956a3a9fdebdbf7f338cf2d439b45fc728)
1 /* Analyze RTL for GNU compiler.
2    Copyright (C) 2020-2022 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 
is_reg()58   bool is_reg () const { return regno != MEM_REGNO; }
is_mem()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.  */
is_read()64   bool is_read () const { return flags & rtx_obj_flags::IS_READ; }
is_write()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.  */
is_clobber()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.  */
is_pre_post_modify()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.  */
is_multireg()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.  */
in_mem_load()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.  */
in_mem_store()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.  */
in_address()87   bool in_address () const { return in_mem_load () || in_mem_store (); }
88 
89   /* True if the reference occurs in a SUBREG.  */
in_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.  */
in_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 
rtx_obj_reference(unsigned int regno,uint16_t flags,machine_mode mode,unsigned int multireg_offset)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.  */
num_refs()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 
rtx_properties()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
try_to_add_note(const_rtx x)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.cc clobbers).  */
191 
192 inline bool
has_side_effects()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 *>
refs()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>
growing_rtx_properties(Args...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
repeat(AddFn add)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
add_dest(const_rtx x,unsigned int flags)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
add_src(const_rtx x,unsigned int flags)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
add_pattern(const_rtx pat)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
add_note(const_rtx x)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
add_insn(const rtx_insn * insn,bool include_notes)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 
vec_rtx_properties_base()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 
~vec_rtx_properties_base()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 
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
344