1 // Implementation of public inline member functions for RTL SSA -*- C++ -*-
2 // Copyright (C) 2020-2021 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 // 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.
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.
30 access_array_builder::reserve (unsigned int num_accesses)
32 obstack_make_room (m_obstack, num_accesses * sizeof (access_info *));
36 access_array_builder::quick_push (access_info *access)
38 obstack_ptr_grow_fast (m_obstack, access);
41 inline array_slice<access_info *>
42 access_array_builder::finish ()
44 auto num_accesses = obstack_object_size (m_obstack) / sizeof (access_info *);
45 if (num_accesses == 0)
48 auto **base = static_cast<access_info **> (obstack_finish (m_obstack));
50 return { base, num_accesses };
54 access_info::is_set_with_nondebug_insn_uses () const
56 return m_is_set_with_nondebug_insn_uses;
60 use_info::is_in_debug_insn () const
62 return m_insn_or_phi.is_first () && m_is_in_debug_insn_or_phi;
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 ();
74 use_info::ebb () const
80 use_info::prev_use () const
82 return m_last_use_or_prev_use.second_or_null ();
86 use_info::next_use () const
88 return m_last_nondebug_insn_use_or_next_use.second_or_null ();
92 use_info::is_first_use () const
94 return m_last_use_or_prev_use.is_first ();
98 use_info::is_last_use () const
100 return m_last_nondebug_insn_use_or_next_use.is_first ();
104 use_info::next_nondebug_insn_use () const
106 if (m_is_last_nondebug_insn_use)
108 return m_last_nondebug_insn_use_or_next_use.known_second ();
112 use_info::next_any_insn_use () const
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 ())
123 use_info::prev_phi_use () const
125 // This is used less often than next_nondebug_insn_use, so it doesn't
126 // seem worth having an m_is_last_nondebug_insn_use-style end marker.
127 if (use_info *use = prev_use ())
128 if (use->is_in_phi ())
133 // Return the last use of any kind in the list. Only valid when is_first ()
136 use_info::last_use () const
138 return m_last_use_or_prev_use.known_first ();
141 // Return the last nondebug insn use in the list, or null if none. Only valid
142 // when is_last_use () is true.
144 use_info::last_nondebug_insn_use () const
146 return m_last_nondebug_insn_use_or_next_use.known_first ();
150 def_info::prev_def () const
152 return m_last_def_or_prev_def.second_or_null ();
156 def_info::next_def () const
158 return m_splay_root_or_next_def.second_or_null ();
162 def_info::is_first_def () const
164 return m_last_def_or_prev_def.is_first ();
168 def_info::is_last_def () const
170 return m_splay_root_or_next_def.is_first ();
174 def_info::bb () const
176 return m_insn->bb ();
180 def_info::ebb () const
182 return m_insn->ebb ();
185 inline clobber_group *
186 clobber_info::group () const
188 if (!m_group || !m_group->has_been_superceded ())
190 return const_cast<clobber_info *> (this)->recompute_group ();
194 set_info::last_use () const
196 return m_first_use ? m_first_use->last_use () : nullptr;
200 set_info::first_nondebug_insn_use () const
202 if (m_is_set_with_nondebug_insn_uses)
208 set_info::last_nondebug_insn_use () const
210 if (m_is_set_with_nondebug_insn_uses)
211 return m_first_use->last_use ()->last_nondebug_insn_use ();
216 set_info::first_any_insn_use () const
218 if (m_first_use->is_in_any_insn ())
224 set_info::last_phi_use () const
228 use_info *last = m_first_use->last_use ();
229 if (last->is_in_phi ())
236 set_info::has_nondebug_uses () const
238 return has_nondebug_insn_uses () || has_phi_uses ();
242 set_info::has_nondebug_insn_uses () const
244 return m_is_set_with_nondebug_insn_uses;
248 set_info::has_phi_uses () const
250 return m_first_use && m_first_use->last_use ()->is_in_phi ();
254 set_info::single_nondebug_use () const
256 if (!has_phi_uses ())
257 return single_nondebug_insn_use ();
258 if (!has_nondebug_insn_uses ())
259 return single_phi_use ();
264 set_info::single_nondebug_insn_use () const
266 use_info *first = first_nondebug_insn_use ();
267 if (first && !first->next_nondebug_insn_use ())
273 set_info::single_phi_use () const
275 use_info *last = last_phi_use ();
276 if (last && !last->prev_phi_use ())
282 set_info::is_local_to_ebb () const
287 use_info *last = m_first_use->last_use ();
288 if (last->is_in_phi ())
291 last = last->last_nondebug_insn_use ();
292 return !last || last->ebb () == ebb ();
295 inline iterator_range<use_iterator>
296 set_info::all_uses () const
298 return { m_first_use, nullptr };
301 inline iterator_range<reverse_use_iterator>
302 set_info::reverse_all_uses () const
304 return { last_use (), nullptr };
307 inline iterator_range<nondebug_insn_use_iterator>
308 set_info::nondebug_insn_uses () const
310 return { first_nondebug_insn_use (), nullptr };
313 inline iterator_range<reverse_use_iterator>
314 set_info::reverse_nondebug_insn_uses () const
316 return { last_nondebug_insn_use (), nullptr };
319 inline iterator_range<any_insn_use_iterator>
320 set_info::all_insn_uses () const
322 return { first_any_insn_use (), nullptr };
325 inline iterator_range<phi_use_iterator>
326 set_info::phi_uses () const
328 return { last_phi_use (), nullptr };
332 phi_info::inputs () const
334 if (m_num_inputs == 1)
335 return use_array (&m_single_input, 1);
336 return use_array (m_inputs, m_num_inputs);
340 phi_info::input_use (unsigned int i) const
342 if (m_num_inputs == 1)
343 return as_a<use_info *> (m_single_input);
344 return as_a<use_info *> (m_inputs[i]);
348 phi_info::input_value (unsigned int i) const
350 return input_use (i)->def ();
354 def_node::first_def () const
356 // This should get optimized into an AND with -2.
357 if (m_clobber_or_set.is_first ())
358 return m_clobber_or_set.known_first ();
359 return m_clobber_or_set.known_second ();
362 inline clobber_info *
363 clobber_group::first_clobber () const
365 return m_clobber_or_set.known_first ();
368 inline iterator_range<def_iterator>
369 clobber_group::clobbers () const
371 return { first_clobber (), m_last_clobber->next_def () };
375 def_mux::first_def () const
378 return known_first ();
379 return known_second ()->first_def ();
383 def_mux::last_def () const
386 return known_first ();
388 def_node *node = known_second ();
389 if (auto *clobber = ::dyn_cast<clobber_group *> (node))
390 return clobber->last_clobber ();
392 return node->first_def ();
396 def_mux::set () const
399 return ::safe_dyn_cast<set_info *> (known_first ());
400 return ::dyn_cast<set_info *> (known_second ()->first_def ());
404 def_lookup::prev_def () const
410 return mux.last_def ();
412 return mux.first_def ()->prev_def ();
416 def_lookup::next_def () const
422 return mux.first_def ();
424 return mux.last_def ()->next_def ();
428 def_lookup::matching_set () const
436 def_lookup::matching_or_prev_def () const
438 if (set_info *set = matching_set ())
444 def_lookup::matching_or_next_def () const
446 if (set_info *set = matching_set ())
451 inline insn_note::insn_note (insn_note_kind kind)
452 : m_next_note (nullptr),
464 using deref_type = decltype (*std::declval<T> ());
465 using derived = typename std::remove_reference<deref_type>::type;
466 gcc_checking_assert (m_kind == derived::kind);
467 return static_cast<T> (this);
472 insn_note::dyn_cast ()
474 using deref_type = decltype (*std::declval<T> ());
475 using derived = typename std::remove_reference<deref_type>::type;
476 if (m_kind == derived::kind)
477 return static_cast<T> (this);
482 insn_info::operator< (const insn_info &other) const
487 if (__builtin_expect (m_point != other.m_point, 1))
488 return m_point < other.m_point;
490 return slow_compare_with (other) < 0;
494 insn_info::operator> (const insn_info &other) const
496 return other < *this;
500 insn_info::operator<= (const insn_info &other) const
502 return !(other < *this);
506 insn_info::operator>= (const insn_info &other) const
508 return !(*this < other);
512 insn_info::compare_with (const insn_info *other) const
517 if (__builtin_expect (m_point != other->m_point, 1))
518 // Assume that points remain in [0, INT_MAX].
519 return m_point - other->m_point;
521 return slow_compare_with (*other);
525 insn_info::prev_nondebug_insn () const
527 gcc_checking_assert (!is_debug_insn ());
528 return m_prev_insn_or_last_debug_insn.known_first ();
532 insn_info::next_nondebug_insn () const
534 gcc_checking_assert (!is_debug_insn ());
535 const insn_info *from = this;
536 if (insn_info *first_debug = m_next_nondebug_or_debug_insn.second_or_null ())
537 from = first_debug->last_debug_insn ();
538 return from->m_next_nondebug_or_debug_insn.known_first ();
542 insn_info::prev_any_insn () const
544 const insn_info *from = this;
545 if (insn_info *last_debug = m_prev_insn_or_last_debug_insn.second_or_null ())
546 // This instruction is the first in a subsequence of debug instructions.
547 // Move to the following nondebug instruction.
548 from = last_debug->m_next_nondebug_or_debug_insn.known_first ();
549 return from->m_prev_insn_or_last_debug_insn.known_first ();
553 insn_info::next_any_insn () const
555 // This should get optimized into an AND with -2.
556 if (m_next_nondebug_or_debug_insn.is_first ())
557 return m_next_nondebug_or_debug_insn.known_first ();
558 return m_next_nondebug_or_debug_insn.known_second ();
562 insn_info::is_phi () const
564 return this == ebb ()->phi_insn ();
568 insn_info::is_bb_head () const
570 return this == m_bb->head_insn ();
574 insn_info::is_bb_end () const
576 return this == m_bb->end_insn ();
580 insn_info::ebb () const
586 insn_info::uid () const
588 return m_cost_or_uid < 0 ? m_cost_or_uid : INSN_UID (m_rtl);
592 insn_info::uses () const
594 return use_array (m_accesses + m_num_defs, m_num_uses);
598 insn_info::has_call_clobbers () const
600 return find_note<insn_call_clobbers_note> ();
604 insn_info::defs () const
606 return def_array (m_accesses, m_num_defs);
610 insn_info::cost () const
612 if (m_cost_or_uid < 0)
614 if (m_cost_or_uid == UNKNOWN_COST)
616 return m_cost_or_uid;
621 insn_info::find_note () const
623 // We could break if the note kind is > T::kind, but since the number
624 // of notes should be very small, the check is unlikely to pay for itself.
625 for (const insn_note *note = first_note (); note; note = note->next_note ())
626 if (note->kind () == T::kind)
627 return static_cast<const T *> (note);
631 // Only valid for debug instructions that come after a nondebug instruction,
632 // and so start a subsequence of debug instructions. Return the last debug
633 // instruction in the subsequence.
635 insn_info::last_debug_insn () const
637 return m_prev_insn_or_last_debug_insn.known_second ();
640 inline insn_range_info::insn_range_info (insn_info *first, insn_info *last)
641 : first (first), last (last)
646 insn_range_info::operator== (const insn_range_info &other) const
648 return first == other.first && last == other.last;
652 insn_range_info::operator!= (const insn_range_info &other) const
654 return first != other.first || last != other.last;
658 insn_range_info::singleton () const
660 return first == last ? last : nullptr;
664 insn_range_info::includes (insn_info *insn) const
666 return *insn >= *first && *insn <= *last;
670 insn_range_info::clamp_insn_to_range (insn_info *insn) const
680 insn_range_info::is_subrange_of (const insn_range_info &other) const
682 return *first >= *other.first && *last <= *other.last;
685 inline iterator_range<any_insn_iterator>
686 bb_info::all_insns () const
688 return { m_head_insn, m_end_insn->next_any_insn () };
691 inline iterator_range<reverse_any_insn_iterator>
692 bb_info::reverse_all_insns () const
694 return { m_end_insn, m_head_insn->prev_any_insn () };
697 inline iterator_range<nondebug_insn_iterator>
698 bb_info::nondebug_insns () const
700 return { m_head_insn, m_end_insn->next_nondebug_insn () };
703 inline iterator_range<reverse_nondebug_insn_iterator>
704 bb_info::reverse_nondebug_insns () const
706 return { m_end_insn, m_head_insn->prev_nondebug_insn () };
709 inline iterator_range<any_insn_iterator>
710 bb_info::real_insns () const
712 return { m_head_insn->next_any_insn (), m_end_insn };
715 inline iterator_range<reverse_any_insn_iterator>
716 bb_info::reverse_real_insns () const
718 return { m_end_insn->prev_any_insn (), m_head_insn };
721 inline iterator_range<nondebug_insn_iterator>
722 bb_info::real_nondebug_insns () const
724 return { m_head_insn->next_nondebug_insn (), m_end_insn };
727 inline iterator_range<reverse_nondebug_insn_iterator>
728 bb_info::reverse_real_nondebug_insns () const
730 return { m_end_insn->prev_nondebug_insn (), m_head_insn };
734 ebb_call_clobbers_info::clobbers (resource_info resource) const
736 // Only register clobbers are tracked this way. Other clobbers are
737 // recorded explicitly.
738 return (resource.is_reg ()
739 && m_abi->clobbers_reg_p (resource.mode, resource.regno));
743 ebb_info::prev_ebb () const
745 if (bb_info *prev_bb = m_first_bb->prev_bb ())
746 return prev_bb->ebb ();
751 ebb_info::next_ebb () const
753 if (bb_info *next_bb = m_last_bb->next_bb ())
754 return next_bb->ebb ();
758 inline iterator_range<phi_iterator>
759 ebb_info::phis () const
761 return { m_first_phi, nullptr };
764 inline iterator_range<bb_iterator>
765 ebb_info::bbs () const
767 return { m_first_bb, m_last_bb->next_bb () };
770 inline iterator_range<reverse_bb_iterator>
771 ebb_info::reverse_bbs () const
773 return { m_last_bb, m_first_bb->prev_bb () };
776 inline iterator_range<any_insn_iterator>
777 ebb_info::all_insns () const
779 return { m_phi_insn, m_last_bb->end_insn ()->next_any_insn () };
782 inline iterator_range<reverse_any_insn_iterator>
783 ebb_info::reverse_all_insns () const
785 return { m_last_bb->end_insn (), m_phi_insn->prev_any_insn () };
788 inline iterator_range<nondebug_insn_iterator>
789 ebb_info::nondebug_insns () const
791 return { m_phi_insn, m_last_bb->end_insn ()->next_nondebug_insn () };
794 inline iterator_range<reverse_nondebug_insn_iterator>
795 ebb_info::reverse_nondebug_insns () const
797 return { m_last_bb->end_insn (), m_phi_insn->prev_nondebug_insn () };
800 inline insn_range_info
801 ebb_info::insn_range () const
803 return { m_phi_insn, m_last_bb->end_insn () };
807 ebb_info::set_first_call_clobbers (ebb_call_clobbers_info *call_clobbers)
809 m_first_call_clobbers = call_clobbers;
812 inline ebb_call_clobbers_info *
813 ebb_info::first_call_clobbers () const
815 return m_first_call_clobbers;
818 inline iterator_range<ebb_call_clobbers_iterator>
819 ebb_info::call_clobbers () const
821 return { m_first_call_clobbers, nullptr };
824 inline insn_change::insn_change (insn_info *insn)
826 new_defs (insn->defs ()),
827 new_uses (insn->uses ()),
829 new_cost (UNKNOWN_COST),
830 m_is_deletion (false)
834 inline insn_change::insn_change (insn_info *insn, delete_action)
844 inline insn_is_changing_closure::
845 insn_is_changing_closure (array_slice<insn_change *const> changes)
846 : m_changes (changes)
851 insn_is_changing_closure::operator() (const insn_info *insn) const
853 for (const insn_change *change : m_changes)
854 if (change->insn () == insn)
859 inline iterator_range<bb_iterator>
860 function_info::bbs () const
862 return { m_first_bb, nullptr };
865 inline iterator_range<reverse_bb_iterator>
866 function_info::reverse_bbs () const
868 return { m_last_bb, nullptr };
871 inline iterator_range<ebb_iterator>
872 function_info::ebbs () const
874 return { m_first_bb->ebb (), nullptr };
877 inline iterator_range<reverse_ebb_iterator>
878 function_info::reverse_ebbs () const
880 return { m_last_bb->ebb (), nullptr };
883 inline iterator_range<any_insn_iterator>
884 function_info::all_insns () const
886 return { m_first_insn, nullptr };
889 inline iterator_range<reverse_any_insn_iterator>
890 function_info::reverse_all_insns () const
892 return { m_last_insn, nullptr };
895 inline iterator_range<nondebug_insn_iterator>
896 function_info::nondebug_insns () const
898 return { m_first_insn, nullptr };
901 inline iterator_range<reverse_nondebug_insn_iterator>
902 function_info::reverse_nondebug_insns () const
904 return { m_last_insn, nullptr };
907 inline iterator_range<def_iterator>
908 function_info::mem_defs () const
910 return { m_defs[0], nullptr };
913 inline iterator_range<def_iterator>
914 function_info::reg_defs (unsigned int regno) const
916 return { m_defs[regno + 1], nullptr };
920 function_info::single_dominating_def (unsigned int regno) const
922 if (set_info *set = safe_dyn_cast<set_info *> (m_defs[regno + 1]))
923 if (is_single_dominating_def (set))
928 template<typename IgnorePredicate>
930 function_info::add_regno_clobber (obstack_watermark &watermark,
931 insn_change &change, unsigned int regno,
932 IgnorePredicate ignore)
934 // Check whether CHANGE already clobbers REGNO.
935 if (find_access (change.new_defs, regno))
938 // Get the closest position to INSN at which the new instruction
940 insn_info *insn = change.move_range.clamp_insn_to_range (change.insn ());
941 def_array new_defs = insert_temp_clobber (watermark, insn, regno,
943 if (!new_defs.is_valid ())
946 // Find a definition at or neighboring INSN.
947 insn_range_info move_range = change.move_range;
948 if (!restrict_movement_for_dead_range (move_range, regno, insn, ignore))
951 change.new_defs = new_defs;
952 change.move_range = move_range;