1 // Implementation of public inline member functions for RTL SSA -*- C++ -*-
2 // Copyright (C) 2020-2024 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::next_debug_insn_use () const
125 if (auto use = next_use ())
126 if (use->is_in_debug_insn ())
132 use_info::prev_phi_use () const
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 ())
142 // Return the last use of any kind in the list. Only valid when is_first ()
145 use_info::last_use () const
147 return m_last_use_or_prev_use.known_first ();
150 // Return the last nondebug insn use in the list, or null if none. Only valid
151 // when is_last_use () is true.
153 use_info::last_nondebug_insn_use () const
155 return m_last_nondebug_insn_use_or_next_use.known_first ();
159 def_info::prev_def () const
161 return m_last_def_or_prev_def.second_or_null ();
165 def_info::next_def () const
167 return m_splay_root_or_next_def.second_or_null ();
171 def_info::is_first_def () const
173 return m_last_def_or_prev_def.is_first ();
177 def_info::is_last_def () const
179 return m_splay_root_or_next_def.is_first ();
183 def_info::bb () const
185 return m_insn->bb ();
189 def_info::ebb () const
191 return m_insn->ebb ();
194 inline clobber_group *
195 clobber_info::group () const
197 if (!m_group || !m_group->has_been_superceded ())
199 return const_cast<clobber_info *> (this)->recompute_group ();
203 set_info::last_use () const
205 return m_first_use ? m_first_use->last_use () : nullptr;
209 set_info::first_nondebug_insn_use () const
211 if (m_is_set_with_nondebug_insn_uses)
217 set_info::last_nondebug_insn_use () const
219 if (m_is_set_with_nondebug_insn_uses)
220 return m_first_use->last_use ()->last_nondebug_insn_use ();
225 set_info::first_debug_insn_use () const
228 if (has_nondebug_insn_uses ())
229 use = last_nondebug_insn_use ()->next_use ();
233 if (use && use->is_in_debug_insn ())
239 set_info::first_any_insn_use () const
241 if (m_first_use && m_first_use->is_in_any_insn ())
247 set_info::last_phi_use () const
251 use_info *last = m_first_use->last_use ();
252 if (last->is_in_phi ())
259 set_info::has_nondebug_uses () const
261 return has_nondebug_insn_uses () || has_phi_uses ();
265 set_info::has_nondebug_insn_uses () const
267 return m_is_set_with_nondebug_insn_uses;
271 set_info::has_phi_uses () const
273 return m_first_use && m_first_use->last_use ()->is_in_phi ();
277 set_info::single_nondebug_use () const
279 if (!has_phi_uses ())
280 return single_nondebug_insn_use ();
281 if (!has_nondebug_insn_uses ())
282 return single_phi_use ();
287 set_info::single_nondebug_insn_use () const
289 use_info *first = first_nondebug_insn_use ();
290 if (first && !first->next_nondebug_insn_use ())
296 set_info::single_phi_use () const
298 use_info *last = last_phi_use ();
299 if (last && !last->prev_phi_use ())
305 set_info::is_local_to_ebb () const
310 use_info *last = m_first_use->last_use ();
311 if (last->is_in_phi ())
314 last = last->last_nondebug_insn_use ();
315 return !last || last->ebb () == ebb ();
318 inline iterator_range<use_iterator>
319 set_info::all_uses () const
321 return { m_first_use, nullptr };
324 inline iterator_range<reverse_use_iterator>
325 set_info::reverse_all_uses () const
327 return { last_use (), nullptr };
330 inline iterator_range<nondebug_insn_use_iterator>
331 set_info::nondebug_insn_uses () const
333 return { first_nondebug_insn_use (), nullptr };
336 inline iterator_range<debug_insn_use_iterator>
337 set_info::debug_insn_uses () const
339 return { first_debug_insn_use (), nullptr };
342 inline iterator_range<reverse_use_iterator>
343 set_info::reverse_nondebug_insn_uses () const
345 return { last_nondebug_insn_use (), nullptr };
348 inline iterator_range<any_insn_use_iterator>
349 set_info::all_insn_uses () const
351 return { first_any_insn_use (), nullptr };
354 inline iterator_range<phi_use_iterator>
355 set_info::phi_uses () const
357 return { last_phi_use (), nullptr };
361 phi_info::inputs () const
363 if (m_num_inputs == 1)
364 return use_array (&m_single_input, 1);
365 return use_array (m_inputs, m_num_inputs);
369 phi_info::input_use (unsigned int i) const
371 if (m_num_inputs == 1)
372 return as_a<use_info *> (m_single_input);
373 return as_a<use_info *> (m_inputs[i]);
377 phi_info::input_value (unsigned int i) const
379 return input_use (i)->def ();
383 def_node::first_def () const
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 ();
391 inline clobber_info *
392 clobber_group::first_clobber () const
394 return m_clobber_or_set.known_first ();
397 inline iterator_range<def_iterator>
398 clobber_group::clobbers () const
400 return { first_clobber (), m_last_clobber->next_def () };
404 def_mux::first_def () const
407 return known_first ();
408 return known_second ()->first_def ();
412 def_mux::last_def () const
415 return known_first ();
417 def_node *node = known_second ();
418 if (auto *clobber = ::dyn_cast<clobber_group *> (node))
419 return clobber->last_clobber ();
421 return node->first_def ();
425 def_mux::set () const
428 return ::safe_dyn_cast<set_info *> (known_first ());
429 return ::dyn_cast<set_info *> (known_second ()->first_def ());
433 def_lookup::last_def_of_prev_group () const
439 return mux.last_def ();
441 return mux.first_def ()->prev_def ();
445 def_lookup::first_def_of_next_group () const
451 return mux.first_def ();
453 return mux.last_def ()->next_def ();
457 def_lookup::matching_set () const
465 def_lookup::matching_set_or_last_def_of_prev_group () const
467 if (set_info *set = matching_set ())
469 return last_def_of_prev_group ();
473 def_lookup::matching_set_or_first_def_of_next_group () const
475 if (set_info *set = matching_set ())
477 return first_def_of_next_group ();
480 inline insn_note::insn_note (insn_note_kind kind)
481 : m_next_note (nullptr),
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);
501 insn_note::dyn_cast ()
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);
511 insn_info::operator< (const insn_info &other) const
516 if (LIKELY (m_point != other.m_point))
517 return m_point < other.m_point;
519 return slow_compare_with (other) < 0;
523 insn_info::operator> (const insn_info &other) const
525 return other < *this;
529 insn_info::operator<= (const insn_info &other) const
531 return !(other < *this);
535 insn_info::operator>= (const insn_info &other) const
537 return !(*this < other);
541 insn_info::compare_with (const insn_info *other) const
546 if (LIKELY (m_point != other->m_point))
547 // Assume that points remain in [0, INT_MAX].
548 return m_point - other->m_point;
550 return slow_compare_with (*other);
554 insn_info::prev_nondebug_insn () const
556 gcc_checking_assert (!is_debug_insn ());
557 return m_prev_insn_or_last_debug_insn.known_first ();
561 insn_info::next_nondebug_insn () const
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 ();
571 insn_info::prev_any_insn () const
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 ();
582 insn_info::next_any_insn () const
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 ();
591 insn_info::is_phi () const
593 return this == ebb ()->phi_insn ();
597 insn_info::is_bb_head () const
599 return this == m_bb->head_insn ();
603 insn_info::is_bb_end () const
605 return this == m_bb->end_insn ();
609 insn_info::ebb () const
615 insn_info::uid () const
617 return m_cost_or_uid < 0 ? m_cost_or_uid : INSN_UID (m_rtl);
621 insn_info::uses () const
623 return use_array (m_accesses + m_num_defs, m_num_uses);
627 insn_info::has_call_clobbers () const
629 return find_note<insn_call_clobbers_note> ();
633 insn_info::defs () const
635 return def_array (m_accesses, m_num_defs);
639 insn_info::cost () const
641 if (m_cost_or_uid < 0)
643 if (m_cost_or_uid == UNKNOWN_COST)
645 return m_cost_or_uid;
650 insn_info::find_note () const
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);
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.
664 insn_info::last_debug_insn () const
666 return m_prev_insn_or_last_debug_insn.known_second ();
669 inline insn_range_info::insn_range_info (insn_info *first, insn_info *last)
670 : first (first), last (last)
675 insn_range_info::operator== (const insn_range_info &other) const
677 return first == other.first && last == other.last;
681 insn_range_info::operator!= (const insn_range_info &other) const
683 return first != other.first || last != other.last;
687 insn_range_info::singleton () const
689 return first == last ? last : nullptr;
693 insn_range_info::includes (insn_info *insn) const
695 return *insn >= *first && *insn <= *last;
699 insn_range_info::clamp_insn_to_range (insn_info *insn) const
709 insn_range_info::is_subrange_of (const insn_range_info &other) const
711 return *first >= *other.first && *last <= *other.last;
714 inline iterator_range<any_insn_iterator>
715 bb_info::all_insns () const
717 return { m_head_insn, m_end_insn->next_any_insn () };
720 inline iterator_range<reverse_any_insn_iterator>
721 bb_info::reverse_all_insns () const
723 return { m_end_insn, m_head_insn->prev_any_insn () };
726 inline iterator_range<nondebug_insn_iterator>
727 bb_info::nondebug_insns () const
729 return { m_head_insn, m_end_insn->next_nondebug_insn () };
732 inline iterator_range<reverse_nondebug_insn_iterator>
733 bb_info::reverse_nondebug_insns () const
735 return { m_end_insn, m_head_insn->prev_nondebug_insn () };
738 inline iterator_range<any_insn_iterator>
739 bb_info::real_insns () const
741 return { m_head_insn->next_any_insn (), m_end_insn };
744 inline iterator_range<reverse_any_insn_iterator>
745 bb_info::reverse_real_insns () const
747 return { m_end_insn->prev_any_insn (), m_head_insn };
750 inline iterator_range<nondebug_insn_iterator>
751 bb_info::real_nondebug_insns () const
753 return { m_head_insn->next_nondebug_insn (), m_end_insn };
756 inline iterator_range<reverse_nondebug_insn_iterator>
757 bb_info::reverse_real_nondebug_insns () const
759 return { m_end_insn->prev_nondebug_insn (), m_head_insn };
763 ebb_call_clobbers_info::clobbers (resource_info resource) const
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 (resource.mode, resource.regno));
772 ebb_info::prev_ebb () const
774 if (bb_info *prev_bb = m_first_bb->prev_bb ())
775 return prev_bb->ebb ();
780 ebb_info::next_ebb () const
782 if (bb_info *next_bb = m_last_bb->next_bb ())
783 return next_bb->ebb ();
787 inline iterator_range<phi_iterator>
788 ebb_info::phis () const
790 return { m_first_phi, nullptr };
793 inline iterator_range<bb_iterator>
794 ebb_info::bbs () const
796 return { m_first_bb, m_last_bb->next_bb () };
799 inline iterator_range<reverse_bb_iterator>
800 ebb_info::reverse_bbs () const
802 return { m_last_bb, m_first_bb->prev_bb () };
805 inline iterator_range<any_insn_iterator>
806 ebb_info::all_insns () const
808 return { m_phi_insn, m_last_bb->end_insn ()->next_any_insn () };
811 inline iterator_range<reverse_any_insn_iterator>
812 ebb_info::reverse_all_insns () const
814 return { m_last_bb->end_insn (), m_phi_insn->prev_any_insn () };
817 inline iterator_range<nondebug_insn_iterator>
818 ebb_info::nondebug_insns () const
820 return { m_phi_insn, m_last_bb->end_insn ()->next_nondebug_insn () };
823 inline iterator_range<reverse_nondebug_insn_iterator>
824 ebb_info::reverse_nondebug_insns () const
826 return { m_last_bb->end_insn (), m_phi_insn->prev_nondebug_insn () };
829 inline insn_range_info
830 ebb_info::insn_range () const
832 return { m_phi_insn, m_last_bb->end_insn () };
836 ebb_info::set_first_call_clobbers (ebb_call_clobbers_info *call_clobbers)
838 m_first_call_clobbers = call_clobbers;
841 inline ebb_call_clobbers_info *
842 ebb_info::first_call_clobbers () const
844 return m_first_call_clobbers;
847 inline iterator_range<ebb_call_clobbers_iterator>
848 ebb_info::call_clobbers () const
850 return { m_first_call_clobbers, nullptr };
853 inline insn_change::insn_change (insn_info *insn)
855 new_defs (insn->defs ()),
856 new_uses (insn->uses ()),
858 new_cost (UNKNOWN_COST),
859 m_is_deletion (false)
863 inline insn_change::insn_change (insn_info *insn, delete_action)
873 inline insn_is_changing_closure::
874 insn_is_changing_closure (array_slice<insn_change *const> changes)
875 : m_changes (changes)
880 insn_is_changing_closure::operator() (const insn_info *insn) const
882 for (const insn_change *change : m_changes)
883 if (change->insn () == insn)
888 inline iterator_range<bb_iterator>
889 function_info::bbs () const
891 return { m_first_bb, nullptr };
894 inline iterator_range<reverse_bb_iterator>
895 function_info::reverse_bbs () const
897 return { m_last_bb, nullptr };
900 inline iterator_range<ebb_iterator>
901 function_info::ebbs () const
903 return { m_first_bb->ebb (), nullptr };
906 inline iterator_range<reverse_ebb_iterator>
907 function_info::reverse_ebbs () const
909 return { m_last_bb->ebb (), nullptr };
912 inline iterator_range<any_insn_iterator>
913 function_info::all_insns () const
915 return { m_first_insn, nullptr };
918 inline iterator_range<reverse_any_insn_iterator>
919 function_info::reverse_all_insns () const
921 return { m_last_insn, nullptr };
924 inline iterator_range<nondebug_insn_iterator>
925 function_info::nondebug_insns () const
927 return { m_first_insn, nullptr };
930 inline iterator_range<reverse_nondebug_insn_iterator>
931 function_info::reverse_nondebug_insns () const
933 return { m_last_insn, nullptr };
936 inline iterator_range<def_iterator>
937 function_info::mem_defs () const
939 return { m_defs[0], nullptr };
942 inline iterator_range<def_iterator>
943 function_info::reg_defs (unsigned int regno) const
945 return { m_defs[regno + 1], nullptr };
949 function_info::is_single_dominating_def (const set_info *set) const
951 return (set->is_first_def ()
952 && set->is_last_def ()
953 && (!HARD_REGISTER_NUM_P (set->regno ())
954 || !TEST_HARD_REG_BIT (m_clobbered_by_calls, set->regno ())));
958 function_info::single_dominating_def (unsigned int regno) const
960 if (set_info *set = safe_dyn_cast<set_info *> (m_defs[regno + 1]))
961 if (is_single_dominating_def (set))
966 template<typename IgnorePredicate>
968 function_info::add_regno_clobber (obstack_watermark &watermark,
969 insn_change &change, unsigned int regno,
970 IgnorePredicate ignore)
972 // Check whether CHANGE already clobbers REGNO.
973 if (find_access (change.new_defs, regno))
976 // Get the closest position to INSN at which the new instruction
978 insn_info *insn = change.move_range.clamp_insn_to_range (change.insn ());
979 def_array new_defs = insert_temp_clobber (watermark, insn, regno,
981 if (!new_defs.is_valid ())
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))
989 change.new_defs = new_defs;
990 change.move_range = move_range;
994 template<typename T, typename... Ts>
996 function_info::change_alloc (obstack_watermark &wm, Ts... args)
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)...);