1 // Access-related utilities for RTL SSA -*- C++ -*-
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 namespace rtl_ssa {
21
22 // Return a referene to the whole of register REGNO.
23 inline resource_info
full_register(unsigned int regno)24 full_register (unsigned int regno)
25 {
26 return { GET_MODE (regno_reg_rtx[regno]), regno };
27 }
28
29 // Return true if sorted array ACCESSES includes an access to hard registers.
30 inline bool
accesses_include_hard_registers(const access_array & accesses)31 accesses_include_hard_registers (const access_array &accesses)
32 {
33 return accesses.size () && HARD_REGISTER_NUM_P (accesses.front ()->regno ());
34 }
35
36 // Return true if sorted array ACCESSES includes an access to memory.
37 inline bool
accesses_include_memory(const access_array & accesses)38 accesses_include_memory (const access_array &accesses)
39 {
40 return accesses.size () && accesses.back ()->is_mem ();
41 }
42
43 // If sorted array ACCESSES includes an access to memory, return the access,
44 // otherwise return null.
45 template<typename T>
46 inline auto
47 memory_access (T accesses) -> decltype (accesses[0])
48 {
49 if (accesses.size () && accesses.back ()->is_mem ())
50 return accesses.back ();
51 return nullptr;
52 }
53
54 // If sorted array ACCESSES includes a reference to REGNO, return the
55 // access, otherwise return null.
56 template<typename T>
57 inline auto
58 find_access (T accesses, unsigned int regno) -> decltype (accesses[0])
59 {
60 unsigned int start = 0;
61 unsigned int end = accesses.size ();
62 while (start < end)
63 {
64 unsigned int mid = (start + end) / 2;
65 unsigned int found = accesses[mid]->regno ();
66 if (found == regno)
67 return accesses[mid];
68 if (found < regno)
69 start = mid + 1;
70 else
71 end = mid;
72 }
73 return nullptr;
74 }
75
76 // If sorted array ACCESSES includes a reference to REGNO, return the
77 // index of the access, otherwise return -1.
78 inline int
find_access_index(access_array accesses,unsigned int regno)79 find_access_index (access_array accesses, unsigned int regno)
80 {
81 unsigned int start = 0;
82 unsigned int end = accesses.size ();
83 while (start < end)
84 {
85 unsigned int mid = (start + end) / 2;
86 unsigned int found = accesses[mid]->regno ();
87 if (found == regno)
88 return mid;
89 if (found < regno)
90 start = mid + 1;
91 else
92 end = mid;
93 }
94 return -1;
95 }
96
97 // If ACCESS is a set whose result is used by at least one instruction,
98 // return the access as a set_info, otherwise return null.
99 inline const set_info *
set_with_nondebug_insn_uses(const access_info * access)100 set_with_nondebug_insn_uses (const access_info *access)
101 {
102 if (access->is_set_with_nondebug_insn_uses ())
103 // No need for as_a; this test is just as definitive.
104 return static_cast<const set_info *> (access);
105 return nullptr;
106 }
107
108 // A non-const version of the above.
109 inline set_info *
set_with_nondebug_insn_uses(access_info * access)110 set_with_nondebug_insn_uses (access_info *access)
111 {
112 if (access->is_set_with_nondebug_insn_uses ())
113 return static_cast<set_info *> (access);
114 return nullptr;
115 }
116
117 // Return true if SET is the only set of SET->resource () and if it
118 // dominates all uses (excluding uses of SET->resource () at points
119 // where SET->resource () is always undefined).
120 inline bool
is_single_dominating_def(const set_info * set)121 is_single_dominating_def (const set_info *set)
122 {
123 return set->is_first_def () && set->is_last_def ();
124 }
125
126 // SET is known to be available on entry to BB. Return true if it is
127 // also available on exit from BB. (The value might or might not be live.)
128 inline bool
remains_available_on_exit(const set_info * set,bb_info * bb)129 remains_available_on_exit (const set_info *set, bb_info *bb)
130 {
131 return (set->is_last_def ()
132 || *set->next_def ()->insn () > *bb->end_insn ());
133 }
134
135 // ACCESS is known to be associated with an instruction rather than
136 // a phi node. Return which instruction that is.
137 inline insn_info *
access_insn(const access_info * access)138 access_insn (const access_info *access)
139 {
140 // In release builds this function reduces to a single pointer reference.
141 if (auto *def = dyn_cast<const def_info *> (access))
142 return def->insn ();
143 return as_a<const use_info *> (access)->insn ();
144 }
145
146 // If ACCESS records a use, return the value that it uses. If ACCESS records
147 // a set, return that set. If ACCESS records a clobber, return null.
148 inline const set_info *
access_value(const access_info * access)149 access_value (const access_info *access)
150 {
151 if (!access)
152 return nullptr;
153
154 if (auto *use = dyn_cast<const use_info *> (access))
155 return use->def ();
156
157 return dyn_cast<const set_info *> (access);
158 }
159
160 // A non-const version of the above.
161 inline set_info *
access_value(access_info * access)162 access_value (access_info *access)
163 {
164 auto *const_access = const_cast<const access_info *> (access);
165 return const_cast<set_info *> (access_value (const_access));
166 }
167
168 // If ACCESS is a degenerate phi, return the set_info that defines its input,
169 // otherwise return ACCESS itself.
170 template<typename T>
171 inline const T *
look_through_degenerate_phi(const T * access)172 look_through_degenerate_phi (const T *access)
173 {
174 if (auto *phi = dyn_cast<const phi_info *> (access))
175 if (phi->is_degenerate ())
176 return phi->input_value (0);
177 return access;
178 }
179
180 // A non-const version of the above.
181 template<typename T>
182 inline T *
look_through_degenerate_phi(T * access)183 look_through_degenerate_phi (T *access)
184 {
185 auto *const_access = const_cast<const T *> (access);
186 return const_cast<T *> (look_through_degenerate_phi (const_access));
187 }
188
189 // If CLOBBER is in a group, return the first clobber in the group,
190 // otherwise return CLOBBER itself.
191 inline clobber_info *
first_clobber_in_group(clobber_info * clobber)192 first_clobber_in_group (clobber_info *clobber)
193 {
194 if (clobber->is_in_group ())
195 return clobber->group ()->first_clobber ();
196 return clobber;
197 }
198
199 // If CLOBBER is in a group, return the last clobber in the group,
200 // otherwise return CLOBBER itself.
201 inline clobber_info *
last_clobber_in_group(clobber_info * clobber)202 last_clobber_in_group (clobber_info *clobber)
203 {
204 if (clobber->is_in_group ())
205 return clobber->group ()->last_clobber ();
206 return clobber;
207 }
208
209 // If DEF is a clobber in a group, return the containing group,
210 // otherwise return DEF.
211 inline def_mux
clobber_group_or_single_def(def_info * def)212 clobber_group_or_single_def (def_info *def)
213 {
214 if (auto *clobber = dyn_cast<clobber_info *> (def))
215 if (clobber->is_in_group ())
216 return clobber->group ();
217 return def;
218 }
219
220 // Return the first definition associated with NODE. If NODE holds
221 // a single set, the result is that set. If NODE holds a clobber_group,
222 // the result is the first clobber in the group.
223 inline def_info *
first_def(def_node * node)224 first_def (def_node *node)
225 {
226 return node->first_def ();
227 }
228
229 // Likewise for something that is either a node or a single definition.
230 inline def_info *
first_def(def_mux mux)231 first_def (def_mux mux)
232 {
233 return mux.first_def ();
234 }
235
236 // Return the last definition associated with NODE. If NODE holds
237 // a single set, the result is that set. If NODE holds a clobber_group,
238 // the result is the last clobber in the group.
239 inline def_info *
last_def(def_node * node)240 last_def (def_node *node)
241 {
242 if (auto *group = dyn_cast<clobber_group *> (node))
243 return group->last_clobber ();
244 return node->first_def ();
245 }
246
247 // Likewise for something that is either a node or a single definition.
248 inline def_info *
last_def(def_mux mux)249 last_def (def_mux mux)
250 {
251 return mux.last_def ();
252 }
253
254 int lookup_use (splay_tree<use_info *> &, insn_info *);
255 int lookup_def (def_splay_tree &, insn_info *);
256 int lookup_clobber (clobber_tree &, insn_info *);
257 int lookup_call_clobbers (insn_call_clobbers_tree &, insn_info *);
258
259 // Search backwards from immediately before INSN for the first instruction
260 // recorded in TREE, ignoring any instruction I for which IGNORE (I) is true.
261 // Return null if no such instruction exists.
262 template<typename IgnorePredicate>
263 insn_info *
prev_call_clobbers_ignoring(insn_call_clobbers_tree & tree,insn_info * insn,IgnorePredicate ignore)264 prev_call_clobbers_ignoring (insn_call_clobbers_tree &tree, insn_info *insn,
265 IgnorePredicate ignore)
266 {
267 if (!tree)
268 return nullptr;
269
270 int comparison = lookup_call_clobbers (tree, insn);
271 while (comparison <= 0 || ignore (tree->insn ()))
272 {
273 if (!tree.splay_prev_node ())
274 return nullptr;
275
276 comparison = 1;
277 }
278 return tree->insn ();
279 }
280
281 // Search forwards from immediately after INSN for the first instruction
282 // recorded in TREE, ignoring any instruction I for which IGNORE (I) is true.
283 // Return null if no such instruction exists.
284 template<typename IgnorePredicate>
285 insn_info *
next_call_clobbers_ignoring(insn_call_clobbers_tree & tree,insn_info * insn,IgnorePredicate ignore)286 next_call_clobbers_ignoring (insn_call_clobbers_tree &tree, insn_info *insn,
287 IgnorePredicate ignore)
288 {
289 if (!tree)
290 return nullptr;
291
292 int comparison = lookup_call_clobbers (tree, insn);
293 while (comparison >= 0 || ignore (tree->insn ()))
294 {
295 if (!tree.splay_next_node ())
296 return nullptr;
297
298 comparison = -1;
299 }
300 return tree->insn ();
301 }
302
303 // If ACCESS is a set, return the first use of ACCESS by a nondebug insn I
304 // for which IGNORE (I) is false. Return null if ACCESS is not a set or if
305 // no such use exists.
306 template<typename IgnorePredicate>
307 inline use_info *
first_nondebug_insn_use_ignoring(const access_info * access,IgnorePredicate ignore)308 first_nondebug_insn_use_ignoring (const access_info *access,
309 IgnorePredicate ignore)
310 {
311 if (const set_info *set = set_with_nondebug_insn_uses (access))
312 {
313 // Written this way to emphasize to the compiler that first_use
314 // must be nonnull in this situation.
315 use_info *use = set->first_use ();
316 do
317 {
318 if (!ignore (use->insn ()))
319 return use;
320 use = use->next_nondebug_insn_use ();
321 }
322 while (use);
323 }
324 return nullptr;
325 }
326
327 // If ACCESS is a set, return the last use of ACCESS by a nondebug insn I for
328 // which IGNORE (I) is false. Return null if ACCESS is not a set or if no
329 // such use exists.
330 template<typename IgnorePredicate>
331 inline use_info *
last_nondebug_insn_use_ignoring(const access_info * access,IgnorePredicate ignore)332 last_nondebug_insn_use_ignoring (const access_info *access,
333 IgnorePredicate ignore)
334 {
335 if (const set_info *set = set_with_nondebug_insn_uses (access))
336 {
337 // Written this way to emphasize to the compiler that
338 // last_nondebug_insn_use must be nonnull in this situation.
339 use_info *use = set->last_nondebug_insn_use ();
340 do
341 {
342 if (!ignore (use->insn ()))
343 return use;
344 use = use->prev_use ();
345 }
346 while (use);
347 }
348 return nullptr;
349 }
350
351 // If DEF is null, return null.
352 //
353 // Otherwise, search backwards for an access to DEF->resource (), starting at
354 // the end of DEF's live range. Ignore clobbers if IGNORE_CLOBBERS_SETTING
355 // is YES, otherwise treat them like any other access. Also ignore any
356 // access A for which IGNORE (access_insn (A)) is true.
357 //
358 // Thus if DEF is a set that is used by nondebug insns, the first access
359 // that the function considers is the last such use of the set. Otherwise,
360 // the first access that the function considers is DEF itself.
361 //
362 // Return the access found, or null if there is no access that meets
363 // the criteria.
364 //
365 // Note that this function does not consider separately-recorded call clobbers,
366 // although such clobbers are only relevant if IGNORE_CLOBBERS_SETTING is NO.
367 template<typename IgnorePredicate>
368 access_info *
last_access_ignoring(def_info * def,ignore_clobbers ignore_clobbers_setting,IgnorePredicate ignore)369 last_access_ignoring (def_info *def, ignore_clobbers ignore_clobbers_setting,
370 IgnorePredicate ignore)
371 {
372 while (def)
373 {
374 auto *clobber = dyn_cast<clobber_info *> (def);
375 if (clobber && ignore_clobbers_setting == ignore_clobbers::YES)
376 def = first_clobber_in_group (clobber);
377 else
378 {
379 if (use_info *use = last_nondebug_insn_use_ignoring (def, ignore))
380 return use;
381
382 insn_info *insn = def->insn ();
383 if (!ignore (insn))
384 return def;
385 }
386 def = def->prev_def ();
387 }
388 return nullptr;
389 }
390
391 // Search backwards for an access to DEF->resource (), starting
392 // immediately before the point at which DEF occurs. Ignore clobbers
393 // if IGNORE_CLOBBERS_SETTING is YES, otherwise treat them like any other
394 // access. Also ignore any access A for which IGNORE (access_insn (A))
395 // is true.
396 //
397 // Thus if DEF->insn () uses DEF->resource (), that use is the first access
398 // that the function considers, since an instruction's uses occur strictly
399 // before its definitions.
400 //
401 // Note that this function does not consider separately-recorded call clobbers,
402 // although such clobbers are only relevant if IGNORE_CLOBBERS_SETTING is NO.
403 template<typename IgnorePredicate>
404 inline access_info *
prev_access_ignoring(def_info * def,ignore_clobbers ignore_clobbers_setting,IgnorePredicate ignore)405 prev_access_ignoring (def_info *def, ignore_clobbers ignore_clobbers_setting,
406 IgnorePredicate ignore)
407 {
408 return last_access_ignoring (def->prev_def (), ignore_clobbers_setting,
409 ignore);
410 }
411
412 // If DEF is null, return null.
413 //
414 // Otherwise, search forwards for a definition of DEF->resource (),
415 // starting at DEF itself. Ignore clobbers if IGNORE_CLOBBERS_SETTING
416 // is YES, otherwise treat them like any other access. Also ignore any
417 // definition D for which IGNORE (D->insn ()) is true.
418 //
419 // Return the definition found, or null if there is no access that meets
420 // the criteria.
421 //
422 // Note that this function does not consider separately-recorded call clobbers,
423 // although such clobbers are only relevant if IGNORE_CLOBBERS_SETTING is NO.
424 template<typename IgnorePredicate>
425 def_info *
first_def_ignoring(def_info * def,ignore_clobbers ignore_clobbers_setting,IgnorePredicate ignore)426 first_def_ignoring (def_info *def, ignore_clobbers ignore_clobbers_setting,
427 IgnorePredicate ignore)
428 {
429 while (def)
430 {
431 auto *clobber = dyn_cast<clobber_info *> (def);
432 if (clobber && ignore_clobbers_setting == ignore_clobbers::YES)
433 def = last_clobber_in_group (clobber);
434 else if (!ignore (def->insn ()))
435 return def;
436
437 def = def->next_def ();
438 }
439 return nullptr;
440 }
441
442 // Search forwards for the next access to DEF->resource (),
443 // starting immediately after DEF's instruction. Ignore clobbers if
444 // IGNORE_CLOBBERS_SETTING is YES, otherwise treat them like any other access.
445 // Also ignore any access A for which IGNORE (access_insn (A)) is true;
446 // in this context, ignoring a set includes ignoring all uses of the set.
447 //
448 // Thus if DEF is a set with uses by nondebug insns, the first access that the
449 // function considers is the first such use of the set.
450 //
451 // Return the access found, or null if there is no access that meets the
452 // criteria.
453 //
454 // Note that this function does not consider separately-recorded call clobbers,
455 // although such clobbers are only relevant if IGNORE_CLOBBERS_SETTING is NO.
456 template<typename IgnorePredicate>
457 access_info *
next_access_ignoring(def_info * def,ignore_clobbers ignore_clobbers_setting,IgnorePredicate ignore)458 next_access_ignoring (def_info *def, ignore_clobbers ignore_clobbers_setting,
459 IgnorePredicate ignore)
460 {
461 if (use_info *use = first_nondebug_insn_use_ignoring (def, ignore))
462 return use;
463
464 return first_def_ignoring (def->next_def (), ignore_clobbers_setting,
465 ignore);
466 }
467
468 // Return true if ACCESS1 should before ACCESS2 in an access_array.
469 inline bool
compare_access_infos(const access_info * access1,const access_info * access2)470 compare_access_infos (const access_info *access1, const access_info *access2)
471 {
472 gcc_checking_assert (access1 == access2
473 || access1->regno () != access2->regno ());
474 return access1->regno () < access2->regno ();
475 }
476
477 // Sort [BEGIN, END) into ascending regno order. The sequence must have
478 // at most one access to a given a regno.
479 inline void
sort_accesses(access_info ** begin,access_info ** end)480 sort_accesses (access_info **begin, access_info **end)
481 {
482 auto count = end - begin;
483 if (count <= 1)
484 return;
485
486 if (count == 2)
487 {
488 gcc_checking_assert (begin[0]->regno () != begin[1]->regno ());
489 if (begin[0]->regno () > begin[1]->regno ())
490 std::swap (begin[0], begin[1]);
491 return;
492 }
493
494 std::sort (begin, end, compare_access_infos);
495 }
496
497 // Sort the accesses in CONTAINER, which contains pointers to access_infos.
498 template<typename T>
499 inline void
sort_accesses(T & container)500 sort_accesses (T &container)
501 {
502 return sort_accesses (container.begin (), container.end ());
503 }
504
505 // The underlying non-template implementation of merge_access_arrays.
506 access_array merge_access_arrays_base (obstack_watermark &, access_array,
507 access_array);
508 // Merge access arrays ACCESSES1 and ACCESSES2, including the allocation
509 // in the area governed by WATERMARK. Return an invalid access_array if
510 // ACCESSES1 and ACCESSES2 contain conflicting accesses to the same resource.
511 //
512 // T can be an access_array, a def_array or a use_array.
513 template<typename T>
514 inline T
merge_access_arrays(obstack_watermark & watermark,T accesses1,T accesses2)515 merge_access_arrays (obstack_watermark &watermark, T accesses1, T accesses2)
516 {
517 return T (merge_access_arrays_base (watermark, accesses1, accesses2));
518 }
519
520 // The underlying non-template implementation of insert_access.
521 access_array insert_access_base (obstack_watermark &, access_info *,
522 access_array);
523
524 // Return a new access_array that contains the result of inserting ACCESS1
525 // into sorted access array ACCESSES2. Allocate the returned array in the
526 // area governed by WATERMARK. Return an invalid access_array if ACCESSES2
527 // contains a conflicting access to the same resource as ACCESS1.
528 //
529 // T can be an access_array, a def_array or a use_array.
530 template<typename T>
531 inline T
insert_access(obstack_watermark & watermark,typename T::value_type access1,T accesses2)532 insert_access (obstack_watermark &watermark,
533 typename T::value_type access1, T accesses2)
534 {
535 return T (insert_access_base (watermark, access1, accesses2));
536 }
537
538 // The underlying non-template implementation of remove_note_accesses.
539 access_array remove_note_accesses_base (obstack_watermark &, access_array);
540
541 // If ACCESSES contains accesses that only occur in notes, return a new
542 // array without such accesses, allocating it in the area governed by
543 // WATERMARK. Return ACCESSES itself otherwise.
544 //
545 // T can be an access_array, a def_array or a use_array.
546 template<typename T>
547 inline T
remove_note_accesses(obstack_watermark & watermark,T accesses)548 remove_note_accesses (obstack_watermark &watermark, T accesses)
549 {
550 return T (remove_note_accesses_base (watermark, accesses));
551 }
552
553 }
554