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