• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 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 <vector>
20 #include <iostream>
21 #include "constants.h"
22 #include "datatype.h"
23 
24 #ifdef PANDA_COMPILER_DEBUG_INFO
25 #include "debug_info.h"
26 #endif
27 
28 #include "ir-dyn-base-types.h"
29 #include "marker.h"
30 #include "utils/arena_containers.h"
31 #include "utils/span.h"
32 #include "utils/bit_field.h"
33 #include "utils/bit_utils.h"
34 #include "utils/bit_vector.h"
35 #include "macros.h"
36 #include "mem/arena_allocator.h"
37 #include "opcodes.h"
38 #include "compiler_options.h"
39 #include "runtime_interface.h"
40 #include "spill_fill_data.h"
41 #include "compiler/code_info/vreg_info.h"
42 namespace ark::compiler {
43 class Inst;
44 class BasicBlock;
45 class Graph;
46 class GraphVisitor;
47 class VnObject;
48 class SaveStateItem;
49 class LocationsInfo;
50 using InstVector = ArenaVector<Inst *>;
51 
52 template <size_t N>
53 class FixedInputsInst;
54 
55 /*
56  * Condition code, used in Compare, If[Imm] and Select[Imm] instructions.
57  *
58  * N.B. BranchElimination and Peephole rely on the order of these codes. Change carefully.
59  */
60 enum ConditionCode {
61     // All types.
62     CC_EQ = 0,  // ==
63     CC_NE,      // !=
64     // Signed integers and floating-point numbers.
65     CC_LT,  // <
66     CC_LE,  // <=
67     CC_GT,  // >
68     CC_GE,  // >=
69     // Unsigned integers.
70     CC_B,   // <
71     CC_BE,  // <=
72     CC_A,   // >
73     CC_AE,  // >=
74     // Compare result of bitwise AND with zero
75     CC_TST_EQ,  // (lhs AND rhs) == 0
76     CC_TST_NE,  // (lhs AND rhs) != 0
77     // First and last aliases.
78     CC_FIRST = CC_EQ,
79     CC_LAST = CC_TST_NE,
80 };
81 
82 ConditionCode GetInverseConditionCode(ConditionCode code);
83 ConditionCode InverseSignednessConditionCode(ConditionCode code);
84 bool IsSignedConditionCode(ConditionCode code);
85 PANDA_PUBLIC_API ConditionCode SwapOperandsConditionCode(ConditionCode code);
86 
87 template <typename T>
Compare(ConditionCode cc,T lhs,T rhs)88 bool Compare(ConditionCode cc, T lhs, T rhs)
89 {
90     using SignedT = std::make_signed_t<T>;
91     using UnsignedT = std::make_unsigned_t<T>;
92     auto lhsU = bit_cast<UnsignedT>(lhs);
93     auto rhsU = bit_cast<UnsignedT>(rhs);
94     auto lhsS = bit_cast<SignedT>(lhs);
95     auto rhsS = bit_cast<SignedT>(rhs);
96 
97     switch (cc) {
98         case ConditionCode::CC_EQ:
99             return lhsU == rhsU;
100         case ConditionCode::CC_NE:
101             return lhsU != rhsU;
102         case ConditionCode::CC_LT:
103             return lhsS < rhsS;
104         case ConditionCode::CC_LE:
105             return lhsS <= rhsS;
106         case ConditionCode::CC_GT:
107             return lhsS > rhsS;
108         case ConditionCode::CC_GE:
109             return lhsS >= rhsS;
110         case ConditionCode::CC_B:
111             return lhsU < rhsU;
112         case ConditionCode::CC_BE:
113             return lhsU <= rhsU;
114         case ConditionCode::CC_A:
115             return lhsU > rhsU;
116         case ConditionCode::CC_AE:
117             return lhsU >= rhsU;
118         case ConditionCode::CC_TST_EQ:
119             return (lhsU & rhsU) == 0;
120         case ConditionCode::CC_TST_NE:
121             return (lhsU & rhsU) != 0;
122         default:
123             UNREACHABLE();
124             return false;
125     }
126 }
127 
128 enum class Opcode {
129     INVALID = -1,
130 // NOLINTBEGIN(readability-identifier-naming)
131 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
132 #define INST_DEF(opcode, ...) opcode,
133     OPCODE_LIST(INST_DEF)
134 
135 #undef INST_DEF
136     // NOLINTEND(readability-identifier-naming)
137     NUM_OPCODES
138 };
139 
140 /// Convert opcode to its string representation
141 constexpr std::array<const char *const, static_cast<size_t>(Opcode::NUM_OPCODES)> OPCODE_NAMES = {
142 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
143 #define INST_DEF(opcode, ...) #opcode,
144     OPCODE_LIST(INST_DEF)
145 #undef INST_DEF
146 };
147 
GetOpcodeString(Opcode opc)148 constexpr const char *GetOpcodeString(Opcode opc)
149 {
150     ASSERT(static_cast<int>(opc) < static_cast<int>(Opcode::NUM_OPCODES));
151     return OPCODE_NAMES[static_cast<int>(opc)];
152 }
153 
154 /// Instruction flags. See `instrutions.yaml` section `flags` for more information.
155 namespace inst_flags {
156 namespace internal {
157 enum FlagsIndex {
158 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
159 #define FLAG_DEF(flag) flag##_INDEX,
160     FLAGS_LIST(FLAG_DEF)
161 #undef FLAG_DEF
162         FLAGS_COUNT
163 };
164 }  // namespace internal
165 
166 enum Flags : uint32_t {
167 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
168 #define FLAG_DEF(flag) flag = (1U << internal::flag##_INDEX),
169     FLAGS_LIST(FLAG_DEF)
170 #undef FLAG_DEF
171         FLAGS_COUNT = internal::FLAGS_COUNT,
172     NONE = 0
173 };
174 
GetFlagsMask(Opcode opcode)175 inline constexpr uintptr_t GetFlagsMask(Opcode opcode)
176 {
177 #define INST_DEF(OPCODE, BASE, FLAGS) (FLAGS),  // NOLINT(cppcoreguidelines-macro-usage)
178     // NOLINTNEXTLINE(hicpp-signed-bitwise)
179     constexpr std::array<uintptr_t, static_cast<int>(Opcode::NUM_OPCODES)> INST_FLAGS_TABLE = {OPCODE_LIST(INST_DEF)};
180 #undef INST_DEF
181     return INST_FLAGS_TABLE[static_cast<size_t>(opcode)];
182 }
183 }  // namespace inst_flags
184 
185 #ifndef NDEBUG
186 namespace inst_modes {
187 namespace internal {
188 enum ModeIndex {
189 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
190 #define MODE_DEF(mode) mode##_INDEX,
191     MODES_LIST(MODE_DEF)
192 #undef MODE_DEF
193         MODES_COUNT
194 };
195 }  // namespace internal
196 
197 enum Mode : uint8_t {
198 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
199 #define MODE_DEF(mode) mode = (1U << internal::mode##_INDEX),
200     MODES_LIST(MODE_DEF)
201 #undef MODE_DEF
202         MODES_COUNT = internal::MODES_COUNT,
203 };
204 
GetModesMask(Opcode opcode)205 inline constexpr uint8_t GetModesMask(Opcode opcode)
206 {
207     // NOLINTNEXTLINE(hicpp-signed-bitwise)
208     constexpr std::array<uint8_t, static_cast<int>(Opcode::NUM_OPCODES)> INST_MODES_TABLE = {INST_MODES_LIST};
209     return INST_MODES_TABLE[static_cast<size_t>(opcode)];
210 }
211 }  // namespace inst_modes
212 #endif
213 
214 namespace internal {
215 inline constexpr std::array<const char *, ShiftType::INVALID_SHIFT + 1> SHIFT_TYPE_NAMES = {"LSL", "LSR", "ASR", "ROR",
216                                                                                             "INVALID"};
217 }  // namespace internal
218 
GetShiftTypeStr(ShiftType type)219 inline const char *GetShiftTypeStr(ShiftType type)
220 {
221     ASSERT(type <= INVALID_SHIFT);
222     return internal::SHIFT_TYPE_NAMES[type];
223 }
224 
225 /// Describes type of the object produced by an instruction.
226 class ObjectTypeInfo {
227 public:
228     using ClassType = RuntimeInterface::ClassPtr;
229 
230     constexpr ObjectTypeInfo() = default;
ObjectTypeInfo(ClassType klass,bool isExact)231     ObjectTypeInfo(ClassType klass, bool isExact)
232         : class_(reinterpret_cast<uintptr_t>(klass) | static_cast<uintptr_t>(isExact))
233     {
234         ASSERT((reinterpret_cast<uintptr_t>(klass) & EXACT_MASK) == 0);
235     }
236 
237     bool operator==(const ObjectTypeInfo &other) const
238     {
239         return class_ == other.class_;
240     }
241 
242     bool operator!=(const ObjectTypeInfo &other) const
243     {
244         return class_ != other.class_;
245     }
246 
247     // NOLINTNEXTLINE(*-explicit-constructor)
248     operator bool() const
249     {
250         return class_ != 0;
251     }
252 
GetClass()253     ClassType GetClass() const
254     {
255         return reinterpret_cast<ClassType>(class_ & ~EXACT_MASK);
256     }
257 
IsExact()258     bool IsExact() const
259     {
260         return (class_ & EXACT_MASK) != 0;
261     }
262 
IsValid()263     bool IsValid() const
264     {
265         return class_ > 1;
266     }
267 
268     static const ObjectTypeInfo INVALID;
269     static const ObjectTypeInfo UNKNOWN;
270 
271 private:
ObjectTypeInfo(uintptr_t klass)272     explicit constexpr ObjectTypeInfo(uintptr_t klass) : class_(klass) {}
273 
274 private:
275     static constexpr uintptr_t EXACT_MASK = 1;
276     // Lowest bit in ClassPtr is always zero due to alignment, we set it to 1 if `klass` is the exact class
277     // of the object and to 0 if it is some superclass of that class
278     uintptr_t class_ = 0;
279 };
280 
281 using VRegType = VRegInfo::VRegType;
282 
283 /// Class for storing panda bytecode's virtual register
284 class VirtualRegister final {
285 public:
286     using ValueType = uint16_t;
287 
288     static constexpr unsigned BITS_FOR_VREG_TYPE = MinimumBitsToStore(VRegType::COUNT);
289     static constexpr unsigned BITS_FOR_VREG = (sizeof(ValueType) * BITS_PER_BYTE) - BITS_FOR_VREG_TYPE;
290 
291     static constexpr ValueType INVALID = std::numeric_limits<ValueType>::max() >> BITS_FOR_VREG_TYPE;
292     // This value we marked the virtual registers, that create in bridge for SS
293     static constexpr ValueType BRIDGE = INVALID - 1U;
294     static constexpr ValueType MAX_NUM_VIRT_REGS = BRIDGE - 2U;
295 
296     VirtualRegister() = default;
VirtualRegister(ValueType v,VRegType type)297     explicit VirtualRegister(ValueType v, VRegType type) : value_(v)
298     {
299         ASSERT(ValidNumVirtualReg(value_));
300         VRegTypeField::Set(type, &value_);
301     }
302 
uint16_t()303     explicit operator uint16_t() const
304     {
305         return value_;
306     }
307 
Value()308     ValueType Value() const
309     {
310         return ValueField::Get(value_);
311     }
312 
IsAccumulator()313     bool IsAccumulator() const
314     {
315         return VRegTypeField::Get(value_) == VRegType::ACC;
316     }
317 
IsEnv()318     bool IsEnv() const
319     {
320         return IsSpecialReg() && !IsAccumulator();
321     }
322 
IsSpecialReg()323     bool IsSpecialReg() const
324     {
325         return VRegTypeField::Get(value_) != VRegType::VREG;
326     }
327 
GetVRegType()328     VRegType GetVRegType() const
329     {
330         return static_cast<VRegType>(VRegTypeField::Get(value_));
331     }
332 
IsBridge()333     bool IsBridge() const
334     {
335         return ValueField::Get(value_) == BRIDGE;
336     }
337 
ValidNumVirtualReg(uint16_t num)338     static bool ValidNumVirtualReg(uint16_t num)
339     {
340         return num <= INVALID;
341     }
342 
343 private:
344     ValueType value_ {INVALID};
345 
346     using ValueField = BitField<unsigned, 0, BITS_FOR_VREG>;
347     using VRegTypeField = ValueField::NextField<unsigned, BITS_FOR_VREG_TYPE>;
348 };
349 
350 // How many bits will be used in Inst's bit fields for number of inputs.
351 constexpr size_t BITS_PER_INPUTS_NUM = 3;
352 // Maximum number of static inputs
353 constexpr size_t MAX_STATIC_INPUTS = (1U << BITS_PER_INPUTS_NUM) - 1;
354 
355 /// Currently Input class is just a wrapper for the Inst class.
356 class Input final {
357 public:
358     Input() = default;
Input(Inst * inst)359     explicit Input(Inst *inst) : inst_(inst) {}
360 
GetInst()361     Inst *GetInst()
362     {
363         return inst_;
364     }
GetInst()365     const Inst *GetInst() const
366     {
367         return inst_;
368     }
369 
GetPadding(Arch arch,uint32_t inputsCount)370     static inline uint8_t GetPadding(Arch arch, uint32_t inputsCount)
371     {
372         return static_cast<uint8_t>(!Is64BitsArch(arch) && inputsCount % 2U == 1U);
373     }
374 
375 private:
376     Inst *inst_ {nullptr};
377 };
378 
379 inline bool operator==(const Inst *lhs, const Input &rhs)
380 {
381     return lhs == rhs.GetInst();
382 }
383 
384 inline bool operator==(const Input &lhs, const Inst *rhs)
385 {
386     return lhs.GetInst() == rhs;
387 }
388 
389 inline bool operator==(const Input &lhs, const Input &rhs)
390 {
391     return lhs.GetInst() == rhs.GetInst();
392 }
393 
394 inline bool operator!=(const Inst *lhs, const Input &rhs)
395 {
396     return lhs != rhs.GetInst();
397 }
398 
399 inline bool operator!=(const Input &lhs, const Inst *rhs)
400 {
401     return lhs.GetInst() != rhs;
402 }
403 
404 inline bool operator!=(const Input &lhs, const Input &rhs)
405 {
406     return lhs.GetInst() != rhs.GetInst();
407 }
408 
409 /**
410  * User is a intrusive list node, thus it stores pointers to next and previous users.
411  * Also user has properties value to determine owner instruction and corresponding index of the input.
412  */
413 class User final {
414 public:
415     User() = default;
User(bool isStatic,unsigned index,unsigned size)416     User(bool isStatic, unsigned index, unsigned size)
417         : properties_(IsStaticFlag::Encode(isStatic) | IndexField::Encode(index) | SizeField::Encode(size) |
418                       BbNumField::Encode(BbNumField::MaxValue()))
419     {
420         ASSERT(index < 1U << (BITS_FOR_INDEX - 1U));
421         ASSERT(size < 1U << (BITS_FOR_SIZE - 1U));
422     }
423     ~User() = default;
424 
425     // Copy/move semantic is disabled because we use tricky pointer arithmetic based on 'this' value
426     NO_COPY_SEMANTIC(User);
427     NO_MOVE_SEMANTIC(User);
428 
429     PANDA_PUBLIC_API Inst *GetInst();
GetInst()430     const Inst *GetInst() const
431     {
432         return const_cast<User *>(this)->GetInst();
433     }
434 
435     Inst *GetInput();
436     const Inst *GetInput() const;
437 
IsDynamic()438     bool IsDynamic() const
439     {
440         return !IsStaticFlag::Decode(properties_);
441     }
GetIndex()442     unsigned GetIndex() const
443     {
444         return IndexField::Decode(properties_);
445     }
GetSize()446     unsigned GetSize() const
447     {
448         return SizeField::Decode(properties_);
449     }
450 
GetVirtualRegister()451     VirtualRegister GetVirtualRegister() const
452     {
453         ASSERT(IsDynamic());
454         return VirtualRegister(VRegField::Decode(properties_),
455                                static_cast<VRegType>(VRegTypeField::Decode(properties_)));
456     }
457 
SetVirtualRegister(VirtualRegister reg)458     void SetVirtualRegister(VirtualRegister reg)
459     {
460         static_assert(sizeof(reg) <= sizeof(uintptr_t), "Consider passing the register by reference");
461         ASSERT(IsDynamic());
462         VRegField::Set(reg.Value(), &properties_);
463         VRegTypeField::Set(reg.GetVRegType(), &properties_);
464     }
465 
GetBbNum()466     uint32_t GetBbNum() const
467     {
468         ASSERT(IsDynamic());
469         return BbNumField::Decode(properties_);
470     }
471 
SetBbNum(uint32_t bbNum)472     void SetBbNum(uint32_t bbNum)
473     {
474         ASSERT(IsDynamic());
475         BbNumField::Set(bbNum, &properties_);
476     }
477 
GetNext()478     auto GetNext() const
479     {
480         return next_;
481     }
482 
GetPrev()483     auto GetPrev() const
484     {
485         return prev_;
486     }
487 
SetNext(User * next)488     void SetNext(User *next)
489     {
490         next_ = next;
491     }
492 
SetPrev(User * prev)493     void SetPrev(User *prev)
494     {
495         prev_ = prev;
496     }
497 
Remove()498     void Remove()
499     {
500         if (prev_ != nullptr) {
501             prev_->next_ = next_;
502         }
503         if (next_ != nullptr) {
504             next_->prev_ = prev_;
505         }
506     }
507 
508 private:
509     static constexpr unsigned BITS_FOR_INDEX = 21;
510     static constexpr unsigned BITS_FOR_SIZE = BITS_FOR_INDEX;
511     static constexpr unsigned BITS_FOR_BB_NUM = 20;
512     using IndexField = BitField<unsigned, 0, BITS_FOR_INDEX>;
513     using SizeField = IndexField::NextField<unsigned, BITS_FOR_SIZE>;
514     using IsStaticFlag = SizeField::NextFlag;
515 
516     using BbNumField = IsStaticFlag::NextField<uint32_t, BITS_FOR_BB_NUM>;
517 
518     using VRegField = IsStaticFlag::NextField<unsigned, VirtualRegister::BITS_FOR_VREG>;
519     using VRegTypeField = VRegField::NextField<unsigned, VirtualRegister::BITS_FOR_VREG_TYPE>;
520 
521     uint64_t properties_ {0};
522     User *next_ {nullptr};
523     User *prev_ {nullptr};
524 };
525 
526 /**
527  * List of users. Intended for range loop.
528  * @tparam T should be User or const User
529  */
530 template <typename T>
531 class UserList {
532     template <typename U>
533     struct UserIterator {
534         // NOLINTBEGIN(readability-identifier-naming)
535         using iterator_category = std::forward_iterator_tag;
536         using value_type = U;
537         using difference_type = std::ptrdiff_t;
538         using pointer = value_type *;
539         using reference = value_type &;
540         // NOLINTEND(readability-identifier-naming)
541 
542         UserIterator() = default;
UserIteratorUserIterator543         explicit UserIterator(U *u) : user_(u) {}
544 
545         UserIterator &operator++()
546         {
547             user_ = user_->GetNext();
548             return *this;
549         }
550         bool operator!=(const UserIterator &other)
551         {
552             return user_ != other.user_;
553         }
554         bool operator==(const UserIterator &other)
555         {
556             return user_ == other.user_;
557         }
558         U &operator*()
559         {
560             return *user_;
561         }
562         U *operator->()
563         {
564             return user_;
565         }
566 
567     private:
568         U *user_ {nullptr};
569     };
570 
571 public:
572     using Iterator = UserIterator<T>;
573     using ConstIterator = UserIterator<const T>;
574     using PointerType = std::conditional_t<std::is_const_v<T>, T *const *, T **>;
575 
UserList(PointerType head)576     explicit UserList(PointerType head) : head_(head) {}
577 
578     // NOLINTNEXTLINE(readability-identifier-naming)
begin()579     Iterator begin()
580     {
581         return Iterator(*head_);
582     }
583     // NOLINTNEXTLINE(readability-identifier-naming)
end()584     Iterator end()
585     {
586         return Iterator(nullptr);
587     }
588     // NOLINTNEXTLINE(readability-identifier-naming)
begin()589     ConstIterator begin() const
590     {
591         return ConstIterator(*head_);
592     }
593     // NOLINTNEXTLINE(readability-identifier-naming)
end()594     ConstIterator end() const
595     {
596         return ConstIterator(nullptr);
597     }
Empty()598     bool Empty() const
599     {
600         return *head_ == nullptr;
601     }
Front()602     T &Front()
603     {
604         return **head_;
605     }
Front()606     const T &Front() const
607     {
608         return **head_;
609     }
610 
611 private:
612     PointerType head_ {nullptr};
613 };
614 
615 inline bool operator==(const User &lhs, const User &rhs)
616 {
617     return lhs.GetInst() == rhs.GetInst();
618 }
619 
620 /**
621  * Operands class for instructions with fixed inputs count.
622  * Actually, this class do absolutely nothing except that we can get sizeof of it when allocating memory.
623  */
624 template <int N>
625 struct Operands {
626     static_assert(N < MAX_STATIC_INPUTS, "Invalid inputs number");
627 
628     std::array<User, N> users;
629     std::array<Input, N> inputs;
630 };
631 
632 enum InputOrd { INP0 = 0, INP1 = 1, INP2 = 2, INP3 = 3 };
633 
634 /**
635  * Specialized version for instructions with variable inputs count.
636  * Users and inputs are stored outside of this class.
637  */
638 class DynamicOperands {
639 public:
DynamicOperands(ArenaAllocator * allocator)640     explicit DynamicOperands(ArenaAllocator *allocator) : allocator_(allocator) {}
641 
Users()642     User *Users()
643     {
644         return users_;
645     }
646 
Inputs()647     NO_UB_SANITIZE Input *Inputs()
648     {
649         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
650         return reinterpret_cast<Input *>(users_ + capacity_) + 1;
651     }
652 
653     /// Append new input (and user accordingly)
654     PANDA_PUBLIC_API unsigned Append(Inst *inst);
655 
656     /// Remove input and user with index `index`.
657     PANDA_PUBLIC_API void Remove(unsigned index);
658 
659     /// Reallocate inputs/users storage to a new one with specified capacity.
660     void Reallocate(size_t newCapacity = 0);
661 
662     /// Get instruction to which these operands belongs to.
GetOwnerInst()663     Inst *GetOwnerInst() const
664     {
665         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
666         return reinterpret_cast<Inst *>(const_cast<DynamicOperands *>(this) + 1);
667     }
668 
GetUser(unsigned index)669     User *GetUser(unsigned index)
670     {
671         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
672         return &users_[capacity_ - index - 1];
673     }
674 
GetInput(unsigned index)675     Input *GetInput(unsigned index)
676     {
677         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
678         return &Inputs()[index];
679     }
680 
SetInput(unsigned index,Input input)681     void SetInput(unsigned index, Input input)
682     {
683         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
684         Inputs()[index] = input;
685     }
686 
Size()687     size_t Size() const
688     {
689         return size_;
690     }
691 
692 private:
693     User *users_ {nullptr};
694     size_t size_ {0};
695     size_t capacity_ {0};
696     ArenaAllocator *allocator_ {nullptr};
697 };
698 
699 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
700 
701 /// Base class for all instructions, should not be instantiated directly
702 class InstBase {
703     NO_COPY_SEMANTIC(InstBase);
704     NO_MOVE_SEMANTIC(InstBase);
705 
706 public:
707     virtual ~InstBase() = default;
708 
709 public:
delete(void * unused,size_t size)710     ALWAYS_INLINE void operator delete([[maybe_unused]] void *unused, [[maybe_unused]] size_t size)
711     {
712         UNREACHABLE();
713     }
new(size_t size,void * ptr)714     ALWAYS_INLINE void *operator new([[maybe_unused]] size_t size, void *ptr) noexcept
715     {
716         return ptr;
717     }
delete(void * unused1,void * unused2)718     ALWAYS_INLINE void operator delete([[maybe_unused]] void *unused1, [[maybe_unused]] void *unused2) noexcept {}
719 
720     void *operator new([[maybe_unused]] size_t size) = delete;
721 
722 protected:
723     InstBase() = default;
724 };
725 
726 /// Base instruction class
727 class PANDA_PUBLIC_API Inst : public MarkerSet, public InstBase {
728 public:
729     // Used for SFINAE for inputs deduction during CreateInst-calls
730     template <typename... Ds>
731     using CheckBase = std::enable_if_t<std::conjunction_v<std::is_convertible<Ds, Inst *>...>>;
732 
733 public:
734     /**
735      * Create new instruction. All instructions must be created with this method.
736      * It allocates additional space before Inst object for def-use structures.
737      *
738      * @tparam InstType - concrete type of instruction, shall be derived from Inst
739      * @tparam Args - constructor arguments types
740      * @param allocator - allocator for memory allocating
741      * @param args - constructor arguments
742      * @return - new instruction
743      */
744     template <typename InstType, typename... Args>
745     [[nodiscard]] static InstType *New(ArenaAllocator *allocator, Args &&...args);
746 
INST_CAST_TO_DECL()747     INST_CAST_TO_DECL()
748 
749     // Methods for instruction chaining inside basic blocks.
750     Inst *GetNext()
751     {
752         return next_;
753     }
GetNext()754     const Inst *GetNext() const
755     {
756         return next_;
757     }
GetPrev()758     Inst *GetPrev()
759     {
760         return prev_;
761     }
GetPrev()762     const Inst *GetPrev() const
763     {
764         return prev_;
765     }
SetNext(Inst * next)766     void SetNext(Inst *next)
767     {
768         next_ = next;
769     }
SetPrev(Inst * prev)770     void SetPrev(Inst *prev)
771     {
772         prev_ = prev;
773     }
774 
775     // Id accessors
GetId()776     auto GetId() const
777     {
778         return id_;
779     }
SetId(int id)780     void SetId(int id)
781     {
782         id_ = id;
783     }
784 
GetLinearNumber()785     auto GetLinearNumber() const
786     {
787         return linearNumber_;
788     }
SetLinearNumber(LinearNumber number)789     void SetLinearNumber(LinearNumber number)
790     {
791         linearNumber_ = number;
792     }
793 
GetCloneNumber()794     auto GetCloneNumber() const
795     {
796         return cloneNumber_;
797     }
SetCloneNumber(int32_t number)798     void SetCloneNumber(int32_t number)
799     {
800         cloneNumber_ = number;
801     }
802 
803     // Opcode accessors
GetOpcode()804     Opcode GetOpcode() const
805     {
806         return opcode_;
807     }
SetOpcode(Opcode opcode)808     void SetOpcode(Opcode opcode)
809     {
810         opcode_ = opcode;
811         SetField<FieldFlags>(inst_flags::GetFlagsMask(opcode));
812     }
GetOpcodeStr()813     const char *GetOpcodeStr() const
814     {
815         return GetOpcodeString(GetOpcode());
816     }
817 
818     // Bytecode PC accessors
GetPc()819     uint32_t GetPc() const
820     {
821         return pc_;
822     }
SetPc(uint32_t pc)823     void SetPc(uint32_t pc)
824     {
825         pc_ = pc;
826     }
827 
828     // Type accessors
GetType()829     DataType::Type GetType() const
830     {
831         return FieldType::Get(bitFields_);
832     }
SetType(DataType::Type type)833     void SetType(DataType::Type type)
834     {
835         FieldType::Set(type, &bitFields_);
836     }
HasType()837     bool HasType() const
838     {
839         return GetType() != DataType::Type::NO_TYPE;
840     }
841 
GetAnyType()842     virtual AnyBaseType GetAnyType() const
843     {
844         return AnyBaseType::UNDEFINED_TYPE;
845     }
846 
847     // Parent basic block accessors
GetBasicBlock()848     BasicBlock *GetBasicBlock()
849     {
850         return bb_;
851     }
GetBasicBlock()852     const BasicBlock *GetBasicBlock() const
853     {
854         return bb_;
855     }
SetBasicBlock(BasicBlock * bb)856     void SetBasicBlock(BasicBlock *bb)
857     {
858         bb_ = bb;
859     }
860 
861     // Instruction properties getters
IsControlFlow()862     bool IsControlFlow() const
863     {
864         return GetFlag(inst_flags::CF);
865     }
IsVirtualLaunchCall()866     bool IsVirtualLaunchCall() const
867     {
868         return GetOpcode() == Opcode::CallLaunchVirtual || GetOpcode() == Opcode::CallResolvedLaunchVirtual;
869     }
IsVirtualCall()870     bool IsVirtualCall() const
871     {
872         return GetOpcode() == Opcode::CallVirtual || GetOpcode() == Opcode::CallResolvedVirtual ||
873                IsVirtualLaunchCall();
874     }
IsStaticLaunchCall()875     bool IsStaticLaunchCall() const
876     {
877         return GetOpcode() == Opcode::CallLaunchStatic || GetOpcode() == Opcode::CallResolvedLaunchStatic;
878     }
IsStaticCall()879     bool IsStaticCall() const
880     {
881         return GetOpcode() == Opcode::CallStatic || GetOpcode() == Opcode::CallResolvedStatic || IsStaticLaunchCall();
882     }
IsMethodResolver()883     bool IsMethodResolver() const
884     {
885         return opcode_ == Opcode::ResolveVirtual || opcode_ == Opcode::ResolveStatic;
886     }
IsFieldResolver()887     bool IsFieldResolver() const
888     {
889         return opcode_ == Opcode::ResolveObjectField || opcode_ == Opcode::ResolveObjectFieldStatic;
890     }
IsResolver()891     bool IsResolver() const
892     {
893         return IsFieldResolver() || IsMethodResolver();
894     }
IsInitObject()895     bool IsInitObject() const
896     {
897         return GetOpcode() == Opcode::InitObject;
898     }
IsMultiArray()899     bool IsMultiArray() const
900     {
901         return GetOpcode() == Opcode::MultiArray;
902     }
IsDynamicCall()903     bool IsDynamicCall() const
904     {
905         return GetOpcode() == Opcode::CallDynamic;
906     }
IsLaunchCall()907     bool IsLaunchCall() const
908     {
909         return IsStaticLaunchCall() || IsVirtualLaunchCall();
910     }
IsIndirectCall()911     bool IsIndirectCall() const
912     {
913         return GetOpcode() == Opcode::CallIndirect;
914     }
IsIntrinsic()915     bool IsIntrinsic() const
916     {
917         /* Opcode::Builtin is left for backward compatibility, the compiler
918          * itself should never generate an instruction with such an opcode */
919         return GetOpcode() == Opcode::Intrinsic || GetOpcode() == Opcode::Builtin;
920     }
921 
922     /* IsBuiltin actual meaning would be "it MAY be inlined by the CG"
923      * however, since we do not make guarantees about whether it will
924      * actually be inlined nor the safety of the intrinsic itself, just
925      * checking the instruction flags to see if it is suitable for any
926      * particular optimization seems to be a better approach
927      */
IsBuiltin()928     static bool IsBuiltin()
929     {
930         return false;
931     }
932 
IsCall()933     bool IsCall() const
934     {
935         return GetFlag(inst_flags::CALL) && !IsIntrinsic();
936     }
937 
IsCallOrIntrinsic()938     bool IsCallOrIntrinsic() const
939     {
940         return GetFlag(inst_flags::CALL);
941     }
942 
IsSpillFill()943     bool IsSpillFill() const
944     {
945         return GetOpcode() == Opcode::SpillFill;
946     }
947 
IsNullCheck()948     bool IsNullCheck() const
949     {
950         return GetOpcode() == Opcode::NullCheck;
951     }
952 
IsNullPtr()953     bool IsNullPtr() const
954     {
955         return GetOpcode() == Opcode::NullPtr;
956     }
957 
IsLoadUndefined()958     bool IsLoadUndefined() const
959     {
960         return GetOpcode() == Opcode::LoadUndefined;
961     }
962 
IsReturn()963     bool IsReturn() const
964     {
965         return GetOpcode() == Opcode::Return || GetOpcode() == Opcode::ReturnI || GetOpcode() == Opcode::ReturnVoid;
966     }
967 
IsUnresolved()968     bool IsUnresolved() const
969     {
970         switch (GetOpcode()) {
971             case Opcode::UnresolvedLoadAndInitClass:
972             case Opcode::UnresolvedLoadType:
973             case Opcode::UnresolvedStoreStatic:
974                 return true;
975             default:
976                 return false;
977         }
978     }
WithGluedInsts()979     bool WithGluedInsts() const
980     {
981         return GetOpcode() == Opcode::LoadArrayPair || GetOpcode() == Opcode::LoadArrayPairI ||
982                GetOpcode() == Opcode::LoadObjectPair;
983     }
IsLoad()984     bool IsLoad() const
985     {
986         return GetFlag(inst_flags::LOAD);
987     }
IsStore()988     bool IsStore() const
989     {
990         return GetFlag(inst_flags::STORE);
991     }
992     bool IsAccRead() const;
993     bool IsAccWrite() const;
IsMemory()994     bool IsMemory() const
995     {
996         return IsLoad() || IsStore();
997     }
CanThrow()998     bool CanThrow() const
999     {
1000         return GetFlag(inst_flags::CAN_THROW);
1001     }
IsCheck()1002     bool IsCheck() const
1003     {
1004         return GetFlag(inst_flags::IS_CHECK);
1005     }
RequireState()1006     bool RequireState() const
1007     {
1008         return GetFlag(inst_flags::REQUIRE_STATE);
1009     }
1010     // Returns true if the instruction not removable in DCE
IsNotRemovable()1011     bool IsNotRemovable() const
1012     {
1013         return GetFlag(inst_flags::NO_DCE);
1014     }
1015 
1016     // Returns true if the instruction doesn't have destination register
NoDest()1017     bool NoDest() const
1018     {
1019         return GetFlag(inst_flags::PSEUDO_DST) || GetFlag(inst_flags::NO_DST) || GetType() == DataType::VOID;
1020     }
1021 
HasPseudoDestination()1022     bool HasPseudoDestination() const
1023     {
1024         return GetFlag(inst_flags::PSEUDO_DST);
1025     }
1026 
HasImplicitRuntimeCall()1027     bool HasImplicitRuntimeCall() const
1028     {
1029         return GetFlag(inst_flags::IMPLICIT_RUNTIME_CALL);
1030     }
1031 
CanDeoptimize()1032     bool CanDeoptimize() const
1033     {
1034         return GetFlag(inst_flags::CAN_DEOPTIMIZE);
1035     }
1036 
RequireTmpReg()1037     bool RequireTmpReg() const
1038     {
1039         return GetFlag(inst_flags::REQUIRE_TMP);
1040     }
1041 
1042     // Returns true if the instruction is low-level
IsLowLevel()1043     bool IsLowLevel() const
1044     {
1045         return GetFlag(inst_flags::LOW_LEVEL);
1046     }
1047 
1048     // Returns true if the instruction not hoistable
IsNotHoistable()1049     bool IsNotHoistable() const
1050     {
1051         return GetFlag(inst_flags::NO_HOIST);
1052     }
1053 
1054     // Returns true Cse can't be applied to the instruction
IsNotCseApplicable()1055     bool IsNotCseApplicable() const
1056     {
1057         return GetFlag(inst_flags::NO_CSE);
1058     }
1059 
1060     // Returns true if the instruction is a barrier
IsBarrier()1061     virtual bool IsBarrier() const
1062     {
1063         return GetFlag(inst_flags::BARRIER);
1064     }
1065 
1066     // Returns true if opcode can not be moved throught runtime calls (REFERENCE type only)
IsRefSpecial()1067     bool IsRefSpecial() const
1068     {
1069         bool result = GetFlag(inst_flags::REF_SPECIAL);
1070         ASSERT(!result || IsReferenceOrAny());
1071         return result;
1072     }
1073 
1074     // Returns true if the instruction is a commutative
IsCommutative()1075     bool IsCommutative() const
1076     {
1077         return GetFlag(inst_flags::COMMUTATIVE);
1078     }
1079 
1080     // Returns true if the instruction allocates a new object on the heap
IsAllocation()1081     bool IsAllocation() const
1082     {
1083         return GetFlag(inst_flags::ALLOC);
1084     }
1085 
1086     // Returns true if the instruction can be used in if-conversion
IsIfConvertable()1087     bool IsIfConvertable() const
1088     {
1089         return GetFlag(inst_flags::IFCVT);
1090     }
1091 
IsRuntimeCall()1092     virtual bool IsRuntimeCall() const
1093     {
1094         return GetFlag(inst_flags::RUNTIME_CALL);
1095     }
1096 
NoNullPtr()1097     virtual bool NoNullPtr() const
1098     {
1099         return GetFlag(inst_flags::NO_NULLPTR);
1100     }
1101 
1102     PANDA_PUBLIC_API virtual bool IsPropagateLiveness() const;
1103 
1104     // Returns true if the instruction doesn't have side effects(call runtime, throw e.t.c.)
IsSafeInst()1105     virtual bool IsSafeInst() const
1106     {
1107         return false;
1108     }
1109 
IsBinaryInst()1110     virtual bool IsBinaryInst() const
1111     {
1112         return false;
1113     }
1114 
IsBinaryImmInst()1115     virtual bool IsBinaryImmInst() const
1116     {
1117         return false;
1118     }
1119 
1120     bool RequireRegMap() const;
1121 
GetObjectTypeInfo()1122     ObjectTypeInfo GetObjectTypeInfo() const
1123     {
1124         return objectTypeInfo_;
1125     }
1126 
HasObjectTypeInfo()1127     bool HasObjectTypeInfo() const
1128     {
1129         return objectTypeInfo_.IsValid();
1130     }
1131 
SetObjectTypeInfo(ObjectTypeInfo o)1132     void SetObjectTypeInfo(ObjectTypeInfo o)
1133     {
1134         objectTypeInfo_ = o;
1135     }
1136 
GetDataFlowInput(int index)1137     Inst *GetDataFlowInput(int index) const
1138     {
1139         return GetDataFlowInput(GetInput(index).GetInst());
1140     }
1141     static Inst *GetDataFlowInput(Inst *inputInst);
1142 
1143     bool IsPrecedingInSameBlock(const Inst *other) const;
1144 
1145     bool IsDominate(const Inst *other) const;
1146 
1147     bool InSameBlockOrDominate(const Inst *other) const;
1148 
IsAdd()1149     bool IsAdd() const
1150     {
1151         return GetOpcode() == Opcode::Add || GetOpcode() == Opcode::AddOverflowCheck;
1152     }
1153 
IsSub()1154     bool IsSub() const
1155     {
1156         return GetOpcode() == Opcode::Sub || GetOpcode() == Opcode::SubOverflowCheck;
1157     }
1158 
IsAddSub()1159     bool IsAddSub() const
1160     {
1161         return IsAdd() || IsSub();
1162     }
1163 
GetSaveState()1164     const SaveStateInst *GetSaveState() const
1165     {
1166         return const_cast<Inst *>(this)->GetSaveState();
1167     }
1168 
GetSaveState()1169     SaveStateInst *GetSaveState()
1170     {
1171         if (!RequireState()) {
1172             return nullptr;
1173         }
1174         if (GetInputsCount() == 0) {
1175             return nullptr;
1176         }
1177         auto ss = GetInput(GetInputsCount() - 1).GetInst();
1178         if (ss->GetOpcode() == Opcode::SaveStateDeoptimize) {
1179             return ss->CastToSaveStateDeoptimize();
1180         }
1181         if (ss->GetOpcode() != Opcode::SaveState) {
1182             return nullptr;
1183         }
1184 
1185         return ss->CastToSaveState();
1186     }
1187 
SetSaveState(Inst * inst)1188     void SetSaveState(Inst *inst)
1189     {
1190         ASSERT(RequireState());
1191         SetInput(GetInputsCount() - 1, inst);
1192     }
1193 
1194     PANDA_PUBLIC_API virtual uint32_t GetInliningDepth() const;
1195 
1196     bool IsZeroRegInst() const;
1197 
1198     bool IsReferenceOrAny() const;
1199     bool IsMovableObject();
1200 
1201     /// Return instruction clone
1202     PANDA_PUBLIC_API virtual Inst *Clone(const Graph *targetGraph) const;
1203 
GetFlagsMask()1204     uintptr_t GetFlagsMask() const
1205     {
1206         return GetField<FieldFlags>();
1207     }
1208 
SetFlagsMask(inst_flags::Flags flag)1209     void SetFlagsMask(inst_flags::Flags flag)
1210     {
1211         SetField<FieldFlags>(flag);
1212     }
1213 
GetFlag(inst_flags::Flags flag)1214     bool GetFlag(inst_flags::Flags flag) const
1215     {
1216         return (GetFlagsMask() & flag) != 0;
1217     }
1218 
SetFlag(inst_flags::Flags flag)1219     void SetFlag(inst_flags::Flags flag)
1220     {
1221         SetField<FieldFlags>(GetFlagsMask() | flag);
1222     }
1223 
ClearFlag(inst_flags::Flags flag)1224     void ClearFlag(inst_flags::Flags flag)
1225     {
1226         SetField<FieldFlags>(GetFlagsMask() & ~static_cast<uintptr_t>(flag));
1227     }
1228 
1229 #ifndef NDEBUG
GetModesMask()1230     uint8_t GetModesMask() const
1231     {
1232         return inst_modes::GetModesMask(opcode_);
1233     }
1234 
SupportsMode(inst_modes::Mode mode)1235     bool SupportsMode(inst_modes::Mode mode) const
1236     {
1237         return (GetModesMask() & mode) != 0;
1238     }
1239 #endif
1240 
SetTerminator()1241     void SetTerminator()
1242     {
1243         SetFlag(inst_flags::Flags::TERMINATOR);
1244     }
1245 
IsTerminator()1246     bool IsTerminator() const
1247     {
1248         return GetFlag(inst_flags::TERMINATOR);
1249     }
1250 
1251     PANDA_PUBLIC_API void InsertBefore(Inst *inst);
1252     void InsertAfter(Inst *inst);
1253 
1254     /// Return true if instruction has dynamic operands storage.
IsOperandsDynamic()1255     bool IsOperandsDynamic() const
1256     {
1257         return GetField<InputsCount>() == MAX_STATIC_INPUTS;
1258     }
1259 
1260     /**
1261      * Add user to the instruction.
1262      * @param user - pointer to User object
1263      */
AddUser(User * user)1264     void AddUser(User *user)
1265     {
1266         ASSERT(user && user->GetInst());
1267         user->SetNext(firstUser_);
1268         user->SetPrev(nullptr);
1269         if (firstUser_ != nullptr) {
1270             ASSERT(firstUser_->GetPrev() == nullptr);
1271             firstUser_->SetPrev(user);
1272         }
1273         firstUser_ = user;
1274     }
1275 
1276     /**
1277      * Remove instruction from users.
1278      * @param user - pointer to User object
1279      */
RemoveUser(User * user)1280     void RemoveUser(User *user)
1281     {
1282         ASSERT(user);
1283         ASSERT(HasUsers());
1284         if (user == firstUser_) {
1285             firstUser_ = user->GetNext();
1286         }
1287         user->Remove();
1288     }
1289 
1290     /**
1291      * Set input instruction in specified index.
1292      * Old input will be removed.
1293      * @param index - index of input to be set
1294      * @param inst - new input instruction NOTE sherstennikov: currently it can be nullptr, is it correct?
1295      */
SetInput(unsigned index,Inst * inst)1296     void SetInput(unsigned index, Inst *inst)
1297     {
1298         CHECK_LT(index, GetInputsCount());
1299         auto &input = GetInputs()[index];
1300         auto user = GetUser(index);
1301         if (input.GetInst() != nullptr && input.GetInst()->HasUsers()) {
1302             input.GetInst()->RemoveUser(user);
1303         }
1304         if (inst != nullptr) {
1305             inst->AddUser(user);
1306         }
1307         input = Input(inst);
1308     }
1309 
1310     /**
1311      * Replace all inputs that points to specified instruction by new one.
1312      * @param old_input - instruction that should be replaced
1313      * @param new_input - new input instruction
1314      */
ReplaceInput(Inst * oldInput,Inst * newInput)1315     void ReplaceInput(Inst *oldInput, Inst *newInput)
1316     {
1317         unsigned index = 0;
1318         for (auto input : GetInputs()) {
1319             if (input.GetInst() == oldInput) {
1320                 SetInput(index, newInput);
1321             }
1322             index++;
1323         }
1324     }
1325 
1326     /**
1327      * Replace inputs that point to this instruction by given instruction.
1328      * @param inst - new input instruction
1329      */
ReplaceUsers(Inst * inst)1330     void ReplaceUsers(Inst *inst)
1331     {
1332         ASSERT(inst != this);
1333         ASSERT(inst != nullptr);
1334         for (auto it = GetUsers().begin(); it != GetUsers().end(); it = GetUsers().begin()) {
1335             it->GetInst()->SetInput(it->GetIndex(), inst);
1336         }
1337     }
1338 
1339     /**
1340      * Swap first 2 operands of the instruction.
1341      * NB! Don't swap inputs while iterating over instruction's users:
1342      * for (auto user : instruction.GetUsers()) {
1343      *     // Don't do this!
1344      *     user.GetInst()->SwapInputs();
1345      * }
1346      */
SwapInputs()1347     void SwapInputs()
1348     {
1349         ASSERT(GetInputsCount() >= 2U);
1350         auto input0 = GetInput(0).GetInst();
1351         auto input1 = GetInput(1).GetInst();
1352         SetInput(0, input1);
1353         SetInput(1, input0);
1354     }
1355 
1356     /**
1357      * Append input instruction.
1358      * Available only for variadic inputs instructions, such as PHI.
1359      * @param input - input instruction
1360      * @return index in inputs container where new input is placed
1361      */
AppendInput(Inst * input)1362     unsigned AppendInput(Inst *input)
1363     {
1364         ASSERT(input != nullptr);
1365         ASSERT(IsOperandsDynamic());
1366         DynamicOperands *operands = GetDynamicOperands();
1367         return operands->Append(input);
1368     }
1369 
AppendInput(Input input)1370     unsigned AppendInput(Input input)
1371     {
1372         static_assert(sizeof(Input) <= sizeof(uintptr_t));  // Input become larger, so pass it by reference then
1373         return AppendInput(input.GetInst());
1374     }
1375 
1376     /**
1377      * Remove input from inputs container
1378      * Available only for variadic inputs instructions, such as PHI.
1379      * @param index - index of input in inputs container
1380      */
RemoveInput(unsigned index)1381     virtual void RemoveInput(unsigned index)
1382     {
1383         ASSERT(IsOperandsDynamic());
1384         DynamicOperands *operands = GetDynamicOperands();
1385         ASSERT(index < operands->Size());
1386         operands->Remove(index);
1387     }
1388 
1389     /// Remove all inputs
RemoveInputs()1390     void RemoveInputs()
1391     {
1392         if (UNLIKELY(IsOperandsDynamic())) {
1393             for (auto inputsCount = GetInputsCount(); inputsCount != 0; --inputsCount) {
1394                 RemoveInput(inputsCount - 1);
1395             }
1396         } else {
1397             for (size_t i = 0; i < GetInputsCount(); ++i) {
1398                 SetInput(i, nullptr);
1399             }
1400         }
1401     }
1402 
1403     /// Remove all users
1404     template <bool WITH_INPUTS = false>
RemoveUsers()1405     void RemoveUsers()
1406     {
1407         auto users = GetUsers();
1408         while (!users.Empty()) {
1409             // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
1410             if constexpr (WITH_INPUTS) {
1411                 auto &user = users.Front();
1412                 user.GetInst()->RemoveInput(user.GetIndex());
1413                 // NOLINTNEXTLINE(readability-misleading-indentation)
1414             } else {
1415                 RemoveUser(&users.Front());
1416             }
1417         }
1418     }
1419 
1420     /**
1421      * Get input by index
1422      * @param index - index of input
1423      * @return input instruction
1424      */
GetInput(unsigned index)1425     Input GetInput(unsigned index)
1426     {
1427         ASSERT(index < GetInputsCount());
1428         return GetInputs()[index];
1429     }
1430 
GetInput(unsigned index)1431     Input GetInput(unsigned index) const
1432     {
1433         ASSERT(index < GetInputsCount());
1434         return GetInputs()[index];
1435     }
1436 
GetInputs()1437     Span<Input> GetInputs()
1438     {
1439         if (UNLIKELY(IsOperandsDynamic())) {
1440             DynamicOperands *operands = GetDynamicOperands();
1441             return Span<Input>(operands->Inputs(), operands->Size());
1442         }
1443 
1444         auto inputsCount {GetField<InputsCount>()};
1445         return Span<Input>(
1446             reinterpret_cast<Input *>(reinterpret_cast<uintptr_t>(this) -
1447                                       (inputsCount + Input::GetPadding(RUNTIME_ARCH, inputsCount)) * sizeof(Input)),
1448             inputsCount);
1449     }
GetInputs()1450     Span<const Input> GetInputs() const
1451     {
1452         return Span<const Input>(const_cast<Inst *>(this)->GetInputs());
1453     }
1454 
GetInputType(size_t index)1455     virtual DataType::Type GetInputType([[maybe_unused]] size_t index) const
1456     {
1457         ASSERT(index < GetInputsCount());
1458         if (GetInput(index).GetInst()->IsSaveState()) {
1459             return DataType::NO_TYPE;
1460         }
1461         return GetType();
1462     }
1463 
GetUsers()1464     UserList<User> GetUsers()
1465     {
1466         return UserList<User>(&firstUser_);
1467     }
GetUsers()1468     UserList<const User> GetUsers() const
1469     {
1470         return UserList<const User>(&firstUser_);
1471     }
1472 
GetInputsCount()1473     size_t GetInputsCount() const
1474     {
1475         if (UNLIKELY(IsOperandsDynamic())) {
1476             return GetDynamicOperands()->Size();
1477         }
1478         return GetInputs().Size();
1479     }
1480 
HasUsers()1481     bool HasUsers() const
1482     {
1483         return firstUser_ != nullptr;
1484     };
1485 
HasSingleUser()1486     bool HasSingleUser() const
1487     {
1488         return firstUser_ != nullptr && firstUser_->GetNext() == nullptr;
1489     }
1490 
1491     /// Reserve space in dataflow storage for specified inputs count
1492     void ReserveInputs(size_t capacity);
1493 
SetLocation(size_t index,Location location)1494     virtual void SetLocation([[maybe_unused]] size_t index, [[maybe_unused]] Location location) {}
1495 
GetLocation(size_t index)1496     virtual Location GetLocation([[maybe_unused]] size_t index) const
1497     {
1498         return Location::RequireRegister();
1499     }
1500 
GetDstLocation()1501     virtual Location GetDstLocation() const
1502     {
1503         return Location::MakeRegister(GetDstReg(), GetType());
1504     }
1505 
GetDstLocation(unsigned index)1506     virtual Location GetDstLocation([[maybe_unused]] unsigned index) const
1507     {
1508         ASSERT(index == 0);
1509         return GetDstLocation();
1510     }
1511 
SetTmpLocation(Location location)1512     virtual void SetTmpLocation([[maybe_unused]] Location location) {}
1513 
GetTmpLocation()1514     virtual Location GetTmpLocation() const
1515     {
1516         return Location::Invalid();
1517     }
1518 
CanBeNull()1519     virtual bool CanBeNull() const
1520     {
1521         ASSERT_PRINT(GetType() == DataType::Type::REFERENCE, "CanBeNull only applies to reference types");
1522         return true;
1523     }
1524 
Latency()1525     virtual uint32_t Latency() const
1526     {
1527         return g_options.GetCompilerSchedLatency();
1528     }
1529 
1530     template <typename Accessor>
SetField(typename Accessor::ValueType value)1531     void SetField(typename Accessor::ValueType value)
1532     {
1533         Accessor::Set(value, &bitFields_);
1534     }
1535 
1536     template <typename Accessor>
GetField()1537     typename Accessor::ValueType GetField() const
1538     {
1539         return Accessor::Get(bitFields_);
1540     }
1541 
GetAllFields()1542     uint64_t GetAllFields() const
1543     {
1544         return bitFields_;
1545     }
1546 
IsPhi()1547     bool IsPhi() const
1548     {
1549         return opcode_ == Opcode::Phi;
1550     }
1551 
IsCatchPhi()1552     bool IsCatchPhi() const
1553     {
1554         return opcode_ == Opcode::CatchPhi;
1555     }
1556 
IsConst()1557     bool IsConst() const
1558     {
1559         return opcode_ == Opcode::Constant;
1560     }
1561 
IsParameter()1562     bool IsParameter() const
1563     {
1564         return opcode_ == Opcode::Parameter;
1565     }
1566 
IsBoolConst()1567     virtual bool IsBoolConst() const
1568     {
1569         return false;
1570     }
1571 
IsSaveState()1572     bool IsSaveState() const
1573     {
1574         return opcode_ == Opcode::SaveState || opcode_ == Opcode::SafePoint || opcode_ == Opcode::SaveStateOsr ||
1575                opcode_ == Opcode::SaveStateDeoptimize;
1576     }
1577 
IsClassInst()1578     bool IsClassInst() const
1579     {
1580         return opcode_ == Opcode::InitClass || opcode_ == Opcode::LoadClass || opcode_ == Opcode::LoadAndInitClass ||
1581                opcode_ == Opcode::UnresolvedLoadAndInitClass;
1582     }
1583 
GetHashCode()1584     virtual size_t GetHashCode() const
1585     {
1586         // NOTE (Aleksandr Popov) calculate hash code
1587         return 0;
1588     }
1589 
SetVnObject(VnObject * vnObj)1590     virtual void SetVnObject([[maybe_unused]] VnObject *vnObj) {}
1591 
GetDstReg()1592     Register GetDstReg() const
1593     {
1594         return dstReg_;
1595     }
1596 
SetDstReg(Register reg)1597     void SetDstReg(Register reg)
1598     {
1599         dstReg_ = reg;
1600     }
1601 
GetVN()1602     uint32_t GetVN() const
1603     {
1604         return vn_;
1605     }
1606 
SetVN(uint32_t vn)1607     void SetVN(uint32_t vn)
1608     {
1609         vn_ = vn;
1610     }
1611     void Dump(std::ostream *out, bool newLine = true) const;
1612     PANDA_PUBLIC_API virtual bool DumpInputs(std::ostream *out) const;
1613     PANDA_PUBLIC_API virtual void DumpOpcode(std::ostream *out) const;
1614     void DumpBytecode(std::ostream *out) const;
1615 
1616 #ifdef PANDA_COMPILER_DEBUG_INFO
1617     void DumpSourceLine(std::ostream *out) const;
1618 #endif  // PANDA_COMPILER_DEBUG_INFO
1619 
SetDstReg(unsigned index,Register reg)1620     virtual void SetDstReg([[maybe_unused]] unsigned index, Register reg)
1621     {
1622         ASSERT(index == 0);
1623         SetDstReg(reg);
1624     }
1625 
GetDstReg(unsigned index)1626     virtual Register GetDstReg([[maybe_unused]] unsigned index) const
1627     {
1628         ASSERT(index == 0);
1629         return GetDstReg();
1630     }
1631 
GetDstCount()1632     virtual size_t GetDstCount() const
1633     {
1634         return 1;
1635     }
1636 
GetSrcRegIndex()1637     virtual uint32_t GetSrcRegIndex() const
1638     {
1639         return 0;
1640     }
1641 
SetSrcReg(unsigned index,Register reg)1642     virtual void SetSrcReg([[maybe_unused]] unsigned index, [[maybe_unused]] Register reg) {}
1643 
GetSrcReg(unsigned index)1644     virtual Register GetSrcReg([[maybe_unused]] unsigned index) const
1645     {
1646         return GetInvalidReg();
1647     }
1648 
GetFirstUser()1649     User *GetFirstUser() const
1650     {
1651         return firstUser_;
1652     }
1653 
1654 #ifdef PANDA_COMPILER_DEBUG_INFO
GetDebugInfo()1655     InstDebugInfo *GetDebugInfo() const
1656     {
1657         return debugInfo_;
1658     }
1659 
SetDebugInfo(InstDebugInfo * info)1660     void SetDebugInfo(InstDebugInfo *info)
1661     {
1662         debugInfo_ = info;
1663     }
1664 
GetCurrentMethod()1665     RuntimeInterface::MethodPtr GetCurrentMethod() const
1666     {
1667         return currentMethod_;
1668     }
1669 
SetCurrentMethod(RuntimeInterface::MethodPtr currentMethod)1670     void SetCurrentMethod(RuntimeInterface::MethodPtr currentMethod)
1671     {
1672         currentMethod_ = currentMethod;
1673     }
1674 #endif
1675 
1676     using Initializer = std::tuple<Opcode, DataType::Type, uint32_t>;
1677 
1678 protected:
1679     using InstBase::InstBase;
1680     static constexpr int INPUT_COUNT = 0;
1681 
1682     Inst() = default;
1683 
Inst(Opcode opcode)1684     explicit Inst(Opcode opcode) : Inst(Initializer {opcode, DataType::Type::NO_TYPE, INVALID_PC}) {}
1685 
Inst(Initializer t)1686     explicit Inst(Initializer t) : pc_(std::get<uint32_t>(t)), opcode_(std::get<Opcode>(t))
1687     {
1688         bitFields_ = inst_flags::GetFlagsMask(opcode_);
1689         SetField<FieldType>(std::get<DataType::Type>(t));
1690     }
1691 
1692 protected:
1693     using FieldFlags = BitField<uint32_t, 0, MinimumBitsToStore(1U << inst_flags::FLAGS_COUNT)>;
1694     using FieldType = FieldFlags::NextField<DataType::Type, MinimumBitsToStore(DataType::LAST)>;
1695     using InputsCount = FieldType::NextField<uint32_t, BITS_PER_INPUTS_NUM>;
1696     using LastField = InputsCount;
1697 
GetDynamicOperands()1698     DynamicOperands *GetDynamicOperands() const
1699     {
1700         return reinterpret_cast<DynamicOperands *>(reinterpret_cast<uintptr_t>(this) - sizeof(DynamicOperands));
1701     }
1702 
1703 private:
1704     template <typename InstType, typename... Args>
1705     static InstType *ConstructInst(InstType *ptr, ArenaAllocator *allocator, Args &&...args);
1706 
GetUser(unsigned index)1707     User *GetUser(unsigned index)
1708     {
1709         if (UNLIKELY(IsOperandsDynamic())) {
1710             return GetDynamicOperands()->GetUser(index);
1711         }
1712         auto inputsCount {GetField<InputsCount>()};
1713         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1714         return reinterpret_cast<User *>(reinterpret_cast<Input *>(this) -
1715                                         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1716                                         (inputsCount + Input::GetPadding(RUNTIME_ARCH, inputsCount))) -
1717                // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1718                index - 1;  // CC-OFF(G.FMT.02) project code style
1719     }
1720 
OperandsStorageSize()1721     size_t OperandsStorageSize() const
1722     {
1723         if (UNLIKELY(IsOperandsDynamic())) {
1724             return sizeof(DynamicOperands);
1725         }
1726 
1727         auto inputsCount {GetField<InputsCount>()};
1728         return inputsCount * (sizeof(Input) + sizeof(User)) +
1729                Input::GetPadding(RUNTIME_ARCH, inputsCount) * sizeof(Input);
1730     }
1731 
1732 private:
1733     /// Basic block this instruction belongs to
1734     BasicBlock *bb_ {nullptr};
1735 
1736 #ifdef PANDA_COMPILER_DEBUG_INFO
1737     InstDebugInfo *debugInfo_ {nullptr};
1738     RuntimeInterface::MethodPtr currentMethod_ {nullptr};
1739 #endif
1740 
1741     /// Next instruction within basic block
1742     Inst *next_ {nullptr};
1743 
1744     /// Previous instruction within basic block
1745     Inst *prev_ {nullptr};
1746 
1747     /// First user in users chain
1748     User *firstUser_ {nullptr};
1749 
1750     /// This value hold properties of the instruction. It accessed via BitField types(f.e. FieldType).
1751     uint64_t bitFields_ {0};
1752 
1753     /// Unique id of instruction
1754     uint32_t id_ {INVALID_ID};
1755 
1756     /// Unique id of instruction
1757     uint32_t vn_ {INVALID_VN};
1758 
1759     /// Bytecode pc
1760     uint32_t pc_ {INVALID_PC};
1761 
1762     /// Number used in cloning
1763     uint32_t cloneNumber_ {INVALID_ID};
1764 
1765     /// Instruction number getting while visiting graph
1766     LinearNumber linearNumber_ {INVALID_LINEAR_NUM};
1767 
1768     ObjectTypeInfo objectTypeInfo_ {};
1769 
1770     /// Opcode, see opcodes.def
1771     Opcode opcode_ {Opcode::INVALID};
1772 
1773     // Destination register type - defined in FieldType
1774     Register dstReg_ {GetInvalidReg()};
1775 };
1776 
1777 /**
1778  * Proxy class that injects new field - type of the source operands - into property field of the instruction.
1779  * Should be used when instruction has sources of the same type and type of the instruction is not match to type of
1780  * sources. Examples: Cmp, Compare
1781  * @tparam T Base instruction class after which this mixin is injected
1782  */
1783 template <typename T>
1784 class InstWithOperandsType : public T {
1785 public:
1786     using T::T;
1787 
SetOperandsType(DataType::Type type)1788     void SetOperandsType(DataType::Type type)
1789     {
1790         T::template SetField<FieldOperandsType>(type);
1791     }
GetOperandsType()1792     virtual DataType::Type GetOperandsType() const
1793     {
1794         return T::template GetField<FieldOperandsType>();
1795     }
1796 
1797 protected:
1798     using FieldOperandsType =
1799         typename T::LastField::template NextField<DataType::Type, MinimumBitsToStore(DataType::LAST)>;
1800     using LastField = FieldOperandsType;
1801 };
1802 
1803 /**
1804  * Mixin for NeedBarrier flag.
1805  * @tparam T Base instruction class after which this mixin is injected
1806  */
1807 template <typename T>
1808 class NeedBarrierMixin : public T {
1809 public:
1810     using T::T;
1811 
SetNeedBarrier(bool v)1812     void SetNeedBarrier(bool v)
1813     {
1814         T::template SetField<NeedBarrierFlag>(v);
1815     }
GetNeedBarrier()1816     bool GetNeedBarrier() const
1817     {
1818         return T::template GetField<NeedBarrierFlag>();
1819     }
1820 
1821 protected:
1822     using NeedBarrierFlag = typename T::LastField::NextFlag;
1823     using LastField = NeedBarrierFlag;
1824 };
1825 
1826 enum class DynObjectAccessType {
1827     UNKNOWN = 0,  // corresponds by value semantic
1828     BY_NAME = 1,
1829     BY_INDEX = 2,
1830     LAST = BY_INDEX
1831 };
1832 
1833 enum class DynObjectAccessMode {
1834     UNKNOWN = 0,
1835     DICTIONARY = 1,
1836     ARRAY = 2,
1837     LAST = ARRAY,
1838 };
1839 
1840 /**
1841  * Mixin for dynamic object access properties.
1842  * @tparam T Base instruction class after which this mixin is injected
1843  */
1844 template <typename T>
1845 class DynObjectAccessMixin : public T {
1846 public:
1847     using T::T;
1848     using Type = DynObjectAccessType;
1849     using Mode = DynObjectAccessMode;
1850 
SetAccessType(Type type)1851     void SetAccessType(Type type)
1852     {
1853         T::template SetField<AccessType>(type);
1854     }
1855 
GetAccessType()1856     Type GetAccessType() const
1857     {
1858         return T::template GetField<AccessType>();
1859     }
1860 
SetAccessMode(Mode mode)1861     void SetAccessMode(Mode mode)
1862     {
1863         T::template SetField<AccessMode>(mode);
1864     }
1865 
GetAccessMode()1866     Mode GetAccessMode() const
1867     {
1868         return T::template GetField<AccessMode>();
1869     }
1870 
1871 protected:
1872     using AccessType = typename T::LastField::template NextField<Type, MinimumBitsToStore(Type::LAST)>;
1873     using AccessMode = typename AccessType::template NextField<Mode, MinimumBitsToStore(Mode::LAST)>;
1874     using LastField = AccessMode;
1875 };
1876 
1877 enum ObjectType {
1878     MEM_OBJECT = 0,
1879     MEM_STATIC,
1880     MEM_DYN_GLOBAL,
1881     MEM_DYN_INLINED,
1882     MEM_DYN_PROPS,
1883     MEM_DYN_ELEMENTS,
1884     MEM_DYN_CLASS,
1885     MEM_DYN_HCLASS,
1886     MEM_DYN_METHOD,
1887     MEM_DYN_PROTO_HOLDER,
1888     MEM_DYN_PROTO_CELL,
1889     MEM_DYN_CHANGE_FIELD,
1890     MEM_DYN_ARRAY_LENGTH,
1891     LAST = MEM_DYN_ARRAY_LENGTH
1892 };
1893 
ObjectTypeToString(ObjectType objType)1894 inline const char *ObjectTypeToString(ObjectType objType)
1895 {
1896     static constexpr auto COUNT = static_cast<uint8_t>(ObjectType::LAST) + 1;
1897     static constexpr std::array<const char *, COUNT> OBJ_TYPE_NAMES = {
1898         "Object", "Static", "GlobalVar",        "Dynamic inlined", "Properties",     "Elements", "Class",
1899         "Hclass", "Method", "Prototype holder", "Prototype cell",  "IsChangeFieald", "Length"};
1900     auto idx = static_cast<uint8_t>(objType);
1901     ASSERT(idx <= LAST);
1902     return OBJ_TYPE_NAMES[idx];
1903 }
1904 
1905 /// This mixin aims to implement type id accessors.
1906 class TypeIdMixin {
1907 public:
1908     static constexpr uint32_t INVALID_ID = std::numeric_limits<uint32_t>::max();
1909     static constexpr uint32_t MEM_PROMISE_CLASS_ID = RuntimeInterface::MEM_PROMISE_CLASS_ID;
1910     static constexpr uint32_t MEM_DYN_CLASS_ID = MEM_PROMISE_CLASS_ID - ObjectType::MEM_DYN_CLASS;
1911     static constexpr uint32_t MEM_DYN_HCLASS_ID = MEM_PROMISE_CLASS_ID - ObjectType::MEM_DYN_HCLASS;
1912     static constexpr uint32_t MEM_DYN_METHOD_ID = MEM_PROMISE_CLASS_ID - ObjectType::MEM_DYN_METHOD;
1913     static constexpr uint32_t MEM_DYN_PROTO_HOLDER_ID = MEM_PROMISE_CLASS_ID - ObjectType::MEM_DYN_PROTO_HOLDER;
1914     static constexpr uint32_t MEM_DYN_PROTO_CELL_ID = MEM_PROMISE_CLASS_ID - ObjectType::MEM_DYN_PROTO_CELL;
1915     static constexpr uint32_t MEM_DYN_CHANGE_FIELD_ID = MEM_PROMISE_CLASS_ID - ObjectType::MEM_DYN_CHANGE_FIELD;
1916     static constexpr uint32_t MEM_DYN_GLOBAL_ID = MEM_PROMISE_CLASS_ID - ObjectType::MEM_DYN_GLOBAL;
1917     static constexpr uint32_t MEM_DYN_PROPS_ID = MEM_PROMISE_CLASS_ID - ObjectType::MEM_DYN_PROPS;
1918     static constexpr uint32_t MEM_DYN_ELEMENTS_ID = MEM_PROMISE_CLASS_ID - ObjectType::MEM_DYN_ELEMENTS;
1919     static constexpr uint32_t MEM_DYN_ARRAY_LENGTH_ID = MEM_PROMISE_CLASS_ID - ObjectType::MEM_DYN_ARRAY_LENGTH;
1920 
TypeIdMixin(uint32_t typeId,RuntimeInterface::MethodPtr method)1921     TypeIdMixin(uint32_t typeId, RuntimeInterface::MethodPtr method) : typeId_(typeId), method_(method) {}
1922 
1923     TypeIdMixin() = default;
1924     DEFAULT_COPY_SEMANTIC(TypeIdMixin);
1925     DEFAULT_MOVE_SEMANTIC(TypeIdMixin);
1926     virtual ~TypeIdMixin() = default;
1927 
SetTypeId(uint32_t id)1928     void SetTypeId(uint32_t id)
1929     {
1930         typeId_ = id;
1931     }
1932 
GetTypeId()1933     auto GetTypeId() const
1934     {
1935         return typeId_;
1936     }
1937 
SetMethod(RuntimeInterface::MethodPtr method)1938     void SetMethod(RuntimeInterface::MethodPtr method)
1939     {
1940         method_ = method;
1941     }
GetMethod()1942     auto GetMethod() const
1943     {
1944         return method_;
1945     }
1946 
1947 private:
1948     uint32_t typeId_ {0};
1949     // The pointer to the method in which this instruction is executed(inlined method)
1950     RuntimeInterface::MethodPtr method_ {nullptr};
1951 };
1952 
1953 /// This mixin aims to implement two type id accessors.
1954 class TypeIdMixin2 : public TypeIdMixin {
1955     using Base = TypeIdMixin;
1956     using Base::Base;
1957 
1958 public:
TypeIdMixin2(uint32_t typeId0,uint32_t typeId1,RuntimeInterface::MethodPtr method)1959     TypeIdMixin2(uint32_t typeId0, uint32_t typeId1, RuntimeInterface::MethodPtr method)
1960         : TypeIdMixin(typeId1, method), typeId0_(typeId0)
1961     {
1962     }
1963 
1964     TypeIdMixin2() = default;
1965     NO_COPY_SEMANTIC(TypeIdMixin2);
1966     NO_MOVE_SEMANTIC(TypeIdMixin2);
1967     ~TypeIdMixin2() override = default;
1968 
SetTypeId0(uint32_t id)1969     void SetTypeId0(uint32_t id)
1970     {
1971         typeId0_ = id;
1972     }
GetTypeId0()1973     auto GetTypeId0() const
1974     {
1975         return typeId0_;
1976     }
SetTypeId1(uint32_t id)1977     void SetTypeId1(uint32_t id)
1978     {
1979         SetTypeId(id);
1980     }
GetTypeId1()1981     auto GetTypeId1() const
1982     {
1983         return GetTypeId();
1984     }
1985 
1986 private:
1987     uint32_t typeId0_ {0};
1988 };
1989 
1990 /// This mixin aims to implement type of klass.
1991 template <typename T>
1992 class ClassTypeMixin : public T {
1993 public:
1994     using T::T;
1995 
SetClassType(ClassType classType)1996     void SetClassType(ClassType classType)
1997     {
1998         T::template SetField<ClassTypeField>(classType);
1999     }
2000 
GetClassType()2001     ClassType GetClassType() const
2002     {
2003         return T::template GetField<ClassTypeField>();
2004     }
2005 
2006 protected:
2007     using ClassTypeField = typename T::LastField::template NextField<ClassType, MinimumBitsToStore(ClassType::COUNT)>;
2008     using LastField = ClassTypeField;
2009 };
2010 
2011 /// Mixin to check if null check inside CheckCast and IsInstance can be omitted.
2012 template <typename T>
2013 class OmitNullCheckMixin : public T {
2014 public:
2015     using T::T;
2016 
SetOmitNullCheck(bool omitNullCheck)2017     void SetOmitNullCheck(bool omitNullCheck)
2018     {
2019         T::template SetField<OmitNullCheckFlag>(omitNullCheck);
2020     }
2021 
GetOmitNullCheck()2022     bool GetOmitNullCheck() const
2023     {
2024         return T::template GetField<OmitNullCheckFlag>();
2025     }
2026 
2027 protected:
2028     using OmitNullCheckFlag = typename T::LastField::NextFlag;
2029     using LastField = OmitNullCheckFlag;
2030 };
2031 
2032 template <typename T>
2033 class ScaleMixin : public T {
2034 public:
2035     using T::T;
2036 
SetScale(uint32_t scale)2037     void SetScale(uint32_t scale)
2038     {
2039         T::template SetField<ScaleField>(scale);
2040     }
2041 
GetScale()2042     uint32_t GetScale() const
2043     {
2044         return T::template GetField<ScaleField>();
2045     }
2046 
2047 protected:
2048     using ScaleField = typename T::LastField::template NextField<uint32_t, MinimumBitsToStore(MAX_SCALE)>;
2049     using LastField = ScaleField;
2050 };
2051 
2052 template <typename T>
2053 class ObjectTypeMixin : public T {
2054 public:
2055     using T::T;
2056 
SetObjectType(ObjectType type)2057     void SetObjectType(ObjectType type)
2058     {
2059         T::template SetField<ObjectTypeField>(type);
2060     }
2061 
GetObjectType()2062     ObjectType GetObjectType() const
2063     {
2064         return T::template GetField<ObjectTypeField>();
2065     }
2066 
2067 protected:
2068     using ObjectTypeField = typename T::LastField::template NextField<ObjectType, MinimumBitsToStore(ObjectType::LAST)>;
2069     using LastField = ObjectTypeField;
2070 };
2071 
2072 /// This mixin aims to implement field accessors.
2073 class FieldMixin {
2074 public:
FieldMixin(RuntimeInterface::FieldPtr field)2075     explicit FieldMixin(RuntimeInterface::FieldPtr field) : field_(field) {}
2076 
2077     FieldMixin() = default;
2078     NO_COPY_SEMANTIC(FieldMixin);
2079     NO_MOVE_SEMANTIC(FieldMixin);
2080     virtual ~FieldMixin() = default;
2081 
SetObjField(RuntimeInterface::FieldPtr field)2082     void SetObjField(RuntimeInterface::FieldPtr field)
2083     {
2084         field_ = field;
2085     }
GetObjField()2086     auto GetObjField() const
2087     {
2088         return field_;
2089     }
2090 
2091 private:
2092     RuntimeInterface::FieldPtr field_ {nullptr};
2093 };
2094 
2095 /// This mixin aims to implement 2 field accessors.
2096 class FieldMixin2 {
2097 public:
FieldMixin2(RuntimeInterface::FieldPtr field0,RuntimeInterface::FieldPtr field1)2098     explicit FieldMixin2(RuntimeInterface::FieldPtr field0, RuntimeInterface::FieldPtr field1)
2099         : field0_(field0), field1_(field1)
2100     {
2101     }
2102 
2103     FieldMixin2() = default;
2104     NO_COPY_SEMANTIC(FieldMixin2);
2105     NO_MOVE_SEMANTIC(FieldMixin2);
2106     virtual ~FieldMixin2() = default;
2107 
SetObjField0(RuntimeInterface::FieldPtr field)2108     void SetObjField0(RuntimeInterface::FieldPtr field)
2109     {
2110         field0_ = field;
2111     }
GetObjField0()2112     auto GetObjField0() const
2113     {
2114         return field0_;
2115     }
SetObjField1(RuntimeInterface::FieldPtr field)2116     void SetObjField1(RuntimeInterface::FieldPtr field)
2117     {
2118         field1_ = field;
2119     }
GetObjField1()2120     auto GetObjField1() const
2121     {
2122         return field1_;
2123     }
2124 
2125 private:
2126     RuntimeInterface::FieldPtr field0_ {nullptr};
2127     RuntimeInterface::FieldPtr field1_ {nullptr};
2128 };
2129 
2130 /// This mixin aims to implement volatile accessors.
2131 template <typename T>
2132 class VolatileMixin : public T {
2133 public:
2134     using T::T;
2135 
SetVolatile(bool isVolatile)2136     void SetVolatile(bool isVolatile)
2137     {
2138         T::template SetField<IsVolatileFlag>(isVolatile);
2139     }
GetVolatile()2140     bool GetVolatile() const
2141     {
2142         return T::template GetField<IsVolatileFlag>();
2143     }
2144 
2145 protected:
2146     using IsVolatileFlag = typename T::LastField::NextFlag;
2147     using LastField = IsVolatileFlag;
2148 };
2149 /// Mixin for Inlined calls/returns.
2150 template <typename T>
2151 class InlinedInstMixin : public T {
2152 public:
2153     using T::T;
2154 
SetInlined(bool v)2155     void SetInlined(bool v)
2156     {
2157         T::template SetField<IsInlinedFlag>(v);
2158     }
IsInlined()2159     bool IsInlined() const
2160     {
2161         return T::template GetField<IsInlinedFlag>();
2162     }
2163 
2164 protected:
2165     using IsInlinedFlag = typename T::LastField::NextFlag;
2166     using LastField = IsInlinedFlag;
2167 };
2168 
2169 /// Mixin for Array/String instruction
2170 template <typename T>
2171 class ArrayInstMixin : public T {
2172 public:
2173     using T::T;
2174 
SetIsArray(bool v)2175     void SetIsArray(bool v)
2176     {
2177         T::template SetField<IsStringFlag>(!v);
2178     }
2179 
SetIsString(bool v)2180     void SetIsString(bool v)
2181     {
2182         T::template SetField<IsStringFlag>(v);
2183     }
2184 
IsArray()2185     bool IsArray() const
2186     {
2187         return !(T::template GetField<IsStringFlag>());
2188     }
2189 
IsString()2190     bool IsString() const
2191     {
2192         return T::template GetField<IsStringFlag>();
2193     }
2194 
2195 protected:
2196     using IsStringFlag = typename T::LastField::NextFlag;
2197     using LastField = IsStringFlag;
2198 };
2199 
2200 /// Mixin for instructions with immediate constant value
2201 class ImmediateMixin {
2202 public:
ImmediateMixin(uint64_t immediate)2203     explicit ImmediateMixin(uint64_t immediate) : immediate_(immediate) {}
2204 
2205     NO_COPY_SEMANTIC(ImmediateMixin);
2206     NO_MOVE_SEMANTIC(ImmediateMixin);
2207     virtual ~ImmediateMixin() = default;
2208 
SetImm(uint64_t immediate)2209     void SetImm(uint64_t immediate)
2210     {
2211         immediate_ = immediate;
2212     }
GetImm()2213     auto GetImm() const
2214     {
2215         return immediate_;
2216     }
2217 
2218 protected:
2219     ImmediateMixin() = default;
2220 
2221 private:
2222     uint64_t immediate_ {0};
2223 };
2224 
2225 /// Mixin for instructions with ConditionCode
2226 template <typename T>
2227 class ConditionMixin : public T {
2228 public:
2229     enum class Prediction { NONE = 0, LIKELY, UNLIKELY, SIZE = UNLIKELY };
2230 
2231     using T::T;
ConditionMixin(ConditionCode cc)2232     explicit ConditionMixin(ConditionCode cc)
2233     {
2234         T::template SetField<CcFlag>(cc);
2235     }
2236     NO_COPY_SEMANTIC(ConditionMixin);
2237     NO_MOVE_SEMANTIC(ConditionMixin);
2238     ~ConditionMixin() override = default;
2239 
GetCc()2240     auto GetCc() const
2241     {
2242         return T::template GetField<CcFlag>();
2243     }
SetCc(ConditionCode cc)2244     void SetCc(ConditionCode cc)
2245     {
2246         T::template SetField<CcFlag>(cc);
2247     }
InverseConditionCode()2248     void InverseConditionCode()
2249     {
2250         SetCc(GetInverseConditionCode(GetCc()));
2251         if (IsLikely()) {
2252             SetUnlikely();
2253         } else if (IsUnlikely()) {
2254             SetLikely();
2255         }
2256     }
2257 
IsLikely()2258     bool IsLikely() const
2259     {
2260         return T::template GetField<PredictionFlag>() == Prediction::LIKELY;
2261     }
IsUnlikely()2262     bool IsUnlikely() const
2263     {
2264         return T::template GetField<PredictionFlag>() == Prediction::UNLIKELY;
2265     }
SetLikely()2266     void SetLikely()
2267     {
2268         T::template SetField<PredictionFlag>(Prediction::LIKELY);
2269     }
SetUnlikely()2270     void SetUnlikely()
2271     {
2272         T::template SetField<PredictionFlag>(Prediction::UNLIKELY);
2273     }
2274 
2275 protected:
2276     ConditionMixin() = default;
2277 
2278     using CcFlag = typename T::LastField::template NextField<ConditionCode, MinimumBitsToStore(ConditionCode::CC_LAST)>;
2279     using PredictionFlag = typename CcFlag::template NextField<Prediction, MinimumBitsToStore(Prediction::SIZE)>;
2280     using LastField = PredictionFlag;
2281 };
2282 
2283 /// Mixin for instrucion with ShiftType
2284 class ShiftTypeMixin {
2285 public:
ShiftTypeMixin(ShiftType shiftType)2286     explicit ShiftTypeMixin(ShiftType shiftType) : shiftType_(shiftType) {}
2287     NO_COPY_SEMANTIC(ShiftTypeMixin);
2288     NO_MOVE_SEMANTIC(ShiftTypeMixin);
2289     virtual ~ShiftTypeMixin() = default;
2290 
SetShiftType(ShiftType shiftType)2291     void SetShiftType(ShiftType shiftType)
2292     {
2293         shiftType_ = shiftType;
2294     }
2295 
GetShiftType()2296     ShiftType GetShiftType() const
2297     {
2298         return shiftType_;
2299     }
2300 
2301 protected:
2302     ShiftTypeMixin() = default;
2303 
2304 private:
2305     ShiftType shiftType_ {INVALID_SHIFT};
2306 };
2307 
2308 /// Mixin for instructions with multiple return values
2309 template <typename T, size_t N>
2310 class MultipleOutputMixin : public T {
2311 public:
2312     using T::T;
2313 
GetDstReg(unsigned index)2314     Register GetDstReg(unsigned index) const override
2315     {
2316         ASSERT(index < N);
2317         if (index == 0) {
2318             return T::GetDstReg();
2319         }
2320         return dstRegs_[index - 1];
2321     }
2322 
GetDstLocation(unsigned index)2323     Location GetDstLocation(unsigned index) const override
2324     {
2325         ASSERT(index < N);
2326         if (index == 0) {
2327             return Location::MakeRegister(T::GetDstReg());
2328         }
2329         return Location::MakeRegister(dstRegs_[index - 1]);
2330     }
2331 
SetDstReg(unsigned index,Register reg)2332     void SetDstReg(unsigned index, Register reg) override
2333     {
2334         ASSERT(index < N);
2335         if (index == 0) {
2336             T::SetDstReg(reg);
2337         } else {
2338             dstRegs_[index - 1] = reg;
2339         }
2340     }
2341 
GetDstCount()2342     size_t GetDstCount() const override
2343     {
2344         return N;
2345     }
2346 
2347 private:
2348     std::array<Register, N - 1> dstRegs_;
2349 };
2350 
2351 /**
2352  * Instruction with fixed number of inputs.
2353  * Shall not be instantiated directly, only through derived classes.
2354  */
2355 template <size_t N>
2356 class FixedInputsInst : public Inst {
2357 public:
2358     using Inst::Inst;
2359 
2360     static constexpr int INPUT_COUNT = N;
2361 
2362     using InputsArray = std::array<Inst *, INPUT_COUNT>;
2363     struct Initializer {
2364         Inst::Initializer base;
2365         InputsArray inputs;
2366     };
2367 
FixedInputsInst(Initializer t)2368     explicit FixedInputsInst(Initializer t) : Inst(t.base)
2369     {
2370         SetField<InputsCount>(INPUT_COUNT);
2371         for (size_t i = 0; i < t.inputs.size(); i++) {
2372             SetInput(i, t.inputs[i]);
2373         }
2374     }
2375 
2376     template <typename... Inputs, typename = Inst::CheckBase<Inputs...>>
FixedInputsInst(Inst::Initializer t,Inputs...inputs)2377     explicit FixedInputsInst(Inst::Initializer t, Inputs... inputs) : FixedInputsInst(Initializer {t, {inputs...}})
2378     {
2379     }
2380 
FixedInputsInst(Opcode opcode)2381     explicit FixedInputsInst(Opcode opcode) : Inst(opcode)
2382     {
2383         SetField<InputsCount>(INPUT_COUNT);
2384     }
FixedInputsInst(Opcode opcode,DataType::Type type)2385     FixedInputsInst(Opcode opcode, DataType::Type type) : FixedInputsInst({opcode, type, INVALID_PC}) {}
2386 
SetSrcReg(unsigned index,Register reg)2387     void SetSrcReg(unsigned index, Register reg) override
2388     {
2389         ASSERT(index < N);
2390         srcRegs_[index] = reg;
2391     }
2392 
GetSrcReg(unsigned index)2393     Register GetSrcReg(unsigned index) const override
2394     {
2395         ASSERT(index < N);
2396         return srcRegs_[index];
2397     }
2398 
GetLocation(size_t index)2399     Location GetLocation(size_t index) const override
2400     {
2401         return Location::MakeRegister(GetSrcReg(index), GetInputType(index));
2402     }
2403 
SetLocation(size_t index,Location location)2404     void SetLocation(size_t index, Location location) override
2405     {
2406         SetSrcReg(index, location.GetValue());
2407     }
2408 
SetDstLocation(Location location)2409     void SetDstLocation(Location location)
2410     {
2411         SetDstReg(location.GetValue());
2412     }
2413 
SetTmpLocation(Location location)2414     void SetTmpLocation(Location location) override
2415     {
2416         tmpLocation_ = location;
2417     }
2418 
GetTmpLocation()2419     Location GetTmpLocation() const override
2420     {
2421         return tmpLocation_;
2422     }
2423 
2424     PANDA_PUBLIC_API Inst *Clone(const Graph *targetGraph) const override;
2425 
2426 private:
2427     template <typename T, std::size_t... IS>
CreateArray(T value,std::index_sequence<IS...> unused)2428     constexpr auto CreateArray(T value, [[maybe_unused]] std::index_sequence<IS...> unused)
2429     {
2430         return std::array<T, sizeof...(IS)> {(static_cast<void>(IS), value)...};
2431     }
2432 
2433 private:
2434     std::array<Register, N> srcRegs_ = CreateArray(GetInvalidReg(), std::make_index_sequence<INPUT_COUNT>());
2435     Location tmpLocation_ {};
2436 };
2437 
2438 using FixedInputsInst0 = FixedInputsInst<0>;
2439 using FixedInputsInst1 = FixedInputsInst<1>;
2440 using FixedInputsInst2 = FixedInputsInst<2U>;
2441 using FixedInputsInst3 = FixedInputsInst<3U>;
2442 using FixedInputsInst4 = FixedInputsInst<4U>;
2443 
2444 /// Instruction with variable inputs count
2445 class DynamicInputsInst : public Inst {
2446 public:
2447     using Inst::Inst;
2448 
2449     static constexpr int INPUT_COUNT = MAX_STATIC_INPUTS;
2450 
GetLocation(size_t index)2451     Location GetLocation(size_t index) const override
2452     {
2453         if (locations_ == nullptr) {
2454             return Location::Invalid();
2455         }
2456         return locations_->GetLocation(index);
2457     }
2458 
GetDstLocation()2459     Location GetDstLocation() const override
2460     {
2461         if (locations_ == nullptr) {
2462             return Location::Invalid();
2463         }
2464         return locations_->GetDstLocation();
2465     }
2466 
GetTmpLocation()2467     Location GetTmpLocation() const override
2468     {
2469         if (locations_ == nullptr) {
2470             return Location::Invalid();
2471         }
2472         return locations_->GetTmpLocation();
2473     }
2474 
SetLocation(size_t index,Location location)2475     void SetLocation(size_t index, Location location) override
2476     {
2477         ASSERT(locations_ != nullptr);
2478         locations_->SetLocation(index, location);
2479     }
2480 
SetDstLocation(Location location)2481     void SetDstLocation(Location location)
2482     {
2483         ASSERT(locations_ != nullptr);
2484         locations_->SetDstLocation(location);
2485     }
2486 
SetTmpLocation(Location location)2487     void SetTmpLocation(Location location) override
2488     {
2489         ASSERT(locations_ != nullptr);
2490         locations_->SetTmpLocation(location);
2491     }
2492 
SetLocationsInfo(LocationsInfo * info)2493     void SetLocationsInfo(LocationsInfo *info)
2494     {
2495         locations_ = info;
2496     }
2497 
GetSrcReg(unsigned index)2498     Register GetSrcReg(unsigned index) const override
2499     {
2500         return GetLocation(index).GetValue();
2501     }
2502 
SetSrcReg(unsigned index,Register reg)2503     void SetSrcReg(unsigned index, Register reg) override
2504     {
2505         SetLocation(index, Location::MakeRegister(reg, GetInputType(index)));
2506     }
2507 
2508 private:
2509     LocationsInfo *locations_ {nullptr};
2510 };
2511 
2512 /// Unary operation instruction
2513 class PANDA_PUBLIC_API UnaryOperation : public FixedInputsInst<1> {
2514 public:
2515     using FixedInputsInst::FixedInputsInst;
2516 
GetInputType(size_t index)2517     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
2518     {
2519         ASSERT(index < GetInputsCount());
2520         if (GetOpcode() == Opcode::Cast) {
2521             return GetInput(0).GetInst()->GetType();
2522         }
2523         return GetType();
2524     }
2525 
IsSafeInst()2526     bool IsSafeInst() const override
2527     {
2528         return true;
2529     }
2530 
2531     PANDA_PUBLIC_API void SetVnObject(VnObject *vnObj) override;
2532 
2533     Inst *Evaluate();
2534 };
2535 
2536 /// Binary operation instruction
2537 class BinaryOperation : public FixedInputsInst<2U> {
2538 public:
2539     using FixedInputsInst::FixedInputsInst;
2540 
Latency()2541     uint32_t Latency() const override
2542     {
2543         if (GetOpcode() == Opcode::Div) {
2544             return g_options.GetCompilerSchedLatencyLong();
2545         }
2546         return g_options.GetCompilerSchedLatency();
2547     }
2548 
IsSafeInst()2549     bool IsSafeInst() const override
2550     {
2551         return true;
2552     }
2553 
IsBinaryInst()2554     bool IsBinaryInst() const override
2555     {
2556         return true;
2557     }
2558 
2559     Inst *Evaluate();
2560 
GetInputType(size_t index)2561     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
2562     {
2563         ASSERT(index < GetInputsCount());
2564         auto inputType = GetInput(index).GetInst()->GetType();
2565         auto type = GetType();
2566         if (GetOpcode() == Opcode::Sub && !DataType::IsTypeSigned(type)) {
2567             ASSERT(GetCommonType(inputType) == GetCommonType(type) || inputType == DataType::POINTER ||
2568                    DataType::GetCommonType(inputType) == DataType::INT64);
2569             return inputType;
2570         }
2571         if (GetOpcode() == Opcode::Add && type == DataType::POINTER) {
2572             ASSERT(GetCommonType(inputType) == GetCommonType(type) ||
2573                    DataType::GetCommonType(inputType) == DataType::INT64);
2574             return inputType;
2575         }
2576         return GetType();
2577     }
2578 };
2579 
2580 /// Binary operation instruction with c immidiate
2581 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
2582 class PANDA_PUBLIC_API BinaryImmOperation : public FixedInputsInst<1>, public ImmediateMixin {
2583 public:
2584     using FixedInputsInst::FixedInputsInst;
2585 
BinaryImmOperation(Initializer t,uint64_t imm)2586     BinaryImmOperation(Initializer t, uint64_t imm) : FixedInputsInst(std::move(t)), ImmediateMixin(imm) {}
2587 
GetInputType(size_t index)2588     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
2589     {
2590         ASSERT(index < GetInputsCount());
2591         auto inputType = GetInput(index).GetInst()->GetType();
2592         auto type = GetType();
2593         if (GetOpcode() == Opcode::SubI && !DataType::IsTypeSigned(type)) {
2594             ASSERT(GetCommonType(inputType) == GetCommonType(type) || inputType == DataType::POINTER);
2595             return inputType;
2596         }
2597         if (GetOpcode() == Opcode::AddI && type == DataType::POINTER) {
2598             ASSERT(DataType::GetCommonType(inputType) == DataType::GetCommonType(GetType()) ||
2599                    (inputType == DataType::REFERENCE && GetType() == DataType::POINTER));
2600             return inputType;
2601         }
2602         return GetType();
2603     }
2604 
2605     PANDA_PUBLIC_API void SetVnObject(VnObject *vnObj) override;
2606     PANDA_PUBLIC_API bool DumpInputs(std::ostream *out) const override;
2607 
IsSafeInst()2608     bool IsSafeInst() const override
2609     {
2610         return true;
2611     }
2612 
IsBinaryImmInst()2613     bool IsBinaryImmInst() const override
2614     {
2615         return true;
2616     }
2617 
Clone(const Graph * targetGraph)2618     Inst *Clone(const Graph *targetGraph) const override
2619     {
2620         auto clone = FixedInputsInst::Clone(targetGraph);
2621         static_cast<BinaryImmOperation *>(clone)->SetImm(GetImm());
2622         return clone;
2623     }
2624 };
2625 
2626 /// Unary operation that shifts its own operand prior the application.
2627 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
2628 class PANDA_PUBLIC_API UnaryShiftedRegisterOperation : public FixedInputsInst<1>,
2629                                                        public ImmediateMixin,
2630                                                        public ShiftTypeMixin {
2631 public:
2632     using FixedInputsInst::FixedInputsInst;
2633 
UnaryShiftedRegisterOperation(Initializer t,uint64_t imm,ShiftType shiftType)2634     UnaryShiftedRegisterOperation(Initializer t, uint64_t imm, ShiftType shiftType)
2635         : FixedInputsInst(std::move(t)), ImmediateMixin(imm), ShiftTypeMixin(shiftType)
2636     {
2637     }
2638 
GetInputType(size_t index)2639     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
2640     {
2641         ASSERT(index < GetInputsCount());
2642         return GetType();
2643     }
2644 
2645     PANDA_PUBLIC_API void SetVnObject(VnObject *vnObj) override;
2646     PANDA_PUBLIC_API bool DumpInputs(std::ostream *out) const override;
2647     Inst *Clone(const Graph *targetGraph) const override;
2648 };
2649 
2650 /// Binary operation that shifts its second operand prior the application.
2651 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
2652 class PANDA_PUBLIC_API BinaryShiftedRegisterOperation : public FixedInputsInst<2U>,
2653                                                         public ImmediateMixin,
2654                                                         public ShiftTypeMixin {
2655 public:
2656     using FixedInputsInst::FixedInputsInst;
2657 
BinaryShiftedRegisterOperation(Initializer t,uint64_t imm,ShiftType shiftType)2658     BinaryShiftedRegisterOperation(Initializer t, uint64_t imm, ShiftType shiftType)
2659         : FixedInputsInst(std::move(t)), ImmediateMixin(imm), ShiftTypeMixin(shiftType)
2660     {
2661     }
2662 
GetInputType(size_t index)2663     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
2664     {
2665         ASSERT(index < GetInputsCount());
2666         return GetType();
2667     }
2668 
2669     PANDA_PUBLIC_API bool DumpInputs(std::ostream *out) const override;
2670     PANDA_PUBLIC_API void SetVnObject(VnObject *vnObj) override;
2671     PANDA_PUBLIC_API Inst *Clone(const Graph *targetGraph) const override;
2672 };
2673 
2674 class SpillFillInst;
2675 
2676 /// Mixin to hold location data
2677 class LocationDataMixin {
2678 public:
SetLocationData(SpillFillData locationData)2679     void SetLocationData(SpillFillData locationData)
2680     {
2681         locationData_ = locationData;
2682     }
2683 
GetLocationData()2684     auto GetLocationData() const
2685     {
2686         return locationData_;
2687     }
2688 
GetLocationData()2689     auto &GetLocationData()
2690     {
2691         return locationData_;
2692     }
2693 
2694 protected:
2695     LocationDataMixin() = default;
2696     NO_COPY_SEMANTIC(LocationDataMixin);
2697     NO_MOVE_SEMANTIC(LocationDataMixin);
2698     virtual ~LocationDataMixin() = default;
2699 
2700 private:
2701     SpillFillData locationData_ {};
2702 };
2703 
2704 /// Mixin to hold input types of call instruction
2705 template <typename T>
2706 class InputTypesMixin : public T {
2707 public:
2708     using Base = T;
2709     using Base::AppendInput;
2710     using Base::Base;
2711 
AllocateInputTypes(ArenaAllocator * allocator,size_t capacity)2712     void AllocateInputTypes(ArenaAllocator *allocator, size_t capacity)
2713     {
2714         ASSERT(allocator != nullptr);
2715         ASSERT(inputTypes_ == nullptr);
2716         inputTypes_ = allocator->New<ArenaVector<DataType::Type>>(allocator->Adapter());
2717         ASSERT(inputTypes_ != nullptr);
2718         inputTypes_->reserve(capacity);
2719         ASSERT(inputTypes_->capacity() >= capacity);
2720     }
AddInputType(DataType::Type type)2721     void AddInputType(DataType::Type type)
2722     {
2723         ASSERT(inputTypes_ != nullptr);
2724         inputTypes_->push_back(type);
2725     }
SetInputType(unsigned index,DataType::Type type)2726     void SetInputType(unsigned index, DataType::Type type)
2727     {
2728         ASSERT(inputTypes_ != nullptr);
2729         (*inputTypes_)[index] = type;
2730     }
GetInputTypes()2731     ArenaVector<DataType::Type> *GetInputTypes()
2732     {
2733         return inputTypes_;
2734     }
CloneTypes(ArenaAllocator * allocator,InputTypesMixin<T> * targetInst)2735     void CloneTypes(ArenaAllocator *allocator, InputTypesMixin<T> *targetInst) const
2736     {
2737         if (UNLIKELY(inputTypes_ == nullptr)) {
2738             return;
2739         }
2740         targetInst->AllocateInputTypes(allocator, inputTypes_->size());
2741         for (auto inputType : *inputTypes_) {
2742             targetInst->AddInputType(inputType);
2743         }
2744     }
AppendInputs(const std::initializer_list<std::pair<Inst *,DataType::Type>> & inputs)2745     void AppendInputs(const std::initializer_list<std::pair<Inst *, DataType::Type>> &inputs)
2746     {
2747         static_assert(std::is_base_of_v<DynamicInputsInst, T>);
2748         for (auto [input, type] : inputs) {
2749             static_cast<Inst *>(this)->AppendInput(input);
2750             AddInputType(type);
2751         }
2752     }
2753 
AppendInput(Inst * input,DataType::Type type)2754     void AppendInput(Inst *input, DataType::Type type)
2755     {
2756         static_assert(std::is_base_of_v<DynamicInputsInst, T>);
2757         static_cast<Inst *>(this)->AppendInput(input);
2758         AddInputType(type);
2759     }
2760 
SetInputs(ArenaAllocator * allocator,const std::initializer_list<std::pair<Inst *,DataType::Type>> & inputs)2761     void SetInputs(ArenaAllocator *allocator, const std::initializer_list<std::pair<Inst *, DataType::Type>> &inputs)
2762     {
2763         static_assert(std::is_base_of_v<DynamicInputsInst, T>);
2764         static_cast<Inst *>(this)->ReserveInputs(inputs.size());
2765         AllocateInputTypes(allocator, inputs.size());
2766         AppendInputs(inputs);
2767     }
2768 
2769 protected:
2770     // NOLINTNEXTLINE(misc-non-private-member-variables-in-classes)
2771     ArenaVector<DataType::Type> *inputTypes_ {nullptr};
2772 };
2773 
2774 /// Mixin to hold method data
2775 class MethodDataMixin {
2776 public:
2777     static constexpr uint32_t INVALID_METHOD_ID = std::numeric_limits<uint32_t>::max();
2778 
MethodDataMixin(uint32_t id,RuntimeInterface::MethodPtr method)2779     MethodDataMixin(uint32_t id, RuntimeInterface::MethodPtr method)
2780     {
2781         methodId_ = id;
2782         method_ = method;
2783     }
2784 
SetCallMethodId(uint32_t id)2785     void SetCallMethodId(uint32_t id)
2786     {
2787         methodId_ = id;
2788     }
GetCallMethodId()2789     auto GetCallMethodId() const
2790     {
2791         return methodId_;
2792     }
SetCallMethod(RuntimeInterface::MethodPtr method)2793     void SetCallMethod(RuntimeInterface::MethodPtr method)
2794     {
2795         method_ = method;
2796     }
GetCallMethod()2797     RuntimeInterface::MethodPtr GetCallMethod() const
2798     {
2799         return method_;
2800     }
SetFunctionObject(uintptr_t func)2801     void SetFunctionObject(uintptr_t func)
2802     {
2803         function_ = func;
2804     }
GetFunctionObject()2805     auto GetFunctionObject() const
2806     {
2807         return function_;
2808     }
2809 
2810 protected:
2811     MethodDataMixin() = default;
2812     NO_COPY_SEMANTIC(MethodDataMixin);
2813     NO_MOVE_SEMANTIC(MethodDataMixin);
2814     virtual ~MethodDataMixin() = default;
2815 
2816 private:
2817     uint32_t methodId_ {INVALID_METHOD_ID};
2818     RuntimeInterface::MethodPtr method_ {nullptr};
2819     uintptr_t function_ {0};
2820 };
2821 
2822 /// ResolveStatic
2823 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
2824 class PANDA_PUBLIC_API ResolveStaticInst : public FixedInputsInst1, public MethodDataMixin {
2825 public:
2826     using Base = FixedInputsInst1;
2827     using Base::Base;
2828 
ResolveStaticInst(Inst::Initializer t,uint32_t methodId,RuntimeInterface::MethodPtr method)2829     ResolveStaticInst(Inst::Initializer t, uint32_t methodId, RuntimeInterface::MethodPtr method)
2830         : Base(std::move(t)), MethodDataMixin(methodId, method)
2831     {
2832     }
2833 
GetInputType(size_t index)2834     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
2835     {
2836         ASSERT(index == 0);
2837         // This is SaveState input
2838         return DataType::NO_TYPE;
2839     }
2840 
Clone(const Graph * targetGraph)2841     Inst *Clone(const Graph *targetGraph) const override
2842     {
2843         ASSERT(targetGraph != nullptr);
2844         auto instClone = FixedInputsInst1::Clone(targetGraph);
2845         auto rslvClone = static_cast<ResolveStaticInst *>(instClone);
2846         rslvClone->SetCallMethodId(GetCallMethodId());
2847         rslvClone->SetCallMethod(GetCallMethod());
2848         return instClone;
2849     }
2850 
2851     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
2852 };
2853 
2854 /// ResolveVirtual
2855 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
2856 class PANDA_PUBLIC_API ResolveVirtualInst : public FixedInputsInst2, public MethodDataMixin {
2857 public:
2858     using Base = FixedInputsInst2;
2859     using Base::Base;
2860 
ResolveVirtualInst(Inst::Initializer t,uint32_t methodId,RuntimeInterface::MethodPtr method)2861     ResolveVirtualInst(Inst::Initializer t, uint32_t methodId, RuntimeInterface::MethodPtr method)
2862         : Base(std::move(t)), MethodDataMixin(methodId, method)
2863     {
2864     }
2865 
GetInputType(size_t index)2866     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
2867     {
2868         ASSERT(GetInputsCount() == 2U && index < GetInputsCount());
2869         switch (index) {
2870             case 0:
2871                 return DataType::REFERENCE;
2872             case 1:
2873                 // This is SaveState input
2874                 return DataType::NO_TYPE;
2875             default:
2876                 UNREACHABLE();
2877         }
2878     }
2879 
Clone(const Graph * targetGraph)2880     Inst *Clone(const Graph *targetGraph) const override
2881     {
2882         ASSERT(targetGraph != nullptr);
2883         auto instClone = FixedInputsInst2::Clone(targetGraph);
2884         auto rslvClone = static_cast<ResolveVirtualInst *>(instClone);
2885         rslvClone->SetCallMethodId(GetCallMethodId());
2886         rslvClone->SetCallMethod(GetCallMethod());
2887         return instClone;
2888     }
2889 
2890     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
2891 };
2892 
2893 class PANDA_PUBLIC_API InitStringInst : public FixedInputsInst2 {
2894 public:
2895     using Base = FixedInputsInst2;
2896     using Base::Base;
2897 
InitStringInst(Initializer t,StringCtorType ctorType)2898     InitStringInst(Initializer t, StringCtorType ctorType) : Base(std::move(t))
2899     {
2900         SetStringCtorType(ctorType);
2901     }
2902 
IsFromString()2903     bool IsFromString() const
2904     {
2905         return GetField<StringCtorTypeField>() == StringCtorType::STRING;
2906     }
IsFromCharArray()2907     bool IsFromCharArray() const
2908     {
2909         return GetField<StringCtorTypeField>() == StringCtorType::CHAR_ARRAY;
2910     }
2911 
GetInputType(size_t index)2912     DataType::Type GetInputType(size_t index) const override
2913     {
2914         ASSERT(index < GetInputsCount());
2915         if (index == 0) {
2916             return DataType::REFERENCE;
2917         }
2918         return DataType::NO_TYPE;
2919     }
2920 
SetStringCtorType(StringCtorType ctorType)2921     void SetStringCtorType(StringCtorType ctorType)
2922     {
2923         SetField<StringCtorTypeField>(ctorType);
2924     }
2925 
GetStringCtorType()2926     StringCtorType GetStringCtorType() const
2927     {
2928         return GetField<StringCtorTypeField>();
2929     }
2930 
2931     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
2932 
Clone(const Graph * targetGraph)2933     Inst *Clone(const Graph *targetGraph) const override
2934     {
2935         auto clone = FixedInputsInst2::Clone(targetGraph);
2936         clone->CastToInitString()->SetStringCtorType(GetStringCtorType());
2937         return clone;
2938     }
2939 
2940 private:
2941     using StringCtorTypeField = Base::LastField::NextField<StringCtorType, MinimumBitsToStore(StringCtorType::COUNT)>;
2942     using LastField = StringCtorTypeField;
2943 };
2944 
2945 /// Call instruction
2946 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
2947 class PANDA_PUBLIC_API CallInst : public InlinedInstMixin<InputTypesMixin<DynamicInputsInst>>, public MethodDataMixin {
2948 public:
2949     using Base = InlinedInstMixin<InputTypesMixin<DynamicInputsInst>>;
2950     using Base::Base;
2951 
2952     CallInst(Initializer t, uint32_t methodId, RuntimeInterface::MethodPtr method = nullptr)
Base(std::move (t))2953         : Base(std::move(t)), MethodDataMixin(methodId, method)
2954     {
2955     }
2956 
GetObjectIndex()2957     int GetObjectIndex() const
2958     {
2959         return GetOpcode() == Opcode::CallResolvedVirtual ? 1 : 0;
2960     }
2961 
GetObjectInst()2962     Inst *GetObjectInst()
2963     {
2964         return GetInput(GetObjectIndex()).GetInst();
2965     }
2966 
GetInputType(size_t index)2967     DataType::Type GetInputType(size_t index) const override
2968     {
2969         ASSERT(inputTypes_ != nullptr);
2970         ASSERT(index < inputTypes_->size());
2971         ASSERT(index < GetInputsCount());
2972         return (*inputTypes_)[index];
2973     }
2974 
2975     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
2976 
SetCanNativeException(bool isNative)2977     void SetCanNativeException(bool isNative)
2978     {
2979         SetField<IsNativeExceptionFlag>(isNative);
2980     }
2981 
GetCanNativeException()2982     bool GetCanNativeException() const
2983     {
2984         return GetField<IsNativeExceptionFlag>();
2985     }
2986 
2987     PANDA_PUBLIC_API Inst *Clone(const Graph *targetGraph) const override;
2988 
IsRuntimeCall()2989     bool IsRuntimeCall() const override
2990     {
2991         return !IsInlined();
2992     }
2993 
2994 protected:
2995     using IsNativeExceptionFlag = LastField::NextFlag;
2996     using LastField = IsNativeExceptionFlag;
2997 };
2998 
2999 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
3000 class PANDA_PUBLIC_API CallIndirectInst : public InputTypesMixin<DynamicInputsInst> {
3001 public:
3002     using Base = InputTypesMixin<DynamicInputsInst>;
3003     using Base::Base;
3004 
CallIndirectInst(Initializer t)3005     explicit CallIndirectInst(Initializer t) : Base(std::move(t)) {}
3006 
GetInputType(size_t index)3007     DataType::Type GetInputType(size_t index) const override
3008     {
3009         ASSERT(inputTypes_ != nullptr);
3010         ASSERT(index < inputTypes_->size());
3011         ASSERT(index < GetInputsCount());
3012         return (*inputTypes_)[index];
3013     }
3014 
3015     PANDA_PUBLIC_API Inst *Clone(const Graph *targetGraph) const override;
3016 };
3017 
3018 /// Length methods instruction
3019 class LengthMethodInst : public ArrayInstMixin<FixedInputsInst1> {
3020 public:
3021     using Base = ArrayInstMixin<FixedInputsInst1>;
3022     using Base::Base;
3023 
Base(opcode)3024     explicit LengthMethodInst(Opcode opcode, bool isArray = true) : Base(opcode)
3025     {
3026         SetIsArray(isArray);
3027     }
Base(std::move (t))3028     explicit LengthMethodInst(Initializer t, bool isArray = true) : Base(std::move(t))
3029     {
3030         SetIsArray(isArray);
3031     }
3032 
GetInputType(size_t index)3033     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
3034     {
3035         ASSERT(index < GetInputsCount());
3036         return DataType::REFERENCE;
3037     }
3038 
Clone(const Graph * targetGraph)3039     Inst *Clone(const Graph *targetGraph) const override
3040     {
3041         auto clone = FixedInputsInst::Clone(targetGraph);
3042         ASSERT(static_cast<LengthMethodInst *>(clone)->IsArray() == IsArray());
3043         return clone;
3044     }
3045 };
3046 
3047 /// Compare instruction
3048 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
3049 class PANDA_PUBLIC_API CompareInst : public InstWithOperandsType<ConditionMixin<FixedInputsInst2>> {
3050 public:
3051     using BaseInst = InstWithOperandsType<ConditionMixin<FixedInputsInst2>>;
3052     using BaseInst::BaseInst;
3053 
CompareInst(Initializer t,ConditionCode cc)3054     CompareInst(Initializer t, ConditionCode cc) : BaseInst(std::move(t))
3055     {
3056         SetCc(cc);
3057     }
CompareInst(Initializer t,DataType::Type operType,ConditionCode cc)3058     CompareInst(Initializer t, DataType::Type operType, ConditionCode cc) : BaseInst(std::move(t))
3059     {
3060         SetOperandsType(operType);
3061         SetCc(cc);
3062     }
3063 
3064     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
3065     PANDA_PUBLIC_API void SetVnObject(VnObject *vnObj) override;
3066 
GetInputType(size_t index)3067     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
3068     {
3069         ASSERT(index < GetInputsCount());
3070         return GetOperandsType();
3071     }
3072 
Clone(const Graph * targetGraph)3073     Inst *Clone(const Graph *targetGraph) const override
3074     {
3075         auto clone = FixedInputsInst::Clone(targetGraph);
3076         ASSERT(clone->CastToCompare()->GetCc() == GetCc());
3077         ASSERT(clone->CastToCompare()->GetOperandsType() == GetOperandsType());
3078         return clone;
3079     }
3080 };
3081 
3082 /// Mixin for AnyTypeMixin instructions
3083 template <typename T>
3084 class AnyTypeMixin : public T {
3085 public:
3086     using T::T;
3087 
SetAnyType(AnyBaseType anyType)3088     void SetAnyType(AnyBaseType anyType)
3089     {
3090         T::template SetField<AnyBaseTypeField>(anyType);
3091     }
3092 
GetAnyType()3093     AnyBaseType GetAnyType() const override
3094     {
3095         return T::template GetField<AnyBaseTypeField>();
3096     }
3097 
IsIntegerWasSeen()3098     bool IsIntegerWasSeen() const
3099     {
3100         return T::template GetField<IntegerWasSeen>();
3101     }
3102 
SetIsIntegerWasSeen(bool value)3103     void SetIsIntegerWasSeen(bool value)
3104     {
3105         T::template SetField<IntegerWasSeen>(value);
3106     }
3107 
IsSpecialWasSeen()3108     bool IsSpecialWasSeen() const
3109     {
3110         return T::template GetField<SpecialWasSeen>();
3111     }
3112 
GetAllowedInputType()3113     profiling::AnyInputType GetAllowedInputType() const
3114     {
3115         return T::template GetField<AllowedInputType>();
3116     }
3117 
SetAllowedInputType(profiling::AnyInputType type)3118     void SetAllowedInputType(profiling::AnyInputType type)
3119     {
3120         T::template SetField<AllowedInputType>(type);
3121     }
3122 
IsTypeWasProfiled()3123     bool IsTypeWasProfiled() const
3124     {
3125         return T::template GetField<TypeWasProfiled>();
3126     }
3127 
SetIsTypeWasProfiled(bool value)3128     void SetIsTypeWasProfiled(bool value)
3129     {
3130         T::template SetField<TypeWasProfiled>(value);
3131     }
3132 
3133 protected:
3134     using AnyBaseTypeField =
3135         typename T::LastField::template NextField<AnyBaseType, MinimumBitsToStore(AnyBaseType::COUNT)>;
3136     using IntegerWasSeen = typename AnyBaseTypeField::NextFlag;
3137     using SpecialWasSeen = typename IntegerWasSeen::NextFlag;
3138     using AllowedInputType =
3139         typename AnyBaseTypeField::template NextField<profiling::AnyInputType,
3140                                                       MinimumBitsToStore(profiling::AnyInputType::LAST)>;
3141     static_assert(SpecialWasSeen::END_BIT == AllowedInputType::END_BIT);
3142     using TypeWasProfiled = typename AllowedInputType::NextFlag;
3143     using LastField = TypeWasProfiled;
3144 };
3145 
3146 /// CompareAnyTypeInst instruction
3147 class PANDA_PUBLIC_API CompareAnyTypeInst : public AnyTypeMixin<FixedInputsInst1> {
3148 public:
3149     using BaseInst = AnyTypeMixin<FixedInputsInst1>;
3150     using BaseInst::BaseInst;
3151 
3152     CompareAnyTypeInst(Opcode opcode, uint32_t pc, Inst *input0, AnyBaseType anyType = AnyBaseType::UNDEFINED_TYPE)
3153         : BaseInst({opcode, DataType::Type::BOOL, pc}, input0)
3154     {
3155         SetAnyType(anyType);
3156     }
3157 
GetInputType(size_t index)3158     DataType::Type GetInputType(size_t index) const override
3159     {
3160         ASSERT(index < GetInputsCount());
3161         return GetInput(index).GetInst()->GetType();
3162     }
3163 
3164     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
3165     PANDA_PUBLIC_API void SetVnObject(VnObject *vnObj) override;
3166 
Clone(const Graph * targetGraph)3167     Inst *Clone(const Graph *targetGraph) const override
3168     {
3169         auto clone = FixedInputsInst::Clone(targetGraph);
3170         ASSERT(clone->CastToCompareAnyType()->GetAnyType() == GetAnyType());
3171         return clone;
3172     }
3173 };
3174 
3175 /// GetAnyTypeName instruction
3176 class PANDA_PUBLIC_API GetAnyTypeNameInst : public AnyTypeMixin<FixedInputsInst0> {
3177 public:
3178     using BaseInst = AnyTypeMixin<FixedInputsInst0>;
3179     using BaseInst::BaseInst;
3180 
3181     GetAnyTypeNameInst(Opcode opcode, uint32_t pc, AnyBaseType anyType = AnyBaseType::UNDEFINED_TYPE)
3182         : BaseInst({opcode, DataType::Type::ANY, pc})
3183     {
3184         SetAnyType(anyType);
3185     }
3186 
3187     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
3188     PANDA_PUBLIC_API void SetVnObject(VnObject *vnObj) override;
3189 
Clone(const Graph * targetGraph)3190     Inst *Clone(const Graph *targetGraph) const override
3191     {
3192         auto clone = FixedInputsInst::Clone(targetGraph);
3193         clone->CastToGetAnyTypeName()->SetAnyType(GetAnyType());
3194         return clone;
3195     }
3196 };
3197 
3198 /// CastAnyTypeValueInst instruction
3199 class PANDA_PUBLIC_API CastAnyTypeValueInst : public AnyTypeMixin<FixedInputsInst1> {
3200 public:
3201     using BaseInst = AnyTypeMixin<FixedInputsInst1>;
3202     using BaseInst::BaseInst;
3203 
3204     CastAnyTypeValueInst(Opcode opcode, uint32_t pc, Inst *input0, AnyBaseType anyType = AnyBaseType::UNDEFINED_TYPE)
3205         : BaseInst({opcode, AnyBaseTypeToDataType(anyType), pc}, input0)
3206     {
3207         SetAnyType(anyType);
3208     }
3209 
GetInputType(size_t index)3210     DataType::Type GetInputType(size_t index) const override
3211     {
3212         ASSERT(index < GetInputsCount());
3213         return GetInput(index).GetInst()->GetType();
3214     }
3215 
GetDeducedType()3216     DataType::Type GetDeducedType() const
3217     {
3218         return AnyBaseTypeToDataType(GetAnyType());
3219     }
3220 
3221     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
3222 
Clone(const Graph * targetGraph)3223     Inst *Clone(const Graph *targetGraph) const override
3224     {
3225         auto clone = FixedInputsInst::Clone(targetGraph)->CastToCastAnyTypeValue();
3226         ASSERT(clone->GetAnyType() == GetAnyType());
3227         ASSERT(clone->GetType() == GetType());
3228         return clone;
3229     }
3230 };
3231 
3232 /// CastValueToAnyTypeInst instruction
3233 class PANDA_PUBLIC_API CastValueToAnyTypeInst : public AnyTypeMixin<FixedInputsInst1> {
3234 public:
3235     using BaseInst = AnyTypeMixin<FixedInputsInst1>;
3236     using BaseInst::BaseInst;
3237 
CastValueToAnyTypeInst(Opcode opcode,uint32_t pc,AnyBaseType anyType,Inst * input0)3238     CastValueToAnyTypeInst(Opcode opcode, uint32_t pc, AnyBaseType anyType, Inst *input0)
3239         : BaseInst({opcode, DataType::ANY, pc}, input0)
3240     {
3241         SetAnyType(anyType);
3242     }
3243 
GetInputType(size_t index)3244     DataType::Type GetInputType(size_t index) const override
3245     {
3246         ASSERT(index < GetInputsCount());
3247         return GetInput(index).GetInst()->GetType();
3248     }
3249 
3250     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
3251 
Clone(const Graph * targetGraph)3252     Inst *Clone(const Graph *targetGraph) const override
3253     {
3254         auto clone = FixedInputsInst::Clone(targetGraph)->CastToCastValueToAnyType();
3255         ASSERT(clone->GetAnyType() == GetAnyType());
3256         ASSERT(clone->GetType() == GetType());
3257         return clone;
3258     }
3259 };
3260 
3261 /// AnyTypeCheckInst instruction
3262 class PANDA_PUBLIC_API AnyTypeCheckInst : public AnyTypeMixin<FixedInputsInst2> {
3263 public:
3264     using BaseInst = AnyTypeMixin<FixedInputsInst2>;
3265     using BaseInst::BaseInst;
3266 
BaseInst(std::move (t))3267     explicit AnyTypeCheckInst(Initializer t, AnyBaseType anyType = AnyBaseType::UNDEFINED_TYPE) : BaseInst(std::move(t))
3268     {
3269         SetAnyType(anyType);
3270     }
3271 
GetInputType(size_t index)3272     DataType::Type GetInputType(size_t index) const override
3273     {
3274         ASSERT(index < GetInputsCount());
3275         return (index == 0) ? DataType::ANY : DataType::NO_TYPE;
3276     }
3277 
3278     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
3279 
Clone(const Graph * targetGraph)3280     Inst *Clone(const Graph *targetGraph) const override
3281     {
3282         auto clone = FixedInputsInst::Clone(targetGraph);
3283         ASSERT(clone->CastToAnyTypeCheck()->GetAnyType() == GetAnyType());
3284         return clone;
3285     }
3286 
3287     DeoptimizeType GetDeoptimizeType() const;
3288 };
3289 
3290 /// HclassCheck instruction
3291 enum class HclassChecks {
3292     ALL_CHECKS = 0,
3293     IS_FUNCTION,
3294     IS_NOT_CLASS_CONSTRUCTOR,
3295 };
3296 class PANDA_PUBLIC_API HclassCheckInst : public AnyTypeMixin<FixedInputsInst2> {
3297 public:
3298     using BaseInst = AnyTypeMixin<FixedInputsInst2>;
3299     using BaseInst::BaseInst;
3300 
BaseInst(std::move (t))3301     explicit HclassCheckInst(Initializer t, AnyBaseType anyType = AnyBaseType::UNDEFINED_TYPE) : BaseInst(std::move(t))
3302     {
3303         SetAnyType(anyType);
3304     }
3305 
GetInputType(size_t index)3306     DataType::Type GetInputType(size_t index) const override
3307     {
3308         ASSERT(index < GetInputsCount());
3309         return (index == 0) ? DataType::REFERENCE : DataType::NO_TYPE;
3310     }
3311 
SetCheckIsFunction(bool value)3312     void SetCheckIsFunction(bool value)
3313     {
3314         SetField<CheckTypeIsFunction>(value);
3315     }
3316 
GetCheckIsFunction()3317     bool GetCheckIsFunction() const
3318     {
3319         return GetField<CheckTypeIsFunction>();
3320     }
3321 
3322     void SetCheckFunctionIsNotClassConstructor(bool value = true)
3323     {
3324         SetField<CheckFunctionIsNotClassConstructor>(value);
3325     }
3326 
GetCheckFunctionIsNotClassConstructor()3327     bool GetCheckFunctionIsNotClassConstructor() const
3328     {
3329         return GetField<CheckFunctionIsNotClassConstructor>();
3330     }
3331 
3332     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
3333 
3334     void ExtendFlags(Inst *inst);
3335 
Clone(const Graph * targetGraph)3336     Inst *Clone(const Graph *targetGraph) const override
3337     {
3338         auto clone = static_cast<HclassCheckInst *>(FixedInputsInst2::Clone(targetGraph));
3339         clone->SetCheckFunctionIsNotClassConstructor(GetCheckFunctionIsNotClassConstructor());
3340         clone->SetCheckIsFunction(GetCheckIsFunction());
3341         return clone;
3342     }
3343 
3344 protected:
3345     using CheckTypeIsFunction = LastField::NextFlag;
3346     using CheckFunctionIsNotClassConstructor = CheckTypeIsFunction::NextFlag;
3347     using LastField = CheckFunctionIsNotClassConstructor;
3348 };
3349 
3350 /**
3351  * ConstantInst represent constant value.
3352  *
3353  * Available types: INT64, FLOAT32, FLOAT64, ANY. All integer types are stored as INT64 value.
3354  * Once type of constant is set, it can't be changed anymore.
3355  */
3356 class PANDA_PUBLIC_API ConstantInst : public FixedInputsInst<0> {
3357 public:
3358     using FixedInputsInst::FixedInputsInst;
3359 
3360     template <typename T>
FixedInputsInst(Opcode::Constant)3361     explicit ConstantInst(Opcode /* unused */, T value, bool supportInt32 = false) : FixedInputsInst(Opcode::Constant)
3362     {
3363         ASSERT(GetTypeFromCType<T>() != DataType::NO_TYPE);
3364         // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-branch-clone)
3365         if constexpr (GetTypeFromCType<T>() == DataType::FLOAT64) {
3366             value_ = bit_cast<uint64_t, double>(value);
3367             // NOLINTNEXTLINE(readability-braces-around-statements, readability-misleading-indentation)
3368         } else if constexpr (GetTypeFromCType<T>() == DataType::FLOAT32) {
3369             value_ = bit_cast<uint32_t, float>(value);
3370             // NOLINTNEXTLINE(readability-braces-around-statements, readability-misleading-indentation)
3371         } else if constexpr (GetTypeFromCType<T>() == DataType::ANY) {
3372             value_ = value.Raw();
3373             // NOLINTNEXTLINE(readability-braces-around-statements, readability-misleading-indentation)
3374         } else if (GetTypeFromCType<T>(supportInt32) == DataType::INT32) {
3375             value_ = static_cast<int32_t>(value);
3376             // NOLINTNEXTLINE(readability-braces-around-statements, readability-misleading-indentation)
3377         } else {
3378             value_ = value;
3379         }
3380 
3381         SetType(GetTypeFromCType<T>(supportInt32));
3382     }
3383 
IsSafeInst()3384     bool IsSafeInst() const override
3385     {
3386         return true;
3387     }
3388 
GetRawValue()3389     uint64_t GetRawValue() const
3390     {
3391         return value_;
3392     }
3393 
GetInt32Value()3394     uint32_t GetInt32Value() const
3395     {
3396         ASSERT(GetType() == DataType::INT32);
3397         return static_cast<uint32_t>(value_);
3398     }
3399 
GetInt64Value()3400     uint64_t GetInt64Value() const
3401     {
3402         ASSERT(GetType() == DataType::INT64);
3403         return value_;
3404     }
3405 
GetIntValue()3406     uint64_t GetIntValue() const
3407     {
3408         ASSERT(GetType() == DataType::INT64 || GetType() == DataType::INT32);
3409         return value_;
3410     }
3411 
GetFloatValue()3412     float GetFloatValue() const
3413     {
3414         ASSERT(GetType() == DataType::FLOAT32);
3415         return bit_cast<float, uint32_t>(static_cast<uint32_t>(value_));
3416     }
3417 
GetDoubleValue()3418     double GetDoubleValue() const
3419     {
3420         ASSERT(GetType() == DataType::FLOAT64);
3421         return bit_cast<double, uint64_t>(value_);
3422     }
3423 
GetNextConst()3424     ConstantInst *GetNextConst()
3425     {
3426         return nextConst_;
3427     }
SetNextConst(ConstantInst * nextConst)3428     void SetNextConst(ConstantInst *nextConst)
3429     {
3430         nextConst_ = nextConst;
3431     }
3432 
3433     template <typename T>
3434     static constexpr DataType::Type GetTypeFromCType(bool supportInt32 = false)
3435     {
3436         // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-branch-clone)
3437         if constexpr (std::is_integral_v<T>) {
3438             if (supportInt32 && sizeof(T) == sizeof(uint32_t)) {
3439                 return DataType::INT32;
3440             }
3441             return DataType::INT64;
3442             // NOLINTNEXTLINE(readability-braces-around-statements, readability-misleading-indentation)
3443         } else if constexpr (std::is_same_v<T, float>) {
3444             return DataType::FLOAT32;
3445             // NOLINTNEXTLINE(readability-braces-around-statements, readability-misleading-indentation)
3446         } else if constexpr (std::is_same_v<T, double>) {
3447             return DataType::FLOAT64;
3448             // NOLINTNEXTLINE(readability-braces-around-statements, readability-misleading-indentation)
3449         } else if constexpr (std::is_same_v<T, DataType::Any>) {
3450             return DataType::ANY;
3451         }
3452         return DataType::NO_TYPE;
3453     }
3454 
3455     inline bool IsEqualConst(double value, [[maybe_unused]] bool supportInt32 = false)
3456     {
3457         // Special compare for NaN
3458         if (GetType() == DataType::FLOAT64 && std::isnan(value) && std::isnan(bit_cast<double, uint64_t>(value_))) {
3459             return true;
3460         }
3461         return IsEqualConst(DataType::FLOAT64, bit_cast<uint64_t, double>(value));
3462     }
3463     inline bool IsEqualConst(float value, [[maybe_unused]] bool supportInt32 = false)
3464     {
3465         // Special compare for NaN
3466         if (GetType() == DataType::FLOAT32 && std::isnan(value) && std::isnan(bit_cast<float, uint32_t>(value_))) {
3467             return true;
3468         }
3469         return IsEqualConst(DataType::FLOAT32, bit_cast<uint32_t, float>(value));
3470     }
3471     inline bool IsEqualConst(DataType::Any value, [[maybe_unused]] bool supportInt32 = false)
3472     {
3473         return IsEqualConst(DataType::ANY, value.Raw());
3474     }
IsEqualConst(DataType::Type type,uint64_t value)3475     inline bool IsEqualConst(DataType::Type type, uint64_t value)
3476     {
3477         return GetType() == type && value_ == value;
3478     }
3479     template <typename T>
3480     inline bool IsEqualConst(T value, bool supportInt32 = false)
3481     {
3482         static_assert(GetTypeFromCType<T>() == DataType::INT64);
3483         if (supportInt32 && sizeof(T) == sizeof(uint32_t)) {
3484             return (GetType() == DataType::INT32 && static_cast<int32_t>(value_) == static_cast<int32_t>(value));
3485         }
3486         return (GetType() == DataType::INT64 && value_ == static_cast<uint64_t>(value));
3487     }
3488 
3489     inline bool IsEqualConstAllTypes(int64_t value, bool supportInt32 = false)
3490     {
3491         return IsEqualConst(value, supportInt32) || IsEqualConst(static_cast<float>(value)) ||
3492                IsEqualConst(static_cast<double>(value));
3493     }
3494 
IsBoolConst()3495     bool IsBoolConst() const override
3496     {
3497         ASSERT(IsConst());
3498         return (GetType() == DataType::INT32 || GetType() == DataType::INT64) &&
3499                (GetIntValue() == 0 || GetIntValue() == 1);
3500     }
3501 
IsNaNConst()3502     bool IsNaNConst() const
3503     {
3504         ASSERT(DataType::IsFloatType(GetType()));
3505         if (GetType() == DataType::FLOAT32) {
3506             return std::isnan(GetFloatValue());
3507         }
3508         // DataType::FLOAT64
3509         return std::isnan(GetDoubleValue());
3510     }
3511 
SetImmTableSlot(ImmTableSlot immSlot)3512     void SetImmTableSlot(ImmTableSlot immSlot)
3513     {
3514         immSlot_ = immSlot;
3515     }
3516 
GetImmTableSlot()3517     auto GetImmTableSlot() const
3518     {
3519         return immSlot_;
3520     }
3521 
GetDstLocation()3522     Location GetDstLocation() const override
3523     {
3524         if (GetImmTableSlot() != GetInvalidImmTableSlot()) {
3525             return Location::MakeConstant(GetImmTableSlot());
3526         }
3527         return Inst::GetDstLocation();
3528     }
3529 
3530     PANDA_PUBLIC_API bool DumpInputs(std::ostream *out) const override;
3531 
3532     PANDA_PUBLIC_API Inst *Clone(const Graph *targetGraph) const override;
3533 
3534 private:
3535     uint64_t value_ {0};
3536     ConstantInst *nextConst_ {nullptr};
3537     ImmTableSlot immSlot_ {GetInvalidImmTableSlot()};
3538 };
3539 
3540 // Type describing the purpose of the SpillFillInst.
3541 // RegAlloc may use this information to preserve correct order of several SpillFillInst
3542 // instructions placed along each other in the graph.
3543 enum SpillFillType {
3544     UNKNOWN,
3545     INPUT_FILL,
3546     CONNECT_SPLIT_SIBLINGS,
3547     SPLIT_MOVE,
3548 };
3549 
3550 class PANDA_PUBLIC_API SpillFillInst : public FixedInputsInst0 {
3551 public:
3552     explicit SpillFillInst(ArenaAllocator *allocator, Opcode opcode, SpillFillType type = UNKNOWN)
FixedInputsInst0(opcode)3553         : FixedInputsInst0(opcode), spillFills_(allocator->Adapter()), sfType_(type)
3554     {
3555     }
3556 
AddMove(Register src,Register dst,DataType::Type type)3557     void AddMove(Register src, Register dst, DataType::Type type)
3558     {
3559         AddSpillFill(Location::MakeRegister(src, type), Location::MakeRegister(dst, type), type);
3560     }
3561 
AddSpill(Register src,StackSlot dst,DataType::Type type)3562     void AddSpill(Register src, StackSlot dst, DataType::Type type)
3563     {
3564         AddSpillFill(Location::MakeRegister(src, type), Location::MakeStackSlot(dst), type);
3565     }
3566 
AddFill(StackSlot src,Register dst,DataType::Type type)3567     void AddFill(StackSlot src, Register dst, DataType::Type type)
3568     {
3569         AddSpillFill(Location::MakeStackSlot(src), Location::MakeRegister(dst, type), type);
3570     }
3571 
AddMemCopy(StackSlot src,StackSlot dst,DataType::Type type)3572     void AddMemCopy(StackSlot src, StackSlot dst, DataType::Type type)
3573     {
3574         AddSpillFill(Location::MakeStackSlot(src), Location::MakeStackSlot(dst), type);
3575     }
3576 
AddSpillFill(const SpillFillData & spillFill)3577     void AddSpillFill(const SpillFillData &spillFill)
3578     {
3579         spillFills_.emplace_back(spillFill);
3580     }
3581 
AddSpillFill(const Location & src,const Location & dst,DataType::Type type)3582     void AddSpillFill(const Location &src, const Location &dst, DataType::Type type)
3583     {
3584         spillFills_.emplace_back(SpillFillData {src.GetKind(), dst.GetKind(), src.GetValue(), dst.GetValue(), type});
3585     }
3586 
GetSpillFills()3587     const ArenaVector<SpillFillData> &GetSpillFills() const
3588     {
3589         return spillFills_;
3590     }
3591 
GetSpillFills()3592     ArenaVector<SpillFillData> &GetSpillFills()
3593     {
3594         return spillFills_;
3595     }
3596 
GetSpillFill(size_t n)3597     const SpillFillData &GetSpillFill(size_t n) const
3598     {
3599         ASSERT(n < spillFills_.size());
3600         return spillFills_[n];
3601     }
3602 
GetSpillFill(size_t n)3603     SpillFillData &GetSpillFill(size_t n)
3604     {
3605         ASSERT(n < spillFills_.size());
3606         return spillFills_[n];
3607     }
3608 
RemoveSpillFill(size_t n)3609     void RemoveSpillFill(size_t n)
3610     {
3611         ASSERT(n < spillFills_.size());
3612         spillFills_.erase(spillFills_.begin() + n);
3613     }
3614 
3615     // Get register number, holded by n-th spill-fill
GetInputReg(size_t n)3616     Register GetInputReg(size_t n) const
3617     {
3618         ASSERT(n < spillFills_.size());
3619         ASSERT(spillFills_[n].SrcType() == LocationType::REGISTER);
3620         return spillFills_[n].SrcValue();
3621     }
3622 
ClearSpillFills()3623     void ClearSpillFills()
3624     {
3625         spillFills_.clear();
3626     }
3627 
GetSpillFillType()3628     SpillFillType GetSpillFillType() const
3629     {
3630         return sfType_;
3631     }
3632 
SetSpillFillType(SpillFillType type)3633     void SetSpillFillType(SpillFillType type)
3634     {
3635         sfType_ = type;
3636     }
3637 
3638     PANDA_PUBLIC_API bool DumpInputs(std::ostream *out) const override;
3639 
3640 #ifndef NDEBUG
Clone(const Graph * targetGraph)3641     Inst *Clone(const Graph *targetGraph) const override
3642     {
3643         auto clone = FixedInputsInst::Clone(targetGraph)->CastToSpillFill();
3644         clone->SetSpillFillType(GetSpillFillType());
3645         for (auto spillFill : spillFills_) {
3646             clone->AddSpillFill(spillFill);
3647         }
3648         return clone;
3649     }
3650 #endif
3651 
3652 private:
3653     ArenaVector<SpillFillData> spillFills_;
3654     SpillFillType sfType_ {UNKNOWN};
3655 };
3656 
3657 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
3658 class PANDA_PUBLIC_API ParameterInst : public FixedInputsInst<0>, public LocationDataMixin {
3659 public:
3660     using FixedInputsInst::FixedInputsInst;
3661     static constexpr uint16_t DYNAMIC_NUM_ARGS = std::numeric_limits<uint16_t>::max();
3662     static constexpr uint16_t INVALID_ARG_REF_NUM = std::numeric_limits<uint16_t>::max();
3663 
3664     explicit ParameterInst(Opcode /* unused */, uint16_t argNumber, DataType::Type type = DataType::NO_TYPE)
3665         : FixedInputsInst({Opcode::Parameter, type, INVALID_PC}), argNumber_(argNumber)
3666     {
3667     }
GetArgNumber()3668     uint16_t GetArgNumber() const
3669     {
3670         return argNumber_;
3671     }
3672 
SetArgNumber(uint16_t argNumber)3673     void SetArgNumber(uint16_t argNumber)
3674     {
3675         argNumber_ = argNumber;
3676     }
GetArgRefNumber()3677     uint16_t GetArgRefNumber() const
3678     {
3679         return argRefNumber_;
3680     }
3681 
SetArgRefNumber(uint16_t argRefNumber)3682     void SetArgRefNumber(uint16_t argRefNumber)
3683     {
3684         argRefNumber_ = argRefNumber;
3685     }
3686     PANDA_PUBLIC_API bool DumpInputs(std::ostream *out) const override;
3687 
3688     PANDA_PUBLIC_API Inst *Clone(const Graph *targetGraph) const override;
3689 
3690 private:
3691     uint16_t argNumber_ {0};
3692     uint16_t argRefNumber_ {INVALID_ARG_REF_NUM};
3693 };
3694 
IsZeroConstant(const Inst * inst)3695 inline bool IsZeroConstant(const Inst *inst)
3696 {
3697     return inst->IsConst() && inst->GetType() == DataType::INT64 && inst->CastToConstant()->GetIntValue() == 0;
3698 }
3699 
IsZeroConstantOrNullPtr(const Inst * inst)3700 inline bool IsZeroConstantOrNullPtr(const Inst *inst)
3701 {
3702     return IsZeroConstant(inst) || inst->GetOpcode() == Opcode::NullPtr;
3703 }
3704 
3705 /// Phi instruction
3706 class PANDA_PUBLIC_API PhiInst : public AnyTypeMixin<DynamicInputsInst> {
3707 public:
3708     using BaseInst = AnyTypeMixin<DynamicInputsInst>;
3709     using BaseInst::BaseInst;
3710 
BaseInst(std::move (t))3711     explicit PhiInst(Initializer t, AnyBaseType anyType = AnyBaseType::UNDEFINED_TYPE) : BaseInst(std::move(t))
3712     {
3713         SetAnyType(anyType);
3714     }
3715 
3716     /// Get basic block corresponding to given input index. Returned pointer to basic block, can't be nullptr
3717     BasicBlock *GetPhiInputBb(unsigned index);
GetPhiInputBb(unsigned index)3718     const BasicBlock *GetPhiInputBb(unsigned index) const
3719     {
3720         return (const_cast<PhiInst *>(this))->GetPhiInputBb(index);
3721     }
3722 
GetPhiInputBbNum(unsigned index)3723     uint32_t GetPhiInputBbNum(unsigned index) const
3724     {
3725         ASSERT(index < GetInputsCount());
3726         return GetDynamicOperands()->GetUser(index)->GetBbNum();
3727     }
3728 
SetPhiInputBbNum(unsigned index,uint32_t bbNum)3729     void SetPhiInputBbNum(unsigned index, uint32_t bbNum)
3730     {
3731         ASSERT(index < GetInputsCount());
3732         GetDynamicOperands()->GetUser(index)->SetBbNum(bbNum);
3733     }
3734 
Clone(const Graph * targetGraph)3735     Inst *Clone(const Graph *targetGraph) const override
3736     {
3737         auto clone = DynamicInputsInst::Clone(targetGraph);
3738         ASSERT(clone->CastToPhi()->GetAnyType() == GetAnyType());
3739         return clone;
3740     }
3741 
GetAssumedAnyType()3742     AnyBaseType GetAssumedAnyType() const
3743     {
3744         return GetAnyType();
3745     }
3746 
SetAssumedAnyType(AnyBaseType type)3747     void SetAssumedAnyType(AnyBaseType type)
3748     {
3749         SetAnyType(type);
3750     }
3751 
3752     /// Get input instruction corresponding to the given basic block, can't be null.
3753     Inst *GetPhiInput(BasicBlock *bb);
3754     Inst *GetPhiDataflowInput(BasicBlock *bb);
3755     PANDA_PUBLIC_API bool DumpInputs(std::ostream *out) const override;
3756     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
3757 
3758     // Get index of the given block in phi inputs
3759     size_t GetPredBlockIndex(const BasicBlock *block) const;
3760 
3761 protected:
3762     using FlagIsLive = LastField::NextFlag;
3763     using LastField = FlagIsLive;
3764 };
3765 
3766 /**
3767  * Immediate for SaveState:
3768  * value - constant value to be stored
3769  * vreg - virtual register number
3770  */
3771 struct SaveStateImm {
3772     uint64_t value;
3773     uint16_t vreg;
3774     DataType::Type type;
3775     VRegType vregType;
3776 };
3777 
3778 /**
3779  * Frame state saving instruction
3780  * Aims to save pbc registers before calling something that can raise exception
3781  */
3782 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
3783 class PANDA_PUBLIC_API SaveStateInst : public DynamicInputsInst {
3784 public:
3785     using DynamicInputsInst::DynamicInputsInst;
3786 
SaveStateInst(Opcode opcode,uint32_t pc,void * method,CallInst * inst,uint32_t inliningDepth)3787     SaveStateInst(Opcode opcode, uint32_t pc, void *method, CallInst *inst, uint32_t inliningDepth)
3788         : DynamicInputsInst({opcode, DataType::NO_TYPE, pc}),
3789           method_(method),
3790           callerInst_(inst),
3791           inliningDepth_(inliningDepth)
3792     {
3793     }
3794 
3795     PANDA_PUBLIC_API bool DumpInputs(std::ostream *out) const override;
3796 
AppendBridge(Inst * inst)3797     void AppendBridge(Inst *inst)
3798     {
3799         ASSERT(inst != nullptr);
3800         auto newInput = AppendInput(inst);
3801         SetVirtualRegister(newInput, VirtualRegister(VirtualRegister::BRIDGE, VRegType::VREG));
3802     }
3803 
SetVirtualRegister(size_t index,VirtualRegister reg)3804     void SetVirtualRegister(size_t index, VirtualRegister reg)
3805     {
3806         static_assert(sizeof(reg) <= sizeof(uintptr_t), "Consider passing the register by reference");
3807         ASSERT(index < GetInputsCount());
3808         GetDynamicOperands()->GetUser(index)->SetVirtualRegister(reg);
3809     }
3810 
GetVirtualRegister(size_t index)3811     VirtualRegister GetVirtualRegister(size_t index) const
3812     {
3813         ASSERT(index < GetInputsCount());
3814         return GetDynamicOperands()->GetUser(index)->GetVirtualRegister();
3815     }
3816 
Verify()3817     bool Verify() const
3818     {
3819         for (size_t i {0}; i < GetInputsCount(); ++i) {
3820             if (static_cast<uint16_t>(GetVirtualRegister(i)) == VirtualRegister::INVALID) {
3821                 return false;
3822             }
3823         }
3824         return true;
3825     }
3826 
RemoveNumericInputs()3827     bool RemoveNumericInputs()
3828     {
3829         size_t idx = 0;
3830         size_t inputsCount = GetInputsCount();
3831         bool removed = false;
3832         while (idx < inputsCount) {
3833             auto inputInst = GetInput(idx).GetInst();
3834             if (DataType::IsTypeNumeric(inputInst->GetType())) {
3835                 RemoveInput(idx);
3836                 inputsCount--;
3837                 removed = true;
3838             } else {
3839                 idx++;
3840             }
3841         }
3842         return removed;
3843     }
3844 
GetInputType(size_t index)3845     DataType::Type GetInputType(size_t index) const override
3846     {
3847         ASSERT(index < GetInputsCount());
3848         return GetInput(index).GetInst()->GetType();
3849     }
GetMethod()3850     auto GetMethod() const
3851     {
3852         return method_;
3853     }
SetMethod(void * method)3854     auto SetMethod(void *method)
3855     {
3856         method_ = method;
3857     }
3858 
GetCallerInst()3859     auto GetCallerInst() const
3860     {
3861         return callerInst_;
3862     }
SetCallerInst(CallInst * inst)3863     auto SetCallerInst(CallInst *inst)
3864     {
3865         callerInst_ = inst;
3866     }
3867 
GetInliningDepth()3868     uint32_t GetInliningDepth() const override
3869     {
3870         return inliningDepth_;
3871     }
SetInliningDepth(uint32_t inliningDepth)3872     void SetInliningDepth(uint32_t inliningDepth)
3873     {
3874         inliningDepth_ = inliningDepth;
3875     }
3876 
3877     void AppendImmediate(uint64_t imm, uint16_t vreg, DataType::Type type, VRegType vregType);
3878 
GetImmediates()3879     const ArenaVector<SaveStateImm> *GetImmediates() const
3880     {
3881         return immediates_;
3882     }
3883 
GetImmediate(size_t index)3884     const SaveStateImm &GetImmediate(size_t index) const
3885     {
3886         ASSERT(immediates_ != nullptr && index < immediates_->size());
3887         return (*immediates_)[index];
3888     }
3889 
3890     void AllocateImmediates(ArenaAllocator *allocator, size_t size = 0);
3891 
GetImmediatesCount()3892     size_t GetImmediatesCount() const
3893     {
3894         if (immediates_ == nullptr) {
3895             return 0;
3896         }
3897         return immediates_->size();
3898     }
3899 
SetRootsRegMaskBit(size_t reg)3900     void SetRootsRegMaskBit(size_t reg)
3901     {
3902         ASSERT(reg < rootsRegsMask_.size());
3903         rootsRegsMask_.set(reg);
3904     }
3905 
SetRootsStackMaskBit(size_t slot)3906     void SetRootsStackMaskBit(size_t slot)
3907     {
3908         if (rootsStackMask_ != nullptr) {
3909             rootsStackMask_->SetBit(slot);
3910         }
3911     }
3912 
GetRootsStackMask()3913     ArenaBitVector *GetRootsStackMask()
3914     {
3915         return rootsStackMask_;
3916     }
SetRootsStackMask(ArenaBitVector * rootsStackMask)3917     void SetRootsStackMask(ArenaBitVector *rootsStackMask)
3918     {
3919         rootsStackMask_ = rootsStackMask;
3920     }
3921 
GetRootsRegsMask()3922     auto &GetRootsRegsMask()
3923     {
3924         return rootsRegsMask_;
3925     }
3926 
SetRootsRegsMask(uint32_t rootsRegsMask)3927     void SetRootsRegsMask(uint32_t rootsRegsMask)
3928     {
3929         rootsRegsMask_ = rootsRegsMask;
3930     }
3931 
CreateRootsStackMask(ArenaAllocator * allocator)3932     void CreateRootsStackMask(ArenaAllocator *allocator)
3933     {
3934         ASSERT(rootsStackMask_ == nullptr);
3935         rootsStackMask_ = allocator->New<ArenaBitVector>(allocator);
3936         rootsStackMask_->Reset();
3937     }
3938 
3939     Inst *Clone(const Graph *targetGraph) const override;
3940 #ifndef NDEBUG
SetInputsWereDeleted()3941     void SetInputsWereDeleted()
3942     {
3943         SetField<FlagInputsWereDeleted>(true);
3944     }
3945 
GetInputsWereDeleted()3946     bool GetInputsWereDeleted()
3947     {
3948         return GetField<FlagInputsWereDeleted>();
3949     }
3950 #endif
3951 
3952 protected:
3953 #ifndef NDEBUG
3954     using FlagInputsWereDeleted = LastField::NextFlag;
3955     using LastField = FlagInputsWereDeleted;
3956 #endif
3957 
3958 private:
3959     ArenaVector<SaveStateImm> *immediates_ {nullptr};
3960     void *method_ {nullptr};
3961     // If instruction is in the inlined graph, this variable points to the inliner's call instruction.
3962     CallInst *callerInst_ {nullptr};
3963     uint32_t inliningDepth_ {0};
3964     ArenaBitVector *rootsStackMask_ {nullptr};
3965     std::bitset<BITS_PER_UINT32> rootsRegsMask_ {0};
3966 };
3967 
3968 /// Load value from array or string
3969 class PANDA_PUBLIC_API LoadInst : public ArrayInstMixin<NeedBarrierMixin<FixedInputsInst2>> {
3970 public:
3971     using Base = ArrayInstMixin<NeedBarrierMixin<FixedInputsInst2>>;
3972     using Base::Base;
3973 
Base(opcode)3974     explicit LoadInst(Opcode opcode, bool isArray = true) : Base(opcode)
3975     {
3976         SetIsArray(isArray);
3977     }
Base(std::move (t))3978     explicit LoadInst(Initializer t, bool needBarrier = false, bool isArray = true) : Base(std::move(t))
3979     {
3980         SetNeedBarrier(needBarrier);
3981         SetIsArray(isArray);
3982     }
3983 
GetIndex()3984     Inst *GetIndex()
3985     {
3986         return GetInput(1).GetInst();
3987     }
GetArray()3988     Inst *GetArray()
3989     {
3990         return GetInput(0).GetInst();
3991     }
3992 
IsBarrier()3993     bool IsBarrier() const override
3994     {
3995         return Inst::IsBarrier() || GetNeedBarrier();
3996     }
3997 
GetInputType(size_t index)3998     DataType::Type GetInputType(size_t index) const override
3999     {
4000         ASSERT(index < GetInputsCount());
4001         switch (index) {
4002             case 0: {
4003                 auto inputType = GetInput(0).GetInst()->GetType();
4004                 ASSERT(inputType == DataType::NO_TYPE || inputType == DataType::REFERENCE ||
4005                        inputType == DataType::ANY);
4006                 return inputType;
4007             }
4008             case 1:
4009                 return DataType::INT32;
4010             default:
4011                 return DataType::NO_TYPE;
4012         }
4013     }
4014 
Clone(const Graph * targetGraph)4015     Inst *Clone(const Graph *targetGraph) const override
4016     {
4017         auto clone = NeedBarrierMixin<FixedInputsInst2>::Clone(targetGraph);
4018         ASSERT(static_cast<LoadInst *>(clone)->IsArray() == IsArray());
4019         return clone;
4020     }
4021 
Latency()4022     uint32_t Latency() const override
4023     {
4024         return g_options.GetCompilerSchedLatencyLong();
4025     }
4026 };
4027 
4028 class LoadCompressedStringCharInst : public FixedInputsInst3 {
4029 public:
4030     using Base = FixedInputsInst3;
4031     using Base::Base;
4032 
GetArray()4033     Inst *GetArray()
4034     {
4035         return GetInput(0).GetInst();
4036     }
GetIndex()4037     Inst *GetIndex()
4038     {
4039         return GetInput(1).GetInst();
4040     }
GetLength()4041     Inst *GetLength() const
4042     {
4043         return GetInput(2U).GetInst();
4044     }
4045 
GetInputType(size_t index)4046     DataType::Type GetInputType(size_t index) const override
4047     {
4048         ASSERT(index < GetInputsCount());
4049         switch (index) {
4050             case 0:
4051                 return DataType::REFERENCE;
4052             case 1:
4053                 return DataType::INT32;
4054             case 2U:
4055                 return DataType::INT32;
4056             default:
4057                 return DataType::NO_TYPE;
4058         }
4059     }
4060 
Latency()4061     uint32_t Latency() const override
4062     {
4063         return g_options.GetCompilerSchedLatencyLong();
4064     }
4065 };
4066 
4067 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4068 class LoadCompressedStringCharInstI : public FixedInputsInst2, public ImmediateMixin {
4069 public:
4070     using Base = FixedInputsInst2;
4071     using Base::Base;
4072 
LoadCompressedStringCharInstI(Initializer t,uint64_t imm)4073     LoadCompressedStringCharInstI(Initializer t, uint64_t imm) : Base(std::move(t)), ImmediateMixin(imm) {}
4074 
Latency()4075     uint32_t Latency() const override
4076     {
4077         return g_options.GetCompilerSchedLatencyLong();
4078     }
4079 
GetInputType(size_t index)4080     DataType::Type GetInputType(size_t index) const override
4081     {
4082         ASSERT(index < GetInputsCount());
4083         switch (index) {
4084             case 0:
4085                 return DataType::REFERENCE;
4086             case 1:
4087                 return DataType::INT32;
4088             default:
4089                 return DataType::NO_TYPE;
4090         }
4091     }
4092 };
4093 /// Store value into array element
4094 class StoreInst : public NeedBarrierMixin<FixedInputsInst3> {
4095 public:
4096     using Base = NeedBarrierMixin<FixedInputsInst3>;
4097     using Base::Base;
4098 
Base(std::move (t))4099     explicit StoreInst(Initializer t, bool needBarrier = false) : Base(std::move(t))
4100     {
4101         SetNeedBarrier(needBarrier);
4102     }
4103 
IsBarrier()4104     bool IsBarrier() const override
4105     {
4106         return Inst::IsBarrier() || GetNeedBarrier();
4107     }
4108 
GetArray()4109     Inst *GetArray()
4110     {
4111         return GetInput(0).GetInst();
4112     }
GetIndex()4113     Inst *GetIndex()
4114     {
4115         return GetInput(1).GetInst();
4116     }
GetStoredValue()4117     Inst *GetStoredValue()
4118     {
4119         return GetInput(2U).GetInst();
4120     }
GetInputType(size_t index)4121     DataType::Type GetInputType(size_t index) const override
4122     {
4123         ASSERT(index < GetInputsCount());
4124         switch (index) {
4125             case 0: {
4126                 auto input = GetInput(0).GetInst();
4127                 auto inputType = input->GetType();
4128                 ASSERT(inputType == DataType::ANY || inputType == DataType::REFERENCE);
4129                 return inputType;
4130             }
4131             case 1:
4132                 return DataType::INT32;
4133             case 2U:
4134                 return GetType();
4135             default:
4136                 return DataType::NO_TYPE;
4137         }
4138     }
4139 
4140     // StoreArray call barriers twice,so we need to save input register for second call
IsPropagateLiveness()4141     PANDA_PUBLIC_API bool IsPropagateLiveness() const override
4142     {
4143         return GetType() == DataType::REFERENCE;
4144     }
4145 };
4146 
4147 /// Load value from array, using array index as immediate
4148 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4149 class PANDA_PUBLIC_API LoadInstI : public VolatileMixin<ArrayInstMixin<NeedBarrierMixin<FixedInputsInst1>>>,
4150                                    public ImmediateMixin {
4151 public:
4152     using Base = VolatileMixin<ArrayInstMixin<NeedBarrierMixin<FixedInputsInst1>>>;
4153     using Base::Base;
4154 
Base(opcode)4155     LoadInstI(Opcode opcode, uint64_t imm, bool isArray = true) : Base(opcode), ImmediateMixin(imm)
4156     {
4157         SetIsArray(isArray);
4158     }
4159 
4160     LoadInstI(Initializer t, uint64_t imm, bool isVolatile = false, bool needBarrier = false, bool isArray = true)
Base(std::move (t))4161         : Base(std::move(t)), ImmediateMixin(imm)
4162     {
4163         SetIsArray(isArray);
4164         SetVolatile(isVolatile);
4165         SetNeedBarrier(needBarrier);
4166     }
4167 
GetArray()4168     Inst *GetArray()
4169     {
4170         return GetInput(0).GetInst();
4171     }
4172 
GetInputType(size_t index)4173     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
4174     {
4175         ASSERT(index == 0);
4176         auto inputType = GetInput(0).GetInst()->GetType();
4177         ASSERT(inputType == DataType::ANY || inputType == DataType::REFERENCE);
4178         return inputType;
4179     }
4180 
IsBarrier()4181     bool IsBarrier() const override
4182     {
4183         return Inst::IsBarrier() || GetNeedBarrier();
4184     }
4185 
4186     PANDA_PUBLIC_API bool DumpInputs(std::ostream *out) const override;
4187 
Clone(const Graph * targetGraph)4188     Inst *Clone(const Graph *targetGraph) const override
4189     {
4190         auto clone = static_cast<LoadInstI *>(FixedInputsInst::Clone(targetGraph));
4191         clone->SetImm(GetImm());
4192         ASSERT(clone->IsArray() == IsArray());
4193         ASSERT(clone->GetVolatile() == GetVolatile());
4194         return clone;
4195     }
4196 
Latency()4197     uint32_t Latency() const override
4198     {
4199         return g_options.GetCompilerSchedLatencyLong();
4200     }
4201 };
4202 
4203 /// Load value from pointer with offset
4204 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4205 class PANDA_PUBLIC_API LoadMemInstI : public VolatileMixin<NeedBarrierMixin<FixedInputsInst1>>, public ImmediateMixin {
4206 public:
4207     using Base = VolatileMixin<NeedBarrierMixin<FixedInputsInst1>>;
4208     using Base::Base;
4209 
LoadMemInstI(Opcode opcode,uint64_t imm)4210     LoadMemInstI(Opcode opcode, uint64_t imm) : Base(opcode), ImmediateMixin(imm) {}
4211     LoadMemInstI(Initializer t, uint64_t imm, bool isVolatile = false, bool needBarrier = false)
Base(std::move (t))4212         : Base(std::move(t)), ImmediateMixin(imm)
4213     {
4214         SetVolatile(isVolatile);
4215         SetNeedBarrier(needBarrier);
4216     }
4217 
GetPointer()4218     Inst *GetPointer()
4219     {
4220         return GetInput(0).GetInst();
4221     }
4222 
GetInputType(size_t index)4223     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
4224     {
4225         ASSERT(index == 0);
4226         auto input0Type = GetInput(0).GetInst()->GetType();
4227         ASSERT(input0Type == DataType::POINTER || input0Type == DataType::REFERENCE);
4228         return input0Type;
4229     }
4230 
IsBarrier()4231     bool IsBarrier() const override
4232     {
4233         return Inst::IsBarrier() || GetNeedBarrier();
4234     }
4235 
4236     PANDA_PUBLIC_API bool DumpInputs(std::ostream *out) const override;
4237 
Clone(const Graph * targetGraph)4238     Inst *Clone(const Graph *targetGraph) const override
4239     {
4240         auto clone = static_cast<LoadMemInstI *>(FixedInputsInst::Clone(targetGraph));
4241         clone->SetImm(GetImm());
4242         ASSERT(clone->GetVolatile() == GetVolatile());
4243         return clone;
4244     }
4245 
Latency()4246     uint32_t Latency() const override
4247     {
4248         return g_options.GetCompilerSchedLatencyLong();
4249     }
4250 };
4251 
4252 /// Store value into array element, using array index as immediate
4253 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4254 class PANDA_PUBLIC_API StoreInstI : public VolatileMixin<NeedBarrierMixin<FixedInputsInst2>>, public ImmediateMixin {
4255 public:
4256     using Base = VolatileMixin<NeedBarrierMixin<FixedInputsInst2>>;
4257     using Base::Base;
4258 
StoreInstI(Opcode opcode,uint64_t imm)4259     StoreInstI(Opcode opcode, uint64_t imm) : Base(opcode), ImmediateMixin(imm) {}
4260 
IsBarrier()4261     bool IsBarrier() const override
4262     {
4263         return Inst::IsBarrier() || GetNeedBarrier();
4264     }
4265 
GetStoredValue()4266     Inst *GetStoredValue()
4267     {
4268         return GetInput(1).GetInst();
4269     }
GetArray()4270     Inst *GetArray()
4271     {
4272         return GetInput(0).GetInst();
4273     }
GetInputType(size_t index)4274     DataType::Type GetInputType(size_t index) const override
4275     {
4276         ASSERT(index < GetInputsCount());
4277         switch (index) {
4278             case 0: {
4279                 auto inputType = GetInput(0).GetInst()->GetType();
4280                 ASSERT(inputType == DataType::ANY || inputType == DataType::REFERENCE);
4281                 return inputType;
4282             }
4283             case 1:
4284                 return GetType();
4285             default:
4286                 UNREACHABLE();
4287         }
4288     }
4289 
Clone(const Graph * targetGraph)4290     Inst *Clone(const Graph *targetGraph) const override
4291     {
4292         auto clone = static_cast<StoreInstI *>(FixedInputsInst::Clone(targetGraph));
4293         clone->SetImm(GetImm());
4294         ASSERT(clone->GetVolatile() == GetVolatile());
4295         return clone;
4296     }
4297 
4298     PANDA_PUBLIC_API bool DumpInputs(std::ostream *out) const override;
4299 
4300     // StoreArrayI call barriers twice,so we need to save input register for second call
IsPropagateLiveness()4301     bool IsPropagateLiveness() const override
4302     {
4303         return GetType() == DataType::REFERENCE;
4304     }
4305 };
4306 
4307 /// Store value into pointer by offset
4308 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4309 class PANDA_PUBLIC_API StoreMemInstI : public VolatileMixin<NeedBarrierMixin<FixedInputsInst2>>, public ImmediateMixin {
4310 public:
4311     using Base = VolatileMixin<NeedBarrierMixin<FixedInputsInst2>>;
4312     using Base::Base;
4313 
StoreMemInstI(Opcode opcode,uint64_t imm)4314     StoreMemInstI(Opcode opcode, uint64_t imm) : Base(opcode), ImmediateMixin(imm) {}
4315 
IsBarrier()4316     bool IsBarrier() const override
4317     {
4318         return Inst::IsBarrier() || GetNeedBarrier();
4319     }
4320 
GetPointer()4321     Inst *GetPointer()
4322     {
4323         return GetInput(0).GetInst();
4324     }
GetStoredValue()4325     Inst *GetStoredValue()
4326     {
4327         return GetInput(1).GetInst();
4328     }
GetInputType(size_t index)4329     DataType::Type GetInputType(size_t index) const override
4330     {
4331         ASSERT(index < GetInputsCount());
4332         switch (index) {
4333             case 0: {
4334                 auto input0Type = GetInput(0).GetInst()->GetType();
4335                 ASSERT(input0Type == DataType::POINTER || input0Type == DataType::REFERENCE);
4336                 return input0Type;
4337             }
4338             case 1:
4339                 return GetType();
4340             default:
4341                 UNREACHABLE();
4342         }
4343     }
4344 
4345     PANDA_PUBLIC_API bool DumpInputs(std::ostream *out) const override;
4346 
Clone(const Graph * targetGraph)4347     Inst *Clone(const Graph *targetGraph) const override
4348     {
4349         auto clone = static_cast<StoreMemInstI *>(FixedInputsInst::Clone(targetGraph));
4350         clone->SetImm(GetImm());
4351         ASSERT(clone->GetVolatile() == GetVolatile());
4352         return clone;
4353     }
4354 };
4355 
4356 /// Bounds check, using array index as immediate
4357 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4358 class PANDA_PUBLIC_API BoundsCheckInstI : public ArrayInstMixin<FixedInputsInst<2U>>, public ImmediateMixin {
4359 public:
4360     using Base = ArrayInstMixin<FixedInputsInst<2U>>;
4361     using Base::Base;
4362 
Base(opcode)4363     BoundsCheckInstI(Opcode opcode, uint64_t imm, bool isArray = true) : Base(opcode), ImmediateMixin(imm)
4364     {
4365         SetIsArray(isArray);
4366     }
4367 
Base(std::move (t))4368     BoundsCheckInstI(Initializer t, uint64_t imm, bool isArray = true) : Base(std::move(t)), ImmediateMixin(imm)
4369     {
4370         SetIsArray(isArray);
4371     }
4372 
4373     PANDA_PUBLIC_API bool DumpInputs(std::ostream *out) const override;
4374 
Clone(const Graph * targetGraph)4375     Inst *Clone(const Graph *targetGraph) const override
4376     {
4377         auto clone = FixedInputsInst::Clone(targetGraph);
4378         clone->CastToBoundsCheckI()->SetImm(GetImm());
4379         ASSERT(clone->CastToBoundsCheckI()->IsArray() == IsArray());
4380         return clone;
4381     }
4382 };
4383 
4384 /// Bounds check instruction
4385 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4386 class BoundsCheckInst : public ArrayInstMixin<FixedInputsInst<3U>> {
4387 public:
4388     using Base = ArrayInstMixin<FixedInputsInst<3U>>;
4389     using Base::Base;
4390 
Base(opcode)4391     explicit BoundsCheckInst(Opcode opcode, bool isArray = true) : Base(opcode)
4392     {
4393         SetIsArray(isArray);
4394     }
4395 
Base(std::move (t))4396     explicit BoundsCheckInst(Initializer t, bool isArray = true) : Base(std::move(t))
4397     {
4398         SetIsArray(isArray);
4399     }
4400 
Clone(const Graph * targetGraph)4401     Inst *Clone(const Graph *targetGraph) const override
4402     {
4403         auto clone = FixedInputsInst::Clone(targetGraph);
4404         ASSERT(clone->CastToBoundsCheck()->IsArray() == IsArray());
4405         return clone;
4406     }
4407 
GetInputType(size_t index)4408     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
4409     {
4410         if (index == GetInputsCount() - 1) {
4411             return DataType::NO_TYPE;
4412         }
4413         return GetType();
4414     }
4415 };
4416 
4417 class NullCheckInst : public FixedInputsInst2 {
4418 public:
4419     using Base = FixedInputsInst2;
4420     using Base::Base;
4421 
IsImplicit()4422     bool IsImplicit() const
4423     {
4424         return GetField<IsImplicitFlag>();
4425     }
4426 
4427     void SetImplicit(bool isImplicit = true)
4428     {
4429         SetField<IsImplicitFlag>(isImplicit);
4430     }
4431 
GetInputType(size_t index)4432     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
4433     {
4434         if (index == GetInputsCount() - 1) {
4435             return DataType::NO_TYPE;
4436         }
4437         return DataType::REFERENCE;
4438     }
4439 
4440 private:
4441     using IsImplicitFlag = LastField::NextFlag;
4442     using LastField = IsImplicitFlag;
4443 };
4444 
4445 /// Return immediate
4446 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4447 class PANDA_PUBLIC_API ReturnInstI : public FixedInputsInst<0>, public ImmediateMixin {
4448 public:
4449     using FixedInputsInst::FixedInputsInst;
4450 
ReturnInstI(Opcode opcode,uint64_t imm)4451     ReturnInstI(Opcode opcode, uint64_t imm) : FixedInputsInst(opcode), ImmediateMixin(imm) {}
ReturnInstI(Inst::Initializer t,uint64_t imm)4452     ReturnInstI(Inst::Initializer t, uint64_t imm) : FixedInputsInst(std::move(t)), ImmediateMixin(imm) {}
4453 
4454     PANDA_PUBLIC_API bool DumpInputs(std::ostream *out) const override;
4455 
Clone(const Graph * targetGraph)4456     Inst *Clone(const Graph *targetGraph) const override
4457     {
4458         auto clone = FixedInputsInst::Clone(targetGraph);
4459         clone->CastToReturnI()->SetImm(GetImm());
4460         return clone;
4461     }
4462 };
4463 
4464 class ReturnInlinedInst : public FixedInputsInst<1> {
4465 public:
4466     using FixedInputsInst::FixedInputsInst;
4467 
IsExtendedLiveness()4468     bool IsExtendedLiveness() const
4469     {
4470         return GetField<IsExtendedLivenessFlag>();
4471     }
4472 
4473     void SetExtendedLiveness(bool isExtenedLiveness = true)
4474     {
4475         SetField<IsExtendedLivenessFlag>(isExtenedLiveness);
4476     }
4477 
4478 private:
4479     using IsExtendedLivenessFlag = LastField::NextFlag;
4480     using LastField = IsExtendedLivenessFlag;
4481 };
4482 
4483 /// Monitor instruction
4484 class PANDA_PUBLIC_API MonitorInst : public FixedInputsInst2 {
4485 public:
4486     using Base = FixedInputsInst2;
4487     using Base::Base;
4488 
IsExit()4489     bool IsExit() const
4490     {
4491         return GetField<Exit>();
4492     }
4493 
IsEntry()4494     bool IsEntry() const
4495     {
4496         return !GetField<Exit>();
4497     }
4498 
SetExit()4499     void SetExit()
4500     {
4501         SetField<Exit>(true);
4502     }
4503 
SetEntry()4504     void SetEntry()
4505     {
4506         SetField<Exit>(false);
4507     }
4508 
GetInputType(size_t index)4509     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
4510     {
4511         ASSERT(index < GetInputsCount());
4512         if (index == 1) {
4513             return DataType::NO_TYPE;
4514         }
4515         return DataType::REFERENCE;
4516     }
4517 
4518     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
4519 
4520 protected:
4521     using Exit = LastField::NextFlag;
4522     using LastField = Exit;
4523 };
4524 
4525 #include "inst_flags.inl"
4526 #include "intrinsics_flags.inl"
4527 
4528 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4529 class PANDA_PUBLIC_API IntrinsicInst : public InlinedInstMixin<InputTypesMixin<DynamicInputsInst>>, public TypeIdMixin {
4530 public:
4531     using Base = InlinedInstMixin<InputTypesMixin<DynamicInputsInst>>;
4532     using Base::Base;
4533     using IntrinsicId = RuntimeInterface::IntrinsicId;
4534 
IntrinsicInst(Opcode opcode,IntrinsicId intrinsicId)4535     IntrinsicInst(Opcode opcode, IntrinsicId intrinsicId) : Base(opcode), intrinsicId_(intrinsicId)
4536     {
4537         AdjustFlags(intrinsicId, this);
4538     }
4539 
IntrinsicInst(Initializer t,IntrinsicId intrinsicId)4540     IntrinsicInst(Initializer t, IntrinsicId intrinsicId) : Base(std::move(t)), intrinsicId_(intrinsicId)
4541     {
4542         AdjustFlags(intrinsicId, this);
4543     }
4544 
GetIntrinsicId()4545     IntrinsicId GetIntrinsicId() const
4546     {
4547         return intrinsicId_;
4548     }
4549 
SetIntrinsicId(IntrinsicId intrinsicId)4550     void SetIntrinsicId(IntrinsicId intrinsicId)
4551     {
4552         if (intrinsicId_ != RuntimeInterface::IntrinsicId::INVALID) {
4553             SetField<FieldFlags>(inst_flags::GetFlagsMask(GetOpcode()));
4554         }
4555         intrinsicId_ = intrinsicId;
4556         AdjustFlags(intrinsicId, this);
4557     }
4558 
GetInputType(size_t index)4559     DataType::Type GetInputType(size_t index) const override
4560     {
4561         ASSERT(inputTypes_ != nullptr);
4562         ASSERT(index < inputTypes_->size());
4563         ASSERT(index < GetInputsCount());
4564         return (*inputTypes_)[index];
4565     }
4566 
GetImm(size_t index)4567     uint32_t GetImm(size_t index) const
4568     {
4569         ASSERT(HasImms() && index < GetImms().size());
4570         return GetImms()[index];
4571     }
4572 
SetImm(size_t index,uint32_t imm)4573     void SetImm(size_t index, uint32_t imm)
4574     {
4575         ASSERT(HasImms() && index < GetImms().size());
4576         GetImms()[index] = imm;
4577     }
4578 
GetImms()4579     ArenaVector<uint32_t> &GetImms()
4580     {
4581         return *imms_;
4582     }
4583 
GetImms()4584     const ArenaVector<uint32_t> &GetImms() const
4585     {
4586         return *imms_;
4587     }
4588 
HasImms()4589     bool HasImms() const
4590     {
4591         return imms_ != nullptr;
4592     }
4593 
AddImm(ArenaAllocator * allocator,uint32_t imm)4594     void AddImm(ArenaAllocator *allocator, uint32_t imm)
4595     {
4596         if (imms_ == nullptr) {
4597             imms_ = allocator->New<ArenaVector<uint32_t>>(allocator->Adapter());
4598         }
4599         imms_->push_back(imm);
4600     }
4601 
4602     bool IsNativeCall() const;
4603 
HasArgumentsOnStack()4604     bool HasArgumentsOnStack() const
4605     {
4606         return GetField<ArgumentsOnStack>();
4607     }
4608 
SetArgumentsOnStack()4609     void SetArgumentsOnStack()
4610     {
4611         SetField<ArgumentsOnStack>(true);
4612     }
4613 
IsReplaceOnDeoptimize()4614     bool IsReplaceOnDeoptimize() const
4615     {
4616         return GetField<ReplaceOnDeoptimize>();
4617     }
4618 
SetReplaceOnDeoptimize()4619     void SetReplaceOnDeoptimize()
4620     {
4621         SetField<ReplaceOnDeoptimize>(true);
4622     }
4623 
HasIdInput()4624     bool HasIdInput() const
4625     {
4626         return GetField<IdInput>();
4627     }
4628 
SetHasIdInput()4629     void SetHasIdInput()
4630     {
4631         SetField<IdInput>(true);
4632     }
4633 
IsMethodFirstInput()4634     bool IsMethodFirstInput() const
4635     {
4636         return GetField<MethodFirstInput>();
4637     }
4638 
SetMethodFirstInput()4639     void SetMethodFirstInput()
4640     {
4641         SetField<MethodFirstInput>(true);
4642     }
4643 
4644     PANDA_PUBLIC_API Inst *Clone(const Graph *targetGraph) const override;
4645 
CanBeInlined()4646     bool CanBeInlined()
4647     {
4648         return IsInlined();
4649     }
4650 
SetRelocate()4651     void SetRelocate()
4652     {
4653         SetField<Relocate>(true);
4654     }
4655 
GetRelocate()4656     bool GetRelocate() const
4657     {
4658         return GetField<Relocate>();
4659     }
4660 
4661     uint32_t GetTypeId() = delete;  // only method field of TypeIdMixin is used
4662 
4663     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
4664     PANDA_PUBLIC_API bool DumpInputs(std::ostream *out) const override;
4665 
4666     void DumpImms(std::ostream *out) const;
4667 
4668 protected:
4669     using ArgumentsOnStack = LastField::NextFlag;
4670     using Relocate = ArgumentsOnStack::NextFlag;
4671     using ReplaceOnDeoptimize = Relocate::NextFlag;
4672     using IdInput = ReplaceOnDeoptimize::NextFlag;
4673     using MethodFirstInput = IdInput::NextFlag;
4674     using LastField = MethodFirstInput;
4675 
4676 private:
4677     IntrinsicId intrinsicId_ {RuntimeInterface::IntrinsicId::COUNT};
4678     ArenaVector<uint32_t> *imms_ {nullptr};  // record imms appeared in intrinsics
4679 };
4680 
4681 #include <get_intrinsics_names.inl>
4682 #include <intrinsics_enum.inl>
4683 #include <can_encode_builtin.inl>
4684 
4685 /// Cast instruction
4686 class PANDA_PUBLIC_API CastInst : public InstWithOperandsType<FixedInputsInst1> {
4687 public:
4688     using BaseInst = InstWithOperandsType<FixedInputsInst1>;
4689     using BaseInst::BaseInst;
4690 
CastInst(Initializer t,DataType::Type operType)4691     CastInst(Initializer t, DataType::Type operType) : BaseInst(std::move(t))
4692     {
4693         SetOperandsType(operType);
4694     }
4695 
GetInputType(size_t index)4696     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
4697     {
4698         ASSERT(index == 0);
4699         auto type = GetOperandsType();
4700         return type != DataType::NO_TYPE ? type : GetInput(0).GetInst()->GetType();
4701     }
4702 
4703     PANDA_PUBLIC_API void SetVnObject(VnObject *vnObj) override;
4704 
4705     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
4706 
Clone(const Graph * targetGraph)4707     PANDA_PUBLIC_API Inst *Clone(const Graph *targetGraph) const override
4708     {
4709         auto clone = static_cast<CastInst *>(FixedInputsInst::Clone(targetGraph));
4710         ASSERT(clone->GetOperandsType() == GetOperandsType());
4711         return clone;
4712     }
4713 
4714     bool IsDynamicCast() const;
4715 };
4716 
4717 /// Cmp instruction
4718 class PANDA_PUBLIC_API CmpInst : public InstWithOperandsType<FixedInputsInst2> {
4719 public:
4720     using BaseInst = InstWithOperandsType<FixedInputsInst2>;
4721     using BaseInst::BaseInst;
4722 
CmpInst(Initializer t,DataType::Type operType)4723     CmpInst(Initializer t, DataType::Type operType) : BaseInst(std::move(t))
4724     {
4725         SetOperandsType(operType);
4726     }
4727 
IsFcmpg()4728     bool IsFcmpg() const
4729     {
4730         ASSERT(DataType::IsFloatType(GetOperandsType()));
4731         return GetField<Fcmpg>();
4732     }
IsFcmpl()4733     bool IsFcmpl() const
4734     {
4735         ASSERT(DataType::IsFloatType(GetOperandsType()));
4736         return !GetField<Fcmpg>();
4737     }
SetFcmpg()4738     void SetFcmpg()
4739     {
4740         ASSERT(DataType::IsFloatType(GetOperandsType()));
4741         SetField<Fcmpg>(true);
4742     }
SetFcmpg(bool v)4743     void SetFcmpg(bool v)
4744     {
4745         ASSERT(DataType::IsFloatType(GetOperandsType()));
4746         SetField<Fcmpg>(v);
4747     }
SetFcmpl()4748     void SetFcmpl()
4749     {
4750         ASSERT(DataType::IsFloatType(GetOperandsType()));
4751         SetField<Fcmpg>(false);
4752     }
SetFcmpl(bool v)4753     void SetFcmpl(bool v)
4754     {
4755         ASSERT(DataType::IsFloatType(GetOperandsType()));
4756         SetField<Fcmpg>(!v);
4757     }
4758 
GetInputType(size_t index)4759     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
4760     {
4761         ASSERT(index < GetInputsCount());
4762         return GetOperandsType();
4763     }
4764 
4765     PANDA_PUBLIC_API void SetVnObject(VnObject *vnObj) override;
4766 
4767     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
4768 
Clone(const Graph * targetGraph)4769     Inst *Clone(const Graph *targetGraph) const override
4770     {
4771         auto clone = FixedInputsInst::Clone(targetGraph);
4772         ASSERT(clone->CastToCmp()->GetOperandsType() == GetOperandsType());
4773         return clone;
4774     }
4775 
4776 protected:
4777     using Fcmpg = LastField::NextFlag;
4778     using LastField = Fcmpg;
4779 };
4780 
4781 /// Load value from instance field
4782 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4783 class PANDA_PUBLIC_API LoadObjectInst : public ObjectTypeMixin<VolatileMixin<NeedBarrierMixin<FixedInputsInst1>>>,
4784                                         public TypeIdMixin,
4785                                         public FieldMixin {
4786 public:
4787     using Base = ObjectTypeMixin<VolatileMixin<NeedBarrierMixin<FixedInputsInst1>>>;
4788     using Base::Base;
4789 
4790     LoadObjectInst(Initializer t, TypeIdMixin m, RuntimeInterface::FieldPtr field, bool isVolatile = false,
4791                    bool needBarrier = false)
Base(std::move (t))4792         : Base(std::move(t)), TypeIdMixin(std::move(m)), FieldMixin(field)
4793     {
4794         SetVolatile(isVolatile);
4795         SetNeedBarrier(needBarrier);
4796     }
4797 
GetInputType(size_t index)4798     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
4799     {
4800         ASSERT(index < GetInputsCount());
4801         ASSERT(GetInputsCount() == 1);
4802         auto inputType = GetInput(0).GetInst()->GetType();
4803         ASSERT(inputType == DataType::NO_TYPE || inputType == DataType::REFERENCE || inputType == DataType::ANY);
4804         return inputType;
4805     }
4806 
IsBarrier()4807     bool IsBarrier() const override
4808     {
4809         return Inst::IsBarrier() || GetNeedBarrier() || GetVolatile();
4810     }
4811 
4812     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
4813 
Clone(const Graph * targetGraph)4814     Inst *Clone(const Graph *targetGraph) const override
4815     {
4816         auto clone = FixedInputsInst::Clone(targetGraph);
4817         clone->CastToLoadObject()->SetTypeId(GetTypeId());
4818         clone->CastToLoadObject()->SetMethod(GetMethod());
4819         clone->CastToLoadObject()->SetObjField(GetObjField());
4820         ASSERT(clone->CastToLoadObject()->GetVolatile() == GetVolatile());
4821         ASSERT(clone->CastToLoadObject()->GetObjectType() == GetObjectType());
4822         return clone;
4823     }
4824 
Latency()4825     uint32_t Latency() const override
4826     {
4827         return g_options.GetCompilerSchedLatencyLong();
4828     }
4829 };
4830 
4831 /// Load value from memory by offset
4832 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4833 class PANDA_PUBLIC_API LoadMemInst : public ScaleMixin<VolatileMixin<NeedBarrierMixin<FixedInputsInst2>>> {
4834 public:
4835     using Base = ScaleMixin<VolatileMixin<NeedBarrierMixin<FixedInputsInst2>>>;
4836     using Base::Base;
4837 
Base(std::move (t))4838     explicit LoadMemInst(Initializer t, bool isVolatile = false, bool needBarrier = false) : Base(std::move(t))
4839     {
4840         SetVolatile(isVolatile);
4841         SetNeedBarrier(needBarrier);
4842     }
4843 
GetInputType(size_t index)4844     DataType::Type GetInputType(size_t index) const override
4845     {
4846         ASSERT(index < GetInputsCount());
4847         ASSERT(GetInputsCount() == 2U);
4848         if (index == 1U) {
4849             return DataType::IsInt32Bit(GetInput(1).GetInst()->GetType()) ? DataType::INT32 : DataType::INT64;
4850         }
4851 
4852         ASSERT(index == 0U);
4853         auto input0Type = GetInput(0).GetInst()->GetType();
4854         ASSERT((GetInput(0).GetInst()->IsConst() && input0Type == DataType::INT64) || input0Type == DataType::POINTER ||
4855                input0Type == DataType::REFERENCE);
4856         return input0Type;
4857     }
4858 
IsBarrier()4859     bool IsBarrier() const override
4860     {
4861         return Inst::IsBarrier() || GetNeedBarrier() || GetVolatile();
4862     }
4863 
4864     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
4865     PANDA_PUBLIC_API bool DumpInputs(std::ostream *out) const override;
4866 
Clone(const Graph * targetGraph)4867     Inst *Clone(const Graph *targetGraph) const override
4868     {
4869         auto clone = FixedInputsInst::Clone(targetGraph);
4870         ASSERT(clone->CastToLoad()->GetVolatile() == GetVolatile());
4871         ASSERT(clone->CastToLoad()->GetScale() == GetScale());
4872         return clone;
4873     }
4874 
Latency()4875     uint32_t Latency() const override
4876     {
4877         return g_options.GetCompilerSchedLatencyLong();
4878     }
4879 };
4880 
4881 /// Load value from dynamic object
4882 class LoadObjectDynamicInst : public DynObjectAccessMixin<FixedInputsInst3> {
4883 public:
4884     using Base = DynObjectAccessMixin<FixedInputsInst3>;
4885     using Base::Base;
4886 
IsBarrier()4887     bool IsBarrier() const override
4888     {
4889         return true;
4890     }
4891 };
4892 
4893 /// Store value to dynamic object
4894 class StoreObjectDynamicInst : public DynObjectAccessMixin<FixedInputsInst<4U>> {
4895 public:
4896     using Base = DynObjectAccessMixin<FixedInputsInst<4U>>;
4897     using Base::Base;
4898 
IsBarrier()4899     bool IsBarrier() const override
4900     {
4901         return true;
4902     }
4903 };
4904 
4905 /// Resolve instance field
4906 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4907 class PANDA_PUBLIC_API ResolveObjectFieldInst : public NeedBarrierMixin<FixedInputsInst1>, public TypeIdMixin {
4908 public:
4909     using Base = NeedBarrierMixin<FixedInputsInst1>;
4910     using Base::Base;
4911 
4912     ResolveObjectFieldInst(Initializer t, TypeIdMixin m, bool needBarrier = false)
Base(std::move (t))4913         : Base(std::move(t)), TypeIdMixin(std::move(m))
4914     {
4915         SetNeedBarrier(needBarrier);
4916     }
4917 
GetInputType(size_t index)4918     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
4919     {
4920         ASSERT(GetInputsCount() == 1U);
4921         ASSERT(index == 0);
4922         // This is SaveState input
4923         return DataType::NO_TYPE;
4924     }
4925 
Clone(const Graph * targetGraph)4926     Inst *Clone(const Graph *targetGraph) const override
4927     {
4928         auto clone = FixedInputsInst::Clone(targetGraph);
4929         clone->CastToResolveObjectField()->SetTypeId(GetTypeId());
4930         clone->CastToResolveObjectField()->SetMethod(GetMethod());
4931         return clone;
4932     }
4933 
Latency()4934     uint32_t Latency() const override
4935     {
4936         return g_options.GetCompilerSchedLatencyLong();
4937     }
4938 
4939     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
4940 };
4941 
4942 /// Load value from resolved instance field
4943 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4944 class PANDA_PUBLIC_API LoadResolvedObjectFieldInst : public VolatileMixin<NeedBarrierMixin<FixedInputsInst2>>,
4945                                                      public TypeIdMixin {
4946 public:
4947     using Base = VolatileMixin<NeedBarrierMixin<FixedInputsInst2>>;
4948     using Base::Base;
4949 
4950     LoadResolvedObjectFieldInst(Initializer t, TypeIdMixin m, bool isVolatile = false, bool needBarrier = false)
Base(std::move (t))4951         : Base(std::move(t)), TypeIdMixin(std::move(m))
4952     {
4953         SetVolatile(isVolatile);
4954         SetNeedBarrier(needBarrier);
4955     }
4956 
GetInputType(size_t index)4957     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
4958     {
4959         ASSERT(GetInputsCount() == 2U);
4960         ASSERT(index < GetInputsCount());
4961         return index == 0 ? DataType::REFERENCE : DataType::UINT32;
4962     }
4963 
IsBarrier()4964     bool IsBarrier() const override
4965     {
4966         return Inst::IsBarrier() || GetNeedBarrier() || GetVolatile();
4967     }
4968 
Clone(const Graph * targetGraph)4969     Inst *Clone(const Graph *targetGraph) const override
4970     {
4971         auto clone = FixedInputsInst::Clone(targetGraph);
4972         clone->CastToLoadResolvedObjectField()->SetTypeId(GetTypeId());
4973         clone->CastToLoadResolvedObjectField()->SetMethod(GetMethod());
4974         ASSERT(clone->CastToLoadResolvedObjectField()->GetVolatile() == GetVolatile());
4975         return clone;
4976     }
4977 
Latency()4978     uint32_t Latency() const override
4979     {
4980         return g_options.GetCompilerSchedLatencyLong();
4981     }
4982 
4983     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
4984 };
4985 
4986 /// Store value into instance field
4987 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
4988 class PANDA_PUBLIC_API StoreObjectInst : public ObjectTypeMixin<VolatileMixin<NeedBarrierMixin<FixedInputsInst2>>>,
4989                                          public TypeIdMixin,
4990                                          public FieldMixin {
4991 public:
4992     using Base = ObjectTypeMixin<VolatileMixin<NeedBarrierMixin<FixedInputsInst2>>>;
4993     using Base::Base;
4994     static constexpr size_t STORED_INPUT_INDEX = 1;
4995 
4996     StoreObjectInst(Initializer t, TypeIdMixin m, RuntimeInterface::FieldPtr field, bool isVolatile = false,
4997                     bool needBarrier = false)
Base(std::move (t))4998         : Base(std::move(t)), TypeIdMixin(std::move(m)), FieldMixin(field)
4999     {
5000         SetVolatile(isVolatile);
5001         SetNeedBarrier(needBarrier);
5002     }
5003 
GetInputType(size_t index)5004     DataType::Type GetInputType(size_t index) const override
5005     {
5006         ASSERT(index < GetInputsCount());
5007         ASSERT(GetInputsCount() == 2U);
5008         return index == 0 ? DataType::REFERENCE : GetType();
5009     }
5010 
IsBarrier()5011     bool IsBarrier() const override
5012     {
5013         return Inst::IsBarrier() || GetNeedBarrier() || GetVolatile();
5014     }
5015 
Clone(const Graph * targetGraph)5016     Inst *Clone(const Graph *targetGraph) const override
5017     {
5018         auto clone = FixedInputsInst::Clone(targetGraph);
5019         clone->CastToStoreObject()->SetTypeId(GetTypeId());
5020         clone->CastToStoreObject()->SetMethod(GetMethod());
5021         clone->CastToStoreObject()->SetObjField(GetObjField());
5022         ASSERT(clone->CastToStoreObject()->GetVolatile() == GetVolatile());
5023         ASSERT(clone->CastToStoreObject()->GetObjectType() == GetObjectType());
5024         return clone;
5025     }
5026 
5027     // StoreObject call barriers twice,so we need to save input register for second call
IsPropagateLiveness()5028     bool IsPropagateLiveness() const override
5029     {
5030         return GetType() == DataType::REFERENCE;
5031     }
5032 
5033     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
5034 };
5035 
5036 /// Store value into resolved instance field
5037 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
5038 class PANDA_PUBLIC_API StoreResolvedObjectFieldInst : public VolatileMixin<NeedBarrierMixin<FixedInputsInst3>>,
5039                                                       public TypeIdMixin {
5040 public:
5041     using Base = VolatileMixin<NeedBarrierMixin<FixedInputsInst3>>;
5042     using Base::Base;
5043     static constexpr size_t STORED_INPUT_INDEX = 1;
5044 
5045     StoreResolvedObjectFieldInst(Initializer t, TypeIdMixin m, bool isVolatile = false, bool needBarrier = false)
Base(std::move (t))5046         : Base(std::move(t)), TypeIdMixin(std::move(m))
5047     {
5048         SetVolatile(isVolatile);
5049         SetNeedBarrier(needBarrier);
5050     }
5051 
IsBarrier()5052     bool IsBarrier() const override
5053     {
5054         return Inst::IsBarrier() || GetVolatile() || GetNeedBarrier();
5055     }
5056 
GetInputType(size_t index)5057     DataType::Type GetInputType(size_t index) const override
5058     {
5059         ASSERT(index < GetInputsCount());
5060         ASSERT(GetInputsCount() == 3U);
5061         if (index == 0) {
5062             return DataType::REFERENCE;  // null-check
5063         }
5064         if (index == 1) {
5065             return GetType();  // stored value
5066         }
5067         return DataType::UINT32;  // field offset
5068     }
5069 
5070     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
5071 
Clone(const Graph * targetGraph)5072     Inst *Clone(const Graph *targetGraph) const override
5073     {
5074         auto clone = FixedInputsInst::Clone(targetGraph);
5075         clone->CastToStoreResolvedObjectField()->SetTypeId(GetTypeId());
5076         clone->CastToStoreResolvedObjectField()->SetMethod(GetMethod());
5077         ASSERT(clone->CastToStoreResolvedObjectField()->GetVolatile() == GetVolatile());
5078         return clone;
5079     }
5080 
5081     // StoreResolvedObjectField calls barriers twice,
5082     // so we need to save input register for the second call.
IsPropagateLiveness()5083     bool IsPropagateLiveness() const override
5084     {
5085         return GetType() == DataType::REFERENCE;
5086     }
5087 };
5088 
5089 /// Store value in memory by offset
5090 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
5091 class PANDA_PUBLIC_API StoreMemInst : public ScaleMixin<VolatileMixin<NeedBarrierMixin<FixedInputsInst3>>> {
5092 public:
5093     using Base = ScaleMixin<VolatileMixin<NeedBarrierMixin<FixedInputsInst3>>>;
5094     using Base::Base;
5095 
5096     static constexpr size_t STORED_INPUT_INDEX = 2;
5097 
Base(std::move (t))5098     explicit StoreMemInst(Initializer t, bool isVolatile = false, bool needBarrier = false) : Base(std::move(t))
5099     {
5100         SetVolatile(isVolatile);
5101         SetNeedBarrier(needBarrier);
5102     }
5103 
IsBarrier()5104     bool IsBarrier() const override
5105     {
5106         return Inst::IsBarrier() || GetNeedBarrier() || GetVolatile();
5107     }
5108 
GetInputType(size_t index)5109     DataType::Type GetInputType(size_t index) const override
5110     {
5111         ASSERT(index < GetInputsCount());
5112         ASSERT(GetInputsCount() == 3U);
5113         if (index == 1U) {
5114             return DataType::IsInt32Bit(GetInput(1).GetInst()->GetType()) ? DataType::INT32 : DataType::INT64;
5115         }
5116         if (index == 2U) {
5117             return GetType();
5118         }
5119 
5120         ASSERT(index == 0U);
5121         auto input0Type = GetInput(0).GetInst()->GetType();
5122         ASSERT(input0Type == DataType::POINTER || input0Type == DataType::REFERENCE);
5123         return input0Type;
5124     }
5125 
5126     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
5127     PANDA_PUBLIC_API bool DumpInputs(std::ostream *out) const override;
5128 
Clone(const Graph * targetGraph)5129     Inst *Clone(const Graph *targetGraph) const override
5130     {
5131         auto clone = FixedInputsInst::Clone(targetGraph);
5132         ASSERT(clone->CastToStore()->GetVolatile() == GetVolatile());
5133         ASSERT(clone->CastToStore()->GetScale() == GetScale());
5134         return clone;
5135     }
5136 };
5137 
5138 /// Load static field from class.
5139 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
5140 class PANDA_PUBLIC_API LoadStaticInst : public VolatileMixin<NeedBarrierMixin<FixedInputsInst1>>,
5141                                         public TypeIdMixin,
5142                                         public FieldMixin {
5143 public:
5144     using Base = VolatileMixin<NeedBarrierMixin<FixedInputsInst1>>;
5145     using Base::Base;
5146 
5147     LoadStaticInst(Initializer t, TypeIdMixin m, RuntimeInterface::FieldPtr field, bool isVolatile = false,
5148                    bool needBarrier = false)
Base(std::move (t))5149         : Base(std::move(t)), TypeIdMixin(std::move(m)), FieldMixin(field)
5150     {
5151         SetVolatile(isVolatile);
5152         SetNeedBarrier(needBarrier);
5153     }
5154 
IsBarrier()5155     bool IsBarrier() const override
5156     {
5157         return GetNeedBarrier() || GetVolatile() || Inst::IsBarrier();
5158     }
5159 
5160     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
5161 
GetInputType(size_t index)5162     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
5163     {
5164         ASSERT(index < GetInputsCount());
5165         ASSERT(index == 0);
5166         return DataType::REFERENCE;
5167     }
5168 
Clone(const Graph * targetGraph)5169     Inst *Clone(const Graph *targetGraph) const override
5170     {
5171         auto clone = FixedInputsInst::Clone(targetGraph);
5172         clone->CastToLoadStatic()->SetTypeId(GetTypeId());
5173         clone->CastToLoadStatic()->SetMethod(GetMethod());
5174         clone->CastToLoadStatic()->SetObjField(GetObjField());
5175         ASSERT(clone->CastToLoadStatic()->GetVolatile() == GetVolatile());
5176         return clone;
5177     }
5178 
Latency()5179     uint32_t Latency() const override
5180     {
5181         return g_options.GetCompilerSchedLatencyLong();
5182     }
5183 };
5184 
5185 /// Resolve static instance field
5186 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
5187 class PANDA_PUBLIC_API ResolveObjectFieldStaticInst : public NeedBarrierMixin<FixedInputsInst1>, public TypeIdMixin {
5188 public:
5189     using Base = NeedBarrierMixin<FixedInputsInst1>;
5190     using Base::Base;
5191 
5192     ResolveObjectFieldStaticInst(Initializer t, TypeIdMixin m, bool needBarrier = false)
Base(std::move (t))5193         : Base(std::move(t)), TypeIdMixin(std::move(m))
5194     {
5195         SetNeedBarrier(needBarrier);
5196     }
5197 
Clone(const Graph * targetGraph)5198     Inst *Clone(const Graph *targetGraph) const override
5199     {
5200         auto clone = FixedInputsInst::Clone(targetGraph);
5201         clone->CastToResolveObjectFieldStatic()->SetTypeId(GetTypeId());
5202         clone->CastToResolveObjectFieldStatic()->SetMethod(GetMethod());
5203         return clone;
5204     }
5205 
GetInputType(size_t index)5206     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
5207     {
5208         ASSERT(GetInputsCount() == 1U);
5209         ASSERT(index == 0);
5210         // This is SaveState input
5211         return DataType::NO_TYPE;
5212     }
5213 
Latency()5214     uint32_t Latency() const override
5215     {
5216         return g_options.GetCompilerSchedLatencyLong();
5217     }
5218 
5219     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
5220 };
5221 
5222 /// Load value from resolved static instance field
5223 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
5224 class PANDA_PUBLIC_API LoadResolvedObjectFieldStaticInst : public VolatileMixin<NeedBarrierMixin<FixedInputsInst1>>,
5225                                                            public TypeIdMixin {
5226 public:
5227     using Base = VolatileMixin<NeedBarrierMixin<FixedInputsInst1>>;
5228     using Base::Base;
5229 
5230     LoadResolvedObjectFieldStaticInst(Initializer t, TypeIdMixin m, bool isVolatile = false, bool needBarrier = false)
Base(std::move (t))5231         : Base(std::move(t)), TypeIdMixin(std::move(m))
5232     {
5233         SetVolatile(isVolatile);
5234         SetNeedBarrier(needBarrier);
5235     }
5236 
GetInputType(size_t index)5237     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
5238     {
5239         ASSERT(GetInputsCount() == 1U);
5240         ASSERT(index < GetInputsCount());
5241         return DataType::REFERENCE;
5242     }
5243 
IsBarrier()5244     bool IsBarrier() const override
5245     {
5246         return Inst::IsBarrier() || GetNeedBarrier() || GetVolatile();
5247     }
5248 
Clone(const Graph * targetGraph)5249     Inst *Clone(const Graph *targetGraph) const override
5250     {
5251         auto clone = FixedInputsInst::Clone(targetGraph);
5252         clone->CastToLoadResolvedObjectFieldStatic()->SetTypeId(GetTypeId());
5253         clone->CastToLoadResolvedObjectFieldStatic()->SetMethod(GetMethod());
5254         ASSERT(clone->CastToLoadResolvedObjectFieldStatic()->GetVolatile() == GetVolatile());
5255         return clone;
5256     }
5257 
Latency()5258     uint32_t Latency() const override
5259     {
5260         return g_options.GetCompilerSchedLatencyLong();
5261     }
5262 
5263     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
5264 };
5265 
5266 /// Store value into static field.
5267 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
5268 class PANDA_PUBLIC_API StoreStaticInst : public VolatileMixin<NeedBarrierMixin<FixedInputsInst2>>,
5269                                          public TypeIdMixin,
5270                                          public FieldMixin {
5271 public:
5272     using Base = VolatileMixin<NeedBarrierMixin<FixedInputsInst2>>;
5273     using Base::Base;
5274     static constexpr size_t STORED_INPUT_INDEX = 1;
5275 
5276     StoreStaticInst(Initializer t, TypeIdMixin m, RuntimeInterface::FieldPtr field, bool isVolatile = false,
5277                     bool needBarrier = false)
Base(std::move (t))5278         : Base(std::move(t)), TypeIdMixin(std::move(m)), FieldMixin(field)
5279     {
5280         SetNeedBarrier(needBarrier);
5281         SetVolatile(isVolatile);
5282     }
5283 
IsBarrier()5284     bool IsBarrier() const override
5285     {
5286         return Inst::IsBarrier() || GetNeedBarrier() || GetVolatile();
5287     }
5288 
5289     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
5290 
GetInputType(size_t index)5291     DataType::Type GetInputType(size_t index) const override
5292     {
5293         ASSERT(index < GetInputsCount());
5294         if (index == 0) {
5295             return DataType::REFERENCE;
5296         }
5297         return GetType();
5298     }
5299 
Clone(const Graph * targetGraph)5300     Inst *Clone(const Graph *targetGraph) const override
5301     {
5302         auto clone = FixedInputsInst::Clone(targetGraph);
5303         clone->CastToStoreStatic()->SetTypeId(GetTypeId());
5304         clone->CastToStoreStatic()->SetMethod(GetMethod());
5305         clone->CastToStoreStatic()->SetObjField(GetObjField());
5306         ASSERT(clone->CastToStoreStatic()->GetVolatile() == GetVolatile());
5307         return clone;
5308     }
5309 
5310     // StoreStatic call barriers twice,so we need to save input register for second call
IsPropagateLiveness()5311     bool IsPropagateLiveness() const override
5312     {
5313         return GetType() == DataType::REFERENCE;
5314     }
5315 };
5316 
5317 /// Store value into unresolved static field.
5318 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
5319 class PANDA_PUBLIC_API UnresolvedStoreStaticInst : public NeedBarrierMixin<FixedInputsInst2>, public TypeIdMixin {
5320 public:
5321     using Base = NeedBarrierMixin<FixedInputsInst2>;
5322     using Base::Base;
5323 
5324     UnresolvedStoreStaticInst(Initializer t, TypeIdMixin m, bool needBarrier = false)
Base(std::move (t))5325         : Base(std::move(t)), TypeIdMixin(std::move(m))
5326     {
5327         SetNeedBarrier(needBarrier);
5328     }
5329 
IsBarrier()5330     bool IsBarrier() const override
5331     {
5332         return true;
5333     }
5334 
5335     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
5336 
GetInputType(size_t index)5337     DataType::Type GetInputType(size_t index) const override
5338     {
5339         ASSERT(index < GetInputsCount());
5340         if (index == 1) {
5341             // This is SaveState input
5342             return DataType::NO_TYPE;
5343         }
5344         ASSERT(index == 0);
5345         return GetType();
5346     }
5347 
Clone(const Graph * targetGraph)5348     Inst *Clone(const Graph *targetGraph) const override
5349     {
5350         auto clone = FixedInputsInst::Clone(targetGraph);
5351         clone->CastToUnresolvedStoreStatic()->SetTypeId(GetTypeId());
5352         clone->CastToUnresolvedStoreStatic()->SetMethod(GetMethod());
5353         return clone;
5354     }
5355 };
5356 
5357 /// Store value into resolved static field.
5358 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
5359 class PANDA_PUBLIC_API StoreResolvedObjectFieldStaticInst : public NeedBarrierMixin<FixedInputsInst2>,
5360                                                             public TypeIdMixin {
5361 public:
5362     using Base = NeedBarrierMixin<FixedInputsInst2>;
5363     using Base::Base;
5364 
5365     StoreResolvedObjectFieldStaticInst(Initializer t, TypeIdMixin m, bool needBarrier = false)
Base(std::move (t))5366         : Base(std::move(t)), TypeIdMixin(std::move(m))
5367     {
5368         SetNeedBarrier(needBarrier);
5369     }
5370 
IsBarrier()5371     bool IsBarrier() const override
5372     {
5373         return true;
5374     }
5375 
GetInputType(size_t index)5376     DataType::Type GetInputType(size_t index) const override
5377     {
5378         ASSERT(GetInputsCount() == 2U);
5379         ASSERT(index < GetInputsCount());
5380         if (index == 0) {
5381             return DataType::REFERENCE;
5382         }
5383         return GetType();  // stored value
5384     }
5385 
Clone(const Graph * targetGraph)5386     Inst *Clone(const Graph *targetGraph) const override
5387     {
5388         auto clone = FixedInputsInst::Clone(targetGraph);
5389         clone->CastToStoreResolvedObjectFieldStatic()->SetTypeId(GetTypeId());
5390         clone->CastToStoreResolvedObjectFieldStatic()->SetMethod(GetMethod());
5391         return clone;
5392     }
5393 
5394     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
5395 };
5396 
5397 /// Create new object
5398 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
5399 class PANDA_PUBLIC_API NewObjectInst : public NeedBarrierMixin<FixedInputsInst2>, public TypeIdMixin {
5400 public:
5401     using Base = NeedBarrierMixin<FixedInputsInst2>;
5402     using Base::Base;
5403 
5404     NewObjectInst(Initializer t, TypeIdMixin m, bool needBarrier = false)
Base(std::move (t))5405         : Base(std::move(t)), TypeIdMixin(std::move(m))
5406     {
5407         SetNeedBarrier(needBarrier);
5408     }
5409 
IsBarrier()5410     bool IsBarrier() const override
5411     {
5412         return Inst::IsBarrier() || GetNeedBarrier();
5413     }
GetInputType(size_t index)5414     DataType::Type GetInputType(size_t index) const override
5415     {
5416         ASSERT(index < GetInputsCount());
5417         if (index == 0) {
5418             return DataType::REFERENCE;
5419         }
5420         return DataType::NO_TYPE;
5421     }
5422 
5423     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
5424 
Clone(const Graph * targetGraph)5425     Inst *Clone(const Graph *targetGraph) const override
5426     {
5427         auto clone = FixedInputsInst::Clone(targetGraph);
5428         clone->CastToNewObject()->SetTypeId(GetTypeId());
5429         clone->CastToNewObject()->SetMethod(GetMethod());
5430         return clone;
5431     }
5432 };
5433 
5434 /// Create new array
5435 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
5436 class PANDA_PUBLIC_API NewArrayInst : public NeedBarrierMixin<FixedInputsInst3>, public TypeIdMixin {
5437 public:
5438     using Base = NeedBarrierMixin<FixedInputsInst3>;
5439     using Base::Base;
5440 
5441     static constexpr size_t INDEX_CLASS = 0;
5442     static constexpr size_t INDEX_SIZE = 1;
5443     static constexpr size_t INDEX_SAVE_STATE = 2;
5444 
Base(std::move (t))5445     NewArrayInst(Initializer t, TypeIdMixin m, bool needBarrier = false) : Base(std::move(t)), TypeIdMixin(std::move(m))
5446     {
5447         SetNeedBarrier(needBarrier);
5448     }
5449 
GetInputType(size_t index)5450     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
5451     {
5452         ASSERT(index < GetInputsCount());
5453         switch (index) {
5454             case INDEX_CLASS:
5455                 return GetInput(0).GetInst()->GetType();
5456             case INDEX_SIZE:
5457                 return DataType::INT32;
5458             case INDEX_SAVE_STATE:
5459                 // This is SaveState input
5460                 return DataType::NO_TYPE;
5461             default:
5462                 UNREACHABLE();
5463         }
5464     }
5465 
IsBarrier()5466     bool IsBarrier() const override
5467     {
5468         return Inst::IsBarrier() || GetNeedBarrier();
5469     }
5470 
5471     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
5472 
Clone(const Graph * targetGraph)5473     Inst *Clone(const Graph *targetGraph) const override
5474     {
5475         auto clone = FixedInputsInst::Clone(targetGraph);
5476         clone->CastToNewArray()->SetTypeId(GetTypeId());
5477         clone->CastToNewArray()->SetMethod(GetMethod());
5478         return clone;
5479     }
5480 };
5481 
5482 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
5483 class PANDA_PUBLIC_API LoadConstArrayInst : public NeedBarrierMixin<FixedInputsInst1>, public TypeIdMixin {
5484 public:
5485     using Base = NeedBarrierMixin<FixedInputsInst1>;
5486     using Base::Base;
5487 
5488     LoadConstArrayInst(Initializer t, TypeIdMixin m, bool needBarrier = false)
Base(std::move (t))5489         : Base(std::move(t)), TypeIdMixin(std::move(m))
5490     {
5491         SetNeedBarrier(needBarrier);
5492     }
5493 
IsBarrier()5494     bool IsBarrier() const override
5495     {
5496         return Inst::IsBarrier() || GetNeedBarrier();
5497     }
5498 
GetInputType(size_t index)5499     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
5500     {
5501         ASSERT(index < GetInputsCount());
5502         return DataType::NO_TYPE;
5503     }
5504 
5505     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
5506 
Clone(const Graph * targetGraph)5507     Inst *Clone(const Graph *targetGraph) const override
5508     {
5509         auto clone = FixedInputsInst::Clone(targetGraph);
5510         clone->CastToLoadConstArray()->SetTypeId(GetTypeId());
5511         clone->CastToLoadConstArray()->SetMethod(GetMethod());
5512         return clone;
5513     }
5514 };
5515 
5516 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
5517 class PANDA_PUBLIC_API FillConstArrayInst : public NeedBarrierMixin<FixedInputsInst2>,
5518                                             public TypeIdMixin,
5519                                             public ImmediateMixin {
5520 public:
5521     using Base = NeedBarrierMixin<FixedInputsInst2>;
5522     using Base::Base;
5523 
5524     FillConstArrayInst(Initializer t, TypeIdMixin m, uint64_t imm, bool needBarrier = false)
Base(std::move (t))5525         : Base(std::move(t)), TypeIdMixin(std::move(m)), ImmediateMixin(imm)
5526     {
5527         SetNeedBarrier(needBarrier);
5528     }
5529 
IsBarrier()5530     bool IsBarrier() const override
5531     {
5532         return GetNeedBarrier() || Inst::IsBarrier();
5533     }
5534 
GetInputType(size_t index)5535     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
5536     {
5537         ASSERT(index < GetInputsCount());
5538         return index == 0 ? DataType::REFERENCE : DataType::NO_TYPE;
5539     }
5540 
5541     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
5542 
Clone(const Graph * targetGraph)5543     Inst *Clone(const Graph *targetGraph) const override
5544     {
5545         auto clone = FixedInputsInst::Clone(targetGraph);
5546         clone->CastToFillConstArray()->SetTypeId(GetTypeId());
5547         clone->CastToFillConstArray()->SetMethod(GetMethod());
5548         clone->CastToFillConstArray()->SetImm(GetImm());
5549         return clone;
5550     }
5551 };
5552 
5553 /// Checkcast
5554 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
5555 class PANDA_PUBLIC_API CheckCastInst : public OmitNullCheckMixin<ClassTypeMixin<NeedBarrierMixin<FixedInputsInst3>>>,
5556                                        public TypeIdMixin {
5557 public:
5558     using Base = OmitNullCheckMixin<ClassTypeMixin<NeedBarrierMixin<FixedInputsInst3>>>;
5559     using Base::Base;
5560 
5561     CheckCastInst(Initializer t, TypeIdMixin m, ClassType classType, bool needBarrier = false)
Base(std::move (t))5562         : Base(std::move(t)), TypeIdMixin(std::move(m))
5563     {
5564         SetClassType(classType);
5565         SetNeedBarrier(needBarrier);
5566     }
5567 
IsBarrier()5568     bool IsBarrier() const override
5569     {
5570         return Inst::IsBarrier() || GetNeedBarrier();
5571     }
5572 
GetInputType(size_t index)5573     DataType::Type GetInputType(size_t index) const override
5574     {
5575         ASSERT(index < GetInputsCount());
5576         ASSERT(GetInputsCount() == 3U);
5577         if (index < 2U) {
5578             return DataType::REFERENCE;
5579         }
5580         return DataType::NO_TYPE;
5581     }
5582 
5583     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
5584 
Clone(const Graph * targetGraph)5585     Inst *Clone(const Graph *targetGraph) const override
5586     {
5587         auto clone = FixedInputsInst::Clone(targetGraph);
5588         clone->CastToCheckCast()->SetTypeId(GetTypeId());
5589         clone->CastToCheckCast()->SetMethod(GetMethod());
5590         ASSERT(clone->CastToCheckCast()->GetClassType() == GetClassType());
5591         ASSERT(clone->CastToCheckCast()->GetOmitNullCheck() == GetOmitNullCheck());
5592         return clone;
5593     }
5594 };
5595 
5596 /// Is instance
5597 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
5598 class PANDA_PUBLIC_API IsInstanceInst : public OmitNullCheckMixin<ClassTypeMixin<NeedBarrierMixin<FixedInputsInst3>>>,
5599                                         public TypeIdMixin {
5600 public:
5601     using Base = OmitNullCheckMixin<ClassTypeMixin<NeedBarrierMixin<FixedInputsInst3>>>;
5602     using Base::Base;
5603 
5604     IsInstanceInst(Initializer t, TypeIdMixin m, ClassType classType, bool needBarrier = false)
Base(std::move (t))5605         : Base(std::move(t)), TypeIdMixin(std::move(m))
5606     {
5607         SetClassType(classType);
5608         SetNeedBarrier(needBarrier);
5609     }
5610 
IsBarrier()5611     bool IsBarrier() const override
5612     {
5613         return Inst::IsBarrier() || GetNeedBarrier();
5614     }
5615 
GetInputType(size_t index)5616     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
5617     {
5618         ASSERT(index < GetInputsCount());
5619         ASSERT(GetInputsCount() == 3U);
5620         if (index < 2U) {
5621             return DataType::REFERENCE;
5622         }
5623         return DataType::NO_TYPE;
5624     }
5625 
Clone(const Graph * targetGraph)5626     Inst *Clone(const Graph *targetGraph) const override
5627     {
5628         auto clone = FixedInputsInst::Clone(targetGraph);
5629         clone->CastToIsInstance()->SetTypeId(GetTypeId());
5630         clone->CastToIsInstance()->SetMethod(GetMethod());
5631         ASSERT(clone->CastToIsInstance()->GetClassType() == GetClassType());
5632         ASSERT(clone->CastToIsInstance()->GetOmitNullCheck() == GetOmitNullCheck());
5633         return clone;
5634     }
5635 
5636     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
5637 };
5638 
5639 /// Load data from constant pool.
5640 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
5641 class PANDA_PUBLIC_API LoadFromPool : public NeedBarrierMixin<FixedInputsInst1>, public TypeIdMixin {
5642 public:
5643     using Base = NeedBarrierMixin<FixedInputsInst1>;
5644     using Base::Base;
5645 
Base(std::move (t))5646     LoadFromPool(Initializer t, TypeIdMixin m, bool needBarrier = false) : Base(std::move(t)), TypeIdMixin(std::move(m))
5647     {
5648         SetNeedBarrier(needBarrier);
5649     }
5650 
GetInputType(size_t index)5651     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
5652     {
5653         ASSERT(index < GetInputsCount());
5654         return DataType::NO_TYPE;
5655     }
5656 
IsBarrier()5657     bool IsBarrier() const override
5658     {
5659         return GetNeedBarrier() || Inst::IsBarrier();
5660     }
5661 
5662     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
5663 
Clone(const Graph * targetGraph)5664     Inst *Clone(const Graph *targetGraph) const override
5665     {
5666         auto clone = FixedInputsInst::Clone(targetGraph);
5667         static_cast<LoadFromPool *>(clone)->SetTypeId(GetTypeId());
5668         static_cast<LoadFromPool *>(clone)->SetMethod(GetMethod());
5669         return clone;
5670     }
5671 };
5672 
5673 /// Load data from dynamic constant pool.
5674 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
5675 class PANDA_PUBLIC_API LoadFromPoolDynamic : public NeedBarrierMixin<FixedInputsInst1>, public TypeIdMixin {
5676 public:
5677     using Base = NeedBarrierMixin<FixedInputsInst1>;
5678     using Base::Base;
5679 
5680     LoadFromPoolDynamic(Initializer t, TypeIdMixin m, bool needBarrier = false)
Base(std::move (t))5681         : Base(std::move(t)), TypeIdMixin(std::move(m))
5682     {
5683         SetNeedBarrier(needBarrier);
5684     }
5685 
GetInputType(size_t index)5686     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
5687     {
5688         ASSERT(index < GetInputsCount());
5689         return DataType::ANY;
5690     }
5691 
5692     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
5693 
Clone(const Graph * targetGraph)5694     Inst *Clone(const Graph *targetGraph) const override
5695     {
5696         auto clone = FixedInputsInst::Clone(targetGraph);
5697         static_cast<LoadFromPoolDynamic *>(clone)->SetTypeId(GetTypeId());
5698         static_cast<LoadFromPoolDynamic *>(clone)->SetMethod(GetMethod());
5699         return clone;
5700     }
5701 
IsString()5702     bool IsString() const
5703     {
5704         return GetField<StringFlag>();
5705     }
5706 
SetString(bool v)5707     void SetString(bool v)
5708     {
5709         SetField<StringFlag>(v);
5710     }
5711 
5712     PANDA_PUBLIC_API void SetVnObject(VnObject *vnObj) override;
5713 
5714 protected:
5715     using StringFlag = LastField::NextFlag;
5716     using LastField = StringFlag;
5717 };
5718 
5719 /// Initialization or loading of the class.
5720 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
5721 class PANDA_PUBLIC_API ClassInst : public NeedBarrierMixin<FixedInputsInst1>, public TypeIdMixin {
5722 public:
5723     using Base = NeedBarrierMixin<FixedInputsInst1>;
5724     using Base::Base;
5725 
5726     ClassInst(Initializer t, TypeIdMixin m, RuntimeInterface::ClassPtr klass, bool needBarrier = false)
Base(std::move (t))5727         : Base(std::move(t)), TypeIdMixin(std::move(m)), klass_(klass)
5728     {
5729         SetNeedBarrier(needBarrier);
5730     }
5731 
IsBarrier()5732     bool IsBarrier() const override
5733     {
5734         return Inst::IsBarrier() || GetNeedBarrier();
5735     }
5736 
5737     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
5738 
Clone(const Graph * targetGraph)5739     Inst *Clone(const Graph *targetGraph) const override
5740     {
5741         auto clone = FixedInputsInst::Clone(targetGraph);
5742         static_cast<ClassInst *>(clone)->SetTypeId(GetTypeId());
5743         static_cast<ClassInst *>(clone)->SetMethod(GetMethod());
5744         static_cast<ClassInst *>(clone)->SetClass(GetClass());
5745         return clone;
5746     }
5747 
GetClass()5748     RuntimeInterface::ClassPtr GetClass() const
5749     {
5750         return klass_;
5751     }
5752 
SetClass(RuntimeInterface::ClassPtr klass)5753     void SetClass(RuntimeInterface::ClassPtr klass)
5754     {
5755         klass_ = klass;
5756     }
5757 
GetInputType(size_t index)5758     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
5759     {
5760         return DataType::NO_TYPE;
5761     }
5762 
5763 private:
5764     RuntimeInterface::ClassPtr klass_ {nullptr};
5765 };
5766 
5767 /// Loading of the runtime class.
5768 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
5769 class PANDA_PUBLIC_API RuntimeClassInst : public NeedBarrierMixin<FixedInputsInst0>, public TypeIdMixin {
5770 public:
5771     using Base = NeedBarrierMixin<FixedInputsInst0>;
5772     using Base::Base;
5773 
5774     RuntimeClassInst(Inst::Initializer t, TypeIdMixin m, RuntimeInterface::ClassPtr klass, bool needBarrier = false)
Base(std::move (t))5775         : Base(std::move(t)), TypeIdMixin(std::move(m)), klass_(klass)
5776     {
5777         SetNeedBarrier(needBarrier);
5778     }
5779 
IsBarrier()5780     bool IsBarrier() const override
5781     {
5782         return GetNeedBarrier() || Inst::IsBarrier();
5783     }
5784 
5785     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
5786 
Clone(const Graph * targetGraph)5787     Inst *Clone(const Graph *targetGraph) const override
5788     {
5789         auto clone = FixedInputsInst::Clone(targetGraph);
5790         static_cast<RuntimeClassInst *>(clone)->SetTypeId(GetTypeId());
5791         static_cast<RuntimeClassInst *>(clone)->SetMethod(GetMethod());
5792         static_cast<RuntimeClassInst *>(clone)->SetClass(GetClass());
5793         return clone;
5794     }
5795 
GetClass()5796     RuntimeInterface::ClassPtr GetClass() const
5797     {
5798         return klass_;
5799     }
5800 
5801     PANDA_PUBLIC_API void SetVnObject(VnObject *vnObj) override;
5802 
SetClass(RuntimeInterface::ClassPtr klass)5803     void SetClass(RuntimeInterface::ClassPtr klass)
5804     {
5805         klass_ = klass;
5806     }
5807 
5808 private:
5809     RuntimeInterface::ClassPtr klass_ {nullptr};
5810 };
5811 
5812 /// Get global var address inst
5813 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
5814 class PANDA_PUBLIC_API GlobalVarInst : public NeedBarrierMixin<FixedInputsInst2>, public TypeIdMixin {
5815 public:
5816     using Base = NeedBarrierMixin<FixedInputsInst2>;
5817     using Base::Base;
5818 
GlobalVarInst(Initializer t,uintptr_t address)5819     GlobalVarInst(Initializer t, uintptr_t address) : Base(std::move(t)), address_(address) {}
5820 
5821     GlobalVarInst(Initializer t, TypeIdMixin m, uintptr_t address, bool needBarrier = false)
Base(std::move (t))5822         : Base(std::move(t)), TypeIdMixin(std::move(m)), address_(address)
5823     {
5824         SetNeedBarrier(needBarrier);
5825     }
5826 
IsBarrier()5827     bool IsBarrier() const override
5828     {
5829         return Inst::IsBarrier() || GetNeedBarrier();
5830     }
5831 
Clone(const Graph * targetGraph)5832     Inst *Clone(const Graph *targetGraph) const override
5833     {
5834         auto clone = FixedInputsInst::Clone(targetGraph);
5835         static_cast<GlobalVarInst *>(clone)->SetTypeId(GetTypeId());
5836         static_cast<GlobalVarInst *>(clone)->SetMethod(GetMethod());
5837         return clone;
5838     }
5839 
5840     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
5841 
GetInputType(size_t index)5842     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
5843     {
5844         ASSERT(index < GetInputsCount());
5845         if (index == 0) {
5846             return DataType::ANY;
5847         }
5848         return DataType::NO_TYPE;
5849     }
5850 
GetAddress()5851     uintptr_t GetAddress() const
5852     {
5853         return address_;
5854     }
5855 
5856 private:
5857     uintptr_t address_ {0};
5858 };
5859 
5860 /// Get object pointer from the specific source.
5861 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
5862 class PANDA_PUBLIC_API LoadImmediateInst : public FixedInputsInst<0> {
5863 public:
5864     using Base = FixedInputsInst;
5865     using Base::Base;
5866 
5867     enum class ObjectType {
5868         UNKNOWN,
5869         CLASS,
5870         METHOD,
5871         CONSTANT_POOL,
5872         STRING,
5873         PANDA_FILE_OFFSET,
5874         OBJECT,
5875         TLS_OFFSET,
5876         LAST
5877     };
5878 
5879     LoadImmediateInst(Inst::Initializer t, const void *obj, ObjectType objType = ObjectType::CLASS)
Base(std::move (t))5880         : Base(std::move(t)), obj_(reinterpret_cast<uint64_t>(obj))
5881     {
5882         SetObjectType(objType);
5883     }
5884 
5885     LoadImmediateInst(Inst::Initializer t, uint64_t obj, ObjectType objType = ObjectType::CLASS)
Base(std::move (t))5886         : Base(std::move(t)), obj_(obj)
5887     {
5888         SetObjectType(objType);
5889     }
5890 
Clone(const Graph * targetGraph)5891     Inst *Clone(const Graph *targetGraph) const override
5892     {
5893         auto clone = FixedInputsInst::Clone(targetGraph);
5894         clone->CastToLoadImmediate()->SetObjectType(GetObjectType());
5895         clone->CastToLoadImmediate()->obj_ = obj_;
5896         return clone;
5897     }
5898 
GetObject()5899     void *GetObject() const
5900     {
5901         return reinterpret_cast<void *>(obj_);
5902     }
5903 
GetObjectType()5904     ObjectType GetObjectType() const
5905     {
5906         return GetField<ObjectTypeField>();
5907     }
5908 
SetObjectType(ObjectType objType)5909     void SetObjectType(ObjectType objType)
5910     {
5911         SetField<ObjectTypeField>(objType);
5912     }
5913 
SetMethod(RuntimeInterface::MethodPtr obj)5914     void SetMethod(RuntimeInterface::MethodPtr obj)
5915     {
5916         ASSERT(GetObjectType() == ObjectType::METHOD);
5917         obj_ = reinterpret_cast<uint64_t>(obj);
5918     }
5919 
GetMethod()5920     RuntimeInterface::MethodPtr GetMethod() const
5921     {
5922         ASSERT(GetObjectType() == ObjectType::METHOD);
5923         return reinterpret_cast<RuntimeInterface::MethodPtr>(obj_);
5924     }
5925 
IsMethod()5926     bool IsMethod() const
5927     {
5928         return GetField<ObjectTypeField>() == ObjectType::METHOD;
5929     }
5930 
SetClass(RuntimeInterface::ClassPtr obj)5931     void SetClass(RuntimeInterface::ClassPtr obj)
5932     {
5933         ASSERT(GetObjectType() == ObjectType::CLASS);
5934         obj_ = reinterpret_cast<uint64_t>(obj);
5935     }
5936 
GetClass()5937     RuntimeInterface::ClassPtr GetClass() const
5938     {
5939         ASSERT(GetObjectType() == ObjectType::CLASS);
5940         return reinterpret_cast<RuntimeInterface::ClassPtr>(obj_);
5941     }
5942 
IsConstantPool()5943     bool IsConstantPool() const
5944     {
5945         return GetField<ObjectTypeField>() == ObjectType::CONSTANT_POOL;
5946     }
5947 
GetConstantPool()5948     uintptr_t GetConstantPool() const
5949     {
5950         ASSERT(GetObjectType() == ObjectType::CONSTANT_POOL);
5951         return static_cast<uintptr_t>(obj_);
5952     }
5953 
IsClass()5954     bool IsClass() const
5955     {
5956         return GetField<ObjectTypeField>() == ObjectType::CLASS;
5957     }
5958 
IsString()5959     bool IsString() const
5960     {
5961         return GetField<ObjectTypeField>() == ObjectType::STRING;
5962     }
5963 
GetString()5964     uintptr_t GetString() const
5965     {
5966         ASSERT(GetObjectType() == ObjectType::STRING);
5967         return static_cast<uintptr_t>(obj_);
5968     }
5969 
IsPandaFileOffset()5970     bool IsPandaFileOffset() const
5971     {
5972         return GetField<ObjectTypeField>() == ObjectType::PANDA_FILE_OFFSET;
5973     }
5974 
GetPandaFileOffset()5975     uint64_t GetPandaFileOffset() const
5976     {
5977         ASSERT(GetObjectType() == ObjectType::PANDA_FILE_OFFSET);
5978         return obj_;
5979     }
5980 
IsObject()5981     bool IsObject() const
5982     {
5983         return GetField<ObjectTypeField>() == ObjectType::OBJECT;
5984     }
5985 
IsTlsOffset()5986     bool IsTlsOffset() const
5987     {
5988         return GetField<ObjectTypeField>() == ObjectType::TLS_OFFSET;
5989     }
5990 
GetTlsOffset()5991     uint64_t GetTlsOffset() const
5992     {
5993         ASSERT(GetObjectType() == ObjectType::TLS_OFFSET);
5994         return obj_;
5995     }
5996 
5997     PANDA_PUBLIC_API void SetVnObject(VnObject *vnObj) override;
5998 
5999     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
6000 
6001 private:
6002     uint64_t obj_ {0};
6003     using ObjectTypeField = Base::LastField::NextField<ObjectType, MinimumBitsToStore(ObjectType::LAST)>;
6004     using LastField = ObjectTypeField;
6005 };
6006 
6007 /// Get function from the specific source.
6008 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
6009 class PANDA_PUBLIC_API FunctionImmediateInst : public FixedInputsInst<0> {
6010 public:
6011     using Base = FixedInputsInst;
6012     using Base::Base;
6013 
FunctionImmediateInst(Inst::Initializer t,uintptr_t ptr)6014     FunctionImmediateInst(Inst::Initializer t, uintptr_t ptr) : Base(std::move(t)), functionPtr_(ptr) {}
6015 
Clone(const Graph * targetGraph)6016     Inst *Clone(const Graph *targetGraph) const override
6017     {
6018         auto clone = FixedInputsInst::Clone(targetGraph);
6019         clone->CastToFunctionImmediate()->functionPtr_ = functionPtr_;
6020         return clone;
6021     }
6022 
GetFunctionPtr()6023     uintptr_t GetFunctionPtr() const
6024     {
6025         return functionPtr_;
6026     }
6027 
SetFunctionPtr(uintptr_t ptr)6028     void SetFunctionPtr(uintptr_t ptr)
6029     {
6030         functionPtr_ = ptr;
6031     }
6032 
6033     PANDA_PUBLIC_API void SetVnObject(VnObject *vnObj) override;
6034     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
6035 
6036 private:
6037     uintptr_t functionPtr_ {0};
6038 };
6039 
6040 /// Get object from the specific source(handle).
6041 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
6042 class PANDA_PUBLIC_API LoadObjFromConstInst : public FixedInputsInst<0> {
6043 public:
6044     using Base = FixedInputsInst;
6045     using Base::Base;
6046 
LoadObjFromConstInst(Inst::Initializer t,uintptr_t ptr)6047     LoadObjFromConstInst(Inst::Initializer t, uintptr_t ptr) : Base(std::move(t)), objectPtr_(ptr) {}
6048 
Clone(const Graph * targetGraph)6049     Inst *Clone(const Graph *targetGraph) const override
6050     {
6051         auto clone = FixedInputsInst::Clone(targetGraph);
6052         clone->CastToLoadObjFromConst()->objectPtr_ = objectPtr_;
6053         return clone;
6054     }
6055 
GetObjPtr()6056     uintptr_t GetObjPtr() const
6057     {
6058         return objectPtr_;
6059     }
6060 
SetObjPtr(uintptr_t ptr)6061     void SetObjPtr(uintptr_t ptr)
6062     {
6063         objectPtr_ = ptr;
6064     }
6065 
6066     PANDA_PUBLIC_API void SetVnObject(VnObject *vnObj) override;
6067     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
6068 
6069 private:
6070     uintptr_t objectPtr_ {0};
6071 };
6072 
6073 /// Select instruction
6074 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
6075 class PANDA_PUBLIC_API SelectInst : public ConditionMixin<InstWithOperandsType<FixedInputsInst<4U>>> {
6076 public:
6077     using Base = ConditionMixin<InstWithOperandsType<FixedInputsInst<4U>>>;
6078     using Base::Base;
6079 
SelectInst(Initializer t,DataType::Type operType,ConditionCode cc)6080     SelectInst(Initializer t, DataType::Type operType, ConditionCode cc) : Base(std::move(t))
6081     {
6082         SetOperandsType(operType);
6083         SetCc(cc);
6084         if (IsReferenceOrAny()) {
6085             SetFlag(inst_flags::REF_SPECIAL);
6086             // Select instruction cannot be generated before LICM where NO_HOIST flag is checked
6087             // Set it just for consistency
6088             SetFlag(inst_flags::NO_HOIST);
6089         }
6090     }
6091 
6092     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
6093     PANDA_PUBLIC_API void SetVnObject(VnObject *vnObj) override;
6094 
GetInputType(size_t index)6095     DataType::Type GetInputType(size_t index) const override
6096     {
6097         ASSERT(index < GetInputsCount());
6098         if (index < 2U) {
6099             return GetType();
6100         }
6101         return GetOperandsType();
6102     }
6103 
Clone(const Graph * targetGraph)6104     Inst *Clone(const Graph *targetGraph) const override
6105     {
6106         auto clone = FixedInputsInst::Clone(targetGraph);
6107         ASSERT(clone->CastToSelect()->GetCc() == GetCc());
6108         ASSERT(clone->CastToSelect()->GetOperandsType() == GetOperandsType());
6109         return clone;
6110     }
6111 };
6112 
6113 /// SelectImm with comparison with immediate
6114 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
6115 class PANDA_PUBLIC_API SelectImmInst : public InstWithOperandsType<ConditionMixin<FixedInputsInst3>>,
6116                                        public ImmediateMixin {
6117 public:
6118     using Base = InstWithOperandsType<ConditionMixin<FixedInputsInst3>>;
6119     using Base::Base;
6120 
SelectImmInst(Initializer t,uint64_t imm,DataType::Type operType,ConditionCode cc)6121     SelectImmInst(Initializer t, uint64_t imm, DataType::Type operType, ConditionCode cc)
6122         : Base(std::move(t)), ImmediateMixin(imm)
6123     {
6124         SetOperandsType(operType);
6125         SetCc(cc);
6126         if (IsReferenceOrAny()) {
6127             SetFlag(inst_flags::REF_SPECIAL);
6128             SetFlag(inst_flags::NO_HOIST);
6129         }
6130     }
6131 
GetInputType(size_t index)6132     DataType::Type GetInputType(size_t index) const override
6133     {
6134         ASSERT(index < GetInputsCount());
6135         if (index < 2U) {
6136             return GetType();
6137         }
6138         return GetOperandsType();
6139     }
6140 
6141     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
6142     PANDA_PUBLIC_API bool DumpInputs(std::ostream *out) const override;
6143 
Clone(const Graph * targetGraph)6144     Inst *Clone(const Graph *targetGraph) const override
6145     {
6146         auto clone = FixedInputsInst::Clone(targetGraph);
6147         ASSERT(clone->CastToSelectImm()->GetCc() == GetCc());
6148         ASSERT(clone->CastToSelectImm()->GetOperandsType() == GetOperandsType());
6149         clone->CastToSelectImm()->SetImm(GetImm());
6150         return clone;
6151     }
6152 };
6153 
6154 /// Conditional jump instruction
6155 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
6156 class PANDA_PUBLIC_API IfInst : public InstWithOperandsType<ConditionMixin<FixedInputsInst2>> {
6157 public:
6158     using Base = InstWithOperandsType<ConditionMixin<FixedInputsInst2>>;
6159     using Base::Base;
6160 
IfInst(Initializer t,ConditionCode cc)6161     IfInst(Initializer t, ConditionCode cc) : Base(std::move(t))
6162     {
6163         SetCc(cc);
6164     }
6165 
6166     IfInst(Initializer t, DataType::Type operType, ConditionCode cc, RuntimeInterface::MethodPtr method = nullptr)
Base(std::move (t))6167         : Base(std::move(t)), method_(method)
6168     {
6169         SetOperandsType(operType);
6170         SetCc(cc);
6171     }
6172 
GetInputType(size_t index)6173     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
6174     {
6175         ASSERT(index < GetInputsCount());
6176         return GetOperandsType();
6177     }
6178 
6179     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
6180 
6181     PANDA_PUBLIC_API void SetVnObject(VnObject *vnObj) override;
6182 
Clone(const Graph * targetGraph)6183     Inst *Clone(const Graph *targetGraph) const override
6184     {
6185         auto clone = FixedInputsInst::Clone(targetGraph);
6186         ASSERT(static_cast<IfInst *>(clone)->GetCc() == GetCc());
6187         ASSERT(static_cast<IfInst *>(clone)->GetOperandsType() == GetOperandsType());
6188         static_cast<IfInst *>(clone)->SetMethod(GetMethod());
6189         return clone;
6190     }
6191 
SetMethod(RuntimeInterface::MethodPtr method)6192     void SetMethod(RuntimeInterface::MethodPtr method)
6193     {
6194         method_ = method;
6195     }
6196 
GetMethod()6197     RuntimeInterface::MethodPtr GetMethod() const
6198     {
6199         return method_;
6200     }
6201 
6202 private:
6203     RuntimeInterface::MethodPtr method_ {nullptr};
6204 };
6205 
6206 /// IfImm instruction with immediate
6207 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
6208 class PANDA_PUBLIC_API IfImmInst : public InstWithOperandsType<ConditionMixin<FixedInputsInst1>>,
6209                                    public ImmediateMixin {
6210 public:
6211     using Base = InstWithOperandsType<ConditionMixin<FixedInputsInst1>>;
6212     using Base::Base;
6213 
IfImmInst(Initializer t,ConditionCode cc,uint64_t imm)6214     IfImmInst(Initializer t, ConditionCode cc, uint64_t imm) : Base(std::move(t)), ImmediateMixin(imm)
6215     {
6216         SetCc(cc);
6217     }
6218 
6219     IfImmInst(Initializer t, uint64_t imm, DataType::Type operType, ConditionCode cc,
6220               RuntimeInterface::MethodPtr method = nullptr)
Base(std::move (t))6221         : Base(std::move(t)), ImmediateMixin(imm), method_(method)
6222     {
6223         SetOperandsType(operType);
6224         SetCc(cc);
6225     }
6226 
6227     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
6228     PANDA_PUBLIC_API bool DumpInputs(std::ostream *out) const override;
6229     PANDA_PUBLIC_API void SetVnObject(VnObject *vnObj) override;
6230 
GetInputType(size_t index)6231     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
6232     {
6233         ASSERT(index < GetInputsCount());
6234         return GetOperandsType();
6235     }
6236 
Clone(const Graph * targetGraph)6237     Inst *Clone(const Graph *targetGraph) const override
6238     {
6239         auto clone = FixedInputsInst::Clone(targetGraph);
6240         ASSERT(clone->CastToIfImm()->GetCc() == GetCc());
6241         ASSERT(clone->CastToIfImm()->GetOperandsType() == GetOperandsType());
6242         clone->CastToIfImm()->SetMethod(GetMethod());
6243         clone->CastToIfImm()->SetImm(GetImm());
6244         return clone;
6245     }
6246 
6247     BasicBlock *GetEdgeIfInputTrue();
6248     BasicBlock *GetEdgeIfInputFalse();
6249 
SetMethod(RuntimeInterface::MethodPtr method)6250     void SetMethod(RuntimeInterface::MethodPtr method)
6251     {
6252         method_ = method;
6253     }
6254 
GetMethod()6255     RuntimeInterface::MethodPtr GetMethod() const
6256     {
6257         return method_;
6258     }
6259 
6260 private:
6261     size_t GetTrueInputEdgeIdx();
6262     RuntimeInterface::MethodPtr method_ {nullptr};
6263 };
6264 
6265 /// Load element from a pair of values, using index as immediate
6266 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
6267 class PANDA_PUBLIC_API LoadPairPartInst : public FixedInputsInst1, public ImmediateMixin {
6268 public:
6269     using FixedInputsInst1::FixedInputsInst1;
6270 
LoadPairPartInst(Opcode opcode,uint64_t imm)6271     LoadPairPartInst(Opcode opcode, uint64_t imm) : FixedInputsInst1(opcode), ImmediateMixin(imm) {}
6272 
LoadPairPartInst(Initializer t,uint64_t imm)6273     LoadPairPartInst(Initializer t, uint64_t imm) : FixedInputsInst1(std::move(t)), ImmediateMixin(imm) {}
6274 
GetSrcRegIndex()6275     uint32_t GetSrcRegIndex() const override
6276     {
6277         return GetImm();
6278     }
6279 
6280     PANDA_PUBLIC_API bool DumpInputs(std::ostream *out) const override;
6281 
Clone(const Graph * targetGraph)6282     Inst *Clone(const Graph *targetGraph) const override
6283     {
6284         auto clone = FixedInputsInst::Clone(targetGraph);
6285         clone->CastToLoadPairPart()->SetImm(GetImm());
6286         return clone;
6287     }
6288 
Latency()6289     uint32_t Latency() const override
6290     {
6291         return g_options.GetCompilerSchedLatencyLong();
6292     }
6293 };
6294 
6295 /// Load a pair of consecutive values from array
6296 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
6297 class PANDA_PUBLIC_API LoadArrayPairInst : public NeedBarrierMixin<MultipleOutputMixin<FixedInputsInst2, 2U>>,
6298                                            public ImmediateMixin {
6299 public:
6300     using Base = NeedBarrierMixin<MultipleOutputMixin<FixedInputsInst2, 2U>>;
6301     using Base::Base;
6302 
Base(std::move (t))6303     explicit LoadArrayPairInst(Initializer t, bool needBarrier = false) : Base(std::move(t))
6304     {
6305         SetNeedBarrier(needBarrier);
6306     }
6307 
GetArray()6308     Inst *GetArray()
6309     {
6310         return GetInput(0).GetInst();
6311     }
GetIndex()6312     Inst *GetIndex()
6313     {
6314         return GetInput(1).GetInst();
6315     }
6316 
IsBarrier()6317     bool IsBarrier() const override
6318     {
6319         return Inst::IsBarrier() || GetNeedBarrier();
6320     }
6321 
Clone(const Graph * targetGraph)6322     Inst *Clone(const Graph *targetGraph) const override
6323     {
6324         auto clone = FixedInputsInst::Clone(targetGraph)->CastToLoadArrayPair();
6325         static_cast<LoadArrayPairInst *>(clone)->SetImm(GetImm());
6326 #ifndef NDEBUG
6327         for (size_t i = 0; i < GetDstCount(); ++i) {
6328             clone->SetDstReg(i, GetDstReg(i));
6329         }
6330 #endif
6331         return clone;
6332     }
6333 
GetInputType(size_t index)6334     DataType::Type GetInputType(size_t index) const override
6335     {
6336         ASSERT(index < GetInputsCount());
6337         switch (index) {
6338             case 0:
6339                 return DataType::REFERENCE;
6340             case 1:
6341                 return DataType::INT32;
6342             default:
6343                 return DataType::NO_TYPE;
6344         }
6345     }
6346 
Latency()6347     uint32_t Latency() const override
6348     {
6349         return 0;
6350     }
6351 
6352     PANDA_PUBLIC_API bool DumpInputs(std::ostream *out) const override;
6353 };
6354 
6355 /// Load a pair of consecutive values from object
6356 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
6357 class PANDA_PUBLIC_API LoadObjectPairInst
6358     : public ObjectTypeMixin<VolatileMixin<NeedBarrierMixin<MultipleOutputMixin<FixedInputsInst1, 2U>>>>,
6359       public TypeIdMixin2,
6360       public FieldMixin2 {
6361 public:
6362     using Base = ObjectTypeMixin<VolatileMixin<NeedBarrierMixin<MultipleOutputMixin<FixedInputsInst1, 2U>>>>;
6363     using Base::Base;
6364 
LoadObjectPairInst(Initializer t)6365     explicit LoadObjectPairInst(Initializer t) : Base(std::move(t))
6366     {
6367         SetVolatile(false);
6368         SetNeedBarrier(false);
6369     }
6370 
GetInputType(size_t index)6371     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
6372     {
6373         ASSERT(index < GetInputsCount());
6374         ASSERT(GetInputsCount() == 1);
6375         auto inputType = GetInput(0).GetInst()->GetType();
6376         ASSERT(inputType == DataType::REFERENCE || inputType == DataType::ANY);
6377         return inputType;
6378     }
6379 
IsBarrier()6380     bool IsBarrier() const override
6381     {
6382         return Inst::IsBarrier() || GetNeedBarrier() || GetVolatile();
6383     }
6384 
Clone(const Graph * targetGraph)6385     Inst *Clone(const Graph *targetGraph) const override
6386     {
6387         auto clone = FixedInputsInst::Clone(targetGraph);
6388         clone->CastToLoadObjectPair()->SetTypeId0(GetTypeId0());
6389         clone->CastToLoadObjectPair()->SetTypeId1(GetTypeId1());
6390         clone->CastToLoadObjectPair()->SetMethod(GetMethod());
6391         clone->CastToLoadObjectPair()->SetObjField0(GetObjField0());
6392         clone->CastToLoadObjectPair()->SetObjField1(GetObjField1());
6393         ASSERT(clone->CastToLoadObjectPair()->GetVolatile() == GetVolatile());
6394         ASSERT(clone->CastToLoadObjectPair()->GetObjectType() == GetObjectType());
6395         return clone;
6396     }
6397 
Latency()6398     uint32_t Latency() const override
6399     {
6400         return g_options.GetCompilerSchedLatencyLong();
6401     }
6402 
6403     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
6404 };
6405 
6406 /// Store a pair of consecutive values to array
6407 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
6408 class PANDA_PUBLIC_API StoreArrayPairInst : public NeedBarrierMixin<FixedInputsInst<4U>>, public ImmediateMixin {
6409 public:
6410     using Base = NeedBarrierMixin<FixedInputsInst<4U>>;
6411     using Base::Base;
6412 
Base(std::move (t))6413     explicit StoreArrayPairInst(Initializer t, bool needBarrier = false) : Base(std::move(t))
6414     {
6415         SetNeedBarrier(needBarrier);
6416     }
6417 
GetIndex()6418     Inst *GetIndex()
6419     {
6420         return GetInput(1).GetInst();
6421     }
GetArray()6422     Inst *GetArray()
6423     {
6424         return GetInput(0).GetInst();
6425     }
GetStoredValue(uint64_t index)6426     Inst *GetStoredValue(uint64_t index)
6427     {
6428         return GetInput(2U + index).GetInst();
6429     }
GetInputType(size_t index)6430     DataType::Type GetInputType(size_t index) const override
6431     {
6432         ASSERT(index < GetInputsCount());
6433         switch (index) {
6434             case 0:
6435                 return DataType::REFERENCE;
6436             case 1:
6437                 return DataType::INT32;
6438             case 2U:
6439             case 3U:
6440                 return GetType();
6441             default:
6442                 return DataType::NO_TYPE;
6443         }
6444     }
6445 
6446     // StoreArrayPair call barriers twice,so we need to save input register for second call
IsPropagateLiveness()6447     bool IsPropagateLiveness() const override
6448     {
6449         return GetType() == DataType::REFERENCE;
6450     }
6451 
IsBarrier()6452     bool IsBarrier() const override
6453     {
6454         return Inst::IsBarrier() || GetNeedBarrier();
6455     }
6456 
Clone(const Graph * targetGraph)6457     Inst *Clone(const Graph *targetGraph) const override
6458     {
6459         auto clone = FixedInputsInst::Clone(targetGraph)->CastToStoreArrayPair();
6460         static_cast<StoreArrayPairInst *>(clone)->SetImm(GetImm());
6461         return clone;
6462     }
6463 
6464     PANDA_PUBLIC_API bool DumpInputs(std::ostream *out) const override;
6465 };
6466 
6467 /// Store a pair of consecutive values to object
6468 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
6469 class PANDA_PUBLIC_API StoreObjectPairInst : public ObjectTypeMixin<VolatileMixin<NeedBarrierMixin<FixedInputsInst3>>>,
6470                                              public TypeIdMixin2,
6471                                              public FieldMixin2 {
6472 public:
6473     using Base = ObjectTypeMixin<VolatileMixin<NeedBarrierMixin<FixedInputsInst3>>>;
6474     using Base::Base;
6475     static constexpr size_t STORED_INPUT_INDEX = 2;
6476 
StoreObjectPairInst(Initializer t)6477     explicit StoreObjectPairInst(Initializer t) : Base(std::move(t))
6478     {
6479         SetVolatile(false);
6480         SetNeedBarrier(false);
6481     }
6482 
IsBarrier()6483     bool IsBarrier() const override
6484     {
6485         return Inst::IsBarrier() || GetNeedBarrier() || GetVolatile();
6486     }
6487 
GetInputType(size_t index)6488     DataType::Type GetInputType(size_t index) const override
6489     {
6490         ASSERT(index < GetInputsCount());
6491         ASSERT(GetInputsCount() == 3U);
6492         return index == 0 ? DataType::REFERENCE : GetType();
6493     }
6494 
Clone(const Graph * targetGraph)6495     Inst *Clone(const Graph *targetGraph) const override
6496     {
6497         auto clone = FixedInputsInst::Clone(targetGraph);
6498         clone->CastToStoreObjectPair()->SetTypeId0(GetTypeId0());
6499         clone->CastToStoreObjectPair()->SetTypeId1(GetTypeId1());
6500         clone->CastToStoreObjectPair()->SetMethod(GetMethod());
6501         clone->CastToStoreObjectPair()->SetObjField0(GetObjField0());
6502         clone->CastToStoreObjectPair()->SetObjField1(GetObjField1());
6503         ASSERT(clone->CastToStoreObjectPair()->GetVolatile() == GetVolatile());
6504         ASSERT(clone->CastToStoreObjectPair()->GetObjectType() == GetObjectType());
6505         return clone;
6506     }
6507 
6508     // StoreObject call barriers twice,so we need to save input register for second call
IsPropagateLiveness()6509     bool IsPropagateLiveness() const override
6510     {
6511         return GetType() == DataType::REFERENCE;
6512     }
6513 
6514     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
6515 };
6516 
6517 /// Load a pair of consecutive values from array, using array index as immediate
6518 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
6519 class PANDA_PUBLIC_API LoadArrayPairInstI : public NeedBarrierMixin<MultipleOutputMixin<FixedInputsInst1, 2U>>,
6520                                             public ImmediateMixin {
6521 public:
6522     using Base = NeedBarrierMixin<MultipleOutputMixin<FixedInputsInst1, 2U>>;
6523     using Base::Base;
6524 
LoadArrayPairInstI(Opcode opcode,uint64_t imm)6525     explicit LoadArrayPairInstI(Opcode opcode, uint64_t imm) : Base(opcode), ImmediateMixin(imm) {}
6526 
Base(std::move (t))6527     LoadArrayPairInstI(Initializer t, uint64_t imm, bool needBarrier = false) : Base(std::move(t)), ImmediateMixin(imm)
6528     {
6529         SetNeedBarrier(needBarrier);
6530     }
6531 
GetArray()6532     Inst *GetArray()
6533     {
6534         return GetInput(0).GetInst();
6535     }
6536 
IsBarrier()6537     bool IsBarrier() const override
6538     {
6539         return Inst::IsBarrier() || GetNeedBarrier();
6540     }
6541     PANDA_PUBLIC_API bool DumpInputs(std::ostream *out) const override;
6542 
GetInputType(size_t index)6543     DataType::Type GetInputType(size_t index) const override
6544     {
6545         ASSERT(index < GetInputsCount());
6546         if (index == 0) {
6547             return DataType::REFERENCE;
6548         }
6549         return DataType::NO_TYPE;
6550     }
6551 
Clone(const Graph * targetGraph)6552     Inst *Clone(const Graph *targetGraph) const override
6553     {
6554         auto clone = FixedInputsInst::Clone(targetGraph)->CastToLoadArrayPairI();
6555         clone->SetImm(GetImm());
6556 #ifndef NDEBUG
6557         for (size_t i = 0; i < GetDstCount(); ++i) {
6558             clone->SetDstReg(i, GetDstReg(i));
6559         }
6560 #endif
6561         return clone;
6562     }
6563 
Latency()6564     uint32_t Latency() const override
6565     {
6566         return 0;
6567     }
6568 };
6569 
6570 /// Store a pair of consecutive values to array, using array index as immediate
6571 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
6572 class PANDA_PUBLIC_API StoreArrayPairInstI : public NeedBarrierMixin<FixedInputsInst3>, public ImmediateMixin {
6573 public:
6574     using Base = NeedBarrierMixin<FixedInputsInst3>;
6575     using Base::Base;
6576 
StoreArrayPairInstI(Opcode opcode,uint64_t imm)6577     explicit StoreArrayPairInstI(Opcode opcode, uint64_t imm) : Base(opcode), ImmediateMixin(imm) {}
6578 
Base(std::move (t))6579     StoreArrayPairInstI(Initializer t, uint64_t imm, bool needBarrier = false) : Base(std::move(t)), ImmediateMixin(imm)
6580     {
6581         SetNeedBarrier(needBarrier);
6582     }
6583 
GetInputType(size_t index)6584     DataType::Type GetInputType(size_t index) const override
6585     {
6586         ASSERT(index < GetInputsCount());
6587         switch (index) {
6588             case 0:
6589                 return DataType::REFERENCE;
6590             case 1:
6591             case 2U:
6592                 return GetType();
6593             default:
6594                 return DataType::NO_TYPE;
6595         }
6596     }
GetArray()6597     Inst *GetArray()
6598     {
6599         return GetInput(0).GetInst();
6600     }
GetFirstValue()6601     Inst *GetFirstValue()
6602     {
6603         return GetInput(1).GetInst();
6604     }
GetSecondValue()6605     Inst *GetSecondValue()
6606     {
6607         return GetInput(2U).GetInst();
6608     }
6609 
6610     // StoreArrayPairI call barriers twice,so we need to save input register for second call
IsPropagateLiveness()6611     bool IsPropagateLiveness() const override
6612     {
6613         return GetType() == DataType::REFERENCE;
6614     }
6615 
IsBarrier()6616     bool IsBarrier() const override
6617     {
6618         return Inst::IsBarrier() || GetNeedBarrier();
6619     }
6620 
6621     PANDA_PUBLIC_API bool DumpInputs(std::ostream *out) const override;
6622 
Clone(const Graph * targetGraph)6623     Inst *Clone(const Graph *targetGraph) const override
6624     {
6625         auto clone = FixedInputsInst::Clone(targetGraph);
6626         clone->CastToStoreArrayPairI()->SetImm(GetImm());
6627         return clone;
6628     }
6629 };
6630 
6631 /// CatchPhiInst instruction
6632 class PANDA_PUBLIC_API CatchPhiInst : public DynamicInputsInst {
6633 public:
6634     using DynamicInputsInst::DynamicInputsInst;
6635 
CatchPhiInst(Initializer t)6636     explicit CatchPhiInst(Initializer t) : DynamicInputsInst(std::move(t)) {}
6637 
GetThrowableInsts()6638     const ArenaVector<const Inst *> *GetThrowableInsts() const
6639     {
6640         return throwInsts_;
6641     }
6642 
GetThrowableInst(size_t i)6643     const Inst *GetThrowableInst(size_t i) const
6644     {
6645         ASSERT(throwInsts_ != nullptr && i < throwInsts_->size());
6646         return throwInsts_->at(i);
6647     }
6648 
6649     void AppendThrowableInst(const Inst *inst);
6650     void ReplaceThrowableInst(const Inst *oldInst, const Inst *newInst);
6651     void RemoveInput(unsigned index) override;
6652 
IsAcc()6653     bool IsAcc() const
6654     {
6655         return GetField<IsAccFlag>();
6656     }
6657 
SetIsAcc()6658     void SetIsAcc()
6659     {
6660         SetField<IsAccFlag>(true);
6661     }
6662 
6663 protected:
6664     using IsAccFlag = LastField::NextFlag;
6665     using LastField = IsAccFlag;
6666 
6667 private:
GetThrowableInstIndex(const Inst * inst)6668     size_t GetThrowableInstIndex(const Inst *inst)
6669     {
6670         ASSERT(throwInsts_ != nullptr);
6671         auto it = std::find(throwInsts_->begin(), throwInsts_->end(), inst);
6672         ASSERT(it != throwInsts_->end());
6673         return std::distance(throwInsts_->begin(), it);
6674     }
6675 
6676 private:
6677     ArenaVector<const Inst *> *throwInsts_ {nullptr};
6678 };
6679 
6680 class PANDA_PUBLIC_API TryInst : public FixedInputsInst0 {
6681 public:
6682     using FixedInputsInst0::FixedInputsInst0;
6683 
6684     explicit TryInst(Opcode opcode, BasicBlock *endBb = nullptr)
6685         : FixedInputsInst0({opcode, DataType::NO_TYPE, INVALID_PC}), tryEndBb_(endBb)
6686     {
6687     }
6688 
6689     void AppendCatchTypeId(uint32_t id, uint32_t catchEdgeIndex);
6690 
GetCatchTypeIds()6691     const ArenaVector<uint32_t> *GetCatchTypeIds() const
6692     {
6693         return catchTypeIds_;
6694     }
6695 
GetCatchEdgeIndexes()6696     const ArenaVector<uint32_t> *GetCatchEdgeIndexes() const
6697     {
6698         return catchEdgeIndexes_;
6699     }
6700 
GetCatchTypeIdsCount()6701     size_t GetCatchTypeIdsCount() const
6702     {
6703         return (catchTypeIds_ == nullptr ? 0 : catchTypeIds_->size());
6704     }
6705 
6706     Inst *Clone(const Graph *targetGraph) const override;
6707 
SetTryEndBlock(BasicBlock * tryEndBb)6708     void SetTryEndBlock(BasicBlock *tryEndBb)
6709     {
6710         tryEndBb_ = tryEndBb;
6711     }
6712 
GetTryEndBlock()6713     BasicBlock *GetTryEndBlock() const
6714     {
6715         return tryEndBb_;
6716     }
6717 
6718 private:
6719     ArenaVector<uint32_t> *catchTypeIds_ {nullptr};
6720     ArenaVector<uint32_t> *catchEdgeIndexes_ {nullptr};
6721     BasicBlock *tryEndBb_ {nullptr};
6722 };
6723 
6724 PANDA_PUBLIC_API TryInst *GetTryBeginInst(const BasicBlock *tryBeginBb);
6725 
6726 /// Mixin for Deoptimize instructions
6727 template <typename T>
6728 class DeoptimizeTypeMixin : public T {
6729 public:
6730     using T::T;
6731 
SetDeoptimizeType(DeoptimizeType deoptType)6732     void SetDeoptimizeType(DeoptimizeType deoptType)
6733     {
6734         T::template SetField<DeoptimizeTypeField>(deoptType);
6735     }
6736 
SetDeoptimizeType(Inst * inst)6737     void SetDeoptimizeType(Inst *inst)
6738     {
6739         switch (inst->GetOpcode()) {
6740             case Opcode::NullCheck:
6741                 SetDeoptimizeType(DeoptimizeType::NULL_CHECK);
6742                 break;
6743             case Opcode::BoundsCheck:
6744                 SetDeoptimizeType(DeoptimizeType::BOUNDS_CHECK);
6745                 break;
6746             case Opcode::ZeroCheck:
6747                 SetDeoptimizeType(DeoptimizeType::ZERO_CHECK);
6748                 break;
6749             case Opcode::NegativeCheck:
6750                 SetDeoptimizeType(DeoptimizeType::NEGATIVE_CHECK);
6751                 break;
6752             case Opcode::NotPositiveCheck:
6753                 SetDeoptimizeType(DeoptimizeType::NEGATIVE_CHECK);
6754                 break;
6755             case Opcode::CheckCast:
6756                 SetDeoptimizeType(DeoptimizeType::CHECK_CAST);
6757                 break;
6758             case Opcode::AnyTypeCheck: {
6759                 SetDeoptimizeType(inst->CastToAnyTypeCheck()->GetDeoptimizeType());
6760                 break;
6761             }
6762             case Opcode::AddOverflowCheck:
6763             case Opcode::SubOverflowCheck:
6764             case Opcode::NegOverflowAndZeroCheck:
6765                 SetDeoptimizeType(DeoptimizeType::OVERFLOW);
6766                 break;
6767             case Opcode::DeoptimizeIf:
6768                 SetDeoptimizeType(static_cast<DeoptimizeTypeMixin *>(inst)->GetDeoptimizeType());
6769                 break;
6770             case Opcode::Intrinsic:
6771                 SetDeoptimizeType(DeoptimizeType::NOT_PROFILED);
6772                 break;
6773             default:
6774                 UNREACHABLE();
6775                 break;
6776         }
6777     }
6778 
GetDeoptimizeType()6779     DeoptimizeType GetDeoptimizeType() const
6780     {
6781         return T::template GetField<DeoptimizeTypeField>();
6782     }
6783 
6784 protected:
6785     using DeoptimizeTypeField =
6786         typename T::LastField::template NextField<DeoptimizeType, MinimumBitsToStore(DeoptimizeType::COUNT)>;
6787     using LastField = DeoptimizeTypeField;
6788 };
6789 
6790 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
6791 class PANDA_PUBLIC_API DeoptimizeInst : public DeoptimizeTypeMixin<FixedInputsInst1> {
6792 public:
6793     using Base = DeoptimizeTypeMixin<FixedInputsInst1>;
6794     using Base::Base;
6795 
Base(std::move (t))6796     explicit DeoptimizeInst(Initializer t, DeoptimizeType deoptType = DeoptimizeType::NOT_PROFILED) : Base(std::move(t))
6797     {
6798         SetDeoptimizeType(deoptType);
6799     }
6800 
Clone(const Graph * targetGraph)6801     Inst *Clone(const Graph *targetGraph) const override
6802     {
6803         auto clone = FixedInputsInst::Clone(targetGraph);
6804         ASSERT(clone->CastToDeoptimize()->GetDeoptimizeType() == GetDeoptimizeType());
6805         return clone;
6806     }
6807 
6808     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
6809 };
6810 
6811 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
6812 class PANDA_PUBLIC_API DeoptimizeIfInst : public DeoptimizeTypeMixin<FixedInputsInst2> {
6813     using Base = DeoptimizeTypeMixin<FixedInputsInst2>;
6814 
6815 public:
6816     using Base::Base;
6817 
DeoptimizeIfInst(Opcode opcode,uint32_t pc,Inst * cond,Inst * ss,DeoptimizeType deoptType)6818     DeoptimizeIfInst(Opcode opcode, uint32_t pc, Inst *cond, Inst *ss, DeoptimizeType deoptType)
6819         : Base({opcode, DataType::NO_TYPE, pc}, cond, ss)
6820     {
6821         SetDeoptimizeType(deoptType);
6822     }
6823 
Clone(const Graph * targetGraph)6824     Inst *Clone(const Graph *targetGraph) const override
6825     {
6826         auto clone = FixedInputsInst::Clone(targetGraph);
6827         ASSERT(clone->CastToDeoptimizeIf()->GetDeoptimizeType() == GetDeoptimizeType());
6828         return clone;
6829     }
6830 
GetInputType(size_t index)6831     DataType::Type GetInputType(size_t index) const override
6832     {
6833         ASSERT(index < GetInputsCount());
6834         switch (index) {
6835             case 0:
6836                 return GetInput(0).GetInst()->GetType();
6837             case 1:
6838                 return DataType::NO_TYPE;
6839             default:
6840                 UNREACHABLE();
6841         }
6842     }
6843 
6844     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
6845 };
6846 
6847 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
6848 class PANDA_PUBLIC_API DeoptimizeCompareInst
6849     : public InstWithOperandsType<DeoptimizeTypeMixin<ConditionMixin<FixedInputsInst3>>> {
6850 public:
6851     using Base = InstWithOperandsType<DeoptimizeTypeMixin<ConditionMixin<FixedInputsInst3>>>;
6852     using Base::Base;
6853 
DeoptimizeCompareInst(Opcode opcode,const DeoptimizeIfInst * deoptIf,const CompareInst * compare)6854     explicit DeoptimizeCompareInst(Opcode opcode, const DeoptimizeIfInst *deoptIf, const CompareInst *compare)
6855         : Base({opcode, deoptIf->GetType(), deoptIf->GetPc()})
6856     {
6857         SetDeoptimizeType(deoptIf->GetDeoptimizeType());
6858         SetOperandsType(compare->GetOperandsType());
6859         SetCc(compare->GetCc());
6860     }
6861 
Clone(const Graph * targetGraph)6862     Inst *Clone(const Graph *targetGraph) const override
6863     {
6864         auto clone = FixedInputsInst3::Clone(targetGraph);
6865         ASSERT(clone->CastToDeoptimizeCompare()->GetDeoptimizeType() == GetDeoptimizeType());
6866         ASSERT(clone->CastToDeoptimizeCompare()->GetOperandsType() == GetOperandsType());
6867         ASSERT(clone->CastToDeoptimizeCompare()->GetCc() == GetCc());
6868         return clone;
6869     }
6870 
GetInputType(size_t index)6871     DataType::Type GetInputType(size_t index) const override
6872     {
6873         ASSERT(index < GetInputsCount());
6874         switch (index) {
6875             case 0:
6876             case 1:
6877                 return GetInput(index).GetInst()->GetType();
6878             case 2U:
6879                 return DataType::NO_TYPE;
6880             default:
6881                 UNREACHABLE();
6882         }
6883     }
6884 
6885     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
6886 };
6887 
6888 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
6889 class PANDA_PUBLIC_API DeoptimizeCompareImmInst
6890     : public InstWithOperandsType<DeoptimizeTypeMixin<ConditionMixin<FixedInputsInst2>>>,
6891       public ImmediateMixin {
6892 public:
6893     using Base = InstWithOperandsType<DeoptimizeTypeMixin<ConditionMixin<FixedInputsInst2>>>;
6894     using Base::Base;
6895 
DeoptimizeCompareImmInst(Opcode opcode,const DeoptimizeIfInst * deoptIf,const CompareInst * compare,uint64_t imm)6896     explicit DeoptimizeCompareImmInst(Opcode opcode, const DeoptimizeIfInst *deoptIf, const CompareInst *compare,
6897                                       uint64_t imm)
6898         : Base({opcode, deoptIf->GetType(), deoptIf->GetPc()}), ImmediateMixin(imm)
6899     {
6900         SetDeoptimizeType(deoptIf->GetDeoptimizeType());
6901         SetOperandsType(compare->GetOperandsType());
6902         SetCc(compare->GetCc());
6903     }
6904 
GetInputType(size_t index)6905     DataType::Type GetInputType(size_t index) const override
6906     {
6907         ASSERT(index < GetInputsCount());
6908         switch (index) {
6909             case 0:
6910                 return GetInput(0).GetInst()->GetType();
6911             case 1:
6912                 return DataType::NO_TYPE;
6913             default:
6914                 UNREACHABLE();
6915         }
6916     }
6917 
Clone(const Graph * targetGraph)6918     Inst *Clone(const Graph *targetGraph) const override
6919     {
6920         auto clone = FixedInputsInst2::Clone(targetGraph);
6921         ASSERT(clone->CastToDeoptimizeCompareImm()->GetDeoptimizeType() == GetDeoptimizeType());
6922         ASSERT(clone->CastToDeoptimizeCompareImm()->GetOperandsType() == GetOperandsType());
6923         ASSERT(clone->CastToDeoptimizeCompareImm()->GetCc() == GetCc());
6924         clone->CastToDeoptimizeCompareImm()->SetImm(GetImm());
6925         return clone;
6926     }
6927 
6928     PANDA_PUBLIC_API void DumpOpcode(std::ostream *out) const override;
6929     PANDA_PUBLIC_API bool DumpInputs(std::ostream *out) const override;
6930 };
6931 
6932 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
6933 class ThrowInst : public FixedInputsInst2, public MethodDataMixin {
6934 public:
6935     using Base = FixedInputsInst2;
6936     using Base::Base;
6937 
GetInputType(size_t index)6938     DataType::Type GetInputType(size_t index) const override
6939     {
6940         ASSERT(index < GetInputsCount());
6941         if (index == 0) {
6942             return DataType::REFERENCE;
6943         }
6944         return DataType::NO_TYPE;
6945     }
6946 
IsInlined()6947     bool IsInlined() const
6948     {
6949         auto ss = GetSaveState();
6950         ASSERT(ss != nullptr);
6951         return ss->GetCallerInst() != nullptr;
6952     }
6953 
Clone(const Graph * targetGraph)6954     Inst *Clone(const Graph *targetGraph) const override
6955     {
6956         ASSERT(targetGraph != nullptr);
6957         auto instClone = FixedInputsInst2::Clone(targetGraph);
6958         auto throwClone = static_cast<ThrowInst *>(instClone);
6959         throwClone->SetCallMethodId(GetCallMethodId());
6960         throwClone->SetCallMethod(GetCallMethod());
6961         return instClone;
6962     }
6963 };
6964 
6965 class BinaryOverflowInst : public IfInst {
6966 public:
6967     using Base = IfInst;
6968     using Base::Base;
6969 
BinaryOverflowInst(Initializer t,ConditionCode cc)6970     BinaryOverflowInst(Initializer t, ConditionCode cc) : Base(t, cc)
6971     {
6972         SetOperandsType(GetType());
6973     }
6974 
GetInputType(size_t index)6975     DataType::Type GetInputType([[maybe_unused]] size_t index) const override
6976     {
6977         ASSERT(index < GetInputsCount());
6978         return GetType();
6979     }
6980 
GetOperandsType()6981     DataType::Type GetOperandsType() const override
6982     {
6983         return GetType();
6984     }
6985 };
6986 
6987 bool IsVolatileMemInst(const Inst *inst);
6988 
6989 // Check if instruction is pseudo-user for mutli-output instruction
IsPseudoUserOfMultiOutput(Inst * inst)6990 inline bool IsPseudoUserOfMultiOutput(Inst *inst)
6991 {
6992     ASSERT(inst != nullptr);
6993     switch (inst->GetOpcode()) {
6994         case Opcode::LoadPairPart:
6995             return true;
6996         default:
6997             return false;
6998     }
6999 }
7000 
7001 template <typename T>
7002 struct ConstructWrapper : public T {
7003     template <typename... Args>
ConstructWrapperConstructWrapper7004     explicit ConstructWrapper([[maybe_unused]] ArenaAllocator *a, Args &&...args)
7005         : ConstructWrapper(std::forward<Args>(args)...)
7006     {
7007     }
7008 
7009     // Try wrap Inst::Initializer:
7010     template <typename PC, typename... Args>
ConstructWrapperConstructWrapper7011     ConstructWrapper(Opcode opcode, DataType::Type type, PC pc, Args &&...args)
7012         : ConstructWrapper(Inst::Initializer {opcode, type, pc}, std::forward<Args>(args)...)
7013     {
7014     }
7015 
7016     // Try wrap FixedInputs:
7017     using Initializer = typename T::Initializer;
7018 
7019     template <typename T0, typename... Args, typename = Inst::CheckBase<T0>>
ConstructWrapperConstructWrapper7020     ConstructWrapper(Inst::Initializer t, T0 input0, Args &&...args)
7021         : ConstructWrapper(Initializer {t, std::array<Inst *, 1U> {input0}}, std::forward<Args>(args)...)
7022     {
7023     }
7024 
7025     template <typename T0, typename T1, typename... Args, typename = Inst::CheckBase<T0, T1>>
ConstructWrapperConstructWrapper7026     ConstructWrapper(Inst::Initializer t, T0 input0, T1 input1, Args &&...args)
7027         : ConstructWrapper(Initializer {t, std::array<Inst *, 2U> {input0, input1}}, std::forward<Args>(args)...)
7028     {
7029     }
7030 
7031     template <typename T0, typename T1, typename T2, typename... Args, typename = Inst::CheckBase<T0, T1, T2>>
ConstructWrapperConstructWrapper7032     ConstructWrapper(Inst::Initializer t, T0 input0, T1 input1, T2 input2, Args &&...args)
7033         : ConstructWrapper(Initializer {t, std::array<Inst *, 3U> {input0, input1, input2}},
7034                            std::forward<Args>(args)...)
7035     {
7036     }
7037 
7038     template <size_t N, typename... Args>
ConstructWrapperConstructWrapper7039     ConstructWrapper(Inst::Initializer t, std::array<Inst *, N> &&inputs, Args &&...args)
7040         : ConstructWrapper(Initializer {t, std::move(inputs)}, std::forward<Args>(args)...)
7041     {
7042     }
7043 
7044     // Final forward:
7045     template <typename... Args>
ConstructWrapperConstructWrapper7046     explicit ConstructWrapper(Args &&...args) : T(std::forward<Args>(args)...)
7047     {
7048     }
7049 };
7050 
7051 template <>
7052 struct ConstructWrapper<SpillFillInst> : SpillFillInst {
7053     ConstructWrapper(ArenaAllocator *allocator, Opcode opcode, SpillFillType type = UNKNOWN)
7054         : SpillFillInst(allocator, opcode, type)
7055     {
7056     }
7057 };
7058 
7059 template <typename InstType, typename... Args>
7060 InstType *Inst::ConstructInst(InstType *ptr, ArenaAllocator *allocator, Args &&...args)
7061 {
7062     // NOLINTNEXTLINE(readability-braces-around-statements, readability-misleading-indentation)
7063     if constexpr (InstType::INPUT_COUNT == MAX_STATIC_INPUTS) {
7064         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
7065         auto opsPtr = reinterpret_cast<char *>(ptr) - sizeof(DynamicOperands);
7066         [[maybe_unused]] auto ops = new (opsPtr) DynamicOperands(allocator);
7067         // NOLINTNEXTLINE(readability-braces-around-statements, readability-misleading-indentation)
7068     } else if constexpr (InstType::INPUT_COUNT != 0) {
7069         constexpr size_t OPERANDS_SIZE = sizeof(Operands<InstType::INPUT_COUNT>);
7070         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
7071         auto operands = new (reinterpret_cast<char *>(ptr) - OPERANDS_SIZE) Operands<InstType::INPUT_COUNT>;
7072         unsigned idx = InstType::INPUT_COUNT - 1;
7073         for (auto &user : operands->users) {
7074             new (&user) User(true, idx--, InstType::INPUT_COUNT);
7075         }
7076     }
7077     auto inst = new (ptr) ConstructWrapper<InstType>(allocator, std::forward<Args>(args)...);
7078     inst->template SetField<Inst::InputsCount>(InstType::INPUT_COUNT);
7079     return inst;
7080 }
7081 
7082 template <typename InstType, typename... Args>
7083 InstType *Inst::New(ArenaAllocator *allocator, Args &&...args)
7084 {
7085     static_assert(alignof(InstType) >= alignof(uintptr_t));
7086 
7087     size_t allocSize = sizeof(InstType);
7088     auto alignment = DEFAULT_ALIGNMENT;
7089     size_t operandsSize = 0;
7090     // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-branch-clone)
7091     if constexpr (InstType::INPUT_COUNT == MAX_STATIC_INPUTS) {
7092         constexpr size_t OPERANDS_SIZE = sizeof(DynamicOperands);
7093         static_assert((OPERANDS_SIZE % alignof(InstType)) == 0);
7094         operandsSize = OPERANDS_SIZE;
7095         // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-branch-clone)
7096     } else if constexpr (InstType::INPUT_COUNT != 0) {
7097         constexpr size_t OPERANDS_SIZE = sizeof(Operands<InstType::INPUT_COUNT>);
7098         static_assert((OPERANDS_SIZE % alignof(InstType)) == 0);
7099         operandsSize = OPERANDS_SIZE;
7100         alignment = GetLogAlignment(alignof(Operands<InstType::INPUT_COUNT>));
7101     }
7102 
7103     auto ptr = reinterpret_cast<uintptr_t>(allocator->Alloc(allocSize + operandsSize, alignment));
7104     ASSERT(ptr != 0);
7105     return ConstructInst(reinterpret_cast<InstType *>(ptr + operandsSize), allocator, std::forward<Args>(args)...);
7106 }
7107 
7108 INST_CAST_TO_DEF()
7109 
7110 inline Inst *User::GetInput()
7111 {
7112     return GetInst()->GetInput(GetIndex()).GetInst();
7113 }
7114 
7115 inline const Inst *User::GetInput() const
7116 {
7117     return GetInst()->GetInput(GetIndex()).GetInst();
7118 }
7119 
7120 inline std::ostream &operator<<(std::ostream &os, const Inst &inst)
7121 {
7122     inst.Dump(&os, false);
7123     return os;
7124 }
7125 
7126 }  // namespace ark::compiler
7127 
7128 #endif  // COMPILER_OPTIMIZER_IR_INST_H
7129