• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef COMPILER_OPTIMIZER_IR_INST_H
17 #define COMPILER_OPTIMIZER_IR_INST_H
18 
19 #include <array>
20 #include <vector>
21 #include <iostream>
22 #include "constants.h"
23 #include "datatype.h"
24 #include "ir-dyn-base-types.h"
25 #include "marker.h"
26 #include "utils/arena_containers.h"
27 #include "utils/span.h"
28 #include "utils/bit_field.h"
29 #include "utils/bit_utils.h"
30 #include "utils/bit_vector.h"
31 #include "macros.h"
32 #include "mem/arena_allocator.h"
33 #include "opcodes.h"
34 #include "compiler_options.h"
35 #include "runtime_interface.h"
36 #include "spill_fill_data.h"
37 
38 namespace panda::compiler {
39 class Inst;
40 class BasicBlock;
41 class Graph;
42 class GraphVisitor;
43 class VnObject;
44 class SaveStateItem;
45 class LocationsInfo;
46 using InstVector = ArenaVector<Inst *>;
47 
48 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
49 #define INST_DEF(opcode, base, ...) class base;
50 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
51 OPCODE_LIST(INST_DEF)
52 #undef INST_DEF
53 
54 /*
55  * Condition code, used in Compare, If[Imm] and Select[Imm] instructions.
56  *
57  * N.B. BranchElimination and Peephole rely on the order of these codes. Change carefully.
58  */
59 enum ConditionCode {
60     // All types.
61     CC_EQ = 0,  // ==
62     CC_NE,      // !=
63     // Signed integers and floating-point numbers.
64     CC_LT,  // <
65     CC_LE,  // <=
66     CC_GT,  // >
67     CC_GE,  // >=
68     // Unsigned integers.
69     CC_B,   // <
70     CC_BE,  // <=
71     CC_A,   // >
72     CC_AE,  // >=
73     // Compare result of bitwise AND with zero
74     CC_TST_EQ,  // (lhs AND rhs) == 0
75     CC_TST_NE,  // (lhs AND rhs) != 0
76     // First and last aliases.
77     CC_FIRST = CC_EQ,
78     CC_LAST = CC_TST_NE,
79 };
80 
GetInverseConditionCode(ConditionCode code)81 inline ConditionCode GetInverseConditionCode(ConditionCode code)
82 {
83     switch (code) {
84         case ConditionCode::CC_EQ:
85             return ConditionCode::CC_NE;
86         case ConditionCode::CC_NE:
87             return ConditionCode::CC_EQ;
88 
89         case ConditionCode::CC_LT:
90             return ConditionCode::CC_GE;
91         case ConditionCode::CC_LE:
92             return ConditionCode::CC_GT;
93         case ConditionCode::CC_GT:
94             return ConditionCode::CC_LE;
95         case ConditionCode::CC_GE:
96             return ConditionCode::CC_LT;
97 
98         case ConditionCode::CC_B:
99             return ConditionCode::CC_AE;
100         case ConditionCode::CC_BE:
101             return ConditionCode::CC_A;
102         case ConditionCode::CC_A:
103             return ConditionCode::CC_BE;
104         case ConditionCode::CC_AE:
105             return ConditionCode::CC_B;
106 
107         case ConditionCode::CC_TST_EQ:
108             return ConditionCode::CC_TST_NE;
109         case ConditionCode::CC_TST_NE:
110             return ConditionCode::CC_TST_EQ;
111 
112         default:
113             UNREACHABLE();
114     }
115 }
116 
InverseSignednessConditionCode(ConditionCode code)117 inline ConditionCode InverseSignednessConditionCode(ConditionCode code)
118 {
119     switch (code) {
120         case ConditionCode::CC_EQ:
121             return ConditionCode::CC_EQ;
122         case ConditionCode::CC_NE:
123             return ConditionCode::CC_NE;
124 
125         case ConditionCode::CC_LT:
126             return ConditionCode::CC_B;
127         case ConditionCode::CC_LE:
128             return ConditionCode::CC_BE;
129         case ConditionCode::CC_GT:
130             return ConditionCode::CC_A;
131         case ConditionCode::CC_GE:
132             return ConditionCode::CC_AE;
133 
134         case ConditionCode::CC_B:
135             return ConditionCode::CC_LT;
136         case ConditionCode::CC_BE:
137             return ConditionCode::CC_LE;
138         case ConditionCode::CC_A:
139             return ConditionCode::CC_GT;
140         case ConditionCode::CC_AE:
141             return ConditionCode::CC_GE;
142 
143         case ConditionCode::CC_TST_EQ:
144             return ConditionCode::CC_TST_EQ;
145         case ConditionCode::CC_TST_NE:
146             return ConditionCode::CC_TST_NE;
147 
148         default:
149             UNREACHABLE();
150     }
151 }
152 
IsSignedConditionCode(ConditionCode code)153 inline bool IsSignedConditionCode(ConditionCode code)
154 {
155     switch (code) {
156         case ConditionCode::CC_LT:
157         case ConditionCode::CC_LE:
158         case ConditionCode::CC_GT:
159         case ConditionCode::CC_GE:
160             return true;
161 
162         case ConditionCode::CC_EQ:
163         case ConditionCode::CC_NE:
164         case ConditionCode::CC_B:
165         case ConditionCode::CC_BE:
166         case ConditionCode::CC_A:
167         case ConditionCode::CC_AE:
168         case ConditionCode::CC_TST_EQ:
169         case ConditionCode::CC_TST_NE:
170             return false;
171 
172         default:
173             UNREACHABLE();
174     }
175 }
176 
SwapOperandsConditionCode(ConditionCode code)177 inline ConditionCode SwapOperandsConditionCode(ConditionCode code)
178 {
179     switch (code) {
180         case ConditionCode::CC_EQ:
181         case ConditionCode::CC_NE:
182             return code;
183 
184         case ConditionCode::CC_LT:
185             return ConditionCode::CC_GT;
186         case ConditionCode::CC_LE:
187             return ConditionCode::CC_GE;
188         case ConditionCode::CC_GT:
189             return ConditionCode::CC_LT;
190         case ConditionCode::CC_GE:
191             return ConditionCode::CC_LE;
192 
193         case ConditionCode::CC_B:
194             return ConditionCode::CC_A;
195         case ConditionCode::CC_BE:
196             return ConditionCode::CC_AE;
197         case ConditionCode::CC_A:
198             return ConditionCode::CC_B;
199         case ConditionCode::CC_AE:
200             return ConditionCode::CC_BE;
201 
202         case ConditionCode::CC_TST_EQ:
203         case ConditionCode::CC_TST_NE:
204             return code;
205 
206         default:
207             UNREACHABLE();
208     }
209 }
210 
211 enum class Opcode {
212     INVALID = -1,
213 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
214 #define INST_DEF(opcode, ...) opcode,
215     OPCODE_LIST(INST_DEF)
216 
217 #undef INST_DEF
218         NUM_OPCODES
219 };
220 
221 /**
222  * Convert opcode to its string representation
223  */
224 constexpr std::array<const char *const, static_cast<size_t>(Opcode::NUM_OPCODES)> OPCODE_NAMES = {
225 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
226 #define INST_DEF(opcode, ...) #opcode,
227     OPCODE_LIST(INST_DEF)
228 #undef INST_DEF
229 };
230 
GetOpcodeString(Opcode opc)231 constexpr const char *GetOpcodeString(Opcode opc)
232 {
233     ASSERT(static_cast<int>(opc) < static_cast<int>(Opcode::NUM_OPCODES));
234     return OPCODE_NAMES[static_cast<int>(opc)];
235 }
236 
237 /**
238  * Instruction flags. See `instrutions.yaml` section `flags` for more information.
239  */
240 namespace inst_flags {
241 namespace internal {
242 enum FlagsIndex {
243 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
244 #define FLAG_DEF(flag) flag##_INDEX,
245     FLAGS_LIST(FLAG_DEF)
246 #undef FLAG_DEF
247         FLAGS_COUNT
248 };
249 }  // namespace internal
250 
251 enum Flags : uint32_t {
252 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
253 #define FLAG_DEF(flag) flag = (1U << internal::flag##_INDEX),
254     FLAGS_LIST(FLAG_DEF)
255 #undef FLAG_DEF
256         FLAGS_COUNT = internal::FLAGS_COUNT,
257     NONE = 0
258 };
259 
GetFlagsMask(Opcode opcode)260 inline constexpr uintptr_t GetFlagsMask(Opcode opcode)
261 {
262 #define INST_DEF(OPCODE, BASE, FLAGS) FLAGS,  // NOLINT(cppcoreguidelines-macro-usage)
263     // NOLINTNEXTLINE(hicpp-signed-bitwise)
264     constexpr std::array<uintptr_t, static_cast<int>(Opcode::NUM_OPCODES)> INST_FLAGS_TABLE = {OPCODE_LIST(INST_DEF)};
265 #undef INST_DEF
266     return INST_FLAGS_TABLE[static_cast<size_t>(opcode)];
267 }
268 }  // namespace inst_flags
269 
270 #ifndef NDEBUG
271 namespace inst_modes {
272 namespace internal {
273 enum ModeIndex {
274 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
275 #define MODE_DEF(mode) mode##_INDEX,
276     MODES_LIST(MODE_DEF)
277 #undef MODE_DEF
278         MODES_COUNT
279 };
280 }  // namespace internal
281 
282 enum Mode : uint8_t {
283 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
284 #define MODE_DEF(mode) mode = (1U << internal::mode##_INDEX),
285     MODES_LIST(MODE_DEF)
286 #undef MODE_DEF
287         MODES_COUNT = internal::MODES_COUNT,
288 };
289 
GetModesMask(Opcode opcode)290 inline constexpr uint8_t GetModesMask(Opcode opcode)
291 {
292     // NOLINTNEXTLINE(hicpp-signed-bitwise)
293     constexpr std::array<uint8_t, static_cast<int>(Opcode::NUM_OPCODES)> INST_MODES_TABLE = {INST_MODES_LIST};
294     return INST_MODES_TABLE[static_cast<size_t>(opcode)];
295 }
296 }  // namespace inst_modes
297 #endif
298 
299 namespace internal {
300 inline constexpr std::array<const char *, ShiftType::INVALID_SHIFT + 1> SHIFT_TYPE_NAMES = {"LSL", "LSR", "ASR", "ROR",
301                                                                                             "INVALID"};
302 }  // namespace internal
303 
GetShiftTypeStr(ShiftType type)304 inline const char *GetShiftTypeStr(ShiftType type)
305 {
306     ASSERT(type <= INVALID_SHIFT);
307     return internal::SHIFT_TYPE_NAMES[type];
308 }
309 
310 /**
311  * Describes type of the object produced by an instruction.
312  */
313 class ObjectTypeInfo {
314 public:
315     using ClassType = RuntimeInterface::ClassPtr;
316 
317     ObjectTypeInfo() = default;
ObjectTypeInfo(ClassType v)318     explicit ObjectTypeInfo(ClassType v) : class_(v) {}
319 
320     // NOLINTNEXTLINE(google-explicit-constructor)
321     operator bool() const
322     {
323         return class_ != ClassType();
324     }
325 
GetClass()326     ClassType GetClass() const
327     {
328         return class_;
329     }
330 
IsValid()331     bool IsValid() const
332     {
333         return class_ != ClassType {};
334     }
335 
336 private:
337     ClassType class_ {};
338 };
339 
340 /**
341  * Class for storing panda bytecode's virtual register
342  */
343 class VirtualRegister final {
344 public:
345     using ValueType = uint16_t;
346     static constexpr unsigned BITS_FOR_VREG = (sizeof(ValueType) * BITS_PER_BYTE) - 1;
347     static constexpr ValueType INVALID = std::numeric_limits<ValueType>::max();
348 
349     VirtualRegister() = default;
VirtualRegister(uint16_t v,bool is_acc)350     explicit VirtualRegister(uint16_t v, bool is_acc) : value_(v)
351     {
352         IsAccFlag::Set(is_acc, &value_);
353     }
354 
uint16_t()355     explicit operator uint16_t() const
356     {
357         return value_;
358     }
359 
Value()360     uint16_t Value() const
361     {
362         return ValueField::Get(value_);
363     }
364 
IsAccumulator()365     bool IsAccumulator() const
366     {
367         return IsAccFlag::Get(value_);
368     }
369 
370 private:
371     uint16_t value_ {INVALID};
372 
373     using ValueField = BitField<unsigned, 0, BITS_FOR_VREG>;
374     using IsAccFlag = ValueField::NextFlag;
375 };
376 
377 // How many bits will be used in Inst's bit fields for number of inputs.
378 constexpr size_t BITS_PER_INPUTS_NUM = 3;
379 // Maximum number of static inputs
380 constexpr size_t MAX_STATIC_INPUTS = (1U << BITS_PER_INPUTS_NUM) - 1;
381 
382 /**
383  * Currently Input class is just a wrapper for the Inst class.
384  */
385 class Input final {
386 public:
387     Input() = default;
Input(Inst * inst)388     explicit Input(Inst *inst) : inst_(inst) {}
389 
GetInst()390     Inst *GetInst()
391     {
392         return inst_;
393     }
GetInst()394     const Inst *GetInst() const
395     {
396         return inst_;
397     }
398 
GetPadding(Arch arch,uint32_t inputs_count)399     static inline uint8_t GetPadding(Arch arch, uint32_t inputs_count)
400     {
401         return static_cast<uint8_t>(!Is64BitsArch(arch) && inputs_count % 2U == 1U);
402     }
403 
404 private:
405     Inst *inst_ {nullptr};
406 };
407 
408 /**
409  * User is a intrusive list node, thus it stores pointers to next and previous users.
410  * Also user has properties value to determine owner instruction and corresponding index of the input.
411  */
412 class User final {
413 public:
414     User() = default;
User(bool is_static,unsigned index,unsigned size)415     User(bool is_static, unsigned index, unsigned size)
416         : properties_(IsStaticFlag::Encode(is_static) | IndexField::Encode(index) | SizeField::Encode(size) |
417                       BbNumField::Encode(BbNumField::MaxValue()))
418     {
419         ASSERT(index < 1U << (BITS_FOR_INDEX - 1U));
420         ASSERT(size < 1U << (BITS_FOR_SIZE - 1U));
421     }
422     ~User() = default;
423 
424     // Copy/move semantic is disabled because we use tricky pointer arithmetic based on 'this' value
425     NO_COPY_SEMANTIC(User);
426     NO_MOVE_SEMANTIC(User);
427 
428     Inst *GetInst();
GetInst()429     const Inst *GetInst() const
430     {
431         return const_cast<User *>(this)->GetInst();
432     }
433 
434     Inst *GetInput();
435     const Inst *GetInput() const;
436 
IsDynamic()437     bool IsDynamic() const
438     {
439         return !IsStaticFlag::Decode(properties_);
440     }
GetIndex()441     unsigned GetIndex() const
442     {
443         return IndexField::Decode(properties_);
444     }
GetSize()445     unsigned GetSize() const
446     {
447         return SizeField::Decode(properties_);
448     }
449 
GetVirtualRegister()450     VirtualRegister GetVirtualRegister() const
451     {
452         ASSERT(IsDynamic());
453         return VirtualRegister(VregField::Decode(properties_), IsAccFlag::Decode(properties_));
454     }
455 
SetVirtualRegister(VirtualRegister reg)456     void SetVirtualRegister(VirtualRegister reg)
457     {
458         static_assert(sizeof(reg) <= sizeof(uintptr_t), "Consider passing the register by reference");
459         ASSERT(IsDynamic());
460         VregField::Set(reg.Value(), &properties_);
461         IsAccFlag::Set(reg.IsAccumulator(), &properties_);
462     }
463 
GetBbNum()464     uint32_t GetBbNum() const
465     {
466         ASSERT(IsDynamic());
467         return BbNumField::Decode(properties_);
468     }
469 
SetBbNum(uint32_t bb_num)470     void SetBbNum(uint32_t bb_num)
471     {
472         ASSERT(IsDynamic());
473         BbNumField::Set(bb_num, &properties_);
474     }
475 
GetNext()476     auto GetNext() const
477     {
478         return next_;
479     }
480 
GetPrev()481     auto GetPrev() const
482     {
483         return prev_;
484     }
485 
SetNext(User * next)486     void SetNext(User *next)
487     {
488         next_ = next;
489     }
490 
SetPrev(User * prev)491     void SetPrev(User *prev)
492     {
493         prev_ = prev;
494     }
495 
Remove()496     void Remove()
497     {
498         if (prev_ != nullptr) {
499             prev_->next_ = next_;
500         }
501         if (next_ != nullptr) {
502             next_->prev_ = prev_;
503         }
504     }
505 
506 private:
507     static constexpr unsigned BITS_FOR_INDEX = 21;
508     static constexpr unsigned BITS_FOR_SIZE = BITS_FOR_INDEX;
509     static constexpr unsigned BITS_FOR_BB_NUM = 20;
510     using IndexField = BitField<unsigned, 0, BITS_FOR_INDEX>;
511     using SizeField = IndexField::NextField<unsigned, BITS_FOR_SIZE>;
512     using IsStaticFlag = SizeField::NextFlag;
513 
514     using BbNumField = IsStaticFlag::NextField<uint32_t, BITS_FOR_BB_NUM>;
515 
516     using VregField = IsStaticFlag::NextField<unsigned, VirtualRegister::BITS_FOR_VREG>;
517     using IsAccFlag = VregField::NextFlag;
518 
519     uint64_t properties_ {0};
520     User *next_ {nullptr};
521     User *prev_ {nullptr};
522 };
523 
524 /**
525  * List of users. Intended for range loop.
526  * @tparam T should be User or const User
527  */
528 template <typename T>
529 class UserList {
530     template <typename U>
531     struct UserIterator {
532         UserIterator() = default;
UserIteratorUserIterator533         explicit UserIterator(U *u) : user_(u) {}
534 
535         UserIterator &operator++()
536         {
537             user_ = user_->GetNext();
538             return *this;
539         }
540         bool operator!=(const UserIterator &other)
541         {
542             return user_ != other.user_;
543         }
544         U &operator*()
545         {
546             return *user_;
547         }
548         U *operator->()
549         {
550             return user_;
551         }
552 
553     private:
554         U *user_ {nullptr};
555     };
556 
557 public:
558     using Iterator = UserIterator<T>;
559     using ConstIterator = UserIterator<const T>;
560     using PointerType = std::conditional_t<std::is_const_v<T>, T *const *, T **>;
561 
UserList(PointerType head)562     explicit UserList(PointerType head) : head_(head) {}
563 
564     // NOLINTNEXTLINE(readability-identifier-naming)
begin()565     Iterator begin()
566     {
567         return Iterator(*head_);
568     }
569     // NOLINTNEXTLINE(readability-identifier-naming)
end()570     Iterator end()
571     {
572         return Iterator(nullptr);
573     }
574     // NOLINTNEXTLINE(readability-identifier-naming)
begin()575     ConstIterator begin() const
576     {
577         return ConstIterator(*head_);
578     }
579     // NOLINTNEXTLINE(readability-identifier-naming)
end()580     ConstIterator end() const
581     {
582         return ConstIterator(nullptr);
583     }
Empty()584     bool Empty() const
585     {
586         return *head_ == nullptr;
587     }
Front()588     T &Front()
589     {
590         return **head_;
591     }
Front()592     const T &Front() const
593     {
594         return **head_;
595     }
596 
597 private:
598     PointerType head_ {nullptr};
599 };
600 
601 inline bool operator==(const User &lhs, const User &rhs)
602 {
603     return lhs.GetInst() == rhs.GetInst();
604 }
605 
606 /**
607  * Operands class for instructions with fixed inputs count.
608  * Actually, this class do absolutely nothing except that we can get sizeof of it when allocating memory.
609  */
610 template <int N>
611 struct Operands {
612     static_assert(N < MAX_STATIC_INPUTS, "Invalid inputs number");
613 
614     std::array<User, N> users;
615     std::array<Input, N> inputs;
616 };
617 
618 /**
619  * Specialized version for instructions with variable inputs count.
620  * Users and inputs are stored outside of this class.
621  */
622 class DynamicOperands {
623 public:
DynamicOperands(ArenaAllocator * allocator)624     explicit DynamicOperands(ArenaAllocator *allocator) : allocator_(allocator) {}
625 
Users()626     User *Users()
627     {
628         return users_;
629     }
630 
Inputs()631     Input *Inputs()
632     {
633         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
634         return reinterpret_cast<Input *>(users_ + capacity_) + 1;
635     }
636 
637     /// Append new input (and user accordingly)
638     unsigned Append(Inst *inst);
639 
640     /// Remove input and user with index `index`.
641     void Remove(unsigned index);
642 
643     /// Reallocate inputs/users storage to a new one with specified capacity.
644     void Reallocate(size_t new_capacity = 0);
645 
646     /// Get instruction to which these operands belongs to.
GetOwnerInst()647     Inst *GetOwnerInst() const
648     {
649         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
650         return reinterpret_cast<Inst *>(const_cast<DynamicOperands *>(this) + 1);
651     }
652 
GetUser(unsigned index)653     User *GetUser(unsigned index)
654     {
655         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
656         return &users_[capacity_ - index - 1];
657     }
658 
GetInput(unsigned index)659     Input *GetInput(unsigned index)
660     {
661         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
662         return &Inputs()[index];
663     }
664 
SetInput(unsigned index,Input input)665     void SetInput(unsigned index, Input input)
666     {
667         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
668         Inputs()[index] = input;
669     }
670 
Size()671     size_t Size() const
672     {
673         return size_;
674     }
675 
676 private:
677     User *users_ {nullptr};
678     size_t size_ {0};
679     size_t capacity_ {0};
680     ArenaAllocator *allocator_ {nullptr};
681 };
682 
683 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
684 #define DECLARE_INST(TYPE) void Accept(GraphVisitor *v) override
685 
686 /**
687  * Base class for all instructions, should not be instantiated directly
688  */
689 class InstBase {
690     NO_COPY_SEMANTIC(InstBase);
691     NO_MOVE_SEMANTIC(InstBase);
692 
693 public:
694     virtual ~InstBase() = default;
695 
696 public:
697     virtual void Accept(GraphVisitor *v) = 0;
698 
delete(void * unused,size_t size)699     ALWAYS_INLINE void operator delete([[maybe_unused]] void *unused, [[maybe_unused]] size_t size)
700     {
701         UNREACHABLE();
702     }
new(size_t size,void * ptr)703     ALWAYS_INLINE void *operator new([[maybe_unused]] size_t size, void *ptr) noexcept
704     {
705         return ptr;
706     }
delete(void * unused1,void * unused2)707     ALWAYS_INLINE void operator delete([[maybe_unused]] void *unused1, [[maybe_unused]] void *unused2) noexcept {}
708 
709     void *operator new([[maybe_unused]] size_t size) = delete;
710 
711 protected:
712     InstBase() = default;
713 };
714 
715 /**
716  * Base instruction class
717  */
718 class Inst : public MarkerSet, public InstBase {
719 public:
720     DECLARE_INST(Inst);
721 
722 public:
723     /**
724      * Create new instruction. All instructions must be created with this method.
725      * It allocates additional space before Inst object for def-use structures.
726      *
727      * @tparam InstType - concrete type of instruction, shall be derived from Inst
728      * @tparam Args - constructor arguments types
729      * @param allocator - allocator for memory allocating
730      * @param args - constructor arguments
731      * @return - new instruction
732      */
733     template <typename InstType, typename... Args>
734     [[nodiscard]] static InstType *New(ArenaAllocator *allocator, Args &&... args);
735 
736     // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
737 #define INST_DEF(opcode, base, ...) inline const base *CastTo##opcode() const;
738     OPCODE_LIST(INST_DEF)
739 #undef INST_DEF
740 
741     // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
742 #define INST_DEF(opcode, base, ...) inline base *CastTo##opcode();
OPCODE_LIST(INST_DEF)743     OPCODE_LIST(INST_DEF)
744 #undef INST_DEF
745 
746     // Methods for instruction chaining inside basic blocks.
747     Inst *GetNext()
748     {
749         return next_;
750     }
GetNext()751     const Inst *GetNext() const
752     {
753         return next_;
754     }
GetPrev()755     Inst *GetPrev()
756     {
757         return prev_;
758     }
GetPrev()759     const Inst *GetPrev() const
760     {
761         return prev_;
762     }
SetNext(Inst * next)763     void SetNext(Inst *next)
764     {
765         next_ = next;
766     }
SetPrev(Inst * prev)767     void SetPrev(Inst *prev)
768     {
769         prev_ = prev;
770     }
771 
772     // Id accessors
GetId()773     auto GetId() const
774     {
775         return id_;
776     }
SetId(int id)777     void SetId(int id)
778     {
779         id_ = id;
780     }
781 
GetLinearNumber()782     auto GetLinearNumber() const
783     {
784         return linear_number_;
785     }
SetLinearNumber(LinearNumber number)786     void SetLinearNumber(LinearNumber number)
787     {
788         linear_number_ = number;
789     }
790 
GetCloneNumber()791     auto GetCloneNumber() const
792     {
793         return clone_number_;
794     }
SetCloneNumber(int32_t number)795     void SetCloneNumber(int32_t number)
796     {
797         clone_number_ = number;
798     }
799 
800     // Opcode accessors
GetOpcode()801     Opcode GetOpcode() const
802     {
803         return opcode_;
804     }
SetOpcode(Opcode opcode)805     void SetOpcode(Opcode opcode)
806     {
807         opcode_ = opcode;
808         SetField<FieldFlags>(inst_flags::GetFlagsMask(opcode));
809     }
GetOpcodeStr()810     const char *GetOpcodeStr() const
811     {
812         return GetOpcodeString(GetOpcode());
813     }
814 
815     // Bytecode PC accessors
GetPc()816     uint32_t GetPc() const
817     {
818         return pc_;
819     }
SetPc(uint32_t pc)820     void SetPc(uint32_t pc)
821     {
822         pc_ = pc;
823     }
824 
825     // Type accessors
GetType()826     DataType::Type GetType() const
827     {
828         return FieldType::Get(bit_fields_);
829     }
SetType(DataType::Type type)830     void SetType(DataType::Type type)
831     {
832         FieldType::Set(type, &bit_fields_);
833     }
HasType()834     bool HasType() const
835     {
836         return GetType() != DataType::Type::NO_TYPE;
837     }
838 
839     // Parent basic block accessors
GetBasicBlock()840     BasicBlock *GetBasicBlock()
841     {
842         return bb_;
843     }
GetBasicBlock()844     const BasicBlock *GetBasicBlock() const
845     {
846         return bb_;
847     }
SetBasicBlock(BasicBlock * bb)848     void SetBasicBlock(BasicBlock *bb)
849     {
850         bb_ = bb;
851     }
852 
853     // Instruction properties getters
IsControlFlow()854     bool IsControlFlow() const
855     {
856         return GetFlag(inst_flags::CF);
857     }
IsVirtualCall()858     bool IsVirtualCall() const
859     {
860         return GetOpcode() == Opcode::CallVirtual || GetOpcode() == Opcode::UnresolvedCallVirtual;
861     }
IsStaticCall()862     bool IsStaticCall() const
863     {
864         return GetOpcode() == Opcode::CallStatic || GetOpcode() == Opcode::UnresolvedCallStatic;
865     }
IsInitObject()866     bool IsInitObject() const
867     {
868         return GetOpcode() == Opcode::InitObject;
869     }
IsMultiArray()870     bool IsMultiArray() const
871     {
872         return GetOpcode() == Opcode::MultiArray;
873     }
IsDynamicCall()874     bool IsDynamicCall() const
875     {
876         return GetOpcode() == Opcode::CallDynamic;
877     }
IsIndirectCall()878     bool IsIndirectCall() const
879     {
880         return GetOpcode() == Opcode::CallIndirect;
881     }
IsIntrinsic()882     bool IsIntrinsic() const
883     {
884         /* Opcode::Builtin is left for backward compatibility, the compiler
885          * itself should never generate an instruction with such an opcode */
886         return GetOpcode() == Opcode::Intrinsic || GetOpcode() == Opcode::Builtin;
887     }
888 
889     /* IsBuiltin actual meaning would be "it MAY be inlined by the CG"
890      * however, since we do not make guarantees about whether it will
891      * actually be inlined nor the safety of the intrinsic itself, just
892      * checking the instruction flags to see if it is suitable for any
893      * particular optimization seems to be a better approach
894      */
IsBuiltin()895     static bool IsBuiltin()
896     {
897         return false;
898     }
899 
IsCall()900     bool IsCall() const
901     {
902         return GetFlag(inst_flags::CALL);
903     }
904 
IsSpillFill()905     bool IsSpillFill() const
906     {
907         return GetOpcode() == Opcode::SpillFill;
908     }
909 
IsNullCheck()910     bool IsNullCheck() const
911     {
912         return GetOpcode() == Opcode::NullCheck;
913     }
914 
IsNullPtr()915     bool IsNullPtr() const
916     {
917         return GetOpcode() == Opcode::NullPtr;
918     }
919 
IsUnresolved()920     bool IsUnresolved() const
921     {
922         switch (GetOpcode()) {
923             case Opcode::UnresolvedCallStatic:
924             case Opcode::UnresolvedCallVirtual:
925             case Opcode::UnresolvedLoadAndInitClass:
926             case Opcode::UnresolvedLoadType:
927             case Opcode::UnresolvedLoadStatic:
928             case Opcode::UnresolvedStoreStatic:
929             case Opcode::UnresolvedLoadObject:
930             case Opcode::UnresolvedStoreObject:
931                 return true;
932             default:
933                 return false;
934         }
935     }
IsLoad()936     bool IsLoad() const
937     {
938         return GetFlag(inst_flags::LOAD);
939     }
IsStore()940     bool IsStore() const
941     {
942         return GetFlag(inst_flags::STORE);
943     }
944     bool IsAccRead() const;
945     bool IsAccWrite() const;
IsMemory()946     bool IsMemory() const
947     {
948         return IsLoad() || IsStore();
949     }
CanThrow()950     bool CanThrow() const
951     {
952         return GetFlag(inst_flags::CAN_THROW);
953     }
IsCheck()954     bool IsCheck() const
955     {
956         return GetFlag(inst_flags::IS_CHECK);
957     }
RequireState()958     bool RequireState() const
959     {
960         return GetFlag(inst_flags::REQUIRE_STATE);
961     }
962     // Returns true if the instruction not removable in DCE
IsNotRemovable()963     bool IsNotRemovable() const
964     {
965         return GetFlag(inst_flags::NO_DCE);
966     }
967 
968     // Returns true if the instruction doesn't have destination register
NoDest()969     bool NoDest() const
970     {
971         return GetFlag(inst_flags::PSEUDO_DST) || GetFlag(inst_flags::NO_DST) || GetType() == DataType::VOID;
972     }
973 
HasPseudoDestination()974     bool HasPseudoDestination() const
975     {
976         return GetFlag(inst_flags::PSEUDO_DST);
977     }
978 
HasImplicitRuntimeCall()979     bool HasImplicitRuntimeCall() const
980     {
981         return GetFlag(inst_flags::IMPLICIT_RUNTIME_CALL);
982     }
983 
CanDeoptimize()984     bool CanDeoptimize() const
985     {
986         return GetFlag(inst_flags::CAN_DEOPTIMIZE);
987     }
988 
989     // Returns true if the instruction is low-level
IsLowLevel()990     bool IsLowLevel() const
991     {
992         return GetFlag(inst_flags::LOW_LEVEL);
993     }
994 
995     // Returns true if the instruction not hoistable
IsNotHoistable()996     bool IsNotHoistable() const
997     {
998         return GetFlag(inst_flags::NO_HOIST);
999     }
1000 
1001     // Returns true Cse can't be applied to the instruction
IsNotCseApplicable()1002     bool IsNotCseApplicable() const
1003     {
1004         return GetFlag(inst_flags::NO_CSE);
1005     }
1006 
1007     // Returns true if the instruction is a barrier
IsBarrier()1008     virtual bool IsBarrier() const
1009     {
1010         return GetFlag(inst_flags::BARRIER);
1011     }
1012 
1013     // Returns true if opcode can not be moved throught runtime calls (REFERENCE type only)
IsRefSpecial()1014     bool IsRefSpecial() const
1015     {
1016         bool result = GetFlag(inst_flags::REF_SPECIAL);
1017         ASSERT(!result || GetType() == DataType::Type::REFERENCE);
1018         return result;
1019     }
1020 
1021     // Returns true if the instruction is a commutative
IsCommutative()1022     bool IsCommutative() const
1023     {
1024         return GetFlag(inst_flags::COMMUTATIVE);
1025     }
1026 
1027     // Returns true if the instruction allocates a new object on the heap
IsAllocation()1028     bool IsAllocation() const
1029     {
1030         return GetFlag(inst_flags::ALLOC);
1031     }
1032 
1033     // Returns true if the instruction can be used in if-conversion
IsIfConvertable()1034     bool IsIfConvertable() const
1035     {
1036         return GetFlag(inst_flags::IFCVT);
1037     }
1038 
IsRuntimeCall()1039     virtual bool IsRuntimeCall() const
1040     {
1041         return GetFlag(inst_flags::RUNTIME_CALL);
1042     }
1043 
1044     virtual bool IsPropagateLiveness() const;
1045 
1046     // Returns true if the instruction doesn't have side effects(call runtime, throw e.t.c.)
IsSafeInst()1047     virtual bool IsSafeInst() const
1048     {
1049         return false;
1050     }
1051 
1052     bool RequireRegMap() const;
1053 
GetObjectTypeInfo()1054     ObjectTypeInfo GetObjectTypeInfo() const
1055     {
1056         return object_type_info_;
1057     }
1058 
HasObjectTypeInfo()1059     bool HasObjectTypeInfo() const
1060     {
1061         return object_type_info_.IsValid();
1062     }
1063 
SetObjectTypeInfo(ObjectTypeInfo o)1064     void SetObjectTypeInfo(ObjectTypeInfo o)
1065     {
1066         object_type_info_ = o;
1067     }
1068 
GetDataFlowInput(int index)1069     Inst *GetDataFlowInput(int index) const
1070     {
1071         return GetDataFlowInput(GetInput(index).GetInst());
1072     }
1073     Inst *GetDataFlowInput(Inst *input_inst) const;
1074 
1075     bool IsPrecedingInSameBlock(const Inst *other) const;
1076 
1077     bool IsDominate(const Inst *other) const;
1078 
1079     bool InSameBlockOrDominate(const Inst *other) const;
1080 
GetSaveState()1081     const SaveStateInst *GetSaveState() const
1082     {
1083         return const_cast<Inst *>(this)->GetSaveState();
1084     }
1085 
GetSaveState()1086     SaveStateInst *GetSaveState()
1087     {
1088         if (!RequireState()) {
1089             return nullptr;
1090         }
1091         if (GetInputsCount() == 0) {
1092             return nullptr;
1093         }
1094         auto ss = GetInput(GetInputsCount() - 1).GetInst();
1095         if (ss->GetOpcode() == Opcode::SaveStateDeoptimize) {
1096             return ss->CastToSaveStateDeoptimize();
1097         }
1098         if (ss->GetOpcode() != Opcode::SaveState) {
1099             return nullptr;
1100         }
1101 
1102         return ss->CastToSaveState();
1103     }
1104 
SetSaveState(Inst * inst)1105     void SetSaveState(Inst *inst)
1106     {
1107         ASSERT(RequireState());
1108         SetInput(GetInputsCount() - 1, inst);
1109     }
1110 
1111     bool IsZeroRegInst() const;
1112 
1113     /**
1114      * Return instruction clone
1115      */
1116     virtual Inst *Clone(const Graph *targetGraph) const;
1117 
GetFlagsMask()1118     uintptr_t GetFlagsMask() const
1119     {
1120         return GetField<FieldFlags>();
1121     }
1122 
GetFlag(inst_flags::Flags flag)1123     bool GetFlag(inst_flags::Flags flag) const
1124     {
1125         return (GetFlagsMask() & flag) != 0;
1126     }
1127 
SetFlag(inst_flags::Flags flag)1128     void SetFlag(inst_flags::Flags flag)
1129     {
1130         SetField<FieldFlags>(GetFlagsMask() | flag);
1131     }
1132 
ClearFlag(inst_flags::Flags flag)1133     void ClearFlag(inst_flags::Flags flag)
1134     {
1135         SetField<FieldFlags>(GetFlagsMask() & ~static_cast<uintptr_t>(flag));
1136     }
1137 
1138 #ifndef NDEBUG
GetModesMask()1139     uint8_t GetModesMask() const
1140     {
1141         return inst_modes::GetModesMask(opcode_);
1142     }
1143 
SupportsMode(inst_modes::Mode mode)1144     bool SupportsMode(inst_modes::Mode mode) const
1145     {
1146         return (GetModesMask() & mode) != 0;
1147     }
1148 #endif
1149 
SetTerminator()1150     void SetTerminator()
1151     {
1152         SetFlag(inst_flags::Flags::TERMINATOR);
1153     }
1154 
1155     void InsertBefore(Inst *inst);
1156     void InsertAfter(Inst *inst);
1157 
1158     /**
1159      * Return true if instruction has dynamic operands storage.
1160      */
IsOperandsDynamic()1161     bool IsOperandsDynamic() const
1162     {
1163         return GetField<InputsCount>() == MAX_STATIC_INPUTS;
1164     }
1165 
1166     /**
1167      * Add user to the instruction.
1168      * @param user - pointer to User object
1169      */
AddUser(User * user)1170     void AddUser(User *user)
1171     {
1172         ASSERT(user && user->GetInst());
1173         user->SetNext(first_user_);
1174         user->SetPrev(nullptr);
1175         if (first_user_ != nullptr) {
1176             ASSERT(first_user_->GetPrev() == nullptr);
1177             first_user_->SetPrev(user);
1178         }
1179         first_user_ = user;
1180     }
1181 
1182     /**
1183      * Remove instruction from users.
1184      * @param user - pointer to User object
1185      */
RemoveUser(User * user)1186     void RemoveUser(User *user)
1187     {
1188         ASSERT(user);
1189         ASSERT(HasUsers());
1190         if (user == first_user_) {
1191             first_user_ = user->GetNext();
1192         }
1193         user->Remove();
1194     }
1195 
1196     /**
1197      * Set input instruction in specified index.
1198      * Old input will be removed.
1199      * @param index - index of input to be set
1200      * @param inst - new input instruction TODO sherstennikov: currently it can be nullptr, is it correct?
1201      */
SetInput(unsigned index,Inst * inst)1202     void SetInput(unsigned index, Inst *inst)
1203     {
1204         CHECK_LT(index, GetInputsCount());
1205         auto &input = GetInputs()[index];
1206         auto user = GetUser(index);
1207         if (input.GetInst() != nullptr && input.GetInst()->HasUsers()) {
1208             input.GetInst()->RemoveUser(user);
1209         }
1210         if (inst != nullptr) {
1211             inst->AddUser(user);
1212         }
1213         input = Input(inst);
1214     }
1215 
1216     /**
1217      * Replace all inputs that points to specified instruction by new one.
1218      * @param old_input - instruction that should be replaced
1219      * @param new_input - new input instruction
1220      */
ReplaceInput(Inst * old_input,Inst * new_input)1221     void ReplaceInput(Inst *old_input, Inst *new_input)
1222     {
1223         unsigned index = 0;
1224         for (auto input : GetInputs()) {
1225             if (input.GetInst() == old_input) {
1226                 SetInput(index, new_input);
1227             }
1228             index++;
1229         }
1230     }
1231 
1232     /**
1233      * Replace inputs that point to this instruction by given instruction.
1234      * @param inst - new input instruction
1235      */
ReplaceUsers(Inst * inst)1236     void ReplaceUsers(Inst *inst)
1237     {
1238         ASSERT(inst != this);
1239         ASSERT(inst != nullptr);
1240         for (auto it = GetUsers().begin(); it != GetUsers().end(); it = GetUsers().begin()) {
1241             it->GetInst()->SetInput(it->GetIndex(), inst);
1242         }
1243     }
1244 
1245     /**
1246      * Swap the operands of the instruction.
1247      * NB! Don't swap inputs while iterating over instruction's users:
1248      * for (auto user : instruction.GetUsers()) {
1249      *     // Don't do this!
1250      *     user.GetInst()->SwapInputs();
1251      * }
1252      */
SwapInputs()1253     void SwapInputs()
1254     {
1255 #ifndef NDEBUG
1256         constexpr auto INPUTS_COUNT_2 = 2;
1257 #endif
1258         ASSERT(GetInputsCount() == INPUTS_COUNT_2);
1259         auto input0 = GetInput(0).GetInst();
1260         auto input1 = GetInput(1).GetInst();
1261         SetInput(0, input1);
1262         SetInput(1, input0);
1263     }
1264 
1265     /**
1266      * Append input instruction.
1267      * Available only for variadic inputs instructions, such as PHI.
1268      * @param input - input instruction
1269      * @return index in inputs container where new input is placed
1270      */
AppendInput(Inst * input)1271     unsigned AppendInput(Inst *input)
1272     {
1273         ASSERT(input != nullptr);
1274         ASSERT(IsOperandsDynamic());
1275         DynamicOperands *operands = GetDynamicOperands();
1276         return operands->Append(input);
1277     }
1278 
AppendInput(Input input)1279     unsigned AppendInput(Input input)
1280     {
1281         static_assert(sizeof(Input) <= sizeof(uintptr_t));  // Input become larger, so pass it by reference then
1282         return AppendInput(input.GetInst());
1283     }
1284 
1285     /**
1286      * Remove input from inputs container
1287      * Available only for variadic inputs instructions, such as PHI.
1288      * @param index - index of input in inputs container
1289      */
RemoveInput(unsigned index)1290     virtual void RemoveInput(unsigned index)
1291     {
1292         ASSERT(IsOperandsDynamic());
1293         DynamicOperands *operands = GetDynamicOperands();
1294         ASSERT(index < operands->Size());
1295         operands->Remove(index);
1296     }
1297 
1298     /**
1299      * Remove all inputs
1300      */
RemoveInputs()1301     void RemoveInputs()
1302     {
1303         if (UNLIKELY(IsOperandsDynamic())) {
1304             for (auto inputs_count = GetInputsCount(); inputs_count != 0; --inputs_count) {
1305                 RemoveInput(inputs_count - 1);
1306             }
1307         } else {
1308             for (size_t i = 0; i < GetInputsCount(); ++i) {
1309                 SetInput(i, nullptr);
1310             }
1311         }
1312     }
1313 
1314     /**
1315      * Remove all users
1316      */
1317     template <bool with_inputs = false>
RemoveUsers()1318     void RemoveUsers()
1319     {
1320         auto users = GetUsers();
1321         while (!users.Empty()) {
1322             // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
1323             if constexpr (with_inputs) {
1324                 auto &user = users.Front();
1325                 user.GetInst()->RemoveInput(user.GetIndex());
1326                 // NOLINTNEXTLINE(readability-misleading-indentation)
1327             } else {
1328                 RemoveUser(&users.Front());
1329             }
1330         }
1331     }
1332 
1333     /**
1334      * Get input by index
1335      * @param index - index of input
1336      * @return input instruction
1337      */
GetInput(unsigned index)1338     Input GetInput(unsigned index)
1339     {
1340         ASSERT(index < GetInputsCount());
1341         return GetInputs()[index];
1342     }
1343 
GetInput(unsigned index)1344     Input GetInput(unsigned index) const
1345     {
1346         ASSERT(index < GetInputsCount());
1347         return GetInputs()[index];
1348     }
1349 
GetInputs()1350     Span<Input> GetInputs()
1351     {
1352         if (UNLIKELY(IsOperandsDynamic())) {
1353             DynamicOperands *operands = GetDynamicOperands();
1354             return Span<Input>(operands->Inputs(), operands->Size());
1355         }
1356 
1357         auto inputs_count {GetField<InputsCount>()};
1358         return Span<Input>(
1359             reinterpret_cast<Input *>(reinterpret_cast<uintptr_t>(this) -
1360                                       (inputs_count + Input::GetPadding(RUNTIME_ARCH, inputs_count)) * sizeof(Input)),
1361             inputs_count);
1362     }
GetInputs()1363     Span<const Input> GetInputs() const
1364     {
1365         return Span<const Input>(const_cast<Inst *>(this)->GetInputs());
1366     }
1367 
GetInputType(size_t index)1368     virtual DataType::Type GetInputType([[maybe_unused]] size_t index) const
1369     {
1370         ASSERT(index < GetInputsCount());
1371         return GetType();
1372     }
1373 
GetUsers()1374     UserList<User> GetUsers()
1375     {
1376         return UserList<User>(&first_user_);
1377     }
GetUsers()1378     UserList<const User> GetUsers() const
1379     {
1380         return UserList<const User>(&first_user_);
1381     }
1382 
GetInputsCount()1383     size_t GetInputsCount() const
1384     {
1385         if (UNLIKELY(IsOperandsDynamic())) {
1386             return GetDynamicOperands()->Size();
1387         }
1388         return GetInputs().Size();
1389     }
1390 
HasUsers()1391     bool HasUsers() const
1392     {
1393         return first_user_ != nullptr;
1394     };
1395 
HasSingleUser()1396     bool HasSingleUser() const
1397     {
1398         return first_user_ != nullptr && first_user_->GetNext() == nullptr;
1399     }
1400 
1401     /// Reserve space in dataflow storage for specified inputs count
1402     void ReserveInputs(size_t capacity);
1403 
SetLocation(size_t index,Location location)1404     virtual void SetLocation([[maybe_unused]] size_t index, [[maybe_unused]] Location location) {}
1405 
GetLocation(size_t index)1406     virtual Location GetLocation([[maybe_unused]] size_t index) const
1407     {
1408         return Location::RequireRegister();
1409     }
1410 
GetDstLocation()1411     virtual Location GetDstLocation() const
1412     {
1413         return Location::MakeRegister(GetDstReg(), GetType());
1414     }
1415 
CanBeNull()1416     virtual bool CanBeNull() const
1417     {
1418         ASSERT_PRINT(GetType() == DataType::Type::REFERENCE, "CanBeNull only applies to reference types");
1419         return true;
1420     }
1421 
Latency()1422     virtual uint32_t Latency() const
1423     {
1424         return options.GetCompilerSchedLatency();
1425     }
1426 
1427     template <typename Accessor>
GetField()1428     typename Accessor::ValueType GetField() const
1429     {
1430         return Accessor::Get(bit_fields_);
1431     }
1432 
1433     template <typename Accessor>
SetField(typename Accessor::ValueType value)1434     void SetField(typename Accessor::ValueType value)
1435     {
1436         Accessor::Set(value, &bit_fields_);
1437     }
1438 
GetAllFields()1439     uint64_t GetAllFields() const
1440     {
1441         return bit_fields_;
1442     }
1443 
IsPhi()1444     bool IsPhi() const
1445     {
1446         return opcode_ == Opcode::Phi;
1447     }
1448 
IsCatchPhi()1449     bool IsCatchPhi() const
1450     {
1451         return opcode_ == Opcode::CatchPhi;
1452     }
1453 
IsConst()1454     bool IsConst() const
1455     {
1456         return opcode_ == Opcode::Constant;
1457     }
1458 
IsParameter()1459     bool IsParameter() const
1460     {
1461         return opcode_ == Opcode::Parameter;
1462     }
1463 
IsBoolConst()1464     virtual bool IsBoolConst() const
1465     {
1466         return false;
1467     }
1468 
IsSaveState()1469     bool IsSaveState() const
1470     {
1471         return opcode_ == Opcode::SaveState || opcode_ == Opcode::SafePoint || opcode_ == Opcode::SaveStateOsr ||
1472                opcode_ == Opcode::SaveStateDeoptimize;
1473     }
1474 
IsClassInst()1475     bool IsClassInst() const
1476     {
1477         return opcode_ == Opcode::InitClass || opcode_ == Opcode::LoadClass || opcode_ == Opcode::LoadAndInitClass ||
1478                opcode_ == Opcode::UnresolvedLoadAndInitClass;
1479     }
1480 
GetHashCode()1481     virtual size_t GetHashCode() const
1482     {
1483         // TODO (Aleksandr Popov) calculate hash code
1484         return 0;
1485     }
1486 
SetVnObject(VnObject * vn_obj)1487     virtual void SetVnObject([[maybe_unused]] VnObject *vn_obj) {}
1488 
GetDstReg()1489     Register GetDstReg() const
1490     {
1491         return dst_reg_;
1492     }
1493 
SetDstReg(Register reg)1494     void SetDstReg(Register reg)
1495     {
1496         dst_reg_ = reg;
1497     }
1498 
GetVN()1499     uint32_t GetVN() const
1500     {
1501         return vn_;
1502     }
1503 
SetVN(uint32_t vn)1504     void SetVN(uint32_t vn)
1505     {
1506         vn_ = vn;
1507     }
1508     void Dump(std::ostream *out, bool new_line = true) const;
1509     virtual bool DumpInputs(std::ostream * /* out */) const;
1510     virtual void DumpOpcode(std::ostream * /* out */) const;
1511 
SetDstReg(unsigned index,Register reg)1512     virtual void SetDstReg([[maybe_unused]] unsigned index, Register reg)
1513     {
1514         ASSERT(index == 0);
1515         SetDstReg(reg);
1516     }
1517 
GetDstReg(unsigned index)1518     virtual Register GetDstReg([[maybe_unused]] unsigned index) const
1519     {
1520         ASSERT(index == 0);
1521         return GetDstReg();
1522     }
1523 
GetDstCount()1524     virtual size_t GetDstCount() const
1525     {
1526         return 1;
1527     }
1528 
GetSrcRegIndex()1529     virtual uint32_t GetSrcRegIndex() const
1530     {
1531         return 0;
1532     }
1533 
SetSrcReg(unsigned index,Register reg)1534     virtual void SetSrcReg([[maybe_unused]] unsigned index, [[maybe_unused]] Register reg) {}
1535 
GetSrcReg(unsigned index)1536     virtual Register GetSrcReg([[maybe_unused]] unsigned index) const
1537     {
1538         return INVALID_REG;
1539     }
1540 
GetFirstUser()1541     User *GetFirstUser() const
1542     {
1543         return first_user_;
1544     }
1545 
1546 protected:
1547     using InstBase::InstBase;
1548     static constexpr int INPUT_COUNT = 0;
1549 
1550     Inst() = default;
1551 
Inst(Opcode opcode)1552     explicit Inst(Opcode opcode) : Inst(opcode, DataType::Type::NO_TYPE, INVALID_PC) {}
1553 
Inst(Opcode opcode,DataType::Type type,uint32_t pc)1554     explicit Inst(Opcode opcode, DataType::Type type, uint32_t pc) : pc_(pc), opcode_(opcode)
1555     {
1556         bit_fields_ = inst_flags::GetFlagsMask(opcode);
1557         SetField<FieldType>(type);
1558     }
1559 
1560 protected:
1561     using FieldFlags = BitField<uint32_t, 0, MinimumBitsToStore(1U << inst_flags::FLAGS_COUNT)>;
1562     using FieldType = FieldFlags::NextField<DataType::Type, MinimumBitsToStore(DataType::LAST)>;
1563     using InputsCount = FieldType::NextField<uint32_t, BITS_PER_INPUTS_NUM>;
1564     using LastField = InputsCount;
1565 
GetDynamicOperands()1566     DynamicOperands *GetDynamicOperands() const
1567     {
1568         return reinterpret_cast<DynamicOperands *>(reinterpret_cast<uintptr_t>(this) - sizeof(DynamicOperands));
1569     }
1570 
1571 private:
GetUser(unsigned index)1572     User *GetUser(unsigned index)
1573     {
1574         if (UNLIKELY(IsOperandsDynamic())) {
1575             return GetDynamicOperands()->GetUser(index);
1576         }
1577         auto inputs_count {GetField<InputsCount>()};
1578         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1579         return reinterpret_cast<User *>(reinterpret_cast<Input *>(this) -
1580                                         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1581                                         (inputs_count + Input::GetPadding(RUNTIME_ARCH, inputs_count))) -
1582                // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1583                index - 1;
1584     }
1585 
OperandsStorageSize()1586     size_t OperandsStorageSize() const
1587     {
1588         if (UNLIKELY(IsOperandsDynamic())) {
1589             return sizeof(DynamicOperands);
1590         }
1591 
1592         auto inputs_count {GetField<InputsCount>()};
1593         return inputs_count * (sizeof(Input) + sizeof(User)) +
1594                Input::GetPadding(RUNTIME_ARCH, inputs_count) * sizeof(Input);
1595     }
1596 
1597 private:
1598     /// Basic block this instruction belongs to
1599     BasicBlock *bb_ {nullptr};
1600 
1601     /// Next instruction within basic block
1602     Inst *next_ {nullptr};
1603 
1604     /// Previous instruction within basic block
1605     Inst *prev_ {nullptr};
1606 
1607     /// First user in users chain
1608     User *first_user_ {nullptr};
1609 
1610     /// This value hold properties of the instruction. It accessed via BitField types(f.e. FieldType).
1611     uint64_t bit_fields_ {0};
1612 
1613     /// Unique id of instruction
1614     uint32_t id_ {INVALID_ID};
1615 
1616     /// Unique id of instruction
1617     uint32_t vn_ {INVALID_VN};
1618 
1619     /// Bytecode pc
1620     uint32_t pc_ {INVALID_PC};
1621 
1622     /// Number used in cloning
1623     uint32_t clone_number_ {0};
1624 
1625     /// Instruction number getting while visiting graph
1626     LinearNumber linear_number_ {INVALID_LINEAR_NUM};
1627 
1628     ObjectTypeInfo object_type_info_ {};
1629 
1630     /// Opcode, see opcodes.def
1631     Opcode opcode_ {Opcode::INVALID};
1632 
1633     // Destination register type - defined in FieldType
1634     Register dst_reg_ {INVALID_REG};
1635 };
1636 
1637 /**
1638  * Proxy class that injects new field - type of the source operands - into property field of the instruction.
1639  * Should be used when instruction has sources of the same type and type of the instruction is not match to type of
1640  * sources. Examples: Cmp, Compare
1641  * @tparam T Base instruction class after which this mixin is injected
1642  */
1643 template <typename T>
1644 class InstWithOperandsType : public T {
1645 public:
1646     using T::T;
1647 
SetOperandsType(DataType::Type type)1648     void SetOperandsType(DataType::Type type)
1649     {
1650         T::template SetField<FieldOperandsType>(type);
1651     }
GetOperandsType()1652     virtual DataType::Type GetOperandsType() const
1653     {
1654         return T::template GetField<FieldOperandsType>();
1655     }
1656 
1657 protected:
1658     using FieldOperandsType =
1659         typename T::LastField::template NextField<DataType::Type, MinimumBitsToStore(DataType::LAST)>;
1660     using LastField = FieldOperandsType;
1661 };
1662 
1663 /**
1664  * Mixin for NeedBarrier flag.
1665  * @tparam T Base instruction class after which this mixin is injected
1666  */
1667 template <typename T>
1668 class NeedBarrierMixin : public T {
1669 public:
1670     using T::T;
1671 
SetNeedBarrier(bool v)1672     void SetNeedBarrier(bool v)
1673     {
1674         T::template SetField<NeedBarrierFlag>(v);
1675     }
GetNeedBarrier()1676     bool GetNeedBarrier() const
1677     {
1678         return T::template GetField<NeedBarrierFlag>();
1679     }
1680 
1681 protected:
1682     using NeedBarrierFlag = typename T::LastField::NextFlag;
1683     using LastField = NeedBarrierFlag;
1684 };
1685 
1686 /**
1687  * This mixin aims to implement type id accessors.
1688  */
1689 class TypeIdMixin {
1690 public:
1691     TypeIdMixin() = default;
1692     NO_COPY_SEMANTIC(TypeIdMixin);
1693     NO_MOVE_SEMANTIC(TypeIdMixin);
1694     virtual ~TypeIdMixin() = default;
1695 
SetTypeId(uint32_t id)1696     void SetTypeId(uint32_t id)
1697     {
1698         type_id_ = id;
1699     }
1700 
GetTypeId()1701     auto GetTypeId() const
1702     {
1703         return type_id_;
1704     }
1705 
SetMethod(RuntimeInterface::MethodPtr method)1706     void SetMethod(RuntimeInterface::MethodPtr method)
1707     {
1708         method_ = method;
1709     }
GetMethod()1710     auto GetMethod() const
1711     {
1712         return method_;
1713     }
1714 
1715 private:
1716     uint32_t type_id_ {0};
1717     // The pointer to the method in which this instruction is executed(inlined method)
1718     RuntimeInterface::MethodPtr method_ {nullptr};
1719 };
1720 
1721 /**
1722  * This mixin aims to implement type of klass.
1723  */
1724 template <typename T>
1725 class ClassTypeMixin : public T {
1726 public:
1727     using T::T;
1728 
SetClassType(ClassType class_type)1729     void SetClassType(ClassType class_type)
1730     {
1731         T::template SetField<ClassTypeField>(class_type);
1732     }
1733 
GetClassType()1734     ClassType GetClassType() const
1735     {
1736         return T::template GetField<ClassTypeField>();
1737     }
1738 
1739 protected:
1740     using ClassTypeField = typename T::LastField::template NextField<ClassType, MinimumBitsToStore(ClassType::COUNT)>;
1741     using LastField = ClassTypeField;
1742 };
1743 
1744 /**
1745  * Mixin to check if null check inside CheckCast and IsInstance can be omitted.
1746  */
1747 template <typename T>
1748 class OmitNullCheckMixin : public T {
1749 public:
1750     using T::T;
1751 
SetOmitNullCheck(bool omit_null_check)1752     void SetOmitNullCheck(bool omit_null_check)
1753     {
1754         T::template SetField<OmitNullCheckFlag>(omit_null_check);
1755     }
1756 
GetOmitNullCheck()1757     bool GetOmitNullCheck() const
1758     {
1759         return T::template GetField<OmitNullCheckFlag>();
1760     }
1761 
1762 protected:
1763     using OmitNullCheckFlag = typename T::LastField::NextFlag;
1764     using LastField = OmitNullCheckFlag;
1765 };
1766 
1767 template <typename T>
1768 class ScaleMixin : public T {
1769 public:
1770     using T::T;
1771 
SetScale(uint32_t scale)1772     void SetScale(uint32_t scale)
1773     {
1774         ASSERT(scale <= MAX_SCALE);
1775         T::template SetField<ScaleField>(scale);
1776     }
1777 
GetScale()1778     uint32_t GetScale() const
1779     {
1780         return T::template GetField<ScaleField>();
1781     }
1782 
1783 protected:
1784     using ScaleField = typename T::LastField::template NextField<uint32_t, MinimumBitsToStore(MAX_SCALE)>;
1785     using LastField = ScaleField;
1786 };
1787 
1788 /**
1789  * This mixin aims to implement field accessors.
1790  */
1791 class FieldMixin {
1792 public:
1793     FieldMixin() = default;
1794     NO_COPY_SEMANTIC(FieldMixin);
1795     NO_MOVE_SEMANTIC(FieldMixin);
1796     virtual ~FieldMixin() = default;
1797 
SetObjField(RuntimeInterface::FieldPtr field)1798     void SetObjField(RuntimeInterface::FieldPtr field)
1799     {
1800         field_ = field;
1801     }
GetObjField()1802     auto GetObjField() const
1803     {
1804         return field_;
1805     }
1806 
1807 private:
1808     RuntimeInterface::FieldPtr field_ {nullptr};
1809 };
1810 
1811 /**
1812  * This mixin aims to implement volatile accessors.
1813  */
1814 template <typename T>
1815 class VolatileMixin : public T {
1816 public:
1817     using T::T;
1818 
SetVolatile(bool is_volatile)1819     void SetVolatile(bool is_volatile)
1820     {
1821         T::template SetField<IsVolatileFlag>(is_volatile);
1822     }
GetVolatile()1823     bool GetVolatile() const
1824     {
1825         return T::template GetField<IsVolatileFlag>();
1826     }
1827 
1828 protected:
1829     using IsVolatileFlag = typename T::LastField::NextFlag;
1830     using LastField = IsVolatileFlag;
1831 };
1832 /**
1833  * Mixin for Inlined calls/returns.
1834  */
1835 template <typename T>
1836 class InlinedInstMixin : public T {
1837 public:
1838     using T::T;
1839 
SetInlined(bool v)1840     void SetInlined(bool v)
1841     {
1842         T::template SetField<IsInlinedFlag>(v);
1843     }
IsInlined()1844     bool IsInlined() const
1845     {
1846         return T::template GetField<IsInlinedFlag>();
1847     }
1848 
1849 protected:
1850     using IsInlinedFlag = typename T::LastField::NextFlag;
1851     using LastField = IsInlinedFlag;
1852 };
1853 
1854 /**
1855  * Mixin for Array/String instruction
1856  */
1857 template <typename T>
1858 class ArrayInstMixin : public T {
1859 public:
1860     using T::T;
1861 
SetIsArray(bool v)1862     void SetIsArray(bool v)
1863     {
1864         T::template SetField<IsStringFlag>(!v);
1865     }
1866 
SetIsString(bool v)1867     void SetIsString(bool v)
1868     {
1869         T::template SetField<IsStringFlag>(v);
1870     }
1871 
IsArray()1872     bool IsArray() const
1873     {
1874         return !(T::template GetField<IsStringFlag>());
1875     }
1876 
IsString()1877     bool IsString() const
1878     {
1879         return T::template GetField<IsStringFlag>();
1880     }
1881 
1882 protected:
1883     using IsStringFlag = typename T::LastField::NextFlag;
1884     using LastField = IsStringFlag;
1885 };
1886 
1887 /**
1888  * Mixin for instructions with immediate constant value
1889  */
1890 class ImmediateMixin {
1891 public:
ImmediateMixin(uint64_t immediate)1892     explicit ImmediateMixin(uint64_t immediate) : immediate_(immediate) {}
1893 
1894     NO_COPY_SEMANTIC(ImmediateMixin);
1895     NO_MOVE_SEMANTIC(ImmediateMixin);
1896     virtual ~ImmediateMixin() = default;
1897 
SetImm(uint64_t immediate)1898     void SetImm(uint64_t immediate)
1899     {
1900         immediate_ = immediate;
1901     }
GetImm()1902     auto GetImm() const
1903     {
1904         return immediate_;
1905     }
1906 
1907 protected:
1908     ImmediateMixin() = default;
1909 
1910 private:
1911     uint64_t immediate_ {0};
1912 };
1913 
1914 /**
1915  * Mixin for instructions with ConditionCode
1916  */
1917 template <typename T>
1918 class ConditionMixin : public T {
1919 public:
1920     enum class Prediction { NONE, LIKELY, UNLIKELY, SIZE = UNLIKELY };
1921 
1922     using T::T;
ConditionMixin(ConditionCode cc)1923     explicit ConditionMixin(ConditionCode cc)
1924     {
1925         T::template SetField<CcFlag>(cc);
1926     }
1927     NO_COPY_SEMANTIC(ConditionMixin);
1928     NO_MOVE_SEMANTIC(ConditionMixin);
1929     ~ConditionMixin() override = default;
1930 
GetCc()1931     auto GetCc() const
1932     {
1933         return T::template GetField<CcFlag>();
1934     }
SetCc(ConditionCode cc)1935     void SetCc(ConditionCode cc)
1936     {
1937         T::template SetField<CcFlag>(cc);
1938     }
InverseConditionCode()1939     void InverseConditionCode()
1940     {
1941         SetCc(GetInverseConditionCode(GetCc()));
1942         if (IsLikely()) {
1943             SetUnlikely();
1944         } else if (IsUnlikely()) {
1945             SetLikely();
1946         }
1947     }
1948 
IsLikely()1949     bool IsLikely() const
1950     {
1951         return T::template GetField<PredictionFlag>() == Prediction::LIKELY;
1952     }
IsUnlikely()1953     bool IsUnlikely() const
1954     {
1955         return T::template GetField<PredictionFlag>() == Prediction::UNLIKELY;
1956     }
SetLikely()1957     void SetLikely()
1958     {
1959         T::template SetField<PredictionFlag>(Prediction::LIKELY);
1960     }
SetUnlikely()1961     void SetUnlikely()
1962     {
1963         T::template SetField<PredictionFlag>(Prediction::UNLIKELY);
1964     }
1965 
1966 protected:
1967     ConditionMixin() = default;
1968 
1969     using CcFlag = typename T::LastField::template NextField<ConditionCode, MinimumBitsToStore(ConditionCode::CC_LAST)>;
1970     using PredictionFlag = typename CcFlag::template NextField<Prediction, MinimumBitsToStore(Prediction::SIZE)>;
1971     using LastField = PredictionFlag;
1972 };
1973 
1974 /**
1975  * Mixin for instrucion with ShiftType
1976  */
1977 class ShiftTypeMixin {
1978 public:
ShiftTypeMixin(ShiftType shift_type)1979     explicit ShiftTypeMixin(ShiftType shift_type) : shift_type_(shift_type) {}
1980     NO_COPY_SEMANTIC(ShiftTypeMixin);
1981     NO_MOVE_SEMANTIC(ShiftTypeMixin);
1982     virtual ~ShiftTypeMixin() = default;
1983 
SetShiftType(ShiftType shift_type)1984     void SetShiftType(ShiftType shift_type)
1985     {
1986         shift_type_ = shift_type;
1987     }
1988 
GetShiftType()1989     ShiftType GetShiftType() const
1990     {
1991         return shift_type_;
1992     }
1993 
1994 protected:
1995     ShiftTypeMixin() = default;
1996 
1997 private:
1998     ShiftType shift_type_ {INVALID_SHIFT};
1999 };
2000 
2001 /**
2002  * Mixin for instructions with multiple return values
2003  */
2004 template <typename T, size_t N>
2005 class MultipleOutputMixin : public T {
2006 public:
2007     using T::T;
2008 
GetDstReg(unsigned index)2009     Register GetDstReg(unsigned index) const override
2010     {
2011         ASSERT(index < N);
2012         if (index == 0) {
2013             return T::GetDstReg();
2014         }
2015         return dst_regs_[index - 1];
2016     }
2017 
SetDstReg(unsigned index,Register reg)2018     void SetDstReg(unsigned index, Register reg) override
2019     {
2020         ASSERT(index < N);
2021         if (index == 0) {
2022             T::SetDstReg(reg);
2023         } else {
2024             dst_regs_[index - 1] = reg;
2025         }
2026     }
2027 
GetDstCount()2028     size_t GetDstCount() const override
2029     {
2030         return N;
2031     }
2032 
2033 private:
2034     std::array<Register, N - 1> dst_regs_;
2035 };
2036 
2037 /**
2038  * Mixin for Deoptimize instructions
2039  */
2040 template <typename T>
2041 class DeoptimizeTypeMixin : public T {
2042 public:
2043     using T::T;
2044 
SetDeoptimizeType(DeoptimizeType deopt_type)2045     void SetDeoptimizeType(DeoptimizeType deopt_type)
2046     {
2047         T::template SetField<DeoptimizeTypeField>(deopt_type);
2048     }
2049 
GetDeoptimizeType()2050     DeoptimizeType GetDeoptimizeType() const
2051     {
2052         return T::template GetField<DeoptimizeTypeField>();
2053     }
2054 
2055 protected:
2056     using DeoptimizeTypeField =
2057         typename T::LastField::template NextField<DeoptimizeType, MinimumBitsToStore(DeoptimizeType::COUNT)>;
2058     using LastField = DeoptimizeTypeField;
2059 };
2060 
2061 /**
2062  * Instruction with fixed number of inputs.
2063  * Shall not be instantiated directly, only through derived classes.
2064  */
2065 template <size_t N>
2066 class FixedInputsInst : public Inst {
2067 public:
2068     using Inst::Inst;
2069 
2070     static constexpr int INPUT_COUNT = N;
2071 
SetSrcReg(unsigned index,Register reg)2072     void SetSrcReg(unsigned index, Register reg) override
2073     {
2074         ASSERT(index < N);
2075         src_regs_[index] = reg;
2076     }
2077 
GetSrcReg(unsigned index)2078     Register GetSrcReg(unsigned index) const override
2079     {
2080         ASSERT(index < N);
2081         return src_regs_[index];
2082     }
2083 
GetLocation(size_t index)2084     Location GetLocation(size_t index) const override
2085     {
2086         return Location::MakeRegister(GetSrcReg(index), GetInputType(index));
2087     }
2088 
SetLocation(size_t index,Location location)2089     void SetLocation(size_t index, Location location) override
2090     {
2091         SetSrcReg(index, location.GetValue());
2092     }
2093 
SetDstLocation(Location location)2094     void SetDstLocation(Location location)
2095     {
2096         SetDstReg(location.GetValue());
2097     }
2098 
2099     Inst *Clone(const Graph *targetGraph) const override;
2100 
2101 private:
2102     template <typename T, std::size_t... Is>
CreateArray(T value,std::index_sequence<Is...> unused)2103     constexpr auto CreateArray(T value, [[maybe_unused]] std::index_sequence<Is...> unused)
2104     {
2105         return std::array<T, sizeof...(Is)> {(static_cast<void>(Is), value)...};
2106     }
2107 
2108 private:
2109     std::array<Register, N> src_regs_ = CreateArray(INVALID_REG, std::make_index_sequence<INPUT_COUNT>());
2110 };
2111 
2112 /**
2113  * Instructions with fixed static inputs
2114  * We need to explicitly declare these proxy classes because some code can't work with the templated inst classes, for
2115  * example DEFINE_INST macro.
2116  */
2117 class FixedInputsInst0 : public FixedInputsInst<0> {
2118 public:
2119     DECLARE_INST(FixedInputsInst0);
2120     using FixedInputsInst::FixedInputsInst;
2121 
2122     NO_COPY_SEMANTIC(FixedInputsInst0);
2123     NO_MOVE_SEMANTIC(FixedInputsInst0);
2124     ~FixedInputsInst0() override = default;
2125 };
2126 
2127 class FixedInputsInst1 : public FixedInputsInst<1> {
2128 public:
2129     DECLARE_INST(FixedInputsInst1);
2130     using FixedInputsInst::FixedInputsInst;
2131 
2132     NO_COPY_SEMANTIC(FixedInputsInst1);
2133     NO_MOVE_SEMANTIC(FixedInputsInst1);
2134     ~FixedInputsInst1() override = default;
2135 };
2136 
2137 class FixedInputsInst2 : public FixedInputsInst<2U> {
2138 public:
2139     DECLARE_INST(FixedInputsInst2);
2140     using FixedInputsInst::FixedInputsInst;
2141 
2142     NO_COPY_SEMANTIC(FixedInputsInst2);
2143     NO_MOVE_SEMANTIC(FixedInputsInst2);
2144     ~FixedInputsInst2() override = default;
2145 };
2146 
2147 class FixedInputsInst3 : public FixedInputsInst<3U> {
2148 public:
2149     DECLARE_INST(FixedInputsInst3);
2150     using FixedInputsInst::FixedInputsInst;
2151 };
2152 
2153 class FixedInputsInst4 : public FixedInputsInst<4U> {
2154 public:
2155     DECLARE_INST(FixedInputsInst4);
2156     using FixedInputsInst::FixedInputsInst;
2157 };
2158 
2159 /**
2160  * Instruction with variable inputs count
2161  */
2162 class DynamicInputsInst : public Inst {
2163 public:
2164     DECLARE_INST(DynamicInputsInst);
2165     using Inst::Inst;
2166 
2167     static constexpr int INPUT_COUNT = MAX_STATIC_INPUTS;
2168 
GetLocation(size_t index)2169     Location GetLocation(size_t index) const override
2170     {
2171         if (locations_ == nullptr) {
2172             return Location::Invalid();
2173         }
2174         return locations_->GetLocation(index);
2175     }
2176 
GetDstLocation()2177     Location GetDstLocation() const override
2178     {
2179         if (locations_ == nullptr) {
2180             return Location::Invalid();
2181         }
2182         return locations_->GetDstLocation();
2183     }
2184 
SetLocation(size_t index,Location location)2185     void SetLocation(size_t index, Location location) override
2186     {
2187         ASSERT(locations_ != nullptr);
2188         locations_->SetLocation(index, location);
2189     }
2190 
SetDstLocation(Location location)2191     void SetDstLocation(Location location)
2192     {
2193         ASSERT(locations_ != nullptr);
2194         locations_->SetDstLocation(location);
2195     }
2196 
SetLocationsInfo(LocationsInfo * info)2197     void SetLocationsInfo(LocationsInfo *info)
2198     {
2199         locations_ = info;
2200     }
2201 
GetSrcReg(unsigned index)2202     Register GetSrcReg(unsigned index) const override
2203     {
2204         return GetLocation(index).GetValue();
2205     }
2206 
SetSrcReg(unsigned index,Register reg)2207     void SetSrcReg(unsigned index, Register reg) override
2208     {
2209         SetLocation(index, Location::MakeRegister(reg, GetInputType(index)));
2210     }
2211 
2212 private:
2213     LocationsInfo *locations_ {nullptr};
2214 };
2215 
2216 /**
2217  * Unary operation instruction
2218  */
2219 class UnaryOperation : public FixedInputsInst<1> {
2220 public:
2221     DECLARE_INST(UnaryOperation);
2222     using FixedInputsInst::FixedInputsInst;
UnaryOperation(Opcode opcode,DataType::Type type,uint32_t pc,Inst * input)2223     UnaryOperation(Opcode opcode, DataType::Type type, uint32_t pc, Inst *input) : FixedInputsInst(opcode, type, pc)
2224     {
2225         SetInput(0, input);
2226     }
2227 
GetInputType(size_t index)2228     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
2229     {
2230         ASSERT(index < GetInputsCount());
2231         if (GetOpcode() == Opcode::Cast) {
2232             return GetInput(0).GetInst()->GetType();
2233         }
2234         return GetType();
2235     }
2236 
IsSafeInst()2237     bool IsSafeInst() const override
2238     {
2239         return true;
2240     }
2241 
2242     void SetVnObject(VnObject *vn_obj) override;
2243 
2244     Inst *Evaluate();
2245 };
2246 
2247 /**
2248  * Binary operation instruction
2249  */
2250 class BinaryOperation : public FixedInputsInst<2U> {
2251 public:
2252     DECLARE_INST(BinaryOperation);
2253     using FixedInputsInst::FixedInputsInst;
2254 
Latency()2255     uint32_t Latency() const override
2256     {
2257         if (GetOpcode() == Opcode::Div) {
2258             return options.GetCompilerSchedLatencyLong();
2259         }
2260         return options.GetCompilerSchedLatency();
2261     }
2262 
IsSafeInst()2263     bool IsSafeInst() const override
2264     {
2265         return true;
2266     }
2267 
2268     Inst *Evaluate();
2269 };
2270 
2271 /**
2272  * Binary operation instruction with c immidiate
2273  */
2274 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
2275 class BinaryImmOperation : public FixedInputsInst<1>, public ImmediateMixin {
2276 public:
2277     DECLARE_INST(BinaryImmOperation);
2278     using FixedInputsInst::FixedInputsInst;
2279 
BinaryImmOperation(Opcode opcode,uint64_t imm)2280     explicit BinaryImmOperation(Opcode opcode, uint64_t imm) : FixedInputsInst(opcode), ImmediateMixin(imm) {}
BinaryImmOperation(Opcode opcode,DataType::Type type,uint32_t pc,uint64_t imm)2281     explicit BinaryImmOperation(Opcode opcode, DataType::Type type, uint32_t pc, uint64_t imm)
2282         : FixedInputsInst(opcode, type, pc), ImmediateMixin(imm)
2283     {
2284     }
2285 
GetInputType(size_t index)2286     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
2287     {
2288         ASSERT(index < GetInputsCount());
2289         return GetType();
2290     }
2291 
2292     void SetVnObject(VnObject *vn_obj) override;
2293     bool DumpInputs(std::ostream * /* out */) const override;
2294 
IsSafeInst()2295     bool IsSafeInst() const override
2296     {
2297         return true;
2298     }
2299 
Clone(const Graph * targetGraph)2300     Inst *Clone(const Graph *targetGraph) const override
2301     {
2302         auto clone = FixedInputsInst::Clone(targetGraph);
2303         static_cast<BinaryImmOperation *>(clone)->SetImm(GetImm());
2304         return clone;
2305     }
2306 };
2307 
2308 /**
2309  * Unary operation that shifts its own operand prior the application.
2310  */
2311 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
2312 class UnaryShiftedRegisterOperation : public FixedInputsInst<1>, public ImmediateMixin, public ShiftTypeMixin {
2313 public:
2314     DECLARE_INST(UnaryShiftedRegisterOperation);
2315     using FixedInputsInst::FixedInputsInst;
2316 
UnaryShiftedRegisterOperation(Opcode opcode,ShiftType shift_type,uint64_t imm)2317     explicit UnaryShiftedRegisterOperation(Opcode opcode, ShiftType shift_type, uint64_t imm)
2318         : FixedInputsInst(opcode), ImmediateMixin(imm), ShiftTypeMixin(shift_type)
2319     {
2320     }
UnaryShiftedRegisterOperation(Opcode opcode,DataType::Type type,uint32_t pc,ShiftType shift_type,uint64_t imm)2321     explicit UnaryShiftedRegisterOperation(Opcode opcode, DataType::Type type, uint32_t pc, ShiftType shift_type,
2322                                            uint64_t imm)
2323         : FixedInputsInst(opcode, type, pc), ImmediateMixin(imm), ShiftTypeMixin(shift_type)
2324     {
2325     }
2326 
GetInputType(size_t index)2327     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
2328     {
2329         ASSERT(index < GetInputsCount());
2330         return GetType();
2331     }
2332 
2333     void SetVnObject(VnObject *vn_obj) override;
2334     bool DumpInputs(std::ostream * /* out */) const override;
2335     Inst *Clone(const Graph *targetGraph) const override;
2336 };
2337 
2338 /**
2339  * Binary operation that shifts its second operand prior the application.
2340  */
2341 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
2342 class BinaryShiftedRegisterOperation : public FixedInputsInst<2U>, public ImmediateMixin, public ShiftTypeMixin {
2343 public:
2344     DECLARE_INST(BinaryShiftedRegisterOperation);
2345     using FixedInputsInst::FixedInputsInst;
2346 
BinaryShiftedRegisterOperation(Opcode opcode,ShiftType shift_type,uint64_t imm)2347     explicit BinaryShiftedRegisterOperation(Opcode opcode, ShiftType shift_type, uint64_t imm)
2348         : FixedInputsInst(opcode), ImmediateMixin(imm), ShiftTypeMixin(shift_type)
2349     {
2350     }
BinaryShiftedRegisterOperation(Opcode opcode,DataType::Type type,uint32_t pc,ShiftType shift_type,uint64_t imm)2351     explicit BinaryShiftedRegisterOperation(Opcode opcode, DataType::Type type, uint32_t pc, ShiftType shift_type,
2352                                             uint64_t imm)
2353         : FixedInputsInst(opcode, type, pc), ImmediateMixin(imm), ShiftTypeMixin(shift_type)
2354     {
2355     }
2356 
GetInputType(size_t index)2357     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
2358     {
2359         ASSERT(index < GetInputsCount());
2360         return GetType();
2361     }
2362 
2363     void SetVnObject(VnObject *vn_obj) override;
2364     bool DumpInputs(std::ostream * /* out */) const override;
2365     Inst *Clone(const Graph *targetGraph) const override;
2366 };
2367 
2368 class SpillFillInst;
2369 
2370 /**
2371  * Mixin to hold location data
2372  */
2373 class LocationDataMixin {
2374 public:
SetLocationData(SpillFillData location_data)2375     void SetLocationData(SpillFillData location_data)
2376     {
2377         location_data_ = location_data;
2378     }
2379 
GetLocationData()2380     auto GetLocationData() const
2381     {
2382         return location_data_;
2383     }
2384 
GetLocationData()2385     auto &GetLocationData()
2386     {
2387         return location_data_;
2388     }
2389 
2390 protected:
2391     LocationDataMixin() = default;
2392     NO_COPY_SEMANTIC(LocationDataMixin);
2393     NO_MOVE_SEMANTIC(LocationDataMixin);
2394     virtual ~LocationDataMixin() = default;
2395 
2396 private:
2397     SpillFillData location_data_ {};
2398 };
2399 
2400 /**
2401  * Mixin to hold input types of call instruction
2402  */
2403 class InputTypesMixin {
2404 public:
2405     InputTypesMixin() = default;
2406     NO_COPY_SEMANTIC(InputTypesMixin);
2407     NO_MOVE_SEMANTIC(InputTypesMixin);
2408     virtual ~InputTypesMixin() = default;
2409 
AllocateInputTypes(ArenaAllocator * allocator,size_t capacity)2410     void AllocateInputTypes(ArenaAllocator *allocator, size_t capacity)
2411     {
2412         ASSERT(allocator != nullptr);
2413         ASSERT(input_types_ == nullptr);
2414         input_types_ = allocator->New<ArenaVector<DataType::Type>>(allocator->Adapter());
2415         ASSERT(input_types_ != nullptr);
2416         input_types_->reserve(capacity);
2417         ASSERT(input_types_->capacity() >= capacity);
2418     }
AddInputType(DataType::Type type)2419     void AddInputType(DataType::Type type)
2420     {
2421         ASSERT(input_types_ != nullptr);
2422         input_types_->push_back(type);
2423     }
GetInputTypes()2424     ArenaVector<DataType::Type> *GetInputTypes()
2425     {
2426         return input_types_;
2427     }
CloneTypes(ArenaAllocator * allocator,InputTypesMixin * target_inst)2428     void CloneTypes(ArenaAllocator *allocator, InputTypesMixin *target_inst) const
2429     {
2430         if (UNLIKELY(input_types_ == nullptr)) {
2431             return;
2432         }
2433         target_inst->AllocateInputTypes(allocator, input_types_->size());
2434         for (auto input_type : *input_types_) {
2435             target_inst->AddInputType(input_type);
2436         }
2437     }
2438 
2439 protected:
2440     // NOLINTNEXTLINE(misc-non-private-member-variables-in-classes)
2441     ArenaVector<DataType::Type> *input_types_ {nullptr};
2442 };
2443 
2444 /**
2445  * Call instruction
2446  */
2447 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
2448 class CallInst : public InlinedInstMixin<DynamicInputsInst>, public InputTypesMixin {
2449     static constexpr uint32_t INVALID_METHOD_ID = std::numeric_limits<uint32_t>::max();
2450 
2451 public:
2452     DECLARE_INST(CallInst);
2453     using Base = InlinedInstMixin<DynamicInputsInst>;
2454     using Base::Base;
2455 
CallInst(Opcode opcode,DataType::Type type,uint32_t pc,uint32_t method_id)2456     CallInst(Opcode opcode, DataType::Type type, uint32_t pc, uint32_t method_id)
2457         : Base(opcode, type, pc), method_id_(method_id)
2458     {
2459     }
2460 
SetCallMethodId(uint32_t id)2461     void SetCallMethodId(uint32_t id)
2462     {
2463         method_id_ = id;
2464     }
GetCallMethodId()2465     auto GetCallMethodId() const
2466     {
2467         return method_id_;
2468     }
SetCallMethod(RuntimeInterface::MethodPtr method)2469     void SetCallMethod(RuntimeInterface::MethodPtr method)
2470     {
2471         method_ = method;
2472     }
GetCallMethod()2473     RuntimeInterface::MethodPtr GetCallMethod() const
2474     {
2475         return method_;
2476     }
2477 
GetInputType(size_t index)2478     DataType::Type GetInputType(size_t index) const override
2479     {
2480         ASSERT(input_types_ != nullptr);
2481         ASSERT(index < input_types_->size());
2482         ASSERT(index < GetInputsCount());
2483         return (*input_types_)[index];
2484     }
2485 
2486     void DumpOpcode(std::ostream *out) const override;
2487 
SetCanNativeException(bool is_native)2488     void SetCanNativeException(bool is_native)
2489     {
2490         SetField<IsNativeExceptionFlag>(is_native);
2491     }
2492 
GetCanNativeException()2493     bool GetCanNativeException() const
2494     {
2495         return GetField<IsNativeExceptionFlag>();
2496     }
2497 
2498     Inst *Clone(const Graph *targetGraph) const override;
2499 
IsRuntimeCall()2500     bool IsRuntimeCall() const override
2501     {
2502         return !IsInlined();
2503     }
2504 
2505 protected:
2506     using IsNativeExceptionFlag = LastField::NextFlag;
2507     using LastField = IsNativeExceptionFlag;
2508 
2509 private:
2510     uint32_t method_id_ {INVALID_METHOD_ID};
2511     RuntimeInterface::MethodPtr method_ {nullptr};
2512 };
2513 
2514 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
2515 class CallIndirectInst : public DynamicInputsInst, public InputTypesMixin {
2516 public:
2517     DECLARE_INST(CallIndirectInst);
2518     using Base = DynamicInputsInst;
2519     using Base::Base;
2520 
CallIndirectInst(Opcode opcode,DataType::Type type,uint32_t pc)2521     CallIndirectInst(Opcode opcode, DataType::Type type, uint32_t pc) : Base(opcode, type, pc) {}
2522 
GetInputType(size_t index)2523     DataType::Type GetInputType(size_t index) const override
2524     {
2525         ASSERT(input_types_ != nullptr);
2526         ASSERT(index < input_types_->size());
2527         ASSERT(index < GetInputsCount());
2528         return (*input_types_)[index];
2529     }
2530 
2531     Inst *Clone(const Graph *target_graph) const override;
2532 };
2533 
2534 /**
2535  * Length methods instruction
2536  */
2537 class LengthMethodInst : public ArrayInstMixin<FixedInputsInst1> {
2538 public:
2539     DECLARE_INST(LengthMethodInst);
2540     using Base = ArrayInstMixin<FixedInputsInst1>;
2541     using Base::Base;
2542 
Base(opcode)2543     explicit LengthMethodInst(Opcode opcode, bool is_array = true) : Base(opcode)
2544     {
2545         SetIsArray(is_array);
2546     }
Base(opcode,type,pc)2547     LengthMethodInst(Opcode opcode, DataType::Type type, uint32_t pc, bool is_array = true) : Base(opcode, type, pc)
2548     {
2549         SetIsArray(is_array);
2550     }
2551 
GetInputType(size_t index)2552     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
2553     {
2554         ASSERT(index < GetInputsCount());
2555         return DataType::REFERENCE;
2556     }
2557 
Clone(const Graph * targetGraph)2558     Inst *Clone(const Graph *targetGraph) const override
2559     {
2560         auto clone = FixedInputsInst::Clone(targetGraph);
2561         static_cast<LengthMethodInst *>(clone)->SetIsArray(IsArray());
2562         return clone;
2563     }
2564 };
2565 
2566 /**
2567  * Compare instruction
2568  */
2569 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
2570 class CompareInst : public InstWithOperandsType<ConditionMixin<FixedInputsInst2>> {
2571 public:
2572     DECLARE_INST(CompareInst);
2573     using BaseInst = InstWithOperandsType<ConditionMixin<FixedInputsInst2>>;
2574     using BaseInst::BaseInst;
2575 
CompareInst(Opcode opcode,DataType::Type type,uint32_t pc,ConditionCode cc)2576     CompareInst(Opcode opcode, DataType::Type type, uint32_t pc, ConditionCode cc) : BaseInst(opcode, type, pc)
2577     {
2578         SetCc(cc);
2579     }
2580 
GetInputType(size_t index)2581     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
2582     {
2583         ASSERT(index < GetInputsCount());
2584         return GetOperandsType();
2585     }
2586     void DumpOpcode(std::ostream * /* unused */) const override;
2587 
2588     void SetVnObject(VnObject *vn_obj) override;
2589 
Clone(const Graph * targetGraph)2590     Inst *Clone(const Graph *targetGraph) const override
2591     {
2592         auto clone = FixedInputsInst::Clone(targetGraph);
2593         clone->CastToCompare()->SetCc(GetCc());
2594         clone->CastToCompare()->SetOperandsType(GetOperandsType());
2595         return clone;
2596     }
2597 };
2598 
2599 /**
2600  * Mixin for AnyTypeMixin instructions
2601  */
2602 template <typename T>
2603 class AnyTypeMixin : public T {
2604 public:
2605     using T::T;
2606 
SetAnyType(AnyBaseType any_type)2607     void SetAnyType(AnyBaseType any_type)
2608     {
2609         T::template SetField<AnyBaseTypeField>(any_type);
2610     }
2611 
GetAnyType()2612     AnyBaseType GetAnyType() const
2613     {
2614         return T::template GetField<AnyBaseTypeField>();
2615     }
2616 
2617 protected:
2618     using AnyBaseTypeField =
2619         typename T::LastField::template NextField<AnyBaseType, MinimumBitsToStore(AnyBaseType::COUNT)>;
2620     using LastField = AnyBaseTypeField;
2621 };
2622 
2623 /**
2624  * CompareAnyTypeInst instruction
2625  */
2626 class CompareAnyTypeInst : public AnyTypeMixin<FixedInputsInst1> {
2627 public:
2628     DECLARE_INST(CompareAnyTypeInst);
2629     using BaseInst = AnyTypeMixin<FixedInputsInst1>;
2630     using BaseInst::BaseInst;
2631 
CompareAnyTypeInst(Opcode opcode,uint32_t pc,AnyBaseType any_type)2632     CompareAnyTypeInst(Opcode opcode, uint32_t pc, AnyBaseType any_type) : BaseInst(opcode, DataType::Type::BOOL, pc)
2633     {
2634         SetAnyType(any_type);
2635     }
2636 
GetInputType(size_t index)2637     DataType::Type GetInputType(size_t index) const override
2638     {
2639         ASSERT(index < GetInputsCount());
2640         return GetInput(index).GetInst()->GetType();
2641     }
2642 
2643     void DumpOpcode(std::ostream *out) const override;
2644 
Clone(const Graph * targetGraph)2645     Inst *Clone(const Graph *targetGraph) const override
2646     {
2647         auto clone = FixedInputsInst::Clone(targetGraph);
2648         clone->CastToCompareAnyType()->SetAnyType(GetAnyType());
2649         return clone;
2650     }
2651 };
2652 
2653 /**
2654  * CastAnyTypeValueInst instruction
2655  */
2656 class CastAnyTypeValueInst : public AnyTypeMixin<FixedInputsInst1> {
2657 public:
2658     DECLARE_INST(CastAnyTypeValueInst);
2659     using BaseInst = AnyTypeMixin<FixedInputsInst1>;
2660     using BaseInst::BaseInst;
2661 
CastAnyTypeValueInst(Opcode opcode,uint32_t pc,AnyBaseType any_type)2662     CastAnyTypeValueInst(Opcode opcode, uint32_t pc, AnyBaseType any_type)
2663         : BaseInst(opcode, AnyBaseTypeToDataType(any_type), pc)
2664     {
2665         SetAnyType(any_type);
2666     }
2667 
GetInputType(size_t index)2668     DataType::Type GetInputType(size_t index) const override
2669     {
2670         ASSERT(index < GetInputsCount());
2671         return GetInput(index).GetInst()->GetType();
2672     }
2673 
GetDeducedType()2674     DataType::Type GetDeducedType() const
2675     {
2676         return AnyBaseTypeToDataType(GetAnyType());
2677     }
2678 
2679     void DumpOpcode(std::ostream *out) const override;
2680 
Clone(const Graph * targetGraph)2681     Inst *Clone(const Graph *targetGraph) const override
2682     {
2683         auto clone = FixedInputsInst::Clone(targetGraph)->CastToCastAnyTypeValue();
2684         AnyBaseType any_type = GetAnyType();
2685         clone->SetAnyType(any_type);
2686         clone->SetType(GetType());
2687         return clone;
2688     }
2689 };
2690 
2691 /**
2692  * CastValueToAnyTypeInst instruction
2693  */
2694 class CastValueToAnyTypeInst : public AnyTypeMixin<FixedInputsInst1> {
2695 public:
2696     DECLARE_INST(CastValueToAnyTypeInst);
2697     using BaseInst = AnyTypeMixin<FixedInputsInst1>;
2698     using BaseInst::BaseInst;
2699 
CastValueToAnyTypeInst(Opcode opcode,uint32_t pc)2700     CastValueToAnyTypeInst(Opcode opcode, uint32_t pc) : BaseInst(opcode, DataType::ANY, pc) {}
2701 
GetInputType(size_t index)2702     DataType::Type GetInputType(size_t index) const override
2703     {
2704         ASSERT(index < GetInputsCount());
2705         return GetInput(index).GetInst()->GetType();
2706     }
2707 
2708     void DumpOpcode(std::ostream *out) const override;
2709 
Clone(const Graph * targetGraph)2710     Inst *Clone(const Graph *targetGraph) const override
2711     {
2712         auto clone = FixedInputsInst::Clone(targetGraph)->CastToCastValueToAnyType();
2713         auto any_type = GetAnyType();
2714         clone->SetAnyType(any_type);
2715         clone->SetType(GetType());
2716         return clone;
2717     }
2718 };
2719 
2720 /**
2721  * AnyTypeCheckInst instruction
2722  */
2723 class AnyTypeCheckInst : public AnyTypeMixin<FixedInputsInst2> {
2724 public:
2725     DECLARE_INST(AnyTypeCheckInst);
2726     using BaseInst = AnyTypeMixin<FixedInputsInst2>;
2727     using BaseInst::BaseInst;
2728 
AnyTypeCheckInst(Opcode opcode,uint32_t pc,AnyBaseType any_type)2729     AnyTypeCheckInst(Opcode opcode, uint32_t pc, AnyBaseType any_type) : BaseInst(opcode, DataType::ANY, pc)
2730     {
2731         SetAnyType(any_type);
2732     }
2733 
GetInputType(size_t index)2734     DataType::Type GetInputType(size_t index) const override
2735     {
2736         ASSERT(index < GetInputsCount());
2737         return (index == 0) ? DataType::ANY : DataType::NO_TYPE;
2738     }
2739 
2740     void DumpOpcode(std::ostream *out) const override;
2741 
Clone(const Graph * targetGraph)2742     Inst *Clone(const Graph *targetGraph) const override
2743     {
2744         auto clone = FixedInputsInst::Clone(targetGraph);
2745         clone->CastToAnyTypeCheck()->SetAnyType(GetAnyType());
2746         return clone;
2747     }
2748 };
2749 
2750 /**
2751  * ConstantInst represent constant value.
2752  *
2753  * Available types: INT64, FLOAT32, FLOAT64, ANY. All integer types are stored as INT64 value.
2754  * Once type of constant is set, it can't be changed anymore.
2755  */
2756 class ConstantInst : public Inst {
2757 public:
2758     DECLARE_INST(ConstantInst);
2759     using Inst::Inst;
2760 
2761     template <typename T>
Inst(Opcode::Constant)2762     explicit ConstantInst(Opcode /* unused */, T value, bool support_int32 = false) : Inst(Opcode::Constant)
2763     {
2764         ASSERT(GetTypeFromCType<T>() != DataType::NO_TYPE);
2765         // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-branch-clone)
2766         if constexpr (GetTypeFromCType<T>() == DataType::FLOAT64) {
2767             value_ = bit_cast<uint64_t, double>(value);
2768             // NOLINTNEXTLINE(readability-braces-around-statements, readability-misleading-indentation)
2769         } else if constexpr (GetTypeFromCType<T>() == DataType::FLOAT32) {
2770             value_ = bit_cast<uint32_t, float>(value);
2771             // NOLINTNEXTLINE(readability-braces-around-statements, readability-misleading-indentation)
2772         } else if constexpr (GetTypeFromCType<T>() == DataType::ANY) {
2773             value_ = value.Raw();
2774             // NOLINTNEXTLINE(readability-braces-around-statements, readability-misleading-indentation)
2775         } else if (GetTypeFromCType<T>(support_int32) == DataType::INT32) {
2776             value_ = static_cast<int32_t>(value);
2777             // NOLINTNEXTLINE(readability-braces-around-statements, readability-misleading-indentation)
2778         } else {
2779             value_ = value;
2780         }
2781 
2782         SetType(GetTypeFromCType<T>(support_int32));
2783     }
2784 
IsSafeInst()2785     bool IsSafeInst() const override
2786     {
2787         return true;
2788     }
2789 
GetRawValue()2790     uint64_t GetRawValue() const
2791     {
2792         return value_;
2793     }
2794 
GetInt32Value()2795     uint32_t GetInt32Value() const
2796     {
2797         ASSERT(GetType() == DataType::INT32);
2798         return static_cast<uint32_t>(value_);
2799     }
2800 
GetInt64Value()2801     uint64_t GetInt64Value() const
2802     {
2803         ASSERT(GetType() == DataType::INT64);
2804         return value_;
2805     }
2806 
GetIntValue()2807     uint64_t GetIntValue() const
2808     {
2809         ASSERT(GetType() == DataType::INT64 || GetType() == DataType::INT32);
2810         return value_;
2811     }
2812 
GetFloatValue()2813     float GetFloatValue() const
2814     {
2815         ASSERT(GetType() == DataType::FLOAT32);
2816         return bit_cast<float, uint32_t>(static_cast<uint32_t>(value_));
2817     }
2818 
GetDoubleValue()2819     double GetDoubleValue() const
2820     {
2821         ASSERT(GetType() == DataType::FLOAT64);
2822         return bit_cast<double, uint64_t>(value_);
2823     }
2824 
GetNextConst()2825     ConstantInst *GetNextConst()
2826     {
2827         return next_const_;
2828     }
SetNextConst(ConstantInst * next_const)2829     void SetNextConst(ConstantInst *next_const)
2830     {
2831         next_const_ = next_const;
2832     }
2833 
2834     template <typename T>
2835     static constexpr DataType::Type GetTypeFromCType(bool support_int32 = false)
2836     {
2837         // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-branch-clone)
2838         if constexpr (std::is_integral_v<T>) {
2839             if (support_int32 && sizeof(T) == sizeof(uint32_t)) {
2840                 return DataType::INT32;
2841             }
2842             return DataType::INT64;
2843             // NOLINTNEXTLINE(readability-braces-around-statements, readability-misleading-indentation)
2844         } else if constexpr (std::is_same_v<T, float>) {
2845             return DataType::FLOAT32;
2846             // NOLINTNEXTLINE(readability-braces-around-statements, readability-misleading-indentation)
2847         } else if constexpr (std::is_same_v<T, double>) {
2848             return DataType::FLOAT64;
2849             // NOLINTNEXTLINE(readability-braces-around-statements, readability-misleading-indentation)
2850         } else if constexpr (std::is_same_v<T, DataType::Any>) {
2851             return DataType::ANY;
2852         }
2853         return DataType::NO_TYPE;
2854     }
2855 
2856     inline bool IsEqualConst(double value, [[maybe_unused]] bool support_int32 = false)
2857     {
2858         return IsEqualConst(DataType::FLOAT64, bit_cast<uint64_t, double>(value));
2859     }
2860     inline bool IsEqualConst(float value, [[maybe_unused]] bool support_int32 = false)
2861     {
2862         return IsEqualConst(DataType::FLOAT32, bit_cast<uint32_t, float>(value));
2863     }
2864     inline bool IsEqualConst(DataType::Any value, [[maybe_unused]] bool support_int32 = false)
2865     {
2866         return IsEqualConst(DataType::ANY, value.Raw());
2867     }
IsEqualConst(DataType::Type type,uint64_t value)2868     inline bool IsEqualConst(DataType::Type type, uint64_t value)
2869     {
2870         return GetType() == type && value_ == value;
2871     }
2872     template <typename T>
2873     inline bool IsEqualConst(T value, bool support_int32 = false)
2874     {
2875         static_assert(GetTypeFromCType<T>() == DataType::INT64);
2876         if (support_int32 && sizeof(T) == sizeof(uint32_t)) {
2877             return (GetType() == DataType::INT32 && static_cast<int32_t>(value_) == static_cast<int32_t>(value));
2878         }
2879         return (GetType() == DataType::INT64 && value_ == static_cast<uint64_t>(value));
2880     }
2881 
2882     inline bool IsEqualConstAllTypes(int64_t value, bool support_int32 = false)
2883     {
2884         return IsEqualConst(value, support_int32) || IsEqualConst(static_cast<float>(value)) ||
2885                IsEqualConst(static_cast<double>(value));
2886     }
2887 
IsBoolConst()2888     bool IsBoolConst() const override
2889     {
2890         ASSERT(IsConst());
2891         return GetType() == DataType::INT64 && (GetIntValue() == 0 || GetIntValue() == 1);
2892     }
2893 
SetImmTableSlot(ImmTableSlot imm_slot)2894     void SetImmTableSlot(ImmTableSlot imm_slot)
2895     {
2896         imm_slot_ = imm_slot;
2897     }
2898 
GetImmTableSlot()2899     auto GetImmTableSlot() const
2900     {
2901         return imm_slot_;
2902     }
2903 
2904     bool DumpInputs(std::ostream * /* out */) const override;
2905 
2906     Inst *Clone(const Graph *targetGraph) const override;
2907 
2908 private:
2909     uint64_t value_ {0};
2910     ConstantInst *next_const_ {nullptr};
2911     ImmTableSlot imm_slot_ {INVALID_IMM_TABLE_SLOT};
2912 };
2913 
2914 // Type describing the purpose of the SpillFillInst.
2915 // RegAlloc may use this information to preserve correct order of several SpillFillInst
2916 // instructions placed along each other in the graph.
2917 enum SpillFillType {
2918     UNKNOWN,
2919     INPUT_FILL,
2920     CONNECT_SPLIT_SIBLINGS,
2921     SPLIT_MOVE,
2922 };
2923 
2924 class SpillFillInst : public FixedInputsInst0 {
2925 public:
2926     DECLARE_INST(SpillFillInst);
2927 
SpillFillInst(ArenaAllocator * allocator,Opcode opcode)2928     explicit SpillFillInst(ArenaAllocator *allocator, Opcode opcode)
2929         : FixedInputsInst0(opcode), spill_fills_(allocator->Adapter())
2930     {
2931     }
2932 
AddMove(Register src,Register dst,DataType::Type type)2933     void AddMove(Register src, Register dst, DataType::Type type)
2934     {
2935         AddSpillFill(Location::MakeRegister(src, type), Location::MakeRegister(dst, type), type);
2936     }
2937 
AddSpill(Register src,StackSlot dst,DataType::Type type)2938     void AddSpill(Register src, StackSlot dst, DataType::Type type)
2939     {
2940         AddSpillFill(Location::MakeRegister(src, type), Location::MakeStackSlot(dst), type);
2941     }
2942 
AddFill(StackSlot src,Register dst,DataType::Type type)2943     void AddFill(StackSlot src, Register dst, DataType::Type type)
2944     {
2945         AddSpillFill(Location::MakeStackSlot(src), Location::MakeRegister(dst, type), type);
2946     }
2947 
AddMemCopy(StackSlot src,StackSlot dst,DataType::Type type)2948     void AddMemCopy(StackSlot src, StackSlot dst, DataType::Type type)
2949     {
2950         AddSpillFill(Location::MakeStackSlot(src), Location::MakeStackSlot(dst), type);
2951     }
2952 
AddSpillFill(const SpillFillData & spill_fill)2953     void AddSpillFill(const SpillFillData &spill_fill)
2954     {
2955         spill_fills_.emplace_back(spill_fill);
2956     }
2957 
AddSpillFill(const Location & src,const Location & dst,DataType::Type type)2958     void AddSpillFill(const Location &src, const Location &dst, DataType::Type type)
2959     {
2960         spill_fills_.emplace_back(SpillFillData {src.GetKind(), dst.GetKind(), src.GetValue(), dst.GetValue(), type});
2961     }
2962 
GetSpillFills()2963     const ArenaVector<SpillFillData> &GetSpillFills() const
2964     {
2965         return spill_fills_;
2966     }
2967 
GetSpillFills()2968     ArenaVector<SpillFillData> &GetSpillFills()
2969     {
2970         return spill_fills_;
2971     }
2972 
GetSpillFill(size_t n)2973     const SpillFillData &GetSpillFill(size_t n) const
2974     {
2975         ASSERT(n < spill_fills_.size());
2976         return spill_fills_[n];
2977     }
2978 
GetSpillFill(size_t n)2979     SpillFillData &GetSpillFill(size_t n)
2980     {
2981         ASSERT(n < spill_fills_.size());
2982         return spill_fills_[n];
2983     }
2984 
RemoveSpillFill(size_t n)2985     void RemoveSpillFill(size_t n)
2986     {
2987         ASSERT(n < spill_fills_.size());
2988         spill_fills_.erase(spill_fills_.begin() + n);
2989     }
2990 
2991     // Get register number, holded by n-th spill-fill
GetInputReg(size_t n)2992     Register GetInputReg(size_t n) const
2993     {
2994         ASSERT(n < spill_fills_.size());
2995         ASSERT(spill_fills_[n].SrcType() == LocationType::REGISTER);
2996         return spill_fills_[n].SrcValue();
2997     }
2998 
ClearSpillFills()2999     void ClearSpillFills()
3000     {
3001         spill_fills_.clear();
3002     }
3003 
GetSpillFillType()3004     SpillFillType GetSpillFillType() const
3005     {
3006         return sf_type_;
3007     }
3008 
SetSpillFillType(SpillFillType type)3009     void SetSpillFillType(SpillFillType type)
3010     {
3011         sf_type_ = type;
3012     }
3013 
3014     bool DumpInputs(std::ostream * /* out */) const override;
3015 
3016 #ifndef NDEBUG
Clone(const Graph * targetGraph)3017     Inst *Clone(const Graph *targetGraph) const override
3018     {
3019         auto clone = FixedInputsInst::Clone(targetGraph)->CastToSpillFill();
3020         for (auto spill_fill : spill_fills_) {
3021             clone->AddSpillFill(spill_fill);
3022         }
3023         return clone;
3024     }
3025 #endif
3026 
3027 private:
3028     ArenaVector<SpillFillData> spill_fills_;
3029     SpillFillType sf_type_ {UNKNOWN};
3030 };
3031 
3032 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
3033 class ParameterInst : public Inst, public LocationDataMixin {
3034 public:
3035     DECLARE_INST(ParameterInst);
3036     using Inst::Inst;
3037 
ParameterInst(Opcode,uint16_t arg_number)3038     explicit ParameterInst(Opcode /* unused */, uint16_t arg_number) : Inst(Opcode::Parameter), arg_number_(arg_number)
3039     {
3040     }
GetArgNumber()3041     uint16_t GetArgNumber() const
3042     {
3043         return arg_number_;
3044     }
3045 
SetArgNumber(uint16_t arg_number)3046     void SetArgNumber(uint16_t arg_number)
3047     {
3048         arg_number_ = arg_number;
3049     }
3050 
3051     bool DumpInputs(std::ostream * /* out */) const override;
3052 
3053     Inst *Clone(const Graph *targetGraph) const override;
3054 
3055 private:
3056     uint16_t arg_number_ {0};
3057 };
3058 
IsZeroConstant(const Inst * inst)3059 inline bool IsZeroConstant(const Inst *inst)
3060 {
3061     return inst->IsConst() && inst->GetType() == DataType::INT64 && inst->CastToConstant()->GetIntValue() == 0;
3062 }
3063 
IsZeroConstantOrNullPtr(const Inst * inst)3064 inline bool IsZeroConstantOrNullPtr(const Inst *inst)
3065 {
3066     return IsZeroConstant(inst) || inst->GetOpcode() == Opcode::NullPtr;
3067 }
3068 
3069 /**
3070  * Phi instruction
3071  */
3072 class PhiInst : public AnyTypeMixin<DynamicInputsInst> {
3073 public:
3074     DECLARE_INST(PhiInst);
3075     using BaseInst = AnyTypeMixin<DynamicInputsInst>;
3076     using BaseInst::BaseInst;
3077     /// Get basic block corresponding to given input index. Returned pointer to basic block, can't be nullptr
3078     BasicBlock *GetPhiInputBb(unsigned index);
GetPhiInputBb(unsigned index)3079     const BasicBlock *GetPhiInputBb(unsigned index) const
3080     {
3081         return (const_cast<PhiInst *>(this))->GetPhiInputBb(index);
3082     }
3083 
GetPhiInputBbNum(unsigned index)3084     uint32_t GetPhiInputBbNum(unsigned index) const
3085     {
3086         ASSERT(index < GetInputsCount());
3087         return GetDynamicOperands()->GetUser(index)->GetBbNum();
3088     }
3089 
SetPhiInputBbNum(unsigned index,uint32_t bb_num)3090     void SetPhiInputBbNum(unsigned index, uint32_t bb_num)
3091     {
3092         ASSERT(index < GetInputsCount());
3093         GetDynamicOperands()->GetUser(index)->SetBbNum(bb_num);
3094     }
3095 
Clone(const Graph * targetGraph)3096     Inst *Clone(const Graph *targetGraph) const override
3097     {
3098         auto clone = DynamicInputsInst::Clone(targetGraph);
3099         clone->CastToPhi()->SetAnyType(GetAnyType());
3100         return clone;
3101     }
3102 
GetAssumedAnyType()3103     AnyBaseType GetAssumedAnyType()
3104     {
3105         return GetAnyType();
3106     }
3107 
SetAssumedAnyType(AnyBaseType type)3108     void SetAssumedAnyType(AnyBaseType type)
3109     {
3110         SetAnyType(type);
3111     }
3112 
3113     /// Get input instruction corresponding to the given basic block, can't be null.
3114     Inst *GetPhiInput(BasicBlock *bb);
3115     Inst *GetPhiDataflowInput(BasicBlock *bb);
3116     bool DumpInputs(std::ostream * /* out */) const override;
3117 
3118     // Get index of the given block in phi inputs
3119     size_t GetPredBlockIndex(const BasicBlock *block) const;
3120 
3121 protected:
3122     using FlagIsLive = LastField::NextFlag;
3123     using LastField = FlagIsLive;
3124 };
3125 
3126 /**
3127  * Immediate for SavaState:
3128  * value - constant value to be stored
3129  * vreg - virtual register number
3130  */
3131 struct SaveStateImm {
3132     uint64_t value;
3133     uint16_t vreg;
3134     DataType::Type type;
3135     bool is_acc;
3136 };
3137 
3138 /**
3139  * Frame state saving instruction
3140  * Aims to save pbc registers before calling something that can raise exception
3141  */
3142 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
3143 class SaveStateInst : public DynamicInputsInst {
3144 public:
3145     DECLARE_INST(SaveStateInst);
3146     using DynamicInputsInst::DynamicInputsInst;
3147 
3148     bool DumpInputs(std::ostream *out) const override;
3149 
SetVirtualRegister(size_t index,VirtualRegister reg)3150     void SetVirtualRegister(size_t index, VirtualRegister reg)
3151     {
3152         static_assert(sizeof(reg) <= sizeof(uintptr_t), "Consider passing the register by reference");
3153         ASSERT(index < GetInputsCount());
3154         GetDynamicOperands()->GetUser(index)->SetVirtualRegister(reg);
3155     }
3156 
GetVirtualRegister(size_t index)3157     VirtualRegister GetVirtualRegister(size_t index) const
3158     {
3159         ASSERT(index < GetInputsCount());
3160         return GetDynamicOperands()->GetUser(index)->GetVirtualRegister();
3161     }
3162 
Verify()3163     bool Verify() const
3164     {
3165         for (size_t i {0}; i < GetInputsCount(); ++i) {
3166             if (static_cast<uint16_t>(GetVirtualRegister(i)) == VirtualRegister::INVALID) {
3167                 return false;
3168             }
3169         }
3170         return true;
3171     }
3172 
RemoveNumericInputs()3173     bool RemoveNumericInputs()
3174     {
3175         size_t idx = 0;
3176         size_t inputs_count = GetInputsCount();
3177         bool removed = false;
3178         while (idx < inputs_count) {
3179             auto input_inst = GetInput(idx).GetInst();
3180             if (DataType::IsTypeNumeric(input_inst->GetType())) {
3181                 RemoveInput(idx);
3182                 inputs_count--;
3183                 removed = true;
3184             } else {
3185                 idx++;
3186             }
3187         }
3188         return removed;
3189     }
3190 
GetInputType(size_t index)3191     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
3192     {
3193         ASSERT(index < GetInputsCount());
3194         return DataType::NO_TYPE;
3195     }
GetMethod()3196     auto GetMethod() const
3197     {
3198         return method_;
3199     }
SetMethod(void * method)3200     auto SetMethod(void *method)
3201     {
3202         method_ = method;
3203     }
3204 
GetCallerInst()3205     auto GetCallerInst() const
3206     {
3207         return caller_inst_;
3208     }
SetCallerInst(CallInst * inst)3209     auto SetCallerInst(CallInst *inst)
3210     {
3211         caller_inst_ = inst;
3212     }
3213 
3214     void AppendImmediate(uint64_t imm, uint16_t vreg, DataType::Type type, bool is_acc);
3215 
GetImmediates()3216     const ArenaVector<SaveStateImm> *GetImmediates() const
3217     {
3218         return immediates_;
3219     }
3220 
GetImmediate(size_t index)3221     const SaveStateImm &GetImmediate(size_t index) const
3222     {
3223         ASSERT(immediates_ != nullptr && index < immediates_->size());
3224         return (*immediates_)[index];
3225     }
3226 
3227     void AllocateImmediates(ArenaAllocator *allocator, size_t size = 0);
3228 
GetImmediatesCount()3229     size_t GetImmediatesCount() const
3230     {
3231         if (immediates_ == nullptr) {
3232             return 0;
3233         }
3234         return immediates_->size();
3235     }
3236 
SetRootsRegMaskBit(size_t reg)3237     void SetRootsRegMaskBit(size_t reg)
3238     {
3239         ASSERT(reg < roots_regs_mask_.size());
3240         roots_regs_mask_.set(reg);
3241     }
3242 
SetRootsStackMaskBit(size_t slot)3243     void SetRootsStackMaskBit(size_t slot)
3244     {
3245         if (roots_stack_mask_ != nullptr) {
3246             roots_stack_mask_->SetBit(slot);
3247         }
3248     }
3249 
GetRootsStackMask()3250     ArenaBitVector *GetRootsStackMask()
3251     {
3252         return roots_stack_mask_;
3253     }
3254 
GetRootsRegsMask()3255     auto &GetRootsRegsMask()
3256     {
3257         return roots_regs_mask_;
3258     }
3259 
CreateRootsStackMask(ArenaAllocator * allocator)3260     void CreateRootsStackMask(ArenaAllocator *allocator)
3261     {
3262         ASSERT(roots_stack_mask_ == nullptr);
3263         roots_stack_mask_ = allocator->New<ArenaBitVector>(allocator);
3264         roots_stack_mask_->Reset();
3265     }
3266 
3267     Inst *Clone(const Graph *targetGraph) const override;
3268 #ifndef NDEBUG
SetInputsWereDeleted()3269     void SetInputsWereDeleted()
3270     {
3271         SetField<FlagInputsWereDeleted>(true);
3272     }
3273 
GetInputsWereDeleted()3274     bool GetInputsWereDeleted()
3275     {
3276         return GetField<FlagInputsWereDeleted>();
3277     }
3278 #endif
3279 
3280 protected:
3281 #ifndef NDEBUG
3282     using FlagInputsWereDeleted = LastField::NextFlag;
3283     using LastField = FlagInputsWereDeleted;
3284 #endif
3285 
3286 private:
3287     ArenaVector<SaveStateImm> *immediates_ {nullptr};
3288     void *method_ {nullptr};
3289     /// If instruction is in the inlined graph, this variable points to the inliner's call instruction.
3290     CallInst *caller_inst_ {nullptr};
3291     ArenaBitVector *roots_stack_mask_ {nullptr};
3292     std::bitset<BITS_PER_UINT32> roots_regs_mask_ {0};
3293 };
3294 
3295 /**
3296  * Load value from array or string
3297  */
3298 class LoadInst : public ArrayInstMixin<NeedBarrierMixin<FixedInputsInst2>> {
3299 public:
3300     DECLARE_INST(LoadInst);
3301     using Base = ArrayInstMixin<NeedBarrierMixin<FixedInputsInst2>>;
3302     using Base::Base;
3303 
Base(opcode)3304     explicit LoadInst(Opcode opcode, bool is_array = true) : Base(opcode)
3305     {
3306         SetIsArray(is_array);
3307     }
Base(opcode,type,pc)3308     LoadInst(Opcode opcode, DataType::Type type, uint32_t pc, bool is_array = true) : Base(opcode, type, pc)
3309     {
3310         SetIsArray(is_array);
3311     }
3312 
GetArray()3313     Inst *GetArray()
3314     {
3315         return GetInput(0).GetInst();
3316     }
GetIndex()3317     Inst *GetIndex()
3318     {
3319         return GetInput(1).GetInst();
3320     }
3321 
IsBarrier()3322     bool IsBarrier() const override
3323     {
3324         return Inst::IsBarrier() || GetNeedBarrier();
3325     }
3326 
GetInputType(size_t index)3327     DataType::Type GetInputType(size_t index) const override
3328     {
3329         ASSERT(index < GetInputsCount());
3330         switch (index) {
3331             case 0:
3332                 return DataType::REFERENCE;
3333             case 1:
3334                 return DataType::INT32;
3335             default:
3336                 return DataType::NO_TYPE;
3337         }
3338     }
3339 
Latency()3340     uint32_t Latency() const override
3341     {
3342         return options.GetCompilerSchedLatencyLong();
3343     }
3344 
Clone(const Graph * targetGraph)3345     Inst *Clone(const Graph *targetGraph) const override
3346     {
3347         auto clone = NeedBarrierMixin<FixedInputsInst2>::Clone(targetGraph);
3348         static_cast<LoadInst *>(clone)->SetIsArray(IsArray());
3349         return clone;
3350     }
3351 };
3352 
3353 class LoadCompressedStringCharInst : public FixedInputsInst3 {
3354 public:
3355     DECLARE_INST(LoadCompressedStringCharInst);
3356     using Base = FixedInputsInst3;
3357     using Base::Base;
3358 
GetArray()3359     Inst *GetArray()
3360     {
3361         return GetInput(0).GetInst();
3362     }
GetIndex()3363     Inst *GetIndex()
3364     {
3365         return GetInput(1).GetInst();
3366     }
GetLength()3367     Inst *GetLength() const
3368     {
3369         return GetInput(2U).GetInst();
3370     }
3371 
GetInputType(size_t index)3372     DataType::Type GetInputType(size_t index) const override
3373     {
3374         ASSERT(index < GetInputsCount());
3375         switch (index) {
3376             case 0:
3377                 return DataType::REFERENCE;
3378             case 1:
3379                 return DataType::INT32;
3380             case 2U:
3381                 return DataType::INT32;
3382             default:
3383                 return DataType::NO_TYPE;
3384         }
3385     }
3386 
Latency()3387     uint32_t Latency() const override
3388     {
3389         return options.GetCompilerSchedLatencyLong();
3390     }
3391 };
3392 
3393 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
3394 class LoadCompressedStringCharInstI : public FixedInputsInst2, public ImmediateMixin {
3395 public:
3396     DECLARE_INST(LoadCompressedStringCharInstI);
3397     using Base = FixedInputsInst2;
3398     using Base::Base;
3399 
GetInputType(size_t index)3400     DataType::Type GetInputType(size_t index) const override
3401     {
3402         ASSERT(index < GetInputsCount());
3403         switch (index) {
3404             case 0:
3405                 return DataType::REFERENCE;
3406             case 1:
3407                 return DataType::INT32;
3408             default:
3409                 return DataType::NO_TYPE;
3410         }
3411     }
3412 
Latency()3413     uint32_t Latency() const override
3414     {
3415         return options.GetCompilerSchedLatencyLong();
3416     }
3417 };
3418 /**
3419  * Store value into array element
3420  */
3421 class StoreInst : public NeedBarrierMixin<FixedInputsInst3> {
3422 public:
3423     DECLARE_INST(StoreInst);
3424     using Base = NeedBarrierMixin<FixedInputsInst3>;
3425     using Base::Base;
3426 
IsBarrier()3427     bool IsBarrier() const override
3428     {
3429         return Inst::IsBarrier() || GetNeedBarrier();
3430     }
3431 
GetArray()3432     Inst *GetArray()
3433     {
3434         return GetInput(0).GetInst();
3435     }
GetIndex()3436     Inst *GetIndex()
3437     {
3438         return GetInput(1).GetInst();
3439     }
GetStoredValue()3440     Inst *GetStoredValue()
3441     {
3442         return GetInput(2U).GetInst();
3443     }
GetInputType(size_t index)3444     DataType::Type GetInputType(size_t index) const override
3445     {
3446         ASSERT(index < GetInputsCount());
3447         switch (index) {
3448             case 0:
3449                 return DataType::REFERENCE;
3450             case 1:
3451                 return DataType::INT32;
3452             case 2U:
3453                 return GetType();
3454             default:
3455                 return DataType::NO_TYPE;
3456         }
3457     }
3458 
3459     // StoreArray call barriers twice,so we need to save input register for second call
IsPropagateLiveness()3460     bool IsPropagateLiveness() const override
3461     {
3462         return GetType() == DataType::REFERENCE;
3463     }
3464 };
3465 
3466 /**
3467  * Load value from array, using array index as immediate
3468  */
3469 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
3470 class LoadInstI : public VolatileMixin<ArrayInstMixin<NeedBarrierMixin<FixedInputsInst1>>>, public ImmediateMixin {
3471 public:
3472     DECLARE_INST(LoadInstI);
3473     using Base = VolatileMixin<ArrayInstMixin<NeedBarrierMixin<FixedInputsInst1>>>;
3474     using Base::Base;
3475 
Base(opcode)3476     LoadInstI(Opcode opcode, uint64_t imm, bool is_array = true) : Base(opcode), ImmediateMixin(imm)
3477     {
3478         SetIsArray(is_array);
3479     }
3480     LoadInstI(Opcode opcode, DataType::Type type, uint32_t pc, uint64_t imm, bool is_array = true)
Base(opcode,type,pc)3481         : Base(opcode, type, pc), ImmediateMixin(imm)
3482     {
3483         SetIsArray(is_array);
3484     }
3485 
GetArray()3486     Inst *GetArray()
3487     {
3488         return GetInput(0).GetInst();
3489     }
3490 
GetInputType(size_t index)3491     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
3492     {
3493         ASSERT(index == 0);
3494         return DataType::REFERENCE;
3495     }
3496 
IsBarrier()3497     bool IsBarrier() const override
3498     {
3499         return Inst::IsBarrier() || GetNeedBarrier();
3500     }
3501 
3502     bool DumpInputs(std::ostream * /* out */) const override;
3503 
Clone(const Graph * targetGraph)3504     Inst *Clone(const Graph *targetGraph) const override
3505     {
3506         auto clone = static_cast<LoadInstI *>(FixedInputsInst::Clone(targetGraph));
3507         clone->SetImm(GetImm());
3508         clone->SetIsArray(IsArray());
3509         clone->SetVolatile(GetVolatile());
3510         return clone;
3511     }
3512 
Latency()3513     uint32_t Latency() const override
3514     {
3515         return options.GetCompilerSchedLatencyLong();
3516     }
3517 };
3518 
3519 /**
3520  * Load value from pointer with offset
3521  */
3522 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
3523 class LoadMemInstI : public VolatileMixin<NeedBarrierMixin<FixedInputsInst1>>, public ImmediateMixin {
3524 public:
3525     DECLARE_INST(LoadMemInstI);
3526     using Base = VolatileMixin<NeedBarrierMixin<FixedInputsInst1>>;
3527     using Base::Base;
3528 
LoadMemInstI(Opcode opcode,uint64_t imm)3529     LoadMemInstI(Opcode opcode, uint64_t imm) : Base(opcode), ImmediateMixin(imm) {}
LoadMemInstI(Opcode opcode,DataType::Type type,uint32_t pc,uint64_t imm)3530     LoadMemInstI(Opcode opcode, DataType::Type type, uint32_t pc, uint64_t imm)
3531         : Base(opcode, type, pc), ImmediateMixin(imm)
3532     {
3533     }
3534 
GetPointer()3535     Inst *GetPointer()
3536     {
3537         return GetInput(0).GetInst();
3538     }
3539 
GetInputType(size_t index)3540     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
3541     {
3542         ASSERT(index == 0);
3543         auto input_0_type = GetInput(0).GetInst()->GetType();
3544         ASSERT(input_0_type == DataType::POINTER || input_0_type == DataType::REFERENCE);
3545         return input_0_type;
3546     }
3547 
IsBarrier()3548     bool IsBarrier() const override
3549     {
3550         return Inst::IsBarrier() || GetNeedBarrier();
3551     }
3552 
3553     bool DumpInputs(std::ostream * /* out */) const override;
3554 
Clone(const Graph * targetGraph)3555     Inst *Clone(const Graph *targetGraph) const override
3556     {
3557         auto clone = static_cast<LoadInstI *>(FixedInputsInst::Clone(targetGraph));
3558         clone->SetImm(GetImm());
3559         clone->SetVolatile(GetVolatile());
3560         return clone;
3561     }
3562 
Latency()3563     uint32_t Latency() const override
3564     {
3565         return options.GetCompilerSchedLatencyLong();
3566     }
3567 };
3568 
3569 /**
3570  * Store value into array element, using array index as immediate
3571  */
3572 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
3573 class StoreInstI : public VolatileMixin<NeedBarrierMixin<FixedInputsInst2>>, public ImmediateMixin {
3574 public:
3575     DECLARE_INST(StoreInstI);
3576     using Base = VolatileMixin<NeedBarrierMixin<FixedInputsInst2>>;
3577     using Base::Base;
3578 
StoreInstI(Opcode opcode,uint64_t imm)3579     StoreInstI(Opcode opcode, uint64_t imm) : Base(opcode), ImmediateMixin(imm) {}
StoreInstI(Opcode opcode,DataType::Type type,uint32_t pc,uint64_t imm)3580     StoreInstI(Opcode opcode, DataType::Type type, uint32_t pc, uint64_t imm)
3581         : Base(opcode, type, pc), ImmediateMixin(imm)
3582     {
3583     }
3584 
IsBarrier()3585     bool IsBarrier() const override
3586     {
3587         return Inst::IsBarrier() || GetNeedBarrier();
3588     }
3589 
GetArray()3590     Inst *GetArray()
3591     {
3592         return GetInput(0).GetInst();
3593     }
GetStoredValue()3594     Inst *GetStoredValue()
3595     {
3596         return GetInput(1).GetInst();
3597     }
GetInputType(size_t index)3598     DataType::Type GetInputType(size_t index) const override
3599     {
3600         ASSERT(index < GetInputsCount());
3601         switch (index) {
3602             case 0:
3603                 return DataType::REFERENCE;
3604             case 1:
3605                 return GetType();
3606             default:
3607                 UNREACHABLE();
3608         }
3609     }
3610 
3611     bool DumpInputs(std::ostream * /* out */) const override;
3612 
Clone(const Graph * targetGraph)3613     Inst *Clone(const Graph *targetGraph) const override
3614     {
3615         auto clone = static_cast<StoreInstI *>(FixedInputsInst::Clone(targetGraph));
3616         clone->SetImm(GetImm());
3617         clone->SetVolatile(GetVolatile());
3618         return clone;
3619     }
3620 
3621     // StoreArrayI call barriers twice,so we need to save input register for second call
IsPropagateLiveness()3622     bool IsPropagateLiveness() const override
3623     {
3624         return GetType() == DataType::REFERENCE;
3625     }
3626 };
3627 
3628 /**
3629  * Store value into pointer by offset
3630  */
3631 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
3632 class StoreMemInstI : public VolatileMixin<NeedBarrierMixin<FixedInputsInst2>>, public ImmediateMixin {
3633 public:
3634     DECLARE_INST(StoreMemInstI);
3635     using Base = VolatileMixin<NeedBarrierMixin<FixedInputsInst2>>;
3636     using Base::Base;
3637 
StoreMemInstI(Opcode opcode,uint64_t imm)3638     StoreMemInstI(Opcode opcode, uint64_t imm) : Base(opcode), ImmediateMixin(imm) {}
StoreMemInstI(Opcode opcode,DataType::Type type,uint32_t pc,uint64_t imm)3639     StoreMemInstI(Opcode opcode, DataType::Type type, uint32_t pc, uint64_t imm)
3640         : Base(opcode, type, pc), ImmediateMixin(imm)
3641     {
3642     }
3643 
IsBarrier()3644     bool IsBarrier() const override
3645     {
3646         return Inst::IsBarrier() || GetNeedBarrier();
3647     }
3648 
GetPointer()3649     Inst *GetPointer()
3650     {
3651         return GetInput(0).GetInst();
3652     }
GetStoredValue()3653     Inst *GetStoredValue()
3654     {
3655         return GetInput(1).GetInst();
3656     }
GetInputType(size_t index)3657     DataType::Type GetInputType(size_t index) const override
3658     {
3659         ASSERT(index < GetInputsCount());
3660         switch (index) {
3661             case 0: {
3662                 auto input_0_type = GetInput(0).GetInst()->GetType();
3663                 ASSERT(input_0_type == DataType::POINTER || input_0_type == DataType::REFERENCE);
3664                 return input_0_type;
3665             }
3666             case 1:
3667                 return GetType();
3668             default:
3669                 UNREACHABLE();
3670         }
3671     }
3672 
3673     bool DumpInputs(std::ostream * /* out */) const override;
3674 
Clone(const Graph * targetGraph)3675     Inst *Clone(const Graph *targetGraph) const override
3676     {
3677         auto clone = static_cast<StoreInstI *>(FixedInputsInst::Clone(targetGraph));
3678         clone->SetImm(GetImm());
3679         clone->SetVolatile(GetVolatile());
3680         return clone;
3681     }
3682 };
3683 
3684 /**
3685  * Bounds check, using array index as immediate
3686  */
3687 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
3688 class BoundsCheckInstI : public ArrayInstMixin<FixedInputsInst<2U>>, public ImmediateMixin {
3689 public:
3690     DECLARE_INST(BoundsCheckInstI);
3691     using Base = ArrayInstMixin<FixedInputsInst<2U>>;
3692     using Base::Base;
3693 
Base(opcode)3694     BoundsCheckInstI(Opcode opcode, uint64_t imm, bool is_array = true) : Base(opcode), ImmediateMixin(imm)
3695     {
3696         SetIsArray(is_array);
3697     }
3698 
3699     BoundsCheckInstI(Opcode opcode, DataType::Type type, uint32_t pc, uint64_t imm, bool is_array = true)
Base(opcode,type,pc)3700         : Base(opcode, type, pc), ImmediateMixin(imm)
3701     {
3702         SetIsArray(is_array);
3703     }
3704 
3705     bool DumpInputs(std::ostream * /* out */) const override;
3706 
Clone(const Graph * targetGraph)3707     Inst *Clone(const Graph *targetGraph) const override
3708     {
3709         auto clone = FixedInputsInst::Clone(targetGraph);
3710         clone->CastToBoundsCheckI()->SetImm(GetImm());
3711         clone->CastToBoundsCheckI()->SetIsArray(IsArray());
3712         return clone;
3713     }
3714 };
3715 
3716 /**
3717  * Bounds check instruction
3718  */
3719 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
3720 class BoundsCheckInst : public ArrayInstMixin<FixedInputsInst<3U>> {
3721 public:
3722     DECLARE_INST(BoundsCheckInst);
3723     using Base = ArrayInstMixin<FixedInputsInst<3U>>;
3724     using Base::Base;
3725 
Base(opcode)3726     explicit BoundsCheckInst(Opcode opcode, bool is_array = true) : Base(opcode)
3727     {
3728         SetIsArray(is_array);
3729     }
3730 
Base(opcode,type,pc)3731     BoundsCheckInst(Opcode opcode, DataType::Type type, uint32_t pc, bool is_array = true) : Base(opcode, type, pc)
3732     {
3733         SetIsArray(is_array);
3734     }
3735 
Clone(const Graph * targetGraph)3736     Inst *Clone(const Graph *targetGraph) const override
3737     {
3738         auto clone = FixedInputsInst::Clone(targetGraph);
3739         clone->CastToBoundsCheck()->SetIsArray(IsArray());
3740         return clone;
3741     }
3742 };
3743 
3744 class NullCheckInst : public FixedInputsInst2 {
3745 public:
3746     DECLARE_INST(NullCheckInst);
3747     using Base = FixedInputsInst2;
3748     using Base::Base;
3749 
IsImplicit()3750     bool IsImplicit() const
3751     {
3752         return GetField<IsImplicitFlag>();
3753     }
3754 
3755     void SetImplicit(bool is_implicit = true)
3756     {
3757         SetField<IsImplicitFlag>(is_implicit);
3758     }
3759 
3760 private:
3761     using IsImplicitFlag = LastField::NextFlag;
3762     using LastField = IsImplicitFlag;
3763 };
3764 
3765 /**
3766  * Return immediate
3767  */
3768 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
3769 class ReturnInstI : public FixedInputsInst<0>, public ImmediateMixin {
3770 public:
3771     DECLARE_INST(ReturnInstI);
3772     using FixedInputsInst::FixedInputsInst;
3773 
ReturnInstI(Opcode opcode,uint64_t imm)3774     ReturnInstI(Opcode opcode, uint64_t imm) : FixedInputsInst(opcode), ImmediateMixin(imm) {}
ReturnInstI(Opcode opcode,DataType::Type type,uint32_t pc,uint64_t imm)3775     ReturnInstI(Opcode opcode, DataType::Type type, uint32_t pc, uint64_t imm)
3776         : FixedInputsInst(opcode, type, pc), ImmediateMixin(imm)
3777     {
3778     }
3779 
3780     bool DumpInputs(std::ostream * /* out */) const override;
3781 
Clone(const Graph * targetGraph)3782     Inst *Clone(const Graph *targetGraph) const override
3783     {
3784         auto clone = FixedInputsInst::Clone(targetGraph);
3785         clone->CastToReturnI()->SetImm(GetImm());
3786         return clone;
3787     }
3788 };
3789 
3790 class ReturnInlinedInst : public FixedInputsInst<1> {
3791 public:
3792     DECLARE_INST(ReturnInlinedInst);
3793     using FixedInputsInst::FixedInputsInst;
3794 
IsExtendedLiveness()3795     bool IsExtendedLiveness() const
3796     {
3797         return GetField<IsExtendedLivenessFlag>();
3798     }
3799 
3800     void SetExtendedLiveness(bool is_extened_liveness = true)
3801     {
3802         SetField<IsExtendedLivenessFlag>(is_extened_liveness);
3803     }
3804 
3805 private:
3806     using IsExtendedLivenessFlag = LastField::NextFlag;
3807     using LastField = IsExtendedLivenessFlag;
3808 };
3809 
3810 /**
3811  * Monitor instruction
3812  */
3813 class MonitorInst : public FixedInputsInst2 {
3814 public:
3815     DECLARE_INST(MonitorInst);
3816     using Base = FixedInputsInst2;
3817     using Base::Base;
3818 
IsExit()3819     bool IsExit() const
3820     {
3821         return GetField<Exit>();
3822     }
3823 
IsEntry()3824     bool IsEntry() const
3825     {
3826         return !GetField<Exit>();
3827     }
3828 
SetExit()3829     void SetExit()
3830     {
3831         SetField<Exit>(true);
3832     }
3833 
SetEntry()3834     void SetEntry()
3835     {
3836         SetField<Exit>(false);
3837     }
3838 
GetInputType(size_t index)3839     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
3840     {
3841         return DataType::REFERENCE;
3842     }
3843 
3844     void DumpOpcode(std::ostream * /* unused */) const override;
3845 
3846 protected:
3847     using Exit = LastField::NextFlag;
3848     using LastField = Exit;
3849 };
3850 
3851 #include "intrinsics_flags.inl"
3852 
3853 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
3854 class IntrinsicInst : public InlinedInstMixin<DynamicInputsInst>, public InputTypesMixin {
3855 public:
3856     DECLARE_INST(IntrinsicInst);
3857     using Base = InlinedInstMixin<DynamicInputsInst>;
3858     using Base::Base;
3859     using IntrinsicId = RuntimeInterface::IntrinsicId;
3860 
IntrinsicInst(Opcode opcode,IntrinsicId intrinsic_id)3861     IntrinsicInst(Opcode opcode, IntrinsicId intrinsic_id) : Base(opcode), intrinsic_id_(intrinsic_id)
3862     {
3863         AdjustFlags(intrinsic_id, this);
3864     }
3865 
IntrinsicInst(Opcode opcode,DataType::Type type,uint32_t pc,IntrinsicId intrinsic_id)3866     IntrinsicInst(Opcode opcode, DataType::Type type, uint32_t pc, IntrinsicId intrinsic_id)
3867         : Base(opcode, type, pc), intrinsic_id_(intrinsic_id)
3868     {
3869         AdjustFlags(intrinsic_id, this);
3870     }
3871 
GetIntrinsicId()3872     IntrinsicId GetIntrinsicId() const
3873     {
3874         return intrinsic_id_;
3875     }
3876 
SetIntrinsicId(IntrinsicId intrinsic_id)3877     void SetIntrinsicId(IntrinsicId intrinsic_id)
3878     {
3879         intrinsic_id_ = intrinsic_id;
3880     }
3881 
GetInputType(size_t index)3882     DataType::Type GetInputType(size_t index) const override
3883     {
3884         ASSERT(input_types_ != nullptr);
3885         ASSERT(index < input_types_->size());
3886         ASSERT(index < GetInputsCount());
3887         return (*input_types_)[index];
3888     }
3889 
GetImms()3890     const ArenaVector<uint32_t> &GetImms()
3891     {
3892         return *imms_;
3893     }
3894 
GetImms()3895     const ArenaVector<uint32_t> &GetImms() const
3896     {
3897         return *imms_;
3898     }
3899 
HasImms()3900     bool HasImms() const
3901     {
3902         return imms_ != nullptr;
3903     }
3904 
AddImm(ArenaAllocator * allocator,uint32_t imm)3905     void AddImm(ArenaAllocator *allocator, uint32_t imm)
3906     {
3907         if (imms_ == nullptr) {
3908             imms_ = allocator->New<ArenaVector<uint32_t>>(allocator->Adapter());
3909         }
3910         imms_->push_back(imm);
3911     }
3912 
3913     bool IsNativeCall() const;
3914 
HasArgumentsOnStack()3915     bool HasArgumentsOnStack() const
3916     {
3917         return GetField<ArgumentsOnStack>();
3918     }
3919 
SetArgumentsOnStack()3920     void SetArgumentsOnStack()
3921     {
3922         SetField<ArgumentsOnStack>(true);
3923     }
3924 
3925     Inst *Clone(const Graph *targetGraph) const override;
3926 
CanBeInlined()3927     bool CanBeInlined()
3928     {
3929         return IsInlined();
3930     }
3931 
SetRelocate()3932     void SetRelocate()
3933     {
3934         SetField<Relocate>(true);
3935     }
3936 
GetRelocate()3937     bool GetRelocate() const
3938     {
3939         return GetField<Relocate>();
3940     }
3941 
3942     void DumpOpcode(std::ostream *out) const override;
3943 
3944 protected:
3945     using ArgumentsOnStack = LastField::NextFlag;
3946     using Relocate = ArgumentsOnStack::NextFlag;
3947     using LastField = Relocate;
3948 
3949 private:
3950     IntrinsicId intrinsic_id_ {RuntimeInterface::IntrinsicId::COUNT};
3951     ArenaVector<uint32_t> *imms_ {nullptr};  // record imms appeared in intrinsics
3952 };
3953 
3954 #include <get_intrinsics_names.inl>
3955 #include <intrinsics_enum.inl>
3956 #include <can_encode_builtin.inl>
3957 
3958 /**
3959  *  Cast instruction
3960  */
3961 class CastInst : public InstWithOperandsType<FixedInputsInst1> {
3962 public:
3963     DECLARE_INST(CastInst);
3964     using BaseInst = InstWithOperandsType<FixedInputsInst1>;
3965     using BaseInst::BaseInst;
3966 
GetInputType(size_t index)3967     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
3968     {
3969         ASSERT(index == 0);
3970         return GetOperandsType();
3971     }
3972 
3973     void SetVnObject(VnObject *vn_obj) override;
3974 
3975     void DumpOpcode(std::ostream * /* out */) const override;
3976 
Clone(const Graph * targetGraph)3977     Inst *Clone(const Graph *targetGraph) const override
3978     {
3979         auto clone = FixedInputsInst::Clone(targetGraph);
3980         clone->CastToCast()->SetOperandsType(GetOperandsType());
3981         return clone;
3982     }
3983 };
3984 
3985 /**
3986  * Cmp instruction
3987  */
3988 class CmpInst : public InstWithOperandsType<FixedInputsInst2> {
3989 public:
3990     DECLARE_INST(CmpInst);
3991     using BaseInst = InstWithOperandsType<FixedInputsInst2>;
3992     using BaseInst::BaseInst;
3993 
IsFcmpg()3994     bool IsFcmpg() const
3995     {
3996         ASSERT(DataType::IsFloatType(GetOperandsType()));
3997         return GetField<Fcmpg>();
3998     }
IsFcmpl()3999     bool IsFcmpl() const
4000     {
4001         ASSERT(DataType::IsFloatType(GetOperandsType()));
4002         return !GetField<Fcmpg>();
4003     }
SetFcmpg()4004     void SetFcmpg()
4005     {
4006         ASSERT(DataType::IsFloatType(GetOperandsType()));
4007         SetField<Fcmpg>(true);
4008     }
SetFcmpg(bool v)4009     void SetFcmpg(bool v)
4010     {
4011         ASSERT(DataType::IsFloatType(GetOperandsType()));
4012         SetField<Fcmpg>(v);
4013     }
SetFcmpl()4014     void SetFcmpl()
4015     {
4016         ASSERT(DataType::IsFloatType(GetOperandsType()));
4017         SetField<Fcmpg>(false);
4018     }
SetFcmpl(bool v)4019     void SetFcmpl(bool v)
4020     {
4021         ASSERT(DataType::IsFloatType(GetOperandsType()));
4022         SetField<Fcmpg>(!v);
4023     }
4024 
GetInputType(size_t index)4025     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
4026     {
4027         ASSERT(index < GetInputsCount());
4028         return GetOperandsType();
4029     }
4030 
4031     void SetVnObject(VnObject *vn_obj) override;
4032 
4033     void DumpOpcode(std::ostream * /* out */) const override;
4034 
Clone(const Graph * targetGraph)4035     Inst *Clone(const Graph *targetGraph) const override
4036     {
4037         auto clone = FixedInputsInst::Clone(targetGraph);
4038         clone->CastToCmp()->SetOperandsType(GetOperandsType());
4039         return clone;
4040     }
4041 
4042 protected:
4043     using Fcmpg = LastField::NextFlag;
4044     using LastField = Fcmpg;
4045 };
4046 
4047 /**
4048  * Load value from instance field
4049  */
4050 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4051 class LoadObjectInst : public VolatileMixin<NeedBarrierMixin<FixedInputsInst1>>, public TypeIdMixin, public FieldMixin {
4052 public:
4053     DECLARE_INST(LoadObjectInst);
4054     using Base = VolatileMixin<NeedBarrierMixin<FixedInputsInst1>>;
4055     using Base::Base;
4056 
GetInputType(size_t index)4057     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
4058     {
4059         ASSERT(index < GetInputsCount());
4060         ASSERT(GetInputsCount() == 1);
4061         return DataType::REFERENCE;
4062     }
4063 
IsBarrier()4064     bool IsBarrier() const override
4065     {
4066         return Inst::IsBarrier() || GetNeedBarrier() || GetVolatile();
4067     }
4068 
4069     void DumpOpcode(std::ostream *out) const override;
4070 
Clone(const Graph * targetGraph)4071     Inst *Clone(const Graph *targetGraph) const override
4072     {
4073         auto clone = FixedInputsInst::Clone(targetGraph);
4074         clone->CastToLoadObject()->SetTypeId(GetTypeId());
4075         clone->CastToLoadObject()->SetMethod(GetMethod());
4076         clone->CastToLoadObject()->SetObjField(GetObjField());
4077         clone->CastToLoadObject()->SetVolatile(GetVolatile());
4078         return clone;
4079     }
4080 
Latency()4081     uint32_t Latency() const override
4082     {
4083         return options.GetCompilerSchedLatencyLong();
4084     }
4085 };
4086 
4087 /**
4088  * Load value from memory by offset
4089  */
4090 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4091 class LoadMemInst : public ScaleMixin<VolatileMixin<NeedBarrierMixin<FixedInputsInst2>>> {
4092 public:
4093     DECLARE_INST(LoadMemInst);
4094     using Base = ScaleMixin<VolatileMixin<NeedBarrierMixin<FixedInputsInst2>>>;
4095     using Base::Base;
4096 
GetInputType(size_t index)4097     DataType::Type GetInputType(size_t index) const override
4098     {
4099         ASSERT(index < GetInputsCount());
4100         ASSERT(GetInputsCount() == 2U);
4101         if (index == 1U) {
4102             return DataType::UINT32;
4103         }
4104 
4105         ASSERT(index == 0U);
4106         auto input_0_type = GetInput(0).GetInst()->GetType();
4107         ASSERT(input_0_type == DataType::POINTER || input_0_type == DataType::REFERENCE);
4108         return input_0_type;
4109     }
4110 
IsBarrier()4111     bool IsBarrier() const override
4112     {
4113         return Inst::IsBarrier() || GetNeedBarrier() || GetVolatile();
4114     }
4115 
4116     void DumpOpcode(std::ostream *out) const override;
4117     bool DumpInputs(std::ostream * /* unused */) const override;
4118 
Clone(const Graph * targetGraph)4119     Inst *Clone(const Graph *targetGraph) const override
4120     {
4121         auto clone = FixedInputsInst::Clone(targetGraph);
4122         clone->CastToLoad()->SetVolatile(GetVolatile());
4123         clone->CastToLoad()->SetScale(GetScale());
4124         return clone;
4125     }
4126 
Latency()4127     uint32_t Latency() const override
4128     {
4129         return options.GetCompilerSchedLatencyLong();
4130     }
4131 };
4132 
4133 /**
4134  * Load value from unresolved instance field
4135  */
4136 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4137 class UnresolvedLoadObjectInst : public NeedBarrierMixin<FixedInputsInst2>, public TypeIdMixin {
4138 public:
4139     DECLARE_INST(UnresolvedLoadObjectInst);
4140     using Base = NeedBarrierMixin<FixedInputsInst2>;
4141     using Base::Base;
4142 
GetInputType(size_t index)4143     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
4144     {
4145         ASSERT(index < GetInputsCount());
4146         ASSERT(GetInputsCount() == 2U);
4147         if (index == 1) {
4148             // This is SaveState input
4149             return DataType::NO_TYPE;
4150         }
4151         ASSERT(index == 0);
4152         return DataType::REFERENCE;
4153     }
4154 
IsBarrier()4155     bool IsBarrier() const override
4156     {
4157         return true;
4158     }
4159 
4160     void DumpOpcode(std::ostream *out) const override;
4161 
Clone(const Graph * targetGraph)4162     Inst *Clone(const Graph *targetGraph) const override
4163     {
4164         auto clone = FixedInputsInst::Clone(targetGraph);
4165         clone->CastToUnresolvedLoadObject()->SetTypeId(GetTypeId());
4166         clone->CastToUnresolvedLoadObject()->SetMethod(GetMethod());
4167         return clone;
4168     }
4169 
Latency()4170     uint32_t Latency() const override
4171     {
4172         return options.GetCompilerSchedLatencyLong();
4173     }
4174 };
4175 
4176 /**
4177  * Store value into instance field
4178  */
4179 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4180 class StoreObjectInst : public VolatileMixin<NeedBarrierMixin<FixedInputsInst2>>,
4181                         public TypeIdMixin,
4182                         public FieldMixin {
4183 public:
4184     DECLARE_INST(StoreObjectInst);
4185     using Base = VolatileMixin<NeedBarrierMixin<FixedInputsInst2>>;
4186     using Base::Base;
4187     static constexpr size_t STORED_INPUT_INDEX = 1;
4188 
IsBarrier()4189     bool IsBarrier() const override
4190     {
4191         return Inst::IsBarrier() || GetNeedBarrier() || GetVolatile();
4192     }
4193 
GetInputType(size_t index)4194     DataType::Type GetInputType(size_t index) const override
4195     {
4196         ASSERT(index < GetInputsCount());
4197         ASSERT(GetInputsCount() == 2U);
4198         return index == 0 ? DataType::REFERENCE : GetType();
4199     }
4200 
4201     void DumpOpcode(std::ostream *out) const override;
4202 
Clone(const Graph * targetGraph)4203     Inst *Clone(const Graph *targetGraph) const override
4204     {
4205         auto clone = FixedInputsInst::Clone(targetGraph);
4206         clone->CastToStoreObject()->SetTypeId(GetTypeId());
4207         clone->CastToStoreObject()->SetMethod(GetMethod());
4208         clone->CastToStoreObject()->SetObjField(GetObjField());
4209         clone->CastToStoreObject()->SetVolatile(GetVolatile());
4210         return clone;
4211     }
4212 
4213     // StoreObject call barriers twice,so we need to save input register for second call
IsPropagateLiveness()4214     bool IsPropagateLiveness() const override
4215     {
4216         return GetType() == DataType::REFERENCE;
4217     }
4218 };
4219 
4220 /**
4221  * Store value into unresolved instance field
4222  */
4223 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4224 class UnresolvedStoreObjectInst : public NeedBarrierMixin<FixedInputsInst3>, public TypeIdMixin {
4225 public:
4226     DECLARE_INST(UnresolvedStoreObjectInst);
4227     using Base = NeedBarrierMixin<FixedInputsInst3>;
4228     using Base::Base;
4229 
IsBarrier()4230     bool IsBarrier() const override
4231     {
4232         return true;
4233     }
4234 
GetInputType(size_t index)4235     DataType::Type GetInputType(size_t index) const override
4236     {
4237         ASSERT(index < GetInputsCount());
4238         ASSERT(GetInputsCount() == 3U);
4239         if (index == 2U) {
4240             // This is SaveState input
4241             return DataType::NO_TYPE;
4242         }
4243         return index == 0 ? DataType::REFERENCE : GetType();
4244     }
4245 
4246     void DumpOpcode(std::ostream *out) const override;
4247 
Clone(const Graph * targetGraph)4248     Inst *Clone(const Graph *targetGraph) const override
4249     {
4250         auto clone = FixedInputsInst::Clone(targetGraph);
4251         clone->CastToUnresolvedStoreObject()->SetTypeId(GetTypeId());
4252         clone->CastToUnresolvedStoreObject()->SetMethod(GetMethod());
4253         return clone;
4254     }
4255 };
4256 
4257 /**
4258  * Store value in memory by offset
4259  */
4260 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4261 class StoreMemInst : public ScaleMixin<VolatileMixin<NeedBarrierMixin<FixedInputsInst3>>> {
4262 public:
4263     DECLARE_INST(StoreMemInst);
4264     using Base = ScaleMixin<VolatileMixin<NeedBarrierMixin<FixedInputsInst3>>>;
4265     using Base::Base;
4266 
4267     static constexpr size_t STORED_INPUT_INDEX = 2;
4268 
IsBarrier()4269     bool IsBarrier() const override
4270     {
4271         return Inst::IsBarrier() || GetNeedBarrier() || GetVolatile();
4272     }
4273 
GetInputType(size_t index)4274     DataType::Type GetInputType(size_t index) const override
4275     {
4276         ASSERT(index < GetInputsCount());
4277         ASSERT(GetInputsCount() == 3U);
4278         if (index == 1U) {
4279             return DataType::UINT32;
4280         }
4281         if (index == 2U) {
4282             return GetType();
4283         }
4284 
4285         ASSERT(index == 0U);
4286         auto input_0_type = GetInput(0).GetInst()->GetType();
4287         ASSERT(input_0_type == DataType::POINTER || input_0_type == DataType::REFERENCE);
4288         return input_0_type;
4289     }
4290 
4291     void DumpOpcode(std::ostream *out) const override;
4292     bool DumpInputs(std::ostream * /* unused */) const override;
4293 
Clone(const Graph * targetGraph)4294     Inst *Clone(const Graph *targetGraph) const override
4295     {
4296         auto clone = FixedInputsInst::Clone(targetGraph);
4297         clone->CastToStore()->SetVolatile(GetVolatile());
4298         clone->CastToStore()->SetScale(GetScale());
4299         return clone;
4300     }
4301 };
4302 
4303 /**
4304  * Load static field from class.
4305  */
4306 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4307 class LoadStaticInst : public VolatileMixin<NeedBarrierMixin<FixedInputsInst1>>, public TypeIdMixin, public FieldMixin {
4308 public:
4309     DECLARE_INST(LoadStaticInst);
4310     using Base = VolatileMixin<NeedBarrierMixin<FixedInputsInst1>>;
4311     using Base::Base;
4312 
IsBarrier()4313     bool IsBarrier() const override
4314     {
4315         return Inst::IsBarrier() || GetNeedBarrier() || GetVolatile();
4316     }
4317 
4318     void DumpOpcode(std::ostream *out) const override;
4319 
GetInputType(size_t index)4320     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
4321     {
4322         ASSERT(index < GetInputsCount());
4323         ASSERT(index == 0);
4324         return DataType::REFERENCE;
4325     }
4326 
Clone(const Graph * targetGraph)4327     Inst *Clone(const Graph *targetGraph) const override
4328     {
4329         auto clone = FixedInputsInst::Clone(targetGraph);
4330         clone->CastToLoadStatic()->SetTypeId(GetTypeId());
4331         clone->CastToLoadStatic()->SetMethod(GetMethod());
4332         clone->CastToLoadStatic()->SetObjField(GetObjField());
4333         clone->CastToLoadStatic()->SetVolatile(GetVolatile());
4334         return clone;
4335     }
4336 
Latency()4337     uint32_t Latency() const override
4338     {
4339         return options.GetCompilerSchedLatencyLong();
4340     }
4341 };
4342 
4343 /**
4344  * Load unresolved static field from class.
4345  */
4346 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4347 class UnresolvedLoadStaticInst : public NeedBarrierMixin<FixedInputsInst1>, public TypeIdMixin {
4348 public:
4349     DECLARE_INST(UnresolvedLoadStaticInst);
4350     using Base = NeedBarrierMixin<FixedInputsInst1>;
4351     using Base::Base;
4352 
IsBarrier()4353     bool IsBarrier() const override
4354     {
4355         return true;
4356     }
4357 
4358     void DumpOpcode(std::ostream *out) const override;
4359 
GetInputType(size_t index)4360     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
4361     {
4362         ASSERT(index < GetInputsCount());
4363         // This is SaveState input
4364         return DataType::NO_TYPE;
4365     }
4366 
Clone(const Graph * targetGraph)4367     Inst *Clone(const Graph *targetGraph) const override
4368     {
4369         auto clone = FixedInputsInst::Clone(targetGraph);
4370         clone->CastToUnresolvedLoadStatic()->SetTypeId(GetTypeId());
4371         clone->CastToUnresolvedLoadStatic()->SetMethod(GetMethod());
4372         return clone;
4373     }
4374 
Latency()4375     uint32_t Latency() const override
4376     {
4377         return options.GetCompilerSchedLatencyLong();
4378     }
4379 };
4380 
4381 /**
4382  * Store value into static field.
4383  */
4384 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4385 class StoreStaticInst : public VolatileMixin<NeedBarrierMixin<FixedInputsInst2>>,
4386                         public TypeIdMixin,
4387                         public FieldMixin {
4388 public:
4389     DECLARE_INST(StoreStaticInst);
4390     using Base = VolatileMixin<NeedBarrierMixin<FixedInputsInst2>>;
4391     using Base::Base;
4392     static constexpr size_t STORED_INPUT_INDEX = 1;
4393 
IsBarrier()4394     bool IsBarrier() const override
4395     {
4396         return Inst::IsBarrier() || GetNeedBarrier() || GetVolatile();
4397     }
4398 
4399     void DumpOpcode(std::ostream *out) const override;
4400 
GetInputType(size_t index)4401     DataType::Type GetInputType(size_t index) const override
4402     {
4403         ASSERT(index < GetInputsCount());
4404         if (index == 0) {
4405             return DataType::REFERENCE;
4406         }
4407         return GetType();
4408     }
4409 
Clone(const Graph * targetGraph)4410     Inst *Clone(const Graph *targetGraph) const override
4411     {
4412         auto clone = FixedInputsInst::Clone(targetGraph);
4413         clone->CastToStoreStatic()->SetTypeId(GetTypeId());
4414         clone->CastToStoreStatic()->SetMethod(GetMethod());
4415         clone->CastToStoreStatic()->SetObjField(GetObjField());
4416         clone->CastToStoreStatic()->SetVolatile(GetVolatile());
4417         return clone;
4418     }
4419 
4420     // StoreStatic call barriers twice,so we need to save input register for second call
IsPropagateLiveness()4421     bool IsPropagateLiveness() const override
4422     {
4423         return GetType() == DataType::REFERENCE;
4424     }
4425 };
4426 
4427 /**
4428  * Store value into unresolved static field.
4429  */
4430 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4431 class UnresolvedStoreStaticInst : public NeedBarrierMixin<FixedInputsInst2>, public TypeIdMixin {
4432 public:
4433     DECLARE_INST(UnresolvedStoreStaticInst);
4434     using Base = NeedBarrierMixin<FixedInputsInst2>;
4435     using Base::Base;
4436 
IsBarrier()4437     bool IsBarrier() const override
4438     {
4439         return true;
4440     }
4441 
4442     void DumpOpcode(std::ostream *out) const override;
4443 
GetInputType(size_t index)4444     DataType::Type GetInputType(size_t index) const override
4445     {
4446         ASSERT(index < GetInputsCount());
4447         if (index == 1) {
4448             // This is SaveState input
4449             return DataType::NO_TYPE;
4450         }
4451         ASSERT(index == 0);
4452         return GetType();
4453     }
4454 
Clone(const Graph * targetGraph)4455     Inst *Clone(const Graph *targetGraph) const override
4456     {
4457         auto clone = FixedInputsInst::Clone(targetGraph);
4458         clone->CastToUnresolvedStoreStatic()->SetTypeId(GetTypeId());
4459         clone->CastToUnresolvedStoreStatic()->SetMethod(GetMethod());
4460         return clone;
4461     }
4462 };
4463 
4464 /**
4465  * Create new object
4466  */
4467 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4468 class NewObjectInst : public NeedBarrierMixin<FixedInputsInst2>, public TypeIdMixin {
4469 public:
4470     DECLARE_INST(NewObjectInst);
4471     using Base = NeedBarrierMixin<FixedInputsInst2>;
4472     using Base::Base;
4473 
IsBarrier()4474     bool IsBarrier() const override
4475     {
4476         return Inst::IsBarrier() || GetNeedBarrier();
4477     }
GetInputType(size_t index)4478     DataType::Type GetInputType(size_t index) const override
4479     {
4480         ASSERT(index < GetInputsCount());
4481         if (index == 0) {
4482             return DataType::REFERENCE;
4483         }
4484         return DataType::NO_TYPE;
4485     }
4486 
4487     void DumpOpcode(std::ostream *out) const override;
4488 
Clone(const Graph * targetGraph)4489     Inst *Clone(const Graph *targetGraph) const override
4490     {
4491         auto clone = FixedInputsInst::Clone(targetGraph);
4492         clone->CastToNewObject()->SetTypeId(GetTypeId());
4493         clone->CastToNewObject()->SetMethod(GetMethod());
4494         return clone;
4495     }
4496 };
4497 
4498 /**
4499  * Create new array
4500  */
4501 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4502 class NewArrayInst : public NeedBarrierMixin<FixedInputsInst3>, public TypeIdMixin {
4503 public:
4504     DECLARE_INST(NewArrayInst);
4505     using Base = NeedBarrierMixin<FixedInputsInst3>;
4506     using Base::Base;
4507 
4508     static constexpr size_t INDEX_CLASS = 0;
4509     static constexpr size_t INDEX_SIZE = 1;
4510     static constexpr size_t INDEX_SAVE_STATE = 2;
4511 
IsBarrier()4512     bool IsBarrier() const override
4513     {
4514         return Inst::IsBarrier() || GetNeedBarrier();
4515     }
4516 
GetInputType(size_t index)4517     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
4518     {
4519         ASSERT(index < GetInputsCount());
4520         switch (index) {
4521             case INDEX_CLASS:
4522                 return GetInput(0).GetInst()->GetType();
4523             case INDEX_SIZE:
4524                 return DataType::INT32;
4525             case INDEX_SAVE_STATE:
4526                 // This is SaveState input
4527                 return DataType::NO_TYPE;
4528             default:
4529                 UNREACHABLE();
4530         }
4531     }
4532 
4533     void DumpOpcode(std::ostream *out) const override;
4534 
Clone(const Graph * targetGraph)4535     Inst *Clone(const Graph *targetGraph) const override
4536     {
4537         auto clone = FixedInputsInst::Clone(targetGraph);
4538         clone->CastToNewArray()->SetTypeId(GetTypeId());
4539         clone->CastToNewArray()->SetMethod(GetMethod());
4540         return clone;
4541     }
4542 };
4543 
4544 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4545 class LoadConstArrayInst : public NeedBarrierMixin<FixedInputsInst1>, public TypeIdMixin {
4546 public:
4547     DECLARE_INST(LoadConstArrayInst);
4548     using Base = NeedBarrierMixin<FixedInputsInst1>;
4549     using Base::Base;
4550 
IsBarrier()4551     bool IsBarrier() const override
4552     {
4553         return Inst::IsBarrier() || GetNeedBarrier();
4554     }
4555 
GetInputType(size_t index)4556     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
4557     {
4558         ASSERT(index < GetInputsCount());
4559         return DataType::NO_TYPE;
4560     }
4561 
4562     void DumpOpcode(std::ostream *out) const override;
4563 
Clone(const Graph * targetGraph)4564     Inst *Clone(const Graph *targetGraph) const override
4565     {
4566         auto clone = FixedInputsInst::Clone(targetGraph);
4567         clone->CastToLoadConstArray()->SetTypeId(GetTypeId());
4568         clone->CastToLoadConstArray()->SetMethod(GetMethod());
4569         return clone;
4570     }
4571 };
4572 
4573 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4574 class FillConstArrayInst : public NeedBarrierMixin<FixedInputsInst2>, public TypeIdMixin, public ImmediateMixin {
4575 public:
4576     DECLARE_INST(FillConstArrayInst);
4577     using Base = NeedBarrierMixin<FixedInputsInst2>;
4578     using Base::Base;
4579 
IsBarrier()4580     bool IsBarrier() const override
4581     {
4582         return Inst::IsBarrier() || GetNeedBarrier();
4583     }
4584 
GetInputType(size_t index)4585     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
4586     {
4587         ASSERT(index < GetInputsCount());
4588         return index == 0 ? DataType::REFERENCE : DataType::NO_TYPE;
4589     }
4590 
4591     void DumpOpcode(std::ostream *out) const override;
4592 
Clone(const Graph * targetGraph)4593     Inst *Clone(const Graph *targetGraph) const override
4594     {
4595         auto clone = FixedInputsInst::Clone(targetGraph);
4596         clone->CastToFillConstArray()->SetTypeId(GetTypeId());
4597         clone->CastToFillConstArray()->SetMethod(GetMethod());
4598         clone->CastToFillConstArray()->SetImm(GetImm());
4599         return clone;
4600     }
4601 };
4602 
4603 /**
4604  * Checkcast
4605  */
4606 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4607 class CheckCastInst : public OmitNullCheckMixin<ClassTypeMixin<NeedBarrierMixin<FixedInputsInst3>>>,
4608                       public TypeIdMixin {
4609 public:
4610     DECLARE_INST(CheckCastInst);
4611     using Base = OmitNullCheckMixin<ClassTypeMixin<NeedBarrierMixin<FixedInputsInst3>>>;
4612     using Base::Base;
4613 
IsBarrier()4614     bool IsBarrier() const override
4615     {
4616         return Inst::IsBarrier() || GetNeedBarrier();
4617     }
4618 
GetInputType(size_t index)4619     DataType::Type GetInputType(size_t index) const override
4620     {
4621         ASSERT(index < GetInputsCount());
4622         ASSERT(GetInputsCount() == 3U);
4623         if (index < 2U) {
4624             return DataType::REFERENCE;
4625         }
4626         return DataType::NO_TYPE;
4627     }
4628 
4629     void DumpOpcode(std::ostream *out) const override;
4630 
Clone(const Graph * targetGraph)4631     Inst *Clone(const Graph *targetGraph) const override
4632     {
4633         auto clone = FixedInputsInst::Clone(targetGraph);
4634         clone->CastToCheckCast()->SetTypeId(GetTypeId());
4635         clone->CastToCheckCast()->SetMethod(GetMethod());
4636         clone->CastToCheckCast()->SetClassType(GetClassType());
4637         clone->CastToCheckCast()->SetOmitNullCheck(GetOmitNullCheck());
4638         return clone;
4639     }
4640 };
4641 
4642 /**
4643  * Is instance
4644  */
4645 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4646 class IsInstanceInst : public OmitNullCheckMixin<ClassTypeMixin<NeedBarrierMixin<FixedInputsInst3>>>,
4647                        public TypeIdMixin {
4648 public:
4649     DECLARE_INST(IsInstanceInst);
4650     using Base = OmitNullCheckMixin<ClassTypeMixin<NeedBarrierMixin<FixedInputsInst3>>>;
4651     using Base::Base;
4652 
IsBarrier()4653     bool IsBarrier() const override
4654     {
4655         return Inst::IsBarrier() || GetNeedBarrier();
4656     }
4657 
GetInputType(size_t index)4658     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
4659     {
4660         ASSERT(index < GetInputsCount());
4661         ASSERT(GetInputsCount() == 3U);
4662         if (index < 2U) {
4663             return DataType::REFERENCE;
4664         }
4665         return DataType::NO_TYPE;
4666     }
4667 
4668     void DumpOpcode(std::ostream *out) const override;
4669 
Clone(const Graph * targetGraph)4670     Inst *Clone(const Graph *targetGraph) const override
4671     {
4672         auto clone = FixedInputsInst::Clone(targetGraph);
4673         clone->CastToIsInstance()->SetTypeId(GetTypeId());
4674         clone->CastToIsInstance()->SetMethod(GetMethod());
4675         clone->CastToIsInstance()->SetClassType(GetClassType());
4676         clone->CastToIsInstance()->SetOmitNullCheck(GetOmitNullCheck());
4677         return clone;
4678     }
4679 };
4680 
4681 /**
4682  * Load data from constant pool.
4683  */
4684 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4685 class LoadFromPool : public NeedBarrierMixin<FixedInputsInst1>, public TypeIdMixin {
4686 public:
4687     DECLARE_INST(LoadFromPool);
4688     using Base = NeedBarrierMixin<FixedInputsInst1>;
4689     using Base::Base;
4690 
IsBarrier()4691     bool IsBarrier() const override
4692     {
4693         return Inst::IsBarrier() || GetNeedBarrier();
4694     }
4695 
GetInputType(size_t index)4696     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
4697     {
4698         ASSERT(index < GetInputsCount());
4699         return DataType::NO_TYPE;
4700     }
4701 
4702     void DumpOpcode(std::ostream *out) const override;
4703 
Clone(const Graph * targetGraph)4704     Inst *Clone(const Graph *targetGraph) const override
4705     {
4706         auto clone = FixedInputsInst::Clone(targetGraph);
4707         static_cast<LoadFromPool *>(clone)->SetTypeId(GetTypeId());
4708         static_cast<LoadFromPool *>(clone)->SetMethod(GetMethod());
4709         return clone;
4710     }
4711 };
4712 
4713 /**
4714  * Initialization or loading of the class.
4715  */
4716 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4717 class ClassInst : public NeedBarrierMixin<FixedInputsInst1>, public TypeIdMixin {
4718 public:
4719     DECLARE_INST(ClassInst);
4720     using Base = NeedBarrierMixin<FixedInputsInst1>;
4721     using Base::Base;
4722 
IsBarrier()4723     bool IsBarrier() const override
4724     {
4725         return Inst::IsBarrier() || GetNeedBarrier();
4726     }
4727 
4728     void DumpOpcode(std::ostream *out) const override;
4729 
Clone(const Graph * targetGraph)4730     Inst *Clone(const Graph *targetGraph) const override
4731     {
4732         auto clone = FixedInputsInst::Clone(targetGraph);
4733         static_cast<ClassInst *>(clone)->SetTypeId(GetTypeId());
4734         static_cast<ClassInst *>(clone)->SetMethod(GetMethod());
4735         static_cast<ClassInst *>(clone)->SetClass(GetClass());
4736         return clone;
4737     }
4738 
GetClass()4739     RuntimeInterface::ClassPtr GetClass() const
4740     {
4741         return klass_;
4742     }
4743 
SetClass(RuntimeInterface::ClassPtr klass)4744     void SetClass(RuntimeInterface::ClassPtr klass)
4745     {
4746         klass_ = klass;
4747     }
4748 
4749 private:
4750     RuntimeInterface::ClassPtr klass_ {nullptr};
4751 };
4752 
4753 /**
4754  * Get class pointer from the specific source.
4755  */
4756 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4757 class ClassImmediateInst : public Inst {
4758 public:
4759     DECLARE_INST(ClassImmediateInst);
4760     using Base = Inst;
4761     using Base::Base;
4762 
ClassImmediateInst(Opcode opcode,DataType::Type type,uint32_t pc,RuntimeInterface::ClassPtr cls)4763     ClassImmediateInst(Opcode opcode, DataType::Type type, uint32_t pc, RuntimeInterface::ClassPtr cls)
4764         : Base(opcode, type, pc), class_(cls)
4765     {
4766     }
4767 
Clone(const Graph * targetGraph)4768     Inst *Clone(const Graph *targetGraph) const override
4769     {
4770         auto clone = Inst::Clone(targetGraph);
4771         clone->CastToClassImmediate()->class_ = class_;
4772         return clone;
4773     }
4774 
GetClassPtr()4775     RuntimeInterface::ClassPtr GetClassPtr() const
4776     {
4777         return class_;
4778     }
4779 
4780     void DumpOpcode(std::ostream * /* unused */) const override;
4781 
4782 private:
4783     RuntimeInterface::ClassPtr class_ {nullptr};
4784 };
4785 
4786 /**
4787  * Select instruction
4788  */
4789 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4790 class SelectInst : public ConditionMixin<InstWithOperandsType<FixedInputsInst<4U>>> {
4791 public:
4792     DECLARE_INST(SelectInst);
4793     using Base = ConditionMixin<InstWithOperandsType<FixedInputsInst<4U>>>;
4794     using Base::Base;
4795 
SelectInst(Opcode opcode,DataType::Type type,uint32_t pc,ConditionCode cc)4796     SelectInst(Opcode opcode, DataType::Type type, uint32_t pc, ConditionCode cc) : Base(opcode, type, pc)
4797     {
4798         SetCc(cc);
4799     }
4800 
GetInputType(size_t index)4801     DataType::Type GetInputType(size_t index) const override
4802     {
4803         ASSERT(index < GetInputsCount());
4804         if (index < 2U) {
4805             return GetType();
4806         }
4807         return GetOperandsType();
4808     }
4809 
4810     void DumpOpcode(std::ostream * /* unused */) const override;
4811     void SetVnObject(VnObject *vn_obj) override;
4812 
Clone(const Graph * targetGraph)4813     Inst *Clone(const Graph *targetGraph) const override
4814     {
4815         auto clone = FixedInputsInst::Clone(targetGraph);
4816         clone->CastToSelect()->SetCc(GetCc());
4817         clone->CastToSelect()->SetOperandsType(GetOperandsType());
4818         return clone;
4819     }
4820 };
4821 
4822 /**
4823  * SelectImm with comparison with immediate
4824  */
4825 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4826 class SelectImmInst : public InstWithOperandsType<ConditionMixin<FixedInputsInst3>>, public ImmediateMixin {
4827 public:
4828     DECLARE_INST(SelectImmInst);
4829     using Base = InstWithOperandsType<ConditionMixin<FixedInputsInst3>>;
4830     using Base::Base;
4831 
SelectImmInst(Opcode opcode,DataType::Type type,uint32_t pc,ConditionCode cc,uint64_t imm)4832     SelectImmInst(Opcode opcode, DataType::Type type, uint32_t pc, ConditionCode cc, uint64_t imm)
4833         : Base(opcode, type, pc), ImmediateMixin(imm)
4834     {
4835         SetCc(cc);
4836     }
4837 
GetInputType(size_t index)4838     DataType::Type GetInputType(size_t index) const override
4839     {
4840         ASSERT(index < GetInputsCount());
4841         if (index < 2U) {
4842             return GetType();
4843         }
4844         return GetOperandsType();
4845     }
4846 
4847     void DumpOpcode(std::ostream * /* unused */) const override;
4848     bool DumpInputs(std::ostream * /* unused */) const override;
4849     void SetVnObject(VnObject *vn_obj) override;
4850 
Clone(const Graph * targetGraph)4851     Inst *Clone(const Graph *targetGraph) const override
4852     {
4853         auto clone = FixedInputsInst::Clone(targetGraph);
4854         clone->CastToSelectImm()->SetCc(GetCc());
4855         clone->CastToSelectImm()->SetImm(GetImm());
4856         clone->CastToSelectImm()->SetOperandsType(GetOperandsType());
4857         return clone;
4858     }
4859 };
4860 
4861 /**
4862  * Conditional jump instruction
4863  */
4864 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4865 class IfInst : public InstWithOperandsType<ConditionMixin<FixedInputsInst2>> {
4866 public:
4867     DECLARE_INST(IfInst);
4868     using Base = InstWithOperandsType<ConditionMixin<FixedInputsInst2>>;
4869     using Base::Base;
4870 
IfInst(Opcode opcode,DataType::Type type,uint32_t pc,ConditionCode cc)4871     IfInst(Opcode opcode, DataType::Type type, uint32_t pc, ConditionCode cc) : Base(opcode, type, pc)
4872     {
4873         SetCc(cc);
4874     }
4875 
GetInputType(size_t index)4876     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
4877     {
4878         ASSERT(index < GetInputsCount());
4879         return GetOperandsType();
4880     }
4881 
4882     void DumpOpcode(std::ostream * /* unused */) const override;
4883 
4884     void SetVnObject(VnObject *vn_obj) override;
4885 
Clone(const Graph * targetGraph)4886     Inst *Clone(const Graph *targetGraph) const override
4887     {
4888         auto clone = FixedInputsInst::Clone(targetGraph);
4889         static_cast<IfInst *>(clone)->SetCc(GetCc());
4890         static_cast<IfInst *>(clone)->SetOperandsType(GetOperandsType());
4891         static_cast<IfInst *>(clone)->SetMethod(GetMethod());
4892         return clone;
4893     }
4894 
SetMethod(RuntimeInterface::MethodPtr method)4895     void SetMethod(RuntimeInterface::MethodPtr method)
4896     {
4897         method_ = method;
4898     }
4899 
GetMethod()4900     RuntimeInterface::MethodPtr GetMethod() const
4901     {
4902         return method_;
4903     }
4904 
4905 private:
4906     RuntimeInterface::MethodPtr method_ {nullptr};
4907 };
4908 
4909 /**
4910  * IfImm instruction with immediate
4911  */
4912 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4913 class IfImmInst : public InstWithOperandsType<ConditionMixin<FixedInputsInst1>>, public ImmediateMixin {
4914 public:
4915     DECLARE_INST(IfImmInst);
4916     using Base = InstWithOperandsType<ConditionMixin<FixedInputsInst1>>;
4917     using Base::Base;
4918 
IfImmInst(Opcode opcode,DataType::Type type,uint32_t pc,ConditionCode cc,uint64_t imm)4919     IfImmInst(Opcode opcode, DataType::Type type, uint32_t pc, ConditionCode cc, uint64_t imm)
4920         : Base(opcode, type, pc), ImmediateMixin(imm)
4921     {
4922         SetCc(cc);
4923     }
4924 
GetInputType(size_t index)4925     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
4926     {
4927         ASSERT(index < GetInputsCount());
4928         return GetOperandsType();
4929     }
4930 
4931     void DumpOpcode(std::ostream * /* unused */) const override;
4932     bool DumpInputs(std::ostream * /* unused */) const override;
4933     void SetVnObject(VnObject *vn_obj) override;
4934 
Clone(const Graph * targetGraph)4935     Inst *Clone(const Graph *targetGraph) const override
4936     {
4937         auto clone = FixedInputsInst::Clone(targetGraph);
4938         clone->CastToIfImm()->SetCc(GetCc());
4939         clone->CastToIfImm()->SetImm(GetImm());
4940         clone->CastToIfImm()->SetOperandsType(GetOperandsType());
4941         clone->CastToIfImm()->SetMethod(GetMethod());
4942         return clone;
4943     }
4944 
4945     BasicBlock *GetEdgeIfInputTrue();
4946     BasicBlock *GetEdgeIfInputFalse();
4947 
SetMethod(RuntimeInterface::MethodPtr method)4948     void SetMethod(RuntimeInterface::MethodPtr method)
4949     {
4950         method_ = method;
4951     }
4952 
GetMethod()4953     RuntimeInterface::MethodPtr GetMethod() const
4954     {
4955         return method_;
4956     }
4957 
4958 private:
4959     size_t GetTrueInputEdgeIdx();
4960     RuntimeInterface::MethodPtr method_ {nullptr};
4961 };
4962 
4963 /**
4964  * Load element from a pair of values, using index as immediate
4965  */
4966 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4967 class LoadPairPartInst : public FixedInputsInst1, public ImmediateMixin {
4968 public:
4969     DECLARE_INST(LoadPairPartInst);
4970     using FixedInputsInst1::FixedInputsInst1;
4971 
LoadPairPartInst(Opcode opcode,uint64_t imm)4972     explicit LoadPairPartInst(Opcode opcode, uint64_t imm) : FixedInputsInst1(opcode), ImmediateMixin(imm) {}
4973 
GetSrcRegIndex()4974     uint32_t GetSrcRegIndex() const override
4975     {
4976         return GetImm();
4977     }
4978 
4979     bool DumpInputs(std::ostream * /* out */) const override;
4980 
Clone(const Graph * targetGraph)4981     Inst *Clone(const Graph *targetGraph) const override
4982     {
4983         auto clone = FixedInputsInst::Clone(targetGraph);
4984         clone->CastToLoadPairPart()->SetImm(GetImm());
4985         return clone;
4986     }
4987 
Latency()4988     uint32_t Latency() const override
4989     {
4990         return options.GetCompilerSchedLatencyLong();
4991     }
4992 };
4993 
4994 /**
4995  * Load a pair of consecutive values from array
4996  */
4997 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4998 class LoadArrayPairInst : public NeedBarrierMixin<MultipleOutputMixin<FixedInputsInst2, 2U>> {
4999 public:
5000     DECLARE_INST(LoadArrayPairInst);
5001     using Base = NeedBarrierMixin<MultipleOutputMixin<FixedInputsInst2, 2U>>;
5002     using Base::Base;
5003 
GetArray()5004     Inst *GetArray()
5005     {
5006         return GetInput(0).GetInst();
5007     }
GetIndex()5008     Inst *GetIndex()
5009     {
5010         return GetInput(1).GetInst();
5011     }
5012 
IsBarrier()5013     bool IsBarrier() const override
5014     {
5015         return Inst::IsBarrier() || GetNeedBarrier();
5016     }
5017 
Clone(const Graph * targetGraph)5018     Inst *Clone(const Graph *targetGraph) const override
5019     {
5020         auto clone = FixedInputsInst::Clone(targetGraph)->CastToLoadArrayPair();
5021 #ifndef NDEBUG
5022         for (size_t i = 0; i < GetDstCount(); ++i) {
5023             clone->SetDstReg(i, GetDstReg(i));
5024         }
5025 #endif
5026         return clone;
5027     }
5028 
GetInputType(size_t index)5029     DataType::Type GetInputType(size_t index) const override
5030     {
5031         ASSERT(index < GetInputsCount());
5032         switch (index) {
5033             case 0:
5034                 return DataType::REFERENCE;
5035             case 1:
5036                 return DataType::INT32;
5037             default:
5038                 return DataType::NO_TYPE;
5039         }
5040     }
5041 
Latency()5042     uint32_t Latency() const override
5043     {
5044         return 0;
5045     }
5046 };
5047 
5048 /**
5049  * Store a pair of consecutive values to array
5050  */
5051 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
5052 class StoreArrayPairInst : public NeedBarrierMixin<FixedInputsInst<4U>> {
5053 public:
5054     DECLARE_INST(StoreVectorInst);
5055     using Base = NeedBarrierMixin<FixedInputsInst<4U>>;
5056     using Base::Base;
5057 
GetArray()5058     Inst *GetArray()
5059     {
5060         return GetInput(0).GetInst();
5061     }
GetIndex()5062     Inst *GetIndex()
5063     {
5064         return GetInput(1).GetInst();
5065     }
GetStoredValue(uint64_t index)5066     Inst *GetStoredValue(uint64_t index)
5067     {
5068         return GetInput(2U + index).GetInst();
5069     }
GetInputType(size_t index)5070     DataType::Type GetInputType(size_t index) const override
5071     {
5072         ASSERT(index < GetInputsCount());
5073         switch (index) {
5074             case 0:
5075                 return DataType::REFERENCE;
5076             case 1:
5077                 return DataType::INT32;
5078             case 2U:
5079             case 3U:
5080                 return GetType();
5081             default:
5082                 return DataType::NO_TYPE;
5083         }
5084     }
5085 
5086     // StoreArrayPair call barriers twice,so we need to save input register for second call
IsPropagateLiveness()5087     bool IsPropagateLiveness() const override
5088     {
5089         return GetType() == DataType::REFERENCE;
5090     }
5091 
IsBarrier()5092     bool IsBarrier() const override
5093     {
5094         return Inst::IsBarrier() || GetNeedBarrier();
5095     }
5096 };
5097 
5098 /**
5099  * Load a pair of consecutive values from array, using array index as immediate
5100  */
5101 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
5102 class LoadArrayPairInstI : public NeedBarrierMixin<MultipleOutputMixin<FixedInputsInst1, 2U>>, public ImmediateMixin {
5103 public:
5104     DECLARE_INST(LoadArrayPairInstI);
5105     using Base = NeedBarrierMixin<MultipleOutputMixin<FixedInputsInst1, 2U>>;
5106     using Base::Base;
5107 
LoadArrayPairInstI(Opcode opcode,uint64_t imm)5108     explicit LoadArrayPairInstI(Opcode opcode, uint64_t imm) : Base(opcode), ImmediateMixin(imm) {}
5109 
GetArray()5110     Inst *GetArray()
5111     {
5112         return GetInput(0).GetInst();
5113     }
5114 
IsBarrier()5115     bool IsBarrier() const override
5116     {
5117         return Inst::IsBarrier() || GetNeedBarrier();
5118     }
5119     bool DumpInputs(std::ostream * /* out */) const override;
5120 
Clone(const Graph * targetGraph)5121     Inst *Clone(const Graph *targetGraph) const override
5122     {
5123         auto clone = FixedInputsInst::Clone(targetGraph)->CastToLoadArrayPairI();
5124         clone->SetImm(GetImm());
5125 #ifndef NDEBUG
5126         for (size_t i = 0; i < GetDstCount(); ++i) {
5127             clone->SetDstReg(i, GetDstReg(i));
5128         }
5129 #endif
5130         return clone;
5131     }
5132 
GetInputType(size_t index)5133     DataType::Type GetInputType(size_t index) const override
5134     {
5135         ASSERT(index < GetInputsCount());
5136         if (index == 0) {
5137             return DataType::REFERENCE;
5138         }
5139         return DataType::NO_TYPE;
5140     }
5141 
Latency()5142     uint32_t Latency() const override
5143     {
5144         return 0;
5145     }
5146 };
5147 
5148 /**
5149  * Store a pair of consecutive values to array, using array index as immediate
5150  */
5151 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
5152 class StoreArrayPairInstI : public NeedBarrierMixin<FixedInputsInst3>, public ImmediateMixin {
5153 public:
5154     DECLARE_INST(StoreArrayPairInstI);
5155     using Base = NeedBarrierMixin<FixedInputsInst3>;
5156     using Base::Base;
5157 
StoreArrayPairInstI(Opcode opcode,uint64_t imm)5158     explicit StoreArrayPairInstI(Opcode opcode, uint64_t imm) : Base(opcode), ImmediateMixin(imm) {}
5159 
GetArray()5160     Inst *GetArray()
5161     {
5162         return GetInput(0).GetInst();
5163     }
GetFirstValue()5164     Inst *GetFirstValue()
5165     {
5166         return GetInput(1).GetInst();
5167     }
GetSecondValue()5168     Inst *GetSecondValue()
5169     {
5170         return GetInput(2U).GetInst();
5171     }
GetInputType(size_t index)5172     DataType::Type GetInputType(size_t index) const override
5173     {
5174         ASSERT(index < GetInputsCount());
5175         switch (index) {
5176             case 0:
5177                 return DataType::REFERENCE;
5178             case 1:
5179             case 2U:
5180                 return GetType();
5181             default:
5182                 return DataType::NO_TYPE;
5183         }
5184     }
5185 
5186     // StoreArrayPairI call barriers twice,so we need to save input register for second call
IsPropagateLiveness()5187     bool IsPropagateLiveness() const override
5188     {
5189         return GetType() == DataType::REFERENCE;
5190     }
5191 
IsBarrier()5192     bool IsBarrier() const override
5193     {
5194         return Inst::IsBarrier() || GetNeedBarrier();
5195     }
5196 
5197     bool DumpInputs(std::ostream * /* out */) const override;
5198 
Clone(const Graph * targetGraph)5199     Inst *Clone(const Graph *targetGraph) const override
5200     {
5201         auto clone = FixedInputsInst::Clone(targetGraph);
5202         clone->CastToStoreArrayPairI()->SetImm(GetImm());
5203         return clone;
5204     }
5205 };
5206 
5207 /**
5208  * CatchPhiInst instruction
5209  */
5210 class CatchPhiInst : public DynamicInputsInst {
5211 public:
5212     DECLARE_INST(CatchPhiInst);
5213     using DynamicInputsInst::DynamicInputsInst;
5214 
GetThrowableInsts()5215     const ArenaVector<const Inst *> *GetThrowableInsts() const
5216     {
5217         return throw_insts_;
5218     }
5219 
GetThrowableInst(size_t i)5220     const Inst *GetThrowableInst(size_t i) const
5221     {
5222         ASSERT(throw_insts_ != nullptr && i < throw_insts_->size());
5223         return throw_insts_->at(i);
5224     }
5225 
5226     void AppendThrowableInst(const Inst *inst);
5227     void ReplaceThrowableInst(const Inst *old_inst, const Inst *new_inst);
5228     void RemoveInput(unsigned index) override;
5229 
IsAcc()5230     bool IsAcc() const
5231     {
5232         return GetField<IsAccFlag>();
5233     }
5234 
SetIsAcc()5235     void SetIsAcc()
5236     {
5237         SetField<IsAccFlag>(true);
5238     }
5239 
5240 protected:
5241     using IsAccFlag = LastField::NextFlag;
5242     using LastField = IsAccFlag;
5243 
5244 private:
GetThrowableInstIndex(const Inst * inst)5245     size_t GetThrowableInstIndex(const Inst *inst)
5246     {
5247         ASSERT(throw_insts_ != nullptr);
5248         auto it = std::find(throw_insts_->begin(), throw_insts_->end(), inst);
5249         ASSERT(it != throw_insts_->end());
5250         return std::distance(throw_insts_->begin(), it);
5251     }
5252 
5253 private:
5254     ArenaVector<const Inst *> *throw_insts_ {nullptr};
5255 };
5256 
5257 class TryInst : public FixedInputsInst0 {
5258 public:
5259     DECLARE_INST(TryInst);
5260     using FixedInputsInst0::FixedInputsInst0;
5261 
5262     void AppendCatchTypeId(uint32_t id, uint32_t catch_edge_index);
5263 
GetCatchTypeIds()5264     const ArenaVector<uint32_t> *GetCatchTypeIds() const
5265     {
5266         return catch_type_ids_;
5267     }
5268 
GetCatchEdgeIndexes()5269     const ArenaVector<uint32_t> *GetCatchEdgeIndexes() const
5270     {
5271         return catch_edge_indexes_;
5272     }
5273 
GetCatchTypeIdsCount()5274     size_t GetCatchTypeIdsCount() const
5275     {
5276         return (catch_type_ids_ == nullptr ? 0 : catch_type_ids_->size());
5277     }
5278 
5279     Inst *Clone(const Graph *targetGraph) const override;
5280 
SetTryEndBlock(BasicBlock * try_end_bb)5281     void SetTryEndBlock(BasicBlock *try_end_bb)
5282     {
5283         try_end_bb_ = try_end_bb;
5284     }
5285 
GetTryEndBlock()5286     BasicBlock *GetTryEndBlock() const
5287     {
5288         return try_end_bb_;
5289     }
5290 
5291 private:
5292     ArenaVector<uint32_t> *catch_type_ids_ {nullptr};
5293     ArenaVector<uint32_t> *catch_edge_indexes_ {nullptr};
5294     BasicBlock *try_end_bb_ {nullptr};
5295 };
5296 
5297 TryInst *GetTryBeginInst(const BasicBlock *try_begin_bb);
5298 
5299 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
5300 class DeoptimizeInst : public DeoptimizeTypeMixin<FixedInputsInst1> {
5301 public:
5302     DECLARE_INST(DeoptimizeInst);
5303     using Base = DeoptimizeTypeMixin<FixedInputsInst1>;
5304     using Base::Base;
5305 
Clone(const Graph * targetGraph)5306     Inst *Clone(const Graph *targetGraph) const override
5307     {
5308         auto clone = FixedInputsInst::Clone(targetGraph);
5309         clone->CastToDeoptimize()->SetDeoptimizeType(GetDeoptimizeType());
5310         return clone;
5311     }
5312 
5313     void DumpOpcode(std::ostream *out) const override;
5314 };
5315 
5316 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
5317 class DeoptimizeIfInst : public DeoptimizeTypeMixin<FixedInputsInst2> {
5318     DECLARE_INST(DeoptimizeInst);
5319     using Base = DeoptimizeTypeMixin<FixedInputsInst2>;
5320 
5321 public:
5322     using Base::Base;
5323 
Clone(const Graph * targetGraph)5324     Inst *Clone(const Graph *targetGraph) const override
5325     {
5326         auto clone = FixedInputsInst::Clone(targetGraph);
5327         clone->CastToDeoptimizeIf()->SetDeoptimizeType(GetDeoptimizeType());
5328         return clone;
5329     }
5330 
GetInputType(size_t index)5331     DataType::Type GetInputType(size_t index) const override
5332     {
5333         ASSERT(index < GetInputsCount());
5334         switch (index) {
5335             case 0:
5336                 return GetInput(0).GetInst()->GetType();
5337             case 1:
5338                 return DataType::NO_TYPE;
5339             default:
5340                 UNREACHABLE();
5341         }
5342     }
5343 
5344     void DumpOpcode(std::ostream *out) const override;
5345 };
5346 
5347 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
5348 class DeoptimizeCompareInst : public InstWithOperandsType<DeoptimizeTypeMixin<ConditionMixin<FixedInputsInst3>>> {
5349 public:
5350     DECLARE_INST(DeoptimizeCompareInst);
5351     using Base = InstWithOperandsType<DeoptimizeTypeMixin<ConditionMixin<FixedInputsInst3>>>;
5352     using Base::Base;
5353 
DeoptimizeCompareInst(Opcode opcode,const DeoptimizeIfInst * deoptIf,const CompareInst * compare)5354     explicit DeoptimizeCompareInst(Opcode opcode, const DeoptimizeIfInst *deoptIf, const CompareInst *compare)
5355         : Base(opcode, deoptIf->GetType(), deoptIf->GetPc())
5356     {
5357         SetDeoptimizeType(deoptIf->GetDeoptimizeType());
5358         SetOperandsType(compare->GetOperandsType());
5359         SetCc(compare->GetCc());
5360     }
5361 
Clone(const Graph * targetGraph)5362     Inst *Clone(const Graph *targetGraph) const override
5363     {
5364         auto clone = FixedInputsInst3::Clone(targetGraph);
5365         clone->CastToDeoptimizeCompare()->SetDeoptimizeType(GetDeoptimizeType());
5366         clone->CastToDeoptimizeCompare()->SetOperandsType(GetOperandsType());
5367         clone->CastToDeoptimizeCompare()->SetCc(GetCc());
5368         return clone;
5369     }
5370 
GetInputType(size_t index)5371     DataType::Type GetInputType(size_t index) const override
5372     {
5373         ASSERT(index < GetInputsCount());
5374         switch (index) {
5375             case 0:
5376             case 1:
5377                 return GetInput(index).GetInst()->GetType();
5378             case 2U:
5379                 return DataType::NO_TYPE;
5380             default:
5381                 UNREACHABLE();
5382         }
5383     }
5384 
5385     void DumpOpcode(std::ostream *out) const override;
5386 };
5387 
5388 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
5389 class DeoptimizeCompareImmInst : public InstWithOperandsType<DeoptimizeTypeMixin<ConditionMixin<FixedInputsInst2>>>,
5390                                  public ImmediateMixin {
5391 public:
5392     DECLARE_INST(DeoptimizeCompareImmInst);
5393     using Base = InstWithOperandsType<DeoptimizeTypeMixin<ConditionMixin<FixedInputsInst2>>>;
5394     using Base::Base;
5395 
DeoptimizeCompareImmInst(Opcode opcode,const DeoptimizeIfInst * deoptIf,const CompareInst * compare,uint64_t imm)5396     explicit DeoptimizeCompareImmInst(Opcode opcode, const DeoptimizeIfInst *deoptIf, const CompareInst *compare,
5397                                       uint64_t imm)
5398         : Base(opcode, deoptIf->GetType(), deoptIf->GetPc()), ImmediateMixin(imm)
5399     {
5400         SetDeoptimizeType(deoptIf->GetDeoptimizeType());
5401         SetOperandsType(compare->GetOperandsType());
5402         SetCc(compare->GetCc());
5403     }
5404 
Clone(const Graph * targetGraph)5405     Inst *Clone(const Graph *targetGraph) const override
5406     {
5407         auto clone = FixedInputsInst2::Clone(targetGraph);
5408         clone->CastToDeoptimizeCompareImm()->SetDeoptimizeType(GetDeoptimizeType());
5409         clone->CastToDeoptimizeCompareImm()->SetOperandsType(GetOperandsType());
5410         clone->CastToDeoptimizeCompareImm()->SetCc(GetCc());
5411         clone->CastToDeoptimizeCompareImm()->SetImm(GetImm());
5412         return clone;
5413     }
5414 
GetInputType(size_t index)5415     DataType::Type GetInputType(size_t index) const override
5416     {
5417         ASSERT(index < GetInputsCount());
5418         switch (index) {
5419             case 0:
5420                 return GetInput(0).GetInst()->GetType();
5421             case 1:
5422                 return DataType::NO_TYPE;
5423             default:
5424                 UNREACHABLE();
5425         }
5426     }
5427 
5428     void DumpOpcode(std::ostream *out) const override;
5429     bool DumpInputs(std::ostream *out) const override;
5430 };
5431 
5432 class ThrowInst : public FixedInputsInst2 {
5433 public:
5434     DECLARE_INST(ThrowInst);
5435     using Base = FixedInputsInst2;
5436     using Base::Base;
5437 
GetInputType(size_t index)5438     DataType::Type GetInputType(size_t index) const override
5439     {
5440         ASSERT(index < GetInputsCount());
5441         if (index == 0) {
5442             return DataType::REFERENCE;
5443         }
5444         return DataType::NO_TYPE;
5445     }
5446 };
5447 
5448 class BinaryOverflowInst : public IfInst {
5449 public:
5450     DECLARE_INST(BinaryOverflowInst);
5451     using Base = IfInst;
5452     using Base::Base;
5453 
BinaryOverflowInst(Opcode opcode,DataType::Type type,uint32_t pc,ConditionCode cc)5454     BinaryOverflowInst(Opcode opcode, DataType::Type type, uint32_t pc, ConditionCode cc) : Base(opcode, type, pc, cc)
5455     {
5456         SetOperandsType(type);
5457     }
5458 
GetInputType(size_t index)5459     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
5460     {
5461         ASSERT(index < GetInputsCount());
5462         return GetType();
5463     }
5464 
GetOperandsType()5465     DataType::Type GetOperandsType() const override
5466     {
5467         return GetType();
5468     }
5469 };
5470 
IsVolatileMemInst(Inst * inst)5471 inline bool IsVolatileMemInst(Inst *inst)
5472 {
5473     switch (inst->GetOpcode()) {
5474         case Opcode::LoadObject:
5475             return inst->CastToLoadObject()->GetVolatile();
5476         case Opcode::StoreObject:
5477             return inst->CastToStoreObject()->GetVolatile();
5478         case Opcode::LoadStatic:
5479             return inst->CastToLoadStatic()->GetVolatile();
5480         case Opcode::StoreStatic:
5481             return inst->CastToStoreStatic()->GetVolatile();
5482         case Opcode::UnresolvedLoadObject:
5483         case Opcode::UnresolvedStoreObject:
5484         case Opcode::UnresolvedLoadStatic:
5485         case Opcode::UnresolvedStoreStatic:
5486             return true;
5487         default:
5488             return false;
5489     }
5490 }
5491 
5492 // Check if instruction is pseudo-user for mutli-output instruction
IsPseudoUserOfMultiOutput(Inst * inst)5493 inline bool IsPseudoUserOfMultiOutput(Inst *inst)
5494 {
5495     switch (inst->GetOpcode()) {
5496         case Opcode::LoadPairPart:
5497             return true;
5498         default:
5499             return false;
5500     }
5501 }
5502 
5503 template <typename InstType, typename... Args>
New(ArenaAllocator * allocator,Args &&...args)5504 InstType *Inst::New(ArenaAllocator *allocator, Args &&... args)
5505 {
5506     static_assert(alignof(InstType) >= alignof(uintptr_t));
5507     // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-branch-clone)
5508     if constexpr (std::is_same_v<InstType, SpillFillInst>) {
5509         auto data = reinterpret_cast<uintptr_t>(allocator->Alloc(sizeof(InstType), DEFAULT_ALIGNMENT));
5510         ASSERT(data != 0);
5511         return new (reinterpret_cast<void *>(data)) InstType(allocator, std::forward<Args>(args)...);
5512         // NOLINTNEXTLINE(readability-braces-around-statements, readability-misleading-indentation)
5513     } else if constexpr (InstType::INPUT_COUNT == 0) {
5514         auto data = reinterpret_cast<uintptr_t>(allocator->Alloc(sizeof(InstType), DEFAULT_ALIGNMENT));
5515         ASSERT(data != 0);
5516         return new (reinterpret_cast<void *>(data)) InstType(std::forward<Args>(args)...);
5517         // NOLINTNEXTLINE(readability-braces-around-statements, readability-misleading-indentation)
5518     } else if constexpr (InstType::INPUT_COUNT == MAX_STATIC_INPUTS) {
5519         constexpr size_t OPERANDS_SIZE = sizeof(DynamicOperands);
5520         static_assert((OPERANDS_SIZE % alignof(InstType)) == 0);
5521         auto data = reinterpret_cast<uintptr_t>(allocator->Alloc(OPERANDS_SIZE + sizeof(InstType), DEFAULT_ALIGNMENT));
5522         ASSERT(data != 0);
5523         auto inst = new (reinterpret_cast<void *>(data + OPERANDS_SIZE)) InstType(std::forward<Args>(args)...);
5524         [[maybe_unused]] auto operands = new (reinterpret_cast<void *>(data)) DynamicOperands(allocator);
5525         static_cast<Inst *>(inst)->SetField<InputsCount>(InstType::INPUT_COUNT);
5526         return inst;
5527     } else {  // NOLINT(readability-misleading-indentation)
5528         constexpr size_t OPERANDS_SIZE = sizeof(Operands<InstType::INPUT_COUNT>);
5529         constexpr auto ALIGNMENT {GetLogAlignment(alignof(Operands<InstType::INPUT_COUNT>))};
5530         static_assert((OPERANDS_SIZE % alignof(InstType)) == 0);
5531         auto data = reinterpret_cast<uintptr_t>(allocator->Alloc(OPERANDS_SIZE + sizeof(InstType), ALIGNMENT));
5532         ASSERT(data != 0);
5533         auto inst = new (reinterpret_cast<void *>(data + OPERANDS_SIZE)) InstType(std::forward<Args>(args)...);
5534         auto operands = new (reinterpret_cast<void *>(data)) Operands<InstType::INPUT_COUNT>;
5535         static_cast<Inst *>(inst)->SetField<InputsCount>(InstType::INPUT_COUNT);
5536         unsigned idx = InstType::INPUT_COUNT - 1;
5537         for (auto &user : operands->users) {
5538             new (&user) User(true, idx--, InstType::INPUT_COUNT);
5539         }
5540         return inst;
5541     }
5542 }
5543 
GetInput()5544 inline Inst *User::GetInput()
5545 {
5546     return GetInst()->GetInput(GetIndex()).GetInst();
5547 }
5548 
GetInput()5549 inline const Inst *User::GetInput() const
5550 {
5551     return GetInst()->GetInput(GetIndex()).GetInst();
5552 }
5553 
5554 inline std::ostream &operator<<(std::ostream &os, const Inst &inst)
5555 {
5556     inst.Dump(&os, false);
5557     return os;
5558 }
5559 
5560 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
5561 #define INST_DEF(opcode, base, ...)                 \
5562     inline const base *Inst::CastTo##opcode() const \
5563     {                                               \
5564         ASSERT(GetOpcode() == Opcode::opcode);      \
5565         return static_cast<const base *>(this);     \
5566     }
5567 OPCODE_LIST(INST_DEF)
5568 #undef INST_DEF
5569 
5570 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
5571 #define INST_DEF(opcode, base, ...)            \
5572     inline base *Inst::CastTo##opcode()        \
5573     {                                          \
5574         ASSERT(GetOpcode() == Opcode::opcode); \
5575         return static_cast<base *>(this);      \
5576     }
5577 OPCODE_LIST(INST_DEF)
5578 #undef INST_DEF
5579 }  // namespace panda::compiler
5580 
5581 #endif  // COMPILER_OPTIMIZER_IR_INST_H
5582