1// Implementation of private inline member functions 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
20namespace rtl_ssa {
21
22// Construct a new access with the given resource () and kind () values.
23inline access_info::access_info (resource_info resource, access_kind kind)
24  : m_regno (resource.regno),
25    m_kind (kind),
26    m_is_artificial (false),
27    m_is_set_with_nondebug_insn_uses (false),
28    m_is_pre_post_modify (false),
29    m_is_call_clobber (false),
30    m_is_live_out_use (false),
31    m_includes_address_uses (false),
32    m_includes_read_writes (false),
33    m_includes_subregs (false),
34    m_includes_multiregs (false),
35    m_only_occurs_in_notes (false),
36    m_is_last_nondebug_insn_use (false),
37    m_is_in_debug_insn_or_phi (false),
38    m_has_been_superceded (false),
39    m_is_temp (false),
40    m_spare (0),
41    m_mode (resource.mode)
42{
43}
44
45// Construct a use of RESOURCE in LOCATION.  The resource's value is provided
46// by DEF, or is completely undefined if DEF is null.
47inline use_info::use_info (insn_or_phi location, resource_info resource,
48			   set_info *definition)
49  : access_info (resource, access_kind::USE),
50    m_insn_or_phi (location),
51    m_last_use_or_prev_use (nullptr),
52    m_last_nondebug_insn_use_or_next_use (nullptr),
53    m_def (definition)
54{
55  if (m_insn_or_phi.is_second ())
56    {
57      m_is_in_debug_insn_or_phi = true;
58      m_is_artificial = true;
59    }
60  else
61    {
62      insn_info *insn = m_insn_or_phi.known_first ();
63      m_is_in_debug_insn_or_phi = insn->is_debug_insn ();
64      m_is_artificial = insn->is_artificial ();
65    }
66}
67
68// Return the correct (uncached) value of m_is_last_nondebug_insn_use.
69inline bool
70use_info::calculate_is_last_nondebug_insn_use () const
71{
72  use_info *next = next_use ();
73  return is_in_nondebug_insn () && (!next || next->is_in_debug_insn_or_phi ());
74}
75
76// Accumulate any properties about REF that are also stored in use_infos.
77// IS_FIRST is true if REF is the first access to resource () that we have
78// recorded in this way, false if we have already recorded previous
79// references.
80inline void
81use_info::record_reference (rtx_obj_reference ref, bool is_first)
82{
83  if (is_first)
84    {
85      m_includes_address_uses = ref.in_address ();
86      m_includes_read_writes = ref.is_write ();
87      m_includes_subregs = ref.in_subreg ();
88      m_includes_multiregs = ref.is_multireg ();
89      m_only_occurs_in_notes = ref.in_note ();
90    }
91  else
92    {
93      m_includes_address_uses |= ref.in_address ();
94      m_includes_read_writes |= ref.is_write ();
95      m_includes_subregs |= ref.in_subreg ();
96      m_includes_multiregs |= ref.is_multireg ();
97      m_only_occurs_in_notes &= ref.in_note ();
98    }
99}
100
101// Change the value of insn () to INSN.
102inline void
103use_info::set_insn (insn_info *insn)
104{
105  m_insn_or_phi = insn;
106  m_is_artificial = insn->is_artificial ();
107}
108
109// Copy the overloaded prev link from OTHER.
110inline void
111use_info::copy_prev_from (use_info *other)
112{
113  m_last_use_or_prev_use = other->m_last_use_or_prev_use;
114}
115
116// Copy the overloaded next link from OTHER.
117inline void
118use_info::copy_next_from (use_info *other)
119{
120  m_last_nondebug_insn_use_or_next_use
121    = other->m_last_nondebug_insn_use_or_next_use;
122  m_is_last_nondebug_insn_use = calculate_is_last_nondebug_insn_use ();
123}
124
125// Record that this use is the first in the list and that the last use is LAST.
126inline void
127use_info::set_last_use (use_info *last_use)
128{
129  m_last_use_or_prev_use.set_first (last_use);
130}
131
132// Record that this use is not the first in the list and that the previous
133// use is PREV.
134inline void
135use_info::set_prev_use (use_info *prev_use)
136{
137  m_last_use_or_prev_use.set_second (prev_use);
138}
139
140// Record that this use is the last use in the list.  If USE is nonnull,
141// record that USE is the last use in the list by a nondebug instruction,
142// otherwise record that there are no uses by nondebug instructions
143// in the list.
144inline void
145use_info::set_last_nondebug_insn_use (use_info *use)
146{
147  m_last_nondebug_insn_use_or_next_use.set_first (use);
148  m_is_last_nondebug_insn_use = (use == this);
149}
150
151// Record that this use is not the last in the list and that the next
152// use is NEXT_USE.
153inline void
154use_info::set_next_use (use_info *next_use)
155{
156  m_last_nondebug_insn_use_or_next_use.set_second (next_use);
157  m_is_last_nondebug_insn_use = calculate_is_last_nondebug_insn_use ();
158}
159
160// Clear any information relating to the position of the use in its
161// definition's list.
162inline void
163use_info::clear_use_links ()
164{
165  m_last_use_or_prev_use = nullptr;
166  m_last_nondebug_insn_use_or_next_use = nullptr;
167  m_is_last_nondebug_insn_use = false;
168}
169
170// Return true if the use has any links to other uses.  This is mostly
171// for assert checking.
172inline bool
173use_info::has_use_links ()
174{
175  return (m_last_use_or_prev_use
176	  || m_last_nondebug_insn_use_or_next_use
177	  || m_is_last_nondebug_insn_use);
178}
179
180// Construct a definition of RESOURCE in INSN, giving it kind KIND.
181inline def_info::def_info (insn_info *insn, resource_info resource,
182			   access_kind kind)
183  : access_info (resource, kind),
184    m_insn (insn),
185    m_last_def_or_prev_def (nullptr),
186    m_splay_root_or_next_def (nullptr)
187{
188  m_is_artificial = insn->is_artificial ();
189}
190
191// Record any properties about REF that are also stored in def_infos.
192// IS_FIRST is true if REF is the first access to resource () that we have
193// recorded in this way, false if we have already recorded previous
194// references.
195inline void
196def_info::record_reference (rtx_obj_reference ref, bool is_first)
197{
198  if (is_first)
199    {
200      m_is_pre_post_modify = ref.is_pre_post_modify ();
201      m_includes_read_writes = ref.is_read ();
202      m_includes_subregs = ref.in_subreg ();
203      m_includes_multiregs = ref.is_multireg ();
204    }
205  else
206    {
207      m_is_pre_post_modify |= ref.is_pre_post_modify ();
208      m_includes_read_writes |= ref.is_read ();
209      m_includes_subregs |= ref.in_subreg ();
210      m_includes_multiregs |= ref.is_multireg ();
211    }
212}
213
214// Return the last definition in the list.  Only valid when is_first ()
215// is true.
216inline def_info *
217def_info::last_def () const
218{
219  return m_last_def_or_prev_def.known_first ();
220}
221
222// Return the root of the splay tree of definitions of resource (),
223// or null if no splay tree has been created for this resource.
224// Only valid when is_last () is true.
225inline def_node *
226def_info::splay_root () const
227{
228  return m_splay_root_or_next_def.known_first ();
229}
230
231// Copy the overloaded prev link from OTHER.
232inline void
233def_info::copy_prev_from (def_info *other)
234{
235  m_last_def_or_prev_def
236    = other->m_last_def_or_prev_def;
237}
238
239// Copy the overloaded next link from OTHER.
240inline void
241def_info::copy_next_from (def_info *other)
242{
243  m_splay_root_or_next_def = other->m_splay_root_or_next_def;
244}
245
246// Record that this definition is the first in the list and that the last
247// definition is LAST.
248inline void
249def_info::set_last_def (def_info *last_def)
250{
251  m_last_def_or_prev_def.set_first (last_def);
252}
253
254// Record that this definition is not the first in the list and that the
255// previous definition is PREV.
256inline void
257def_info::set_prev_def (def_info *prev_def)
258{
259  m_last_def_or_prev_def.set_second (prev_def);
260}
261
262// Record that this definition is the last in the list and that the root
263// of the splay tree associated with resource () is ROOT.
264inline void
265def_info::set_splay_root (def_node *root)
266{
267  m_splay_root_or_next_def = root;
268}
269
270// Record that this definition is not the last in the list and that the
271// next definition is NEXT.
272inline void
273def_info::set_next_def (def_info *next_def)
274{
275  m_splay_root_or_next_def = next_def;
276}
277
278// Clear the prev and next links
279inline void
280def_info::clear_def_links ()
281{
282  m_last_def_or_prev_def = nullptr;
283  m_splay_root_or_next_def = nullptr;
284}
285
286// Return true if the definition has any links to other definitions.
287// This is mostly for assert checking.
288inline bool
289def_info::has_def_links ()
290{
291  return m_last_def_or_prev_def || m_splay_root_or_next_def;
292}
293
294// Construct a clobber of register REGNO in insn INSN.
295inline clobber_info::clobber_info (insn_info *insn, unsigned int regno)
296  : def_info (insn, { E_BLKmode, regno }, access_kind::CLOBBER),
297    m_children (),
298    m_parent (nullptr),
299    m_group (nullptr)
300{
301}
302
303// Set the containing group to GROUP, if it isn't already.  The main
304// use of this function is to update the new root of GROUP's splay tree.
305inline void
306clobber_info::update_group (clobber_group *group)
307{
308  if (__builtin_expect (m_group != group, 0))
309    m_group = group;
310}
311
312// Cconstruct a set_info for a store to RESOURCE in INSN, giving it
313// kind KIND.
314inline set_info::set_info (insn_info *insn, resource_info resource,
315			   access_kind kind)
316  : def_info (insn, resource, kind),
317    m_first_use (nullptr)
318{
319}
320
321// Cconstruct a set_info for a store to RESOURCE in INSN.
322inline set_info::set_info (insn_info *insn, resource_info resource)
323  : set_info (insn, resource, access_kind::SET)
324{
325}
326
327// Record that USE is the first use of this definition.
328inline void
329set_info::set_first_use (use_info *first_use)
330{
331  m_first_use = first_use;
332  m_is_set_with_nondebug_insn_uses
333    = (first_use && first_use->is_in_nondebug_insn ());
334}
335
336// Construct a phi for RESOURCE in INSN, giving it identifier UID.
337inline phi_info::phi_info (insn_info *insn, resource_info resource,
338			   unsigned int uid)
339  : set_info (insn, resource, access_kind::PHI),
340    m_uid (uid),
341    m_num_inputs (0),
342    m_prev_phi (nullptr),
343    m_next_phi (nullptr)
344{
345}
346
347// Turn the phi into a degenerate phi, with INPUT representing the
348// value of the resource on all incoming edges.
349inline void
350phi_info::make_degenerate (use_info *input)
351{
352  m_num_inputs = 1;
353  m_single_input = input;
354}
355
356// Set the inputs of the phi to INPUTS.
357inline void
358phi_info::set_inputs (use_array inputs)
359{
360  m_num_inputs = inputs.size ();
361  if (inputs.size () == 1)
362    m_single_input = inputs[0];
363  else
364    m_inputs = access_array (inputs).begin ();
365}
366
367// Construct a definition splay tree node for FIRST_DEF, which is either
368// the first clobber_info in a group or a standalone set_info.
369inline def_node::def_node (clobber_or_set first_def)
370  : m_clobber_or_set (first_def),
371    m_children ()
372{
373}
374
375// Construct a new group of clobber_infos that initially contains just CLOBBER.
376inline clobber_group::clobber_group (clobber_info *clobber)
377  : def_node (clobber),
378    m_last_clobber (clobber),
379    m_clobber_tree (clobber)
380{
381  clobber->m_group = this;
382}
383
384// Construct a node for the instruction with uid UID.
385inline insn_info::order_node::order_node (int uid)
386  : insn_note (kind),
387    m_children (),
388    m_parent (nullptr)
389{
390  m_data32 = uid;
391}
392
393// Construct a note for instruction INSN, giving it abi_id () value ABI_ID.
394inline insn_call_clobbers_note::insn_call_clobbers_note (unsigned int abi_id,
395							 insn_info *insn)
396  : insn_note (kind),
397    m_children (),
398    m_insn (insn)
399{
400  m_data32 = abi_id;
401}
402
403// Construct an instruction with the given bb () and rtl () values.
404// If the instruction is real, COST_OR_UID is the value of cost (),
405// otherwise it is the value of uid ().
406inline insn_info::insn_info (bb_info *bb, rtx_insn *rtl, int cost_or_uid)
407  : m_prev_insn_or_last_debug_insn (nullptr),
408    m_next_nondebug_or_debug_insn (nullptr),
409    m_bb (bb),
410    m_rtl (rtl),
411    m_accesses (nullptr),
412    m_num_uses (0),
413    m_num_defs (0),
414    m_is_debug_insn (rtl && DEBUG_INSN_P (rtl)),
415    m_can_be_optimized (false),
416    m_is_asm (false),
417    m_has_pre_post_modify (false),
418    m_has_volatile_refs (false),
419    m_spare (0),
420    m_point (0),
421    m_cost_or_uid (cost_or_uid),
422    m_first_note (nullptr)
423{
424}
425
426// Copy any insn properties from PROPERTIES that are also stored in an
427// insn_info.
428inline void
429insn_info::set_properties (const rtx_properties &properties)
430{
431  m_is_asm = properties.has_asm;
432  m_has_pre_post_modify = properties.has_pre_post_modify;
433  m_has_volatile_refs = properties.has_volatile_refs;
434  // Not strictly related to the properties we've been given, but it's
435  // a convenient location to do this.
436  m_can_be_optimized = (NONDEBUG_INSN_P (m_rtl)
437			& (GET_CODE (PATTERN (m_rtl)) != USE)
438			& (GET_CODE (PATTERN (m_rtl)) != CLOBBER));
439}
440
441// Change the list of instruction accesses to ACCESSES, which contains
442// NUM_DEFS definitions followed by NUM_USES uses.
443inline void
444insn_info::set_accesses (access_info **accesses,
445			 unsigned int num_defs, unsigned int num_uses)
446{
447  m_accesses = accesses;
448  m_num_defs = num_defs;
449  gcc_assert (num_defs == m_num_defs);
450  m_num_uses = num_uses;
451}
452
453// Change defs () and uses () to DEFS and USES respectively, given that
454// the existing m_accesses array has enough room for them.
455inline void
456insn_info::copy_accesses (access_array defs, access_array uses)
457{
458  gcc_assert (defs.size () + uses.size () <= m_num_defs + m_num_uses);
459  memcpy (m_accesses, defs.begin (), defs.size_bytes ());
460  memcpy (m_accesses + defs.size (), uses.begin (), uses.size_bytes ());
461  m_num_defs = defs.size ();
462  gcc_assert (m_num_defs == defs.size ());
463  m_num_uses = uses.size ();
464}
465
466// If the instruction has an insn_info::order_node, return the node,
467// otherwise return null.
468inline insn_info::order_node *
469insn_info::get_order_node () const
470{
471  // The order_node always comes first.
472  if (insn_note *note = first_note ())
473    return note->dyn_cast<insn_info::order_node *> ();
474  return nullptr;
475}
476
477// Like get_order_node (), but the node is known to exist.
478inline insn_info::order_node *
479insn_info::get_known_order_node () const
480{
481  // The order_node always comes first.
482  return first_note ()->as_a<insn_info::order_node *> ();
483}
484
485// Copy the overloaded prev link from OTHER.
486inline void
487insn_info::copy_prev_from (insn_info *other)
488{
489  m_prev_insn_or_last_debug_insn = other->m_prev_insn_or_last_debug_insn;
490}
491
492// Copy the overloaded next link from OTHER.
493inline void
494insn_info::copy_next_from (insn_info *other)
495{
496  m_next_nondebug_or_debug_insn = other->m_next_nondebug_or_debug_insn;
497}
498
499// If this is a nondebug instruction, record that the previous nondebug
500// instruction is PREV.  (There might be intervening debug instructions.)
501//
502// If this is a debug instruction, record that the previous instruction
503// is debug instruction PREV.
504inline void
505insn_info::set_prev_sametype_insn (insn_info *prev)
506{
507  m_prev_insn_or_last_debug_insn.set_first (prev);
508}
509
510// Only valid for debug instructions.  Record that this instruction starts
511// a subsequence of debug instructions that ends with LAST.
512inline void
513insn_info::set_last_debug_insn (insn_info *last)
514{
515  m_prev_insn_or_last_debug_insn.set_second (last);
516}
517
518// Record that the next instruction of any kind is NEXT.
519inline void
520insn_info::set_next_any_insn (insn_info *next)
521{
522  if (next && next->is_debug_insn ())
523    m_next_nondebug_or_debug_insn.set_second (next);
524  else
525    m_next_nondebug_or_debug_insn.set_first (next);
526}
527
528// Clear the list links and point number for this instruction.
529inline void
530insn_info::clear_insn_links ()
531{
532  m_prev_insn_or_last_debug_insn = nullptr;
533  m_next_nondebug_or_debug_insn = nullptr;
534  m_point = 0;
535}
536
537// Return true if the instruction contains any list information.
538// This is used by assert checking.
539inline bool
540insn_info::has_insn_links ()
541{
542  return (m_prev_insn_or_last_debug_insn
543	  || m_next_nondebug_or_debug_insn
544	  || m_point);
545}
546
547// Construct a representation of basic block CFG_BB.
548inline bb_info::bb_info (basic_block cfg_bb)
549  : m_prev_bb (nullptr),
550    m_next_bb (nullptr),
551    m_cfg_bb (cfg_bb),
552    m_ebb (nullptr),
553    m_head_insn (nullptr),
554    m_end_insn (nullptr)
555{
556}
557
558// Construct a tree of call clobbers for the given ABI.
559inline ebb_call_clobbers_info::
560ebb_call_clobbers_info (const predefined_function_abi *abi)
561  : m_next (nullptr),
562    m_abi (abi)
563{
564}
565
566// Construct an EBB whose first block is FIRST_BB and whose last block
567// is LAST_BB.
568inline ebb_info::ebb_info (bb_info *first_bb, bb_info *last_bb)
569  : m_first_phi (nullptr),
570    m_phi_insn (nullptr),
571    m_first_bb (first_bb),
572    m_last_bb (last_bb),
573    m_first_call_clobbers (nullptr)
574{
575}
576
577// Record register definition DEF in last_access, pushing a definition
578// to def_stack where appropriate.
579inline void
580function_info::build_info::record_reg_def (def_info *def)
581{
582  unsigned int regno = def->regno ();
583  auto *prev_dominating_def = safe_as_a<def_info *> (last_access[regno + 1]);
584  if (!prev_dominating_def)
585    // Indicate that DEF is the first dominating definition of REGNO.
586    def_stack.safe_push (def);
587  else if (prev_dominating_def->bb () != def->bb ())
588    // Record that PREV_DOMINATING_DEF was the dominating definition
589    // of REGNO on entry to the current block.
590    def_stack.safe_push (prev_dominating_def);
591  last_access[regno + 1] = def;
592}
593
594// Set the contents of last_access for memory to DEF.
595inline void
596function_info::build_info::record_mem_def (def_info *def)
597{
598  last_access[0] = def;
599}
600
601// Return the current value of live register REGNO, or null if the register's
602// value is completedly undefined.
603inline set_info *
604function_info::build_info::current_reg_value (unsigned int regno) const
605{
606  return safe_dyn_cast<set_info *> (last_access[regno + 1]);
607}
608
609// Return the current value of memory.
610inline set_info *
611function_info::build_info::current_mem_value () const
612{
613  return as_a<set_info *> (last_access[0]);
614}
615
616// Allocate a T on the function's main obstack, passing ARGS
617// to its constructor.
618template<typename T, typename... Ts>
619inline T *
620function_info::allocate (Ts... args)
621{
622  static_assert (std::is_trivially_destructible<T>::value,
623		 "destructor won't be called");
624  static_assert (alignof (T) <= obstack_alignment,
625		 "too much alignment required");
626  void *addr = obstack_alloc (&m_obstack, sizeof (T));
627  return new (addr) T (std::forward<Ts> (args)...);
628}
629
630// Allocate a T on the function's temporary obstack, passing ARGS
631// to its constructor.
632template<typename T, typename... Ts>
633inline T *
634function_info::allocate_temp (Ts... args)
635{
636  static_assert (std::is_trivially_destructible<T>::value,
637		 "destructor won't be called");
638  static_assert (alignof (T) <= obstack_alignment,
639		 "too much alignment required");
640  void *addr = obstack_alloc (&m_temp_obstack, sizeof (T));
641  return new (addr) T (std::forward<Ts> (args)...);
642}
643
644// Add INSN to the end of the function's list of instructions.
645inline void
646function_info::append_insn (insn_info *insn)
647{
648  gcc_checking_assert (!insn->has_insn_links ());
649  if (insn_info *after = m_last_insn)
650    add_insn_after (insn, after);
651  else
652    // The first instruction is for the entry block and is always a nondebug
653    // insn
654    m_first_insn = m_last_insn = m_last_nondebug_insn = insn;
655}
656
657// Start building a new list of uses and definitions for an instruction.
658inline void
659function_info::start_insn_accesses ()
660{
661  gcc_checking_assert (m_temp_defs.is_empty ()
662		       && m_temp_uses.is_empty ());
663}
664
665// Return a mode that encapsulates two distinct references to a register,
666// one with mode MODE1 and one with mode MODE2.  Treat BLKmode as a
667// "don't know" wildcard.
668inline machine_mode
669combine_modes (machine_mode mode1, machine_mode mode2)
670{
671  if (mode1 == E_BLKmode)
672    return mode2;
673
674  if (mode2 == E_BLKmode)
675    return mode1;
676
677  return wider_subreg_mode (mode1, mode2);
678}
679
680// PRINTER (PP, ARGS...) prints ARGS... to a pretty_printer PP.  Use it
681// to print ARGS... to FILE.
682template<typename Printer, typename... Args>
683inline void
684dump_using (FILE *file, Printer printer, Args... args)
685{
686  pretty_printer pp;
687  printer (&pp, args...);
688  pp_newline (&pp);
689  fprintf (file, "%s", pp_formatted_text (&pp));
690}
691
692}
693