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