(root)/
gcc-13.2.0/
gcc/
rtlanal.h
       1  /* Analyze RTL for GNU compiler.
       2     Copyright (C) 2020-2023 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  /* Note that for historical reasons, many rtlanal.cc functions are
      21     declared in rtl.h rather than here.  */
      22  
      23  #ifndef GCC_RTLANAL_H
      24  #define GCC_RTLANAL_H
      25  
      26  /* A dummy register value that represents the whole of variable memory.
      27     Using ~0U means that arrays that track both registers and memory can
      28     be indexed by regno + 1.  */
      29  const unsigned int MEM_REGNO = ~0U;
      30  
      31  /* Bitmasks of flags describing an rtx_obj_reference.  See the accessors
      32     in the class for details.  */
      33  namespace rtx_obj_flags
      34  {
      35    const uint16_t IS_READ = 1U << 0;
      36    const uint16_t IS_WRITE = 1U << 1;
      37    const uint16_t IS_CLOBBER = 1U << 2;
      38    const uint16_t IS_PRE_POST_MODIFY = 1U << 3;
      39    const uint16_t IS_MULTIREG = 1U << 4;
      40    const uint16_t IN_MEM_LOAD = 1U << 5;
      41    const uint16_t IN_MEM_STORE = 1U << 6;
      42    const uint16_t IN_SUBREG = 1U << 7;
      43    const uint16_t IN_NOTE = 1U << 8;
      44  
      45    /* Flags that apply to all subrtxes of the rtx they were originally
      46       added for.  */
      47    static const uint16_t STICKY_FLAGS = IN_NOTE;
      48  }
      49  
      50  /* Contains information about a reference to a register or variable memory.  */
      51  class rtx_obj_reference
      52  {
      53  public:
      54    rtx_obj_reference () = default;
      55    rtx_obj_reference (unsigned int regno, uint16_t flags,
      56  		     machine_mode mode, unsigned int multireg_offset = 0);
      57  
      58    bool is_reg () const { return regno != MEM_REGNO; }
      59    bool is_mem () const { return regno == MEM_REGNO; }
      60  
      61    /* True if the reference is a read or a write respectively.
      62       Both flags are set in a read-modify-write context, such as
      63       for read_modify_subreg_p.  */
      64    bool is_read () const { return flags & rtx_obj_flags::IS_READ; }
      65    bool is_write () const { return flags & rtx_obj_flags::IS_WRITE; }
      66  
      67    /* True if IS_WRITE and if the write is a clobber rather than a set.  */
      68    bool is_clobber () const { return flags & rtx_obj_flags::IS_CLOBBER; }
      69  
      70    /* True if the reference is updated by an RTX_AUTOINC.  Both IS_READ
      71       and IS_WRITE are also true if so.  */
      72    bool is_pre_post_modify () const
      73    {
      74      return flags & rtx_obj_flags::IS_PRE_POST_MODIFY;
      75    }
      76  
      77    /* True if the register is part of a multi-register hard REG.  */
      78    bool is_multireg () const { return flags & rtx_obj_flags::IS_MULTIREG; }
      79  
      80    /* True if the reference occurs in the address of a load MEM.  */
      81    bool in_mem_load () const { return flags & rtx_obj_flags::IN_MEM_LOAD; }
      82  
      83    /* True if the reference occurs in the address of a store MEM.  */
      84    bool in_mem_store () const { return flags & rtx_obj_flags::IN_MEM_STORE; }
      85  
      86    /* True if the reference occurs in any kind of MEM address.  */
      87    bool in_address () const { return in_mem_load () || in_mem_store (); }
      88  
      89    /* True if the reference occurs in a SUBREG.  */
      90    bool in_subreg () const { return flags & rtx_obj_flags::IN_SUBREG; }
      91  
      92    /* True if the reference occurs in a REG_EQUAL or REG_EQUIV note.  */
      93    bool in_note () const { return flags & rtx_obj_flags::IN_NOTE; }
      94  
      95    /* The referenced register, or MEM_REGNO for variable memory.  */
      96    unsigned int regno;
      97  
      98    /* A bitmask of rtx_obj_flags.  */
      99    unsigned int flags : 16;
     100  
     101    /* The mode of the reference.  If IS_MULTIREG, this is the mode of
     102       REGNO - MULTIREG_OFFSET.  */
     103    machine_mode mode : 8;
     104  
     105    /* If IS_MULTIREG, the offset of REGNO from the start of the register.  */
     106    unsigned int multireg_offset : 8;
     107  };
     108  
     109  /* Construct a reference with the given fields.  */
     110  
     111  inline rtx_obj_reference::rtx_obj_reference (unsigned int regno, uint16_t flags,
     112  					     machine_mode mode,
     113  					     unsigned int multireg_offset)
     114    : regno (regno),
     115      flags (flags),
     116      mode (mode),
     117      multireg_offset (multireg_offset)
     118  {
     119  }
     120  
     121  /* Contains information about an rtx or an instruction, including a
     122     list of rtx_obj_references.  The storage backing the list needs
     123     to be filled in by assigning to REF_BEGIN and REF_END.  */
     124  
     125  class rtx_properties
     126  {
     127  public:
     128    rtx_properties ();
     129  
     130    void try_to_add_reg (const_rtx x, unsigned int flags = 0);
     131    void try_to_add_dest (const_rtx x, unsigned int flags = 0);
     132    void try_to_add_src (const_rtx x, unsigned int flags = 0);
     133    void try_to_add_pattern (const_rtx pat);
     134    void try_to_add_note (const_rtx x);
     135    void try_to_add_insn (const rtx_insn *insn, bool include_notes);
     136  
     137    iterator_range<rtx_obj_reference *> refs () const;
     138  
     139    /* Return the number of rtx_obj_references that have been recorded.  */
     140    size_t num_refs () const { return ref_iter - ref_begin; }
     141  
     142    bool has_side_effects () const;
     143  
     144    /* [REF_BEGIN, REF_END) is the maximum extent of the memory available
     145       for recording references.  REG_ITER is the first unused entry.  */
     146    rtx_obj_reference *ref_begin;
     147    rtx_obj_reference *ref_iter;
     148    rtx_obj_reference *ref_end;
     149  
     150    /* True if the rtx includes an asm.  */
     151    unsigned int has_asm : 1;
     152  
     153    /* True if the rtx includes a call.  */
     154    unsigned int has_call : 1;
     155  
     156    /* True if the rtx includes an RTX_AUTOINC expression.  */
     157    unsigned int has_pre_post_modify : 1;
     158  
     159    /* True if the rtx contains volatile references, in the sense of
     160       volatile_refs_p.  */
     161    unsigned int has_volatile_refs : 1;
     162  
     163    /* For future expansion.  */
     164    unsigned int spare : 28;
     165  };
     166  
     167  inline rtx_properties::rtx_properties ()
     168    : ref_begin (nullptr),
     169      ref_iter (nullptr),
     170      ref_end (nullptr),
     171      has_asm (false),
     172      has_call (false),
     173      has_pre_post_modify (false),
     174      has_volatile_refs (false),
     175      spare (0)
     176  {
     177  }
     178  
     179  /* Like add_src, but treat X has being part of a REG_EQUAL or
     180     REG_EQUIV note.  */
     181  
     182  inline void
     183  rtx_properties::try_to_add_note (const_rtx x)
     184  {
     185    try_to_add_src (x, rtx_obj_flags::IN_NOTE);
     186  }
     187  
     188  /* Return true if the rtx has side effects, in the sense of
     189     side_effects_p (except for side_effects_p's special handling
     190     of combine.cc clobbers).  */
     191  
     192  inline bool
     193  rtx_properties::has_side_effects () const
     194  {
     195    return has_volatile_refs || has_pre_post_modify || has_call;
     196  }
     197  
     198  /* Return an iterator range for all the references, suitable for
     199     range-based for loops.  */
     200  
     201  inline iterator_range<rtx_obj_reference *>
     202  rtx_properties::refs () const
     203  {
     204    return { ref_begin, ref_iter };
     205  }
     206  
     207  /* BASE is derived from rtx_properties and provides backing storage
     208     for REF_BEGIN.  It has a grow () method that increases the amount
     209     of memory available if the initial allocation was too small.  */
     210  
     211  template<typename Base>
     212  class growing_rtx_properties : public Base
     213  {
     214  public:
     215    template<typename... Args>
     216    growing_rtx_properties (Args...);
     217  
     218    template<typename AddFn>
     219    void repeat (AddFn add);
     220  
     221    /* Wrappers around the try_to_* functions that always succeed.  */
     222    void add_dest (const_rtx x, unsigned int flags = 0);
     223    void add_src (const_rtx x, unsigned int flags = 0);
     224    void add_pattern (const_rtx pat);
     225    void add_note (const_rtx x);
     226    void add_insn (const rtx_insn *insn, bool include_notes);
     227  };
     228  
     229  template<typename Base>
     230  template<typename... Args>
     231  growing_rtx_properties<Base>::growing_rtx_properties (Args... args)
     232    : Base (std::forward<Args> (args)...)
     233  {
     234  }
     235  
     236  /* Perform ADD until there is enough room to hold the result.  */
     237  
     238  template<typename Base>
     239  template<typename AddFn>
     240  inline void
     241  growing_rtx_properties<Base>::repeat (AddFn add)
     242  {
     243    ptrdiff_t count = this->num_refs ();
     244    for (;;)
     245      {
     246        add ();
     247        /* This retries if the storage happened to be exactly the right size,
     248  	 but that's expected to be a rare case and so isn't worth
     249  	 optimizing for.  */
     250        if (LIKELY (this->ref_iter != this->ref_end))
     251  	break;
     252        this->grow (count);
     253      }
     254  }
     255  
     256  template<typename Base>
     257  inline void
     258  growing_rtx_properties<Base>::add_dest (const_rtx x, unsigned int flags)
     259  {
     260    repeat ([&]() { this->try_to_add_dest (x, flags); });
     261  }
     262  
     263  template<typename Base>
     264  inline void
     265  growing_rtx_properties<Base>::add_src (const_rtx x, unsigned int flags)
     266  {
     267    repeat ([&]() { this->try_to_add_src (x, flags); });
     268  }
     269  
     270  template<typename Base>
     271  inline void
     272  growing_rtx_properties<Base>::add_pattern (const_rtx pat)
     273  {
     274    repeat ([&]() { this->try_to_add_pattern (pat); });
     275  }
     276  
     277  template<typename Base>
     278  inline void
     279  growing_rtx_properties<Base>::add_note (const_rtx x)
     280  {
     281    repeat ([&]() { this->try_to_add_note (x); });
     282  }
     283  
     284  template<typename Base>
     285  inline void
     286  growing_rtx_properties<Base>::add_insn (const rtx_insn *insn, bool include_notes)
     287  {
     288    repeat ([&]() { this->try_to_add_insn (insn, include_notes); });
     289  }
     290  
     291  /* A base class for vec_rtx_properties; see there for details.  */
     292  
     293  class vec_rtx_properties_base : public rtx_properties
     294  {
     295    static const size_t SIZE = 32;
     296  
     297  public:
     298    vec_rtx_properties_base ();
     299    ~vec_rtx_properties_base ();
     300  
     301  protected:
     302    void grow (ptrdiff_t);
     303  
     304  private:
     305    rtx_obj_reference m_storage[SIZE];
     306  };
     307  
     308  inline vec_rtx_properties_base::vec_rtx_properties_base ()
     309  {
     310    ref_begin = ref_iter = m_storage;
     311    ref_end = m_storage + SIZE;
     312  }
     313  
     314  inline vec_rtx_properties_base::~vec_rtx_properties_base ()
     315  {
     316    if (UNLIKELY (ref_begin != m_storage))
     317      free (ref_begin);
     318  }
     319  
     320  /* A rtx_properties that stores its references in a temporary array.
     321     Like auto_vec, the array is initially on the stack, but can switch
     322     to the heap if necessary.
     323  
     324     The reason for implementing this as a derived class is that the
     325     default on-stack size should be enough for the vast majority of
     326     expressions and instructions.  It's therefore not worth paying
     327     the cost of conditionally calling grow code at every site that
     328     records a new reference.  Instead, the rtx_properties code can use
     329     trivial iterator updates for the common case, and in the rare case
     330     that the vector needs to be resized, we can pay the cost of
     331     collecting the references a second time.  */
     332  using vec_rtx_properties = growing_rtx_properties<vec_rtx_properties_base>;
     333  
     334  bool
     335  vec_series_highpart_p (machine_mode result_mode, machine_mode op_mode,
     336  		       rtx sel);
     337  
     338  bool
     339  vec_series_lowpart_p (machine_mode result_mode, machine_mode op_mode, rtx sel);
     340  
     341  bool
     342  contains_paradoxical_subreg_p (rtx x);
     343  #endif