1 | // Implementation of public inline member functions for RTL SSA -*- C++ -*- |
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 | // This file contains inline implementations of public member functions that |
21 | // are too large to be written in the class definition. It also contains |
22 | // some non-inline template definitions of public member functions. |
23 | // See the comments above the function declarations for details. |
24 | // |
25 | // The file also contains the bare minimum of private and protected inline |
26 | // member functions that are needed to make the public functions compile. |
27 | namespace rtl_ssa { |
28 | |
29 | inline void |
30 | access_array_builder::reserve (unsigned int num_accesses) |
31 | { |
32 | obstack_make_room (m_obstack, num_accesses * sizeof (access_info *)); |
33 | } |
34 | |
35 | inline void |
36 | access_array_builder::quick_push (access_info *access) |
37 | { |
38 | obstack_ptr_grow_fast (m_obstack, access); |
39 | } |
40 | |
41 | inline array_slice<access_info *> |
42 | access_array_builder::finish () |
43 | { |
44 | auto num_accesses = obstack_object_size (m_obstack) / sizeof (access_info *); |
45 | if (num_accesses == 0) |
46 | return {}; |
47 | |
48 | auto **base = static_cast<access_info **> (obstack_finish (m_obstack)); |
49 | keep (); |
50 | return { base, num_accesses }; |
51 | } |
52 | |
53 | inline bool |
54 | access_info::is_set_with_nondebug_insn_uses () const |
55 | { |
56 | return m_is_set_with_nondebug_insn_uses; |
57 | } |
58 | |
59 | inline bool |
60 | use_info::is_in_debug_insn () const |
61 | { |
62 | return m_insn_or_phi.is_first () && m_is_in_debug_insn_or_phi; |
63 | } |
64 | |
65 | inline bb_info * |
66 | use_info::bb () const |
67 | { |
68 | if (m_insn_or_phi.is_first ()) |
69 | return m_insn_or_phi.known_first ()->bb (); |
70 | return m_insn_or_phi.known_second ()->bb (); |
71 | } |
72 | |
73 | inline ebb_info * |
74 | use_info::ebb () const |
75 | { |
76 | return bb ()->ebb (); |
77 | } |
78 | |
79 | inline use_info * |
80 | use_info::prev_use () const |
81 | { |
82 | return m_last_use_or_prev_use.second_or_null (); |
83 | } |
84 | |
85 | inline use_info * |
86 | use_info::next_use () const |
87 | { |
88 | return m_last_nondebug_insn_use_or_next_use.second_or_null (); |
89 | } |
90 | |
91 | inline bool |
92 | use_info::is_first_use () const |
93 | { |
94 | return m_last_use_or_prev_use.is_first (); |
95 | } |
96 | |
97 | inline bool |
98 | use_info::is_last_use () const |
99 | { |
100 | return m_last_nondebug_insn_use_or_next_use.is_first (); |
101 | } |
102 | |
103 | inline use_info * |
104 | use_info::next_nondebug_insn_use () const |
105 | { |
106 | if (m_is_last_nondebug_insn_use) |
107 | return nullptr; |
108 | return m_last_nondebug_insn_use_or_next_use.known_second (); |
109 | } |
110 | |
111 | inline use_info * |
112 | use_info::next_any_insn_use () const |
113 | { |
114 | // This is used less often than next_nondebug_insn_use, so it doesn't |
115 | // seem worth having an m_is_last_nondebug_insn_use-style end marker. |
116 | if (use_info *use = next_use ()) |
117 | if (use->is_in_any_insn ()) |
118 | return use; |
119 | return nullptr; |
120 | } |
121 | |
122 | inline use_info * |
123 | use_info::next_debug_insn_use () const |
124 | { |
125 | if (auto use = next_use ()) |
126 | if (use->is_in_debug_insn ()) |
127 | return use; |
128 | return nullptr; |
129 | } |
130 | |
131 | inline use_info * |
132 | use_info::prev_phi_use () const |
133 | { |
134 | // This is used less often than next_nondebug_insn_use, so it doesn't |
135 | // seem worth having an m_is_last_nondebug_insn_use-style end marker. |
136 | if (use_info *use = prev_use ()) |
137 | if (use->is_in_phi ()) |
138 | return use; |
139 | return nullptr; |
140 | } |
141 | |
142 | // Return the last use of any kind in the list. Only valid when is_first () |
143 | // is true. |
144 | inline use_info * |
145 | use_info::last_use () const |
146 | { |
147 | return m_last_use_or_prev_use.known_first (); |
148 | } |
149 | |
150 | // Return the last nondebug insn use in the list, or null if none. Only valid |
151 | // when is_last_use () is true. |
152 | inline use_info * |
153 | use_info::last_nondebug_insn_use () const |
154 | { |
155 | return m_last_nondebug_insn_use_or_next_use.known_first (); |
156 | } |
157 | |
158 | inline def_info * |
159 | def_info::prev_def () const |
160 | { |
161 | return m_last_def_or_prev_def.second_or_null (); |
162 | } |
163 | |
164 | inline def_info * |
165 | def_info::next_def () const |
166 | { |
167 | return m_splay_root_or_next_def.second_or_null (); |
168 | } |
169 | |
170 | inline bool |
171 | def_info::is_first_def () const |
172 | { |
173 | return m_last_def_or_prev_def.is_first (); |
174 | } |
175 | |
176 | inline bool |
177 | def_info::is_last_def () const |
178 | { |
179 | return m_splay_root_or_next_def.is_first (); |
180 | } |
181 | |
182 | inline bb_info * |
183 | def_info::bb () const |
184 | { |
185 | return m_insn->bb (); |
186 | } |
187 | |
188 | inline ebb_info * |
189 | def_info::ebb () const |
190 | { |
191 | return m_insn->ebb (); |
192 | } |
193 | |
194 | inline clobber_group * |
195 | clobber_info::group () const |
196 | { |
197 | if (!m_group || !m_group->has_been_superceded ()) |
198 | return m_group; |
199 | return const_cast<clobber_info *> (this)->recompute_group (); |
200 | } |
201 | |
202 | inline use_info * |
203 | set_info::last_use () const |
204 | { |
205 | return m_first_use ? m_first_use->last_use () : nullptr; |
206 | } |
207 | |
208 | inline use_info * |
209 | set_info::first_nondebug_insn_use () const |
210 | { |
211 | if (m_is_set_with_nondebug_insn_uses) |
212 | return m_first_use; |
213 | return nullptr; |
214 | } |
215 | |
216 | inline use_info * |
217 | set_info::last_nondebug_insn_use () const |
218 | { |
219 | if (m_is_set_with_nondebug_insn_uses) |
220 | return m_first_use->last_use ()->last_nondebug_insn_use (); |
221 | return nullptr; |
222 | } |
223 | |
224 | inline use_info * |
225 | set_info::first_debug_insn_use () const |
226 | { |
227 | use_info *use; |
228 | if (has_nondebug_insn_uses ()) |
229 | use = last_nondebug_insn_use ()->next_use (); |
230 | else |
231 | use = first_use (); |
232 | |
233 | if (use && use->is_in_debug_insn ()) |
234 | return use; |
235 | return nullptr; |
236 | } |
237 | |
238 | inline use_info * |
239 | set_info::first_any_insn_use () const |
240 | { |
241 | if (m_first_use && m_first_use->is_in_any_insn ()) |
242 | return m_first_use; |
243 | return nullptr; |
244 | } |
245 | |
246 | inline use_info * |
247 | set_info::last_phi_use () const |
248 | { |
249 | if (m_first_use) |
250 | { |
251 | use_info *last = m_first_use->last_use (); |
252 | if (last->is_in_phi ()) |
253 | return last; |
254 | } |
255 | return nullptr; |
256 | } |
257 | |
258 | inline bool |
259 | set_info::has_nondebug_uses () const |
260 | { |
261 | return has_nondebug_insn_uses () || has_phi_uses (); |
262 | } |
263 | |
264 | inline bool |
265 | set_info::has_nondebug_insn_uses () const |
266 | { |
267 | return m_is_set_with_nondebug_insn_uses; |
268 | } |
269 | |
270 | inline bool |
271 | set_info::has_phi_uses () const |
272 | { |
273 | return m_first_use && m_first_use->last_use ()->is_in_phi (); |
274 | } |
275 | |
276 | inline use_info * |
277 | set_info::single_nondebug_use () const |
278 | { |
279 | if (!has_phi_uses ()) |
280 | return single_nondebug_insn_use (); |
281 | if (!has_nondebug_insn_uses ()) |
282 | return single_phi_use (); |
283 | return nullptr; |
284 | } |
285 | |
286 | inline use_info * |
287 | set_info::single_nondebug_insn_use () const |
288 | { |
289 | use_info *first = first_nondebug_insn_use (); |
290 | if (first && !first->next_nondebug_insn_use ()) |
291 | return first; |
292 | return nullptr; |
293 | } |
294 | |
295 | inline use_info * |
296 | set_info::single_phi_use () const |
297 | { |
298 | use_info *last = last_phi_use (); |
299 | if (last && !last->prev_phi_use ()) |
300 | return last; |
301 | return nullptr; |
302 | } |
303 | |
304 | inline bool |
305 | set_info::is_local_to_ebb () const |
306 | { |
307 | if (!m_first_use) |
308 | return true; |
309 | |
310 | use_info *last = m_first_use->last_use (); |
311 | if (last->is_in_phi ()) |
312 | return false; |
313 | |
314 | last = last->last_nondebug_insn_use (); |
315 | return !last || last->ebb () == ebb (); |
316 | } |
317 | |
318 | inline iterator_range<use_iterator> |
319 | set_info::all_uses () const |
320 | { |
321 | return { m_first_use, nullptr }; |
322 | } |
323 | |
324 | inline iterator_range<reverse_use_iterator> |
325 | set_info::reverse_all_uses () const |
326 | { |
327 | return { last_use (), nullptr }; |
328 | } |
329 | |
330 | inline iterator_range<nondebug_insn_use_iterator> |
331 | set_info::nondebug_insn_uses () const |
332 | { |
333 | return { first_nondebug_insn_use (), nullptr }; |
334 | } |
335 | |
336 | inline iterator_range<debug_insn_use_iterator> |
337 | set_info::debug_insn_uses () const |
338 | { |
339 | return { first_debug_insn_use (), nullptr }; |
340 | } |
341 | |
342 | inline iterator_range<reverse_use_iterator> |
343 | set_info::reverse_nondebug_insn_uses () const |
344 | { |
345 | return { last_nondebug_insn_use (), nullptr }; |
346 | } |
347 | |
348 | inline iterator_range<any_insn_use_iterator> |
349 | set_info::all_insn_uses () const |
350 | { |
351 | return { first_any_insn_use (), nullptr }; |
352 | } |
353 | |
354 | inline iterator_range<phi_use_iterator> |
355 | set_info::phi_uses () const |
356 | { |
357 | return { last_phi_use (), nullptr }; |
358 | } |
359 | |
360 | inline use_array |
361 | phi_info::inputs () const |
362 | { |
363 | if (m_num_inputs == 1) |
364 | return use_array (&m_single_input, 1); |
365 | return use_array (m_inputs, m_num_inputs); |
366 | } |
367 | |
368 | inline use_info * |
369 | phi_info::input_use (unsigned int i) const |
370 | { |
371 | if (m_num_inputs == 1) |
372 | return as_a<use_info *> (p: m_single_input); |
373 | return as_a<use_info *> (p: m_inputs[i]); |
374 | } |
375 | |
376 | inline set_info * |
377 | phi_info::input_value (unsigned int i) const |
378 | { |
379 | return input_use (i)->def (); |
380 | } |
381 | |
382 | inline def_info * |
383 | def_node::first_def () const |
384 | { |
385 | // This should get optimized into an AND with -2. |
386 | if (m_clobber_or_set.is_first ()) |
387 | return m_clobber_or_set.known_first (); |
388 | return m_clobber_or_set.known_second (); |
389 | } |
390 | |
391 | inline clobber_info * |
392 | clobber_group::first_clobber () const |
393 | { |
394 | return m_clobber_or_set.known_first (); |
395 | } |
396 | |
397 | inline iterator_range<def_iterator> |
398 | clobber_group::clobbers () const |
399 | { |
400 | return { first_clobber (), m_last_clobber->next_def () }; |
401 | } |
402 | |
403 | inline def_info * |
404 | def_mux::first_def () const |
405 | { |
406 | if (is_first ()) |
407 | return known_first (); |
408 | return known_second ()->first_def (); |
409 | } |
410 | |
411 | inline def_info * |
412 | def_mux::last_def () const |
413 | { |
414 | if (is_first ()) |
415 | return known_first (); |
416 | |
417 | def_node *node = known_second (); |
418 | if (auto *clobber = ::dyn_cast<clobber_group *> (p: node)) |
419 | return clobber->last_clobber (); |
420 | |
421 | return node->first_def (); |
422 | } |
423 | |
424 | inline set_info * |
425 | def_mux::set () const |
426 | { |
427 | if (is_first ()) |
428 | return ::safe_dyn_cast<set_info *> (p: known_first ()); |
429 | return ::dyn_cast<set_info *> (p: known_second ()->first_def ()); |
430 | } |
431 | |
432 | inline def_info * |
433 | def_lookup::last_def_of_prev_group () const |
434 | { |
435 | if (!mux) |
436 | return nullptr; |
437 | |
438 | if (comparison > 0) |
439 | return mux.last_def (); |
440 | |
441 | return mux.first_def ()->prev_def (); |
442 | } |
443 | |
444 | inline def_info * |
445 | def_lookup::first_def_of_next_group () const |
446 | { |
447 | if (!mux) |
448 | return nullptr; |
449 | |
450 | if (comparison < 0) |
451 | return mux.first_def (); |
452 | |
453 | return mux.last_def ()->next_def (); |
454 | } |
455 | |
456 | inline set_info * |
457 | def_lookup::matching_set () const |
458 | { |
459 | if (comparison == 0) |
460 | return mux.set (); |
461 | return nullptr; |
462 | } |
463 | |
464 | inline def_info * |
465 | def_lookup::matching_set_or_last_def_of_prev_group () const |
466 | { |
467 | if (set_info *set = matching_set ()) |
468 | return set; |
469 | return last_def_of_prev_group (); |
470 | } |
471 | |
472 | inline def_info * |
473 | def_lookup::matching_set_or_first_def_of_next_group () const |
474 | { |
475 | if (set_info *set = matching_set ()) |
476 | return set; |
477 | return first_def_of_next_group (); |
478 | } |
479 | |
480 | inline insn_note::insn_note (insn_note_kind kind) |
481 | : m_next_note (nullptr), |
482 | m_kind (kind), |
483 | m_data8 (0), |
484 | m_data16 (0), |
485 | m_data32 (0) |
486 | { |
487 | } |
488 | |
489 | template<typename T> |
490 | inline T |
491 | insn_note::as_a () |
492 | { |
493 | using deref_type = decltype (*std::declval<T> ()); |
494 | using derived = typename std::remove_reference<deref_type>::type; |
495 | gcc_checking_assert (m_kind == derived::kind); |
496 | return static_cast<T> (this); |
497 | } |
498 | |
499 | template<typename T> |
500 | inline T |
501 | insn_note::dyn_cast () |
502 | { |
503 | using deref_type = decltype (*std::declval<T> ()); |
504 | using derived = typename std::remove_reference<deref_type>::type; |
505 | if (m_kind == derived::kind) |
506 | return static_cast<T> (this); |
507 | return nullptr; |
508 | } |
509 | |
510 | inline bool |
511 | insn_info::operator< (const insn_info &other) const |
512 | { |
513 | if (this == &other) |
514 | return false; |
515 | |
516 | if (LIKELY (m_point != other.m_point)) |
517 | return m_point < other.m_point; |
518 | |
519 | return slow_compare_with (other) < 0; |
520 | } |
521 | |
522 | inline bool |
523 | insn_info::operator> (const insn_info &other) const |
524 | { |
525 | return other < *this; |
526 | } |
527 | |
528 | inline bool |
529 | insn_info::operator<= (const insn_info &other) const |
530 | { |
531 | return !(other < *this); |
532 | } |
533 | |
534 | inline bool |
535 | insn_info::operator>= (const insn_info &other) const |
536 | { |
537 | return !(*this < other); |
538 | } |
539 | |
540 | inline int |
541 | insn_info::compare_with (const insn_info *other) const |
542 | { |
543 | if (this == other) |
544 | return 0; |
545 | |
546 | if (LIKELY (m_point != other->m_point)) |
547 | // Assume that points remain in [0, INT_MAX]. |
548 | return m_point - other->m_point; |
549 | |
550 | return slow_compare_with (*other); |
551 | } |
552 | |
553 | inline insn_info * |
554 | insn_info::prev_nondebug_insn () const |
555 | { |
556 | gcc_checking_assert (!is_debug_insn ()); |
557 | return m_prev_insn_or_last_debug_insn.known_first (); |
558 | } |
559 | |
560 | inline insn_info * |
561 | insn_info::next_nondebug_insn () const |
562 | { |
563 | gcc_checking_assert (!is_debug_insn ()); |
564 | const insn_info *from = this; |
565 | if (insn_info *first_debug = m_next_nondebug_or_debug_insn.second_or_null ()) |
566 | from = first_debug->last_debug_insn (); |
567 | return from->m_next_nondebug_or_debug_insn.known_first (); |
568 | } |
569 | |
570 | inline insn_info * |
571 | insn_info::prev_any_insn () const |
572 | { |
573 | const insn_info *from = this; |
574 | if (insn_info *last_debug = m_prev_insn_or_last_debug_insn.second_or_null ()) |
575 | // This instruction is the first in a subsequence of debug instructions. |
576 | // Move to the following nondebug instruction. |
577 | from = last_debug->m_next_nondebug_or_debug_insn.known_first (); |
578 | return from->m_prev_insn_or_last_debug_insn.known_first (); |
579 | } |
580 | |
581 | inline insn_info * |
582 | insn_info::next_any_insn () const |
583 | { |
584 | // This should get optimized into an AND with -2. |
585 | if (m_next_nondebug_or_debug_insn.is_first ()) |
586 | return m_next_nondebug_or_debug_insn.known_first (); |
587 | return m_next_nondebug_or_debug_insn.known_second (); |
588 | } |
589 | |
590 | inline bool |
591 | insn_info::is_phi () const |
592 | { |
593 | return this == ebb ()->phi_insn (); |
594 | } |
595 | |
596 | inline bool |
597 | insn_info::is_bb_head () const |
598 | { |
599 | return this == m_bb->head_insn (); |
600 | } |
601 | |
602 | inline bool |
603 | insn_info::is_bb_end () const |
604 | { |
605 | return this == m_bb->end_insn (); |
606 | } |
607 | |
608 | inline ebb_info * |
609 | insn_info::ebb () const |
610 | { |
611 | return m_bb->ebb (); |
612 | } |
613 | |
614 | inline int |
615 | insn_info::uid () const |
616 | { |
617 | return m_cost_or_uid < 0 ? m_cost_or_uid : INSN_UID (insn: m_rtl); |
618 | } |
619 | |
620 | inline use_array |
621 | insn_info::uses () const |
622 | { |
623 | return use_array (m_accesses + m_num_defs, m_num_uses); |
624 | } |
625 | |
626 | inline bool |
627 | insn_info::has_call_clobbers () const |
628 | { |
629 | return find_note<insn_call_clobbers_note> (); |
630 | } |
631 | |
632 | inline def_array |
633 | insn_info::defs () const |
634 | { |
635 | return def_array (m_accesses, m_num_defs); |
636 | } |
637 | |
638 | inline unsigned int |
639 | insn_info::cost () const |
640 | { |
641 | if (m_cost_or_uid < 0) |
642 | return 0; |
643 | if (m_cost_or_uid == UNKNOWN_COST) |
644 | calculate_cost (); |
645 | return m_cost_or_uid; |
646 | } |
647 | |
648 | template<typename T> |
649 | inline const T * |
650 | insn_info::find_note () const |
651 | { |
652 | // We could break if the note kind is > T::kind, but since the number |
653 | // of notes should be very small, the check is unlikely to pay for itself. |
654 | for (const insn_note *note = first_note (); note; note = note->next_note ()) |
655 | if (note->kind () == T::kind) |
656 | return static_cast<const T *> (note); |
657 | return nullptr; |
658 | } |
659 | |
660 | // Only valid for debug instructions that come after a nondebug instruction, |
661 | // and so start a subsequence of debug instructions. Return the last debug |
662 | // instruction in the subsequence. |
663 | inline insn_info * |
664 | insn_info::last_debug_insn () const |
665 | { |
666 | return m_prev_insn_or_last_debug_insn.known_second (); |
667 | } |
668 | |
669 | inline insn_range_info::insn_range_info (insn_info *first, insn_info *last) |
670 | : first (first), last (last) |
671 | { |
672 | } |
673 | |
674 | inline bool |
675 | insn_range_info::operator== (const insn_range_info &other) const |
676 | { |
677 | return first == other.first && last == other.last; |
678 | } |
679 | |
680 | inline bool |
681 | insn_range_info::operator!= (const insn_range_info &other) const |
682 | { |
683 | return first != other.first || last != other.last; |
684 | } |
685 | |
686 | inline insn_info * |
687 | insn_range_info::singleton () const |
688 | { |
689 | return first == last ? last : nullptr; |
690 | } |
691 | |
692 | inline bool |
693 | insn_range_info::includes (insn_info *insn) const |
694 | { |
695 | return *insn >= *first && *insn <= *last; |
696 | } |
697 | |
698 | inline insn_info * |
699 | insn_range_info::clamp_insn_to_range (insn_info *insn) const |
700 | { |
701 | if (*first > *insn) |
702 | return first; |
703 | if (*last < *insn) |
704 | return last; |
705 | return insn; |
706 | } |
707 | |
708 | inline bool |
709 | insn_range_info::is_subrange_of (const insn_range_info &other) const |
710 | { |
711 | return *first >= *other.first && *last <= *other.last; |
712 | } |
713 | |
714 | inline iterator_range<any_insn_iterator> |
715 | bb_info::all_insns () const |
716 | { |
717 | return { m_head_insn, m_end_insn->next_any_insn () }; |
718 | } |
719 | |
720 | inline iterator_range<reverse_any_insn_iterator> |
721 | bb_info::reverse_all_insns () const |
722 | { |
723 | return { m_end_insn, m_head_insn->prev_any_insn () }; |
724 | } |
725 | |
726 | inline iterator_range<nondebug_insn_iterator> |
727 | bb_info::nondebug_insns () const |
728 | { |
729 | return { m_head_insn, m_end_insn->next_nondebug_insn () }; |
730 | } |
731 | |
732 | inline iterator_range<reverse_nondebug_insn_iterator> |
733 | bb_info::reverse_nondebug_insns () const |
734 | { |
735 | return { m_end_insn, m_head_insn->prev_nondebug_insn () }; |
736 | } |
737 | |
738 | inline iterator_range<any_insn_iterator> |
739 | bb_info::real_insns () const |
740 | { |
741 | return { m_head_insn->next_any_insn (), m_end_insn }; |
742 | } |
743 | |
744 | inline iterator_range<reverse_any_insn_iterator> |
745 | bb_info::reverse_real_insns () const |
746 | { |
747 | return { m_end_insn->prev_any_insn (), m_head_insn }; |
748 | } |
749 | |
750 | inline iterator_range<nondebug_insn_iterator> |
751 | bb_info::real_nondebug_insns () const |
752 | { |
753 | return { m_head_insn->next_nondebug_insn (), m_end_insn }; |
754 | } |
755 | |
756 | inline iterator_range<reverse_nondebug_insn_iterator> |
757 | bb_info::reverse_real_nondebug_insns () const |
758 | { |
759 | return { m_end_insn->prev_nondebug_insn (), m_head_insn }; |
760 | } |
761 | |
762 | inline bool |
763 | ebb_call_clobbers_info::clobbers (resource_info resource) const |
764 | { |
765 | // Only register clobbers are tracked this way. Other clobbers are |
766 | // recorded explicitly. |
767 | return (resource.is_reg () |
768 | && m_abi->clobbers_reg_p (mode: resource.mode, regno: resource.regno)); |
769 | } |
770 | |
771 | inline ebb_info * |
772 | ebb_info::prev_ebb () const |
773 | { |
774 | if (bb_info *prev_bb = m_first_bb->prev_bb ()) |
775 | return prev_bb->ebb (); |
776 | return nullptr; |
777 | } |
778 | |
779 | inline ebb_info * |
780 | ebb_info::next_ebb () const |
781 | { |
782 | if (bb_info *next_bb = m_last_bb->next_bb ()) |
783 | return next_bb->ebb (); |
784 | return nullptr; |
785 | } |
786 | |
787 | inline iterator_range<phi_iterator> |
788 | ebb_info::phis () const |
789 | { |
790 | return { m_first_phi, nullptr }; |
791 | } |
792 | |
793 | inline iterator_range<bb_iterator> |
794 | ebb_info::bbs () const |
795 | { |
796 | return { m_first_bb, m_last_bb->next_bb () }; |
797 | } |
798 | |
799 | inline iterator_range<reverse_bb_iterator> |
800 | ebb_info::reverse_bbs () const |
801 | { |
802 | return { m_last_bb, m_first_bb->prev_bb () }; |
803 | } |
804 | |
805 | inline iterator_range<any_insn_iterator> |
806 | ebb_info::all_insns () const |
807 | { |
808 | return { m_phi_insn, m_last_bb->end_insn ()->next_any_insn () }; |
809 | } |
810 | |
811 | inline iterator_range<reverse_any_insn_iterator> |
812 | ebb_info::reverse_all_insns () const |
813 | { |
814 | return { m_last_bb->end_insn (), m_phi_insn->prev_any_insn () }; |
815 | } |
816 | |
817 | inline iterator_range<nondebug_insn_iterator> |
818 | ebb_info::nondebug_insns () const |
819 | { |
820 | return { m_phi_insn, m_last_bb->end_insn ()->next_nondebug_insn () }; |
821 | } |
822 | |
823 | inline iterator_range<reverse_nondebug_insn_iterator> |
824 | ebb_info::reverse_nondebug_insns () const |
825 | { |
826 | return { m_last_bb->end_insn (), m_phi_insn->prev_nondebug_insn () }; |
827 | } |
828 | |
829 | inline insn_range_info |
830 | ebb_info::insn_range () const |
831 | { |
832 | return { m_phi_insn, m_last_bb->end_insn () }; |
833 | } |
834 | |
835 | inline void |
836 | ebb_info::set_first_call_clobbers (ebb_call_clobbers_info *call_clobbers) |
837 | { |
838 | m_first_call_clobbers = call_clobbers; |
839 | } |
840 | |
841 | inline ebb_call_clobbers_info * |
842 | ebb_info::first_call_clobbers () const |
843 | { |
844 | return m_first_call_clobbers; |
845 | } |
846 | |
847 | inline iterator_range<ebb_call_clobbers_iterator> |
848 | ebb_info::call_clobbers () const |
849 | { |
850 | return { m_first_call_clobbers, nullptr }; |
851 | } |
852 | |
853 | inline insn_change::insn_change (insn_info *insn) |
854 | : m_insn (insn), |
855 | new_defs (insn->defs ()), |
856 | new_uses (insn->uses ()), |
857 | move_range (insn), |
858 | new_cost (UNKNOWN_COST), |
859 | m_is_deletion (false) |
860 | { |
861 | } |
862 | |
863 | inline insn_change::insn_change (insn_info *insn, delete_action) |
864 | : m_insn (insn), |
865 | new_defs (), |
866 | new_uses (), |
867 | move_range (insn), |
868 | new_cost (0), |
869 | m_is_deletion (true) |
870 | { |
871 | } |
872 | |
873 | inline insn_is_changing_closure:: |
874 | insn_is_changing_closure (array_slice<insn_change *const> changes) |
875 | : m_changes (changes) |
876 | { |
877 | } |
878 | |
879 | inline bool |
880 | insn_is_changing_closure::operator() (const insn_info *insn) const |
881 | { |
882 | for (const insn_change *change : m_changes) |
883 | if (change->insn () == insn) |
884 | return true; |
885 | return false; |
886 | } |
887 | |
888 | inline iterator_range<bb_iterator> |
889 | function_info::bbs () const |
890 | { |
891 | return { m_first_bb, nullptr }; |
892 | } |
893 | |
894 | inline iterator_range<reverse_bb_iterator> |
895 | function_info::reverse_bbs () const |
896 | { |
897 | return { m_last_bb, nullptr }; |
898 | } |
899 | |
900 | inline iterator_range<ebb_iterator> |
901 | function_info::ebbs () const |
902 | { |
903 | return { m_first_bb->ebb (), nullptr }; |
904 | } |
905 | |
906 | inline iterator_range<reverse_ebb_iterator> |
907 | function_info::reverse_ebbs () const |
908 | { |
909 | return { m_last_bb->ebb (), nullptr }; |
910 | } |
911 | |
912 | inline iterator_range<any_insn_iterator> |
913 | function_info::all_insns () const |
914 | { |
915 | return { m_first_insn, nullptr }; |
916 | } |
917 | |
918 | inline iterator_range<reverse_any_insn_iterator> |
919 | function_info::reverse_all_insns () const |
920 | { |
921 | return { m_last_insn, nullptr }; |
922 | } |
923 | |
924 | inline iterator_range<nondebug_insn_iterator> |
925 | function_info::nondebug_insns () const |
926 | { |
927 | return { m_first_insn, nullptr }; |
928 | } |
929 | |
930 | inline iterator_range<reverse_nondebug_insn_iterator> |
931 | function_info::reverse_nondebug_insns () const |
932 | { |
933 | return { m_last_insn, nullptr }; |
934 | } |
935 | |
936 | inline iterator_range<def_iterator> |
937 | function_info::mem_defs () const |
938 | { |
939 | return { m_defs[0], nullptr }; |
940 | } |
941 | |
942 | inline iterator_range<def_iterator> |
943 | function_info::reg_defs (unsigned int regno) const |
944 | { |
945 | return { m_defs[regno + 1], nullptr }; |
946 | } |
947 | |
948 | inline bool |
949 | function_info::is_single_dominating_def (const set_info *set) const |
950 | { |
951 | return (set->is_first_def () |
952 | && set->is_last_def () |
953 | && (!HARD_REGISTER_NUM_P (set->regno ()) |
954 | || !TEST_HARD_REG_BIT (set: m_clobbered_by_calls, bit: set->regno ()))); |
955 | } |
956 | |
957 | inline set_info * |
958 | function_info::single_dominating_def (unsigned int regno) const |
959 | { |
960 | if (set_info *set = safe_dyn_cast<set_info *> (p: m_defs[regno + 1])) |
961 | if (is_single_dominating_def (set)) |
962 | return set; |
963 | return nullptr; |
964 | } |
965 | |
966 | template<typename IgnorePredicate> |
967 | bool |
968 | function_info::add_regno_clobber (obstack_watermark &watermark, |
969 | insn_change &change, unsigned int regno, |
970 | IgnorePredicate ignore) |
971 | { |
972 | // Check whether CHANGE already clobbers REGNO. |
973 | if (find_access (accesses: change.new_defs, regno)) |
974 | return true; |
975 | |
976 | // Get the closest position to INSN at which the new instruction |
977 | // could be placed. |
978 | insn_info *insn = change.move_range.clamp_insn_to_range (insn: change.insn ()); |
979 | def_array new_defs = insert_temp_clobber (watermark, insn, regno, |
980 | change.new_defs); |
981 | if (!new_defs.is_valid ()) |
982 | return false; |
983 | |
984 | // Find a definition at or neighboring INSN. |
985 | insn_range_info move_range = change.move_range; |
986 | if (!restrict_movement_for_dead_range (move_range, regno, insn, ignore)) |
987 | return false; |
988 | |
989 | change.new_defs = new_defs; |
990 | change.move_range = move_range; |
991 | return true; |
992 | } |
993 | |
994 | template<typename T, typename... Ts> |
995 | inline T * |
996 | function_info::change_alloc (obstack_watermark &wm, Ts... args) |
997 | { |
998 | static_assert (std::is_trivially_destructible<T>::value, |
999 | "destructor won't be called" ); |
1000 | static_assert (alignof (T) <= obstack_alignment, |
1001 | "too much alignment required" ); |
1002 | void *addr = XOBNEW (wm, T); |
1003 | return new (addr) T (std::forward<Ts> (args)...); |
1004 | } |
1005 | |
1006 | } |
1007 | |