analyzer: fix feasibility false +ve on jumps through function ptrs [PR107582]
[platform/upstream/gcc.git] / gcc / rtlanal.h
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
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.cc 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 (LIKELY (this->ref_iter != this->ref_end))
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 (UNLIKELY (ref_begin != m_storage))
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 #endif