diff options
Diffstat (limited to 'gcc/rtlanal.h')
-rw-r--r-- | gcc/rtlanal.h | 334 |
1 files changed, 334 insertions, 0 deletions
diff --git a/gcc/rtlanal.h b/gcc/rtlanal.h new file mode 100644 index 0000000..322761b --- /dev/null +++ b/gcc/rtlanal.h @@ -0,0 +1,334 @@ +/* Analyze RTL for GNU compiler. + Copyright (C) 2020 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +/* Note that for historical reasons, many rtlanal.c functions are + declared in rtl.h rather than here. */ + +#ifndef GCC_RTLANAL_H +#define GCC_RTLANAL_H + +/* A dummy register value that represents the whole of variable memory. + Using ~0U means that arrays that track both registers and memory can + be indexed by regno + 1. */ +const unsigned int MEM_REGNO = ~0U; + +/* Bitmasks of flags describing an rtx_obj_reference. See the accessors + in the class for details. */ +namespace rtx_obj_flags +{ + const uint16_t IS_READ = 1U << 0; + const uint16_t IS_WRITE = 1U << 1; + const uint16_t IS_CLOBBER = 1U << 2; + const uint16_t IS_PRE_POST_MODIFY = 1U << 3; + const uint16_t IS_MULTIREG = 1U << 4; + const uint16_t IN_MEM_LOAD = 1U << 5; + const uint16_t IN_MEM_STORE = 1U << 6; + const uint16_t IN_SUBREG = 1U << 7; + const uint16_t IN_NOTE = 1U << 8; + + /* Flags that apply to all subrtxes of the rtx they were originally + added for. */ + static const uint16_t STICKY_FLAGS = IN_NOTE; +} + +/* Contains information about a reference to a register or variable memory. */ +class rtx_obj_reference +{ +public: + rtx_obj_reference () = default; + rtx_obj_reference (unsigned int regno, uint16_t flags, + machine_mode mode, unsigned int multireg_offset = 0); + + bool is_reg () const { return regno != MEM_REGNO; } + bool is_mem () const { return regno == MEM_REGNO; } + + /* True if the reference is a read or a write respectively. + Both flags are set in a read-modify-write context, such as + for read_modify_subreg_p. */ + bool is_read () const { return flags & rtx_obj_flags::IS_READ; } + bool is_write () const { return flags & rtx_obj_flags::IS_WRITE; } + + /* True if IS_WRITE and if the write is a clobber rather than a set. */ + bool is_clobber () const { return flags & rtx_obj_flags::IS_CLOBBER; } + + /* True if the reference is updated by an RTX_AUTOINC. Both IS_READ + and IS_WRITE are also true if so. */ + bool is_pre_post_modify () const + { + return flags & rtx_obj_flags::IS_PRE_POST_MODIFY; + } + + /* True if the register is part of a multi-register hard REG. */ + bool is_multireg () const { return flags & rtx_obj_flags::IS_MULTIREG; } + + /* True if the reference occurs in the address of a load MEM. */ + bool in_mem_load () const { return flags & rtx_obj_flags::IN_MEM_LOAD; } + + /* True if the reference occurs in the address of a store MEM. */ + bool in_mem_store () const { return flags & rtx_obj_flags::IN_MEM_STORE; } + + /* True if the reference occurs in any kind of MEM address. */ + bool in_address () const { return in_mem_load () || in_mem_store (); } + + /* True if the reference occurs in a SUBREG. */ + bool in_subreg () const { return flags & rtx_obj_flags::IN_SUBREG; } + + /* True if the reference occurs in a REG_EQUAL or REG_EQUIV note. */ + bool in_note () const { return flags & rtx_obj_flags::IN_NOTE; } + + /* The referenced register, or MEM_REGNO for variable memory. */ + unsigned int regno; + + /* A bitmask of rtx_obj_flags. */ + unsigned int flags : 16; + + /* The mode of the reference. If IS_MULTIREG, this is the mode of + REGNO - MULTIREG_OFFSET. */ + machine_mode mode : 8; + + /* If IS_MULTIREG, the offset of REGNO from the start of the register. */ + unsigned int multireg_offset : 8; +}; + +/* Construct a reference with the given fields. */ + +inline rtx_obj_reference::rtx_obj_reference (unsigned int regno, uint16_t flags, + machine_mode mode, + unsigned int multireg_offset) + : regno (regno), + flags (flags), + mode (mode), + multireg_offset (multireg_offset) +{ +} + +/* Contains information about an rtx or an instruction, including a + list of rtx_obj_references. The storage backing the list needs + to be filled in by assigning to REF_BEGIN and REF_END. */ + +class rtx_properties +{ +public: + rtx_properties (); + + void try_to_add_reg (const_rtx x, unsigned int flags = 0); + void try_to_add_dest (const_rtx x, unsigned int flags = 0); + void try_to_add_src (const_rtx x, unsigned int flags = 0); + void try_to_add_pattern (const_rtx pat); + void try_to_add_note (const_rtx x); + void try_to_add_insn (const rtx_insn *insn, bool include_notes); + + iterator_range<rtx_obj_reference *> refs () const; + + /* Return the number of rtx_obj_references that have been recorded. */ + size_t num_refs () const { return ref_iter - ref_begin; } + + bool has_side_effects () const; + + /* [REF_BEGIN, REF_END) is the maximum extent of the memory available + for recording references. REG_ITER is the first unused entry. */ + rtx_obj_reference *ref_begin; + rtx_obj_reference *ref_iter; + rtx_obj_reference *ref_end; + + /* True if the rtx includes an asm. */ + unsigned int has_asm : 1; + + /* True if the rtx includes a call. */ + unsigned int has_call : 1; + + /* True if the rtx includes an RTX_AUTOINC expression. */ + unsigned int has_pre_post_modify : 1; + + /* True if the rtx contains volatile references, in the sense of + volatile_refs_p. */ + unsigned int has_volatile_refs : 1; + + /* For future expansion. */ + unsigned int spare : 28; +}; + +inline rtx_properties::rtx_properties () + : ref_begin (nullptr), + ref_iter (nullptr), + ref_end (nullptr), + has_asm (false), + has_call (false), + has_pre_post_modify (false), + has_volatile_refs (false), + spare (0) +{ +} + +/* Like add_src, but treat X has being part of a REG_EQUAL or + REG_EQUIV note. */ + +inline void +rtx_properties::try_to_add_note (const_rtx x) +{ + try_to_add_src (x, rtx_obj_flags::IN_NOTE); +} + +/* Return true if the rtx has side effects, in the sense of + side_effects_p (except for side_effects_p's special handling + of combine.c clobbers). */ + +inline bool +rtx_properties::has_side_effects () const +{ + return has_volatile_refs || has_pre_post_modify || has_call; +} + +/* Return an iterator range for all the references, suitable for + range-based for loops. */ + +inline iterator_range<rtx_obj_reference *> +rtx_properties::refs () const +{ + return { ref_begin, ref_iter }; +} + +/* BASE is derived from rtx_properties and provides backing storage + for REF_BEGIN. It has a grow () method that increases the amount + of memory available if the initial allocation was too small. */ + +template<typename Base> +class growing_rtx_properties : public Base +{ +public: + template<typename... Args> + growing_rtx_properties (Args...); + + template<typename AddFn> + void repeat (AddFn add); + + /* Wrappers around the try_to_* functions that always succeed. */ + void add_dest (const_rtx x, unsigned int flags = 0); + void add_src (const_rtx x, unsigned int flags = 0); + void add_pattern (const_rtx pat); + void add_note (const_rtx x); + void add_insn (const rtx_insn *insn, bool include_notes); +}; + +template<typename Base> +template<typename... Args> +growing_rtx_properties<Base>::growing_rtx_properties (Args... args) + : Base (std::forward<Args> (args)...) +{ +} + +/* Perform ADD until there is enough room to hold the result. */ + +template<typename Base> +template<typename AddFn> +inline void +growing_rtx_properties<Base>::repeat (AddFn add) +{ + ptrdiff_t count = this->num_refs (); + for (;;) + { + add (); + /* This retries if the storage happened to be exactly the right size, + but that's expected to be a rare case and so isn't worth + optimizing for. */ + if (__builtin_expect (this->ref_iter != this->ref_end, 1)) + break; + this->grow (count); + } +} + +template<typename Base> +inline void +growing_rtx_properties<Base>::add_dest (const_rtx x, unsigned int flags) +{ + repeat ([&]() { this->try_to_add_dest (x, flags); }); +} + +template<typename Base> +inline void +growing_rtx_properties<Base>::add_src (const_rtx x, unsigned int flags) +{ + repeat ([&]() { this->try_to_add_src (x, flags); }); +} + +template<typename Base> +inline void +growing_rtx_properties<Base>::add_pattern (const_rtx pat) +{ + repeat ([&]() { this->try_to_add_pattern (pat); }); +} + +template<typename Base> +inline void +growing_rtx_properties<Base>::add_note (const_rtx x) +{ + repeat ([&]() { this->try_to_add_note (x); }); +} + +template<typename Base> +inline void +growing_rtx_properties<Base>::add_insn (const rtx_insn *insn, bool include_notes) +{ + repeat ([&]() { this->try_to_add_insn (insn, include_notes); }); +} + +/* A base class for vec_rtx_properties; see there for details. */ + +class vec_rtx_properties_base : public rtx_properties +{ + static const size_t SIZE = 32; + +public: + vec_rtx_properties_base (); + ~vec_rtx_properties_base (); + +protected: + void grow (ptrdiff_t); + +private: + rtx_obj_reference m_storage[SIZE]; +}; + +inline vec_rtx_properties_base::vec_rtx_properties_base () +{ + ref_begin = ref_iter = m_storage; + ref_end = m_storage + SIZE; +} + +inline vec_rtx_properties_base::~vec_rtx_properties_base () +{ + if (__builtin_expect (ref_begin != m_storage, 0)) + free (ref_begin); +} + +/* A rtx_properties that stores its references in a temporary array. + Like auto_vec, the array is initially on the stack, but can switch + to the heap if necessary. + + The reason for implementing this as a derived class is that the + default on-stack size should be enough for the vast majority of + expressions and instructions. It's therefore not worth paying + the cost of conditionally calling grow code at every site that + records a new reference. Instead, the rtx_properties code can use + trivial iterator updates for the common case, and in the rare case + that the vector needs to be resized, we can pay the cost of + collecting the references a second time. */ +using vec_rtx_properties = growing_rtx_properties<vec_rtx_properties_base>; + +#endif |