1b1994897Sopenharmony_ci/**
2b1994897Sopenharmony_ci * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3b1994897Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4b1994897Sopenharmony_ci * you may not use this file except in compliance with the License.
5b1994897Sopenharmony_ci * You may obtain a copy of the License at
6b1994897Sopenharmony_ci *
7b1994897Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
8b1994897Sopenharmony_ci *
9b1994897Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10b1994897Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11b1994897Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12b1994897Sopenharmony_ci * See the License for the specific language governing permissions and
13b1994897Sopenharmony_ci * limitations under the License.
14b1994897Sopenharmony_ci */
15b1994897Sopenharmony_ci
16b1994897Sopenharmony_ci#ifndef COMPILER_OPTIMIZER_IR_INST_H
17b1994897Sopenharmony_ci#define COMPILER_OPTIMIZER_IR_INST_H
18b1994897Sopenharmony_ci
19b1994897Sopenharmony_ci#include <array>
20b1994897Sopenharmony_ci#include <vector>
21b1994897Sopenharmony_ci#include <iostream>
22b1994897Sopenharmony_ci#include "constants.h"
23b1994897Sopenharmony_ci#include "datatype.h"
24b1994897Sopenharmony_ci#include "ir-dyn-base-types.h"
25b1994897Sopenharmony_ci#include "marker.h"
26b1994897Sopenharmony_ci#include "utils/arena_containers.h"
27b1994897Sopenharmony_ci#include "utils/span.h"
28b1994897Sopenharmony_ci#include "utils/bit_field.h"
29b1994897Sopenharmony_ci#include "utils/bit_utils.h"
30b1994897Sopenharmony_ci#include "utils/bit_vector.h"
31b1994897Sopenharmony_ci#include "macros.h"
32b1994897Sopenharmony_ci#include "mem/arena_allocator.h"
33b1994897Sopenharmony_ci#include "opcodes.h"
34b1994897Sopenharmony_ci#include "compiler_options.h"
35b1994897Sopenharmony_ci#include "runtime_interface.h"
36b1994897Sopenharmony_ci#include "spill_fill_data.h"
37b1994897Sopenharmony_ci
38b1994897Sopenharmony_cinamespace panda::compiler {
39b1994897Sopenharmony_ciclass Inst;
40b1994897Sopenharmony_ciclass BasicBlock;
41b1994897Sopenharmony_ciclass Graph;
42b1994897Sopenharmony_ciclass GraphVisitor;
43b1994897Sopenharmony_ciclass VnObject;
44b1994897Sopenharmony_ciclass SaveStateItem;
45b1994897Sopenharmony_ciclass LocationsInfo;
46b1994897Sopenharmony_ciusing InstVector = ArenaVector<Inst *>;
47b1994897Sopenharmony_ci
48b1994897Sopenharmony_ci// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
49b1994897Sopenharmony_ci#define INST_DEF(opcode, base, ...) class base;
50b1994897Sopenharmony_ci// NOLINTNEXTLINE(fuchsia-multiple-inheritance)
51b1994897Sopenharmony_ciOPCODE_LIST(INST_DEF)
52b1994897Sopenharmony_ci#undef INST_DEF
53b1994897Sopenharmony_ci
54b1994897Sopenharmony_ci/*
55b1994897Sopenharmony_ci * Condition code, used in Compare, If[Imm] and Select[Imm] instructions.
56b1994897Sopenharmony_ci *
57b1994897Sopenharmony_ci * N.B. BranchElimination and Peephole rely on the order of these codes. Change carefully.
58b1994897Sopenharmony_ci */
59b1994897Sopenharmony_cienum ConditionCode {
60b1994897Sopenharmony_ci    // All types.
61b1994897Sopenharmony_ci    CC_EQ = 0,  // ==
62b1994897Sopenharmony_ci    CC_NE,      // !=
63b1994897Sopenharmony_ci    // Signed integers and floating-point numbers.
64b1994897Sopenharmony_ci    CC_LT,  // <
65b1994897Sopenharmony_ci    CC_LE,  // <=
66b1994897Sopenharmony_ci    CC_GT,  // >
67b1994897Sopenharmony_ci    CC_GE,  // >=
68b1994897Sopenharmony_ci    // Unsigned integers.
69b1994897Sopenharmony_ci    CC_B,   // <
70b1994897Sopenharmony_ci    CC_BE,  // <=
71b1994897Sopenharmony_ci    CC_A,   // >
72b1994897Sopenharmony_ci    CC_AE,  // >=
73b1994897Sopenharmony_ci    // Compare result of bitwise AND with zero
74b1994897Sopenharmony_ci    CC_TST_EQ,  // (lhs AND rhs) == 0
75b1994897Sopenharmony_ci    CC_TST_NE,  // (lhs AND rhs) != 0
76b1994897Sopenharmony_ci    // First and last aliases.
77b1994897Sopenharmony_ci    CC_FIRST = CC_EQ,
78b1994897Sopenharmony_ci    CC_LAST = CC_TST_NE,
79b1994897Sopenharmony_ci};
80b1994897Sopenharmony_ci
81b1994897Sopenharmony_ciinline ConditionCode GetInverseConditionCode(ConditionCode code)
82b1994897Sopenharmony_ci{
83b1994897Sopenharmony_ci    switch (code) {
84b1994897Sopenharmony_ci        case ConditionCode::CC_EQ:
85b1994897Sopenharmony_ci            return ConditionCode::CC_NE;
86b1994897Sopenharmony_ci        case ConditionCode::CC_NE:
87b1994897Sopenharmony_ci            return ConditionCode::CC_EQ;
88b1994897Sopenharmony_ci        default:
89b1994897Sopenharmony_ci            UNREACHABLE();
90b1994897Sopenharmony_ci    }
91b1994897Sopenharmony_ci}
92b1994897Sopenharmony_ci
93b1994897Sopenharmony_ciinline ConditionCode InverseSignednessConditionCode(ConditionCode code)
94b1994897Sopenharmony_ci{
95b1994897Sopenharmony_ci    switch (code) {
96b1994897Sopenharmony_ci        case ConditionCode::CC_EQ:
97b1994897Sopenharmony_ci            return ConditionCode::CC_EQ;
98b1994897Sopenharmony_ci        case ConditionCode::CC_NE:
99b1994897Sopenharmony_ci            return ConditionCode::CC_NE;
100b1994897Sopenharmony_ci
101b1994897Sopenharmony_ci        case ConditionCode::CC_LT:
102b1994897Sopenharmony_ci            return ConditionCode::CC_B;
103b1994897Sopenharmony_ci        case ConditionCode::CC_LE:
104b1994897Sopenharmony_ci            return ConditionCode::CC_BE;
105b1994897Sopenharmony_ci        case ConditionCode::CC_GT:
106b1994897Sopenharmony_ci            return ConditionCode::CC_A;
107b1994897Sopenharmony_ci        case ConditionCode::CC_GE:
108b1994897Sopenharmony_ci            return ConditionCode::CC_AE;
109b1994897Sopenharmony_ci
110b1994897Sopenharmony_ci        case ConditionCode::CC_B:
111b1994897Sopenharmony_ci            return ConditionCode::CC_LT;
112b1994897Sopenharmony_ci        case ConditionCode::CC_BE:
113b1994897Sopenharmony_ci            return ConditionCode::CC_LE;
114b1994897Sopenharmony_ci        case ConditionCode::CC_A:
115b1994897Sopenharmony_ci            return ConditionCode::CC_GT;
116b1994897Sopenharmony_ci        case ConditionCode::CC_AE:
117b1994897Sopenharmony_ci            return ConditionCode::CC_GE;
118b1994897Sopenharmony_ci
119b1994897Sopenharmony_ci        case ConditionCode::CC_TST_EQ:
120b1994897Sopenharmony_ci            return ConditionCode::CC_TST_EQ;
121b1994897Sopenharmony_ci        case ConditionCode::CC_TST_NE:
122b1994897Sopenharmony_ci            return ConditionCode::CC_TST_NE;
123b1994897Sopenharmony_ci
124b1994897Sopenharmony_ci        default:
125b1994897Sopenharmony_ci            UNREACHABLE();
126b1994897Sopenharmony_ci    }
127b1994897Sopenharmony_ci}
128b1994897Sopenharmony_ci
129b1994897Sopenharmony_ciinline bool IsSignedConditionCode(ConditionCode code)
130b1994897Sopenharmony_ci{
131b1994897Sopenharmony_ci    switch (code) {
132b1994897Sopenharmony_ci        case ConditionCode::CC_LT:
133b1994897Sopenharmony_ci        case ConditionCode::CC_LE:
134b1994897Sopenharmony_ci        case ConditionCode::CC_GT:
135b1994897Sopenharmony_ci        case ConditionCode::CC_GE:
136b1994897Sopenharmony_ci            return true;
137b1994897Sopenharmony_ci
138b1994897Sopenharmony_ci        case ConditionCode::CC_EQ:
139b1994897Sopenharmony_ci        case ConditionCode::CC_NE:
140b1994897Sopenharmony_ci        case ConditionCode::CC_B:
141b1994897Sopenharmony_ci        case ConditionCode::CC_BE:
142b1994897Sopenharmony_ci        case ConditionCode::CC_A:
143b1994897Sopenharmony_ci        case ConditionCode::CC_AE:
144b1994897Sopenharmony_ci        case ConditionCode::CC_TST_EQ:
145b1994897Sopenharmony_ci        case ConditionCode::CC_TST_NE:
146b1994897Sopenharmony_ci            return false;
147b1994897Sopenharmony_ci
148b1994897Sopenharmony_ci        default:
149b1994897Sopenharmony_ci            UNREACHABLE();
150b1994897Sopenharmony_ci    }
151b1994897Sopenharmony_ci}
152b1994897Sopenharmony_ci
153b1994897Sopenharmony_ciinline ConditionCode SwapOperandsConditionCode(ConditionCode code)
154b1994897Sopenharmony_ci{
155b1994897Sopenharmony_ci    switch (code) {
156b1994897Sopenharmony_ci        case ConditionCode::CC_EQ:
157b1994897Sopenharmony_ci        case ConditionCode::CC_NE:
158b1994897Sopenharmony_ci            return code;
159b1994897Sopenharmony_ci        default:
160b1994897Sopenharmony_ci            UNREACHABLE();
161b1994897Sopenharmony_ci    }
162b1994897Sopenharmony_ci}
163b1994897Sopenharmony_ci
164b1994897Sopenharmony_cienum class Opcode {
165b1994897Sopenharmony_ci    INVALID = -1,
166b1994897Sopenharmony_ci// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
167b1994897Sopenharmony_ci#define INST_DEF(opcode, ...) opcode,
168b1994897Sopenharmony_ci    OPCODE_LIST(INST_DEF)
169b1994897Sopenharmony_ci
170b1994897Sopenharmony_ci#undef INST_DEF
171b1994897Sopenharmony_ci        NUM_OPCODES
172b1994897Sopenharmony_ci};
173b1994897Sopenharmony_ci
174b1994897Sopenharmony_ci/**
175b1994897Sopenharmony_ci * Convert opcode to its string representation
176b1994897Sopenharmony_ci */
177b1994897Sopenharmony_ciconstexpr std::array<const char *const, static_cast<size_t>(Opcode::NUM_OPCODES)> OPCODE_NAMES = {
178b1994897Sopenharmony_ci// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
179b1994897Sopenharmony_ci#define INST_DEF(opcode, ...) #opcode,
180b1994897Sopenharmony_ci    OPCODE_LIST(INST_DEF)
181b1994897Sopenharmony_ci#undef INST_DEF
182b1994897Sopenharmony_ci};
183b1994897Sopenharmony_ci
184b1994897Sopenharmony_ciconstexpr const char *GetOpcodeString(Opcode opc)
185b1994897Sopenharmony_ci{
186b1994897Sopenharmony_ci    ASSERT(static_cast<int>(opc) < static_cast<int>(Opcode::NUM_OPCODES));
187b1994897Sopenharmony_ci    return OPCODE_NAMES[static_cast<int>(opc)];
188b1994897Sopenharmony_ci}
189b1994897Sopenharmony_ci
190b1994897Sopenharmony_ci/**
191b1994897Sopenharmony_ci * Instruction flags. See `instrutions.yaml` section `flags` for more information.
192b1994897Sopenharmony_ci */
193b1994897Sopenharmony_cinamespace inst_flags {
194b1994897Sopenharmony_cinamespace internal {
195b1994897Sopenharmony_cienum FlagsIndex {
196b1994897Sopenharmony_ci// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
197b1994897Sopenharmony_ci#define FLAG_DEF(flag) flag##_INDEX,
198b1994897Sopenharmony_ci    FLAGS_LIST(FLAG_DEF)
199b1994897Sopenharmony_ci#undef FLAG_DEF
200b1994897Sopenharmony_ci        FLAGS_COUNT
201b1994897Sopenharmony_ci};
202b1994897Sopenharmony_ci}  // namespace internal
203b1994897Sopenharmony_ci
204b1994897Sopenharmony_cienum Flags : uint32_t {
205b1994897Sopenharmony_ci// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
206b1994897Sopenharmony_ci#define FLAG_DEF(flag) flag = (1U << internal::flag##_INDEX),
207b1994897Sopenharmony_ci    FLAGS_LIST(FLAG_DEF)
208b1994897Sopenharmony_ci#undef FLAG_DEF
209b1994897Sopenharmony_ci        FLAGS_COUNT = internal::FLAGS_COUNT,
210b1994897Sopenharmony_ci    NONE = 0
211b1994897Sopenharmony_ci};
212b1994897Sopenharmony_ci
213b1994897Sopenharmony_ciinline constexpr uintptr_t GetFlagsMask(Opcode opcode)
214b1994897Sopenharmony_ci{
215b1994897Sopenharmony_ci#define INST_DEF(OPCODE, BASE, FLAGS) FLAGS,  // NOLINT(cppcoreguidelines-macro-usage)
216b1994897Sopenharmony_ci    // NOLINTNEXTLINE(hicpp-signed-bitwise)
217b1994897Sopenharmony_ci    constexpr std::array<uintptr_t, static_cast<int>(Opcode::NUM_OPCODES)> INST_FLAGS_TABLE = {OPCODE_LIST(INST_DEF)};
218b1994897Sopenharmony_ci#undef INST_DEF
219b1994897Sopenharmony_ci    return INST_FLAGS_TABLE[static_cast<size_t>(opcode)];
220b1994897Sopenharmony_ci}
221b1994897Sopenharmony_ci}  // namespace inst_flags
222b1994897Sopenharmony_ci
223b1994897Sopenharmony_ci#ifndef NDEBUG
224b1994897Sopenharmony_cinamespace inst_modes {
225b1994897Sopenharmony_cinamespace internal {
226b1994897Sopenharmony_cienum ModeIndex {
227b1994897Sopenharmony_ci// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
228b1994897Sopenharmony_ci#define MODE_DEF(mode) mode##_INDEX,
229b1994897Sopenharmony_ci    MODES_LIST(MODE_DEF)
230b1994897Sopenharmony_ci#undef MODE_DEF
231b1994897Sopenharmony_ci        MODES_COUNT
232b1994897Sopenharmony_ci};
233b1994897Sopenharmony_ci}  // namespace internal
234b1994897Sopenharmony_ci
235b1994897Sopenharmony_cienum Mode : uint8_t {
236b1994897Sopenharmony_ci// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
237b1994897Sopenharmony_ci#define MODE_DEF(mode) mode = (1U << internal::mode##_INDEX),
238b1994897Sopenharmony_ci    MODES_LIST(MODE_DEF)
239b1994897Sopenharmony_ci#undef MODE_DEF
240b1994897Sopenharmony_ci        MODES_COUNT = internal::MODES_COUNT,
241b1994897Sopenharmony_ci};
242b1994897Sopenharmony_ci
243b1994897Sopenharmony_ciinline constexpr uint8_t GetModesMask(Opcode opcode)
244b1994897Sopenharmony_ci{
245b1994897Sopenharmony_ci    // NOLINTNEXTLINE(hicpp-signed-bitwise)
246b1994897Sopenharmony_ci    constexpr std::array<uint8_t, static_cast<int>(Opcode::NUM_OPCODES)> INST_MODES_TABLE = {INST_MODES_LIST};
247b1994897Sopenharmony_ci    return INST_MODES_TABLE[static_cast<size_t>(opcode)];
248b1994897Sopenharmony_ci}
249b1994897Sopenharmony_ci}  // namespace inst_modes
250b1994897Sopenharmony_ci#endif
251b1994897Sopenharmony_ci
252b1994897Sopenharmony_cinamespace internal {
253b1994897Sopenharmony_ciinline constexpr std::array<const char *, ShiftType::INVALID_SHIFT + 1> SHIFT_TYPE_NAMES = {"LSL", "LSR", "ASR", "ROR",
254b1994897Sopenharmony_ci                                                                                            "INVALID"};
255b1994897Sopenharmony_ci}  // namespace internal
256b1994897Sopenharmony_ci
257b1994897Sopenharmony_ciinline const char *GetShiftTypeStr(ShiftType type)
258b1994897Sopenharmony_ci{
259b1994897Sopenharmony_ci    ASSERT(type <= INVALID_SHIFT);
260b1994897Sopenharmony_ci    return internal::SHIFT_TYPE_NAMES[type];
261b1994897Sopenharmony_ci}
262b1994897Sopenharmony_ci
263b1994897Sopenharmony_ci/**
264b1994897Sopenharmony_ci * Describes type of the object produced by an instruction.
265b1994897Sopenharmony_ci */
266b1994897Sopenharmony_ciclass ObjectTypeInfo {
267b1994897Sopenharmony_cipublic:
268b1994897Sopenharmony_ci    using ClassType = RuntimeInterface::ClassPtr;
269b1994897Sopenharmony_ci
270b1994897Sopenharmony_ci    ObjectTypeInfo() = default;
271b1994897Sopenharmony_ci    explicit ObjectTypeInfo(ClassType v) : class_(v) {}
272b1994897Sopenharmony_ci
273b1994897Sopenharmony_ci    // NOLINTNEXTLINE(google-explicit-constructor)
274b1994897Sopenharmony_ci    operator bool() const
275b1994897Sopenharmony_ci    {
276b1994897Sopenharmony_ci        return class_ != ClassType();
277b1994897Sopenharmony_ci    }
278b1994897Sopenharmony_ci
279b1994897Sopenharmony_ci    ClassType GetClass() const
280b1994897Sopenharmony_ci    {
281b1994897Sopenharmony_ci        return class_;
282b1994897Sopenharmony_ci    }
283b1994897Sopenharmony_ci
284b1994897Sopenharmony_ci    bool IsValid() const
285b1994897Sopenharmony_ci    {
286b1994897Sopenharmony_ci        return class_ != ClassType {};
287b1994897Sopenharmony_ci    }
288b1994897Sopenharmony_ci
289b1994897Sopenharmony_ciprivate:
290b1994897Sopenharmony_ci    ClassType class_ {};
291b1994897Sopenharmony_ci};
292b1994897Sopenharmony_ci
293b1994897Sopenharmony_ci/**
294b1994897Sopenharmony_ci * Class for storing panda bytecode's virtual register
295b1994897Sopenharmony_ci */
296b1994897Sopenharmony_ciclass VirtualRegister final {
297b1994897Sopenharmony_cipublic:
298b1994897Sopenharmony_ci    using ValueType = uint16_t;
299b1994897Sopenharmony_ci    static constexpr unsigned BITS_FOR_VREG = (sizeof(ValueType) * BITS_PER_BYTE) - 1;
300b1994897Sopenharmony_ci    static constexpr ValueType INVALID = std::numeric_limits<ValueType>::max();
301b1994897Sopenharmony_ci
302b1994897Sopenharmony_ci    VirtualRegister() = default;
303b1994897Sopenharmony_ci    explicit VirtualRegister(uint16_t v, bool is_acc) : value_(v)
304b1994897Sopenharmony_ci    {
305b1994897Sopenharmony_ci        IsAccFlag::Set(is_acc, &value_);
306b1994897Sopenharmony_ci    }
307b1994897Sopenharmony_ci
308b1994897Sopenharmony_ci    explicit operator uint16_t() const
309b1994897Sopenharmony_ci    {
310b1994897Sopenharmony_ci        return value_;
311b1994897Sopenharmony_ci    }
312b1994897Sopenharmony_ci
313b1994897Sopenharmony_ci    uint16_t Value() const
314b1994897Sopenharmony_ci    {
315b1994897Sopenharmony_ci        return ValueField::Get(value_);
316b1994897Sopenharmony_ci    }
317b1994897Sopenharmony_ci
318b1994897Sopenharmony_ci    bool IsAccumulator() const
319b1994897Sopenharmony_ci    {
320b1994897Sopenharmony_ci        return IsAccFlag::Get(value_);
321b1994897Sopenharmony_ci    }
322b1994897Sopenharmony_ci
323b1994897Sopenharmony_ciprivate:
324b1994897Sopenharmony_ci    uint16_t value_ {INVALID};
325b1994897Sopenharmony_ci
326b1994897Sopenharmony_ci    using ValueField = BitField<unsigned, 0, BITS_FOR_VREG>;
327b1994897Sopenharmony_ci    using IsAccFlag = ValueField::NextFlag;
328b1994897Sopenharmony_ci};
329b1994897Sopenharmony_ci
330b1994897Sopenharmony_ci// How many bits will be used in Inst's bit fields for number of inputs.
331b1994897Sopenharmony_ciconstexpr size_t BITS_PER_INPUTS_NUM = 3;
332b1994897Sopenharmony_ci// Maximum number of static inputs
333b1994897Sopenharmony_ciconstexpr size_t MAX_STATIC_INPUTS = (1U << BITS_PER_INPUTS_NUM) - 1;
334b1994897Sopenharmony_ci
335b1994897Sopenharmony_ci/**
336b1994897Sopenharmony_ci * Currently Input class is just a wrapper for the Inst class.
337b1994897Sopenharmony_ci */
338b1994897Sopenharmony_ciclass Input final {
339b1994897Sopenharmony_cipublic:
340b1994897Sopenharmony_ci    Input() = default;
341b1994897Sopenharmony_ci    explicit Input(Inst *inst) : inst_(inst) {}
342b1994897Sopenharmony_ci
343b1994897Sopenharmony_ci    Inst *GetInst()
344b1994897Sopenharmony_ci    {
345b1994897Sopenharmony_ci        return inst_;
346b1994897Sopenharmony_ci    }
347b1994897Sopenharmony_ci    const Inst *GetInst() const
348b1994897Sopenharmony_ci    {
349b1994897Sopenharmony_ci        return inst_;
350b1994897Sopenharmony_ci    }
351b1994897Sopenharmony_ci
352b1994897Sopenharmony_ci    static inline uint8_t GetPadding(Arch arch, uint32_t inputs_count)
353b1994897Sopenharmony_ci    {
354b1994897Sopenharmony_ci        return static_cast<uint8_t>(!Is64BitsArch(arch) && inputs_count % 2U == 1U);
355b1994897Sopenharmony_ci    }
356b1994897Sopenharmony_ci
357b1994897Sopenharmony_ciprivate:
358b1994897Sopenharmony_ci    Inst *inst_ {nullptr};
359b1994897Sopenharmony_ci};
360b1994897Sopenharmony_ci
361b1994897Sopenharmony_ci/**
362b1994897Sopenharmony_ci * User is a intrusive list node, thus it stores pointers to next and previous users.
363b1994897Sopenharmony_ci * Also user has properties value to determine owner instruction and corresponding index of the input.
364b1994897Sopenharmony_ci */
365b1994897Sopenharmony_ciclass User final {
366b1994897Sopenharmony_cipublic:
367b1994897Sopenharmony_ci    User() = default;
368b1994897Sopenharmony_ci    User(bool is_static, unsigned index, unsigned size)
369b1994897Sopenharmony_ci        : properties_(IsStaticFlag::Encode(is_static) | IndexField::Encode(index) | SizeField::Encode(size) |
370b1994897Sopenharmony_ci                      BbNumField::Encode(BbNumField::MaxValue()))
371b1994897Sopenharmony_ci    {
372b1994897Sopenharmony_ci        ASSERT(index < 1U << (BITS_FOR_INDEX - 1U));
373b1994897Sopenharmony_ci        ASSERT(size < 1U << (BITS_FOR_SIZE - 1U));
374b1994897Sopenharmony_ci    }
375b1994897Sopenharmony_ci    ~User() = default;
376b1994897Sopenharmony_ci
377b1994897Sopenharmony_ci    // Copy/move semantic is disabled because we use tricky pointer arithmetic based on 'this' value
378b1994897Sopenharmony_ci    NO_COPY_SEMANTIC(User);
379b1994897Sopenharmony_ci    NO_MOVE_SEMANTIC(User);
380b1994897Sopenharmony_ci
381b1994897Sopenharmony_ci    Inst *GetInst();
382b1994897Sopenharmony_ci    const Inst *GetInst() const
383b1994897Sopenharmony_ci    {
384b1994897Sopenharmony_ci        return const_cast<User *>(this)->GetInst();
385b1994897Sopenharmony_ci    }
386b1994897Sopenharmony_ci
387b1994897Sopenharmony_ci    Inst *GetInput();
388b1994897Sopenharmony_ci    const Inst *GetInput() const;
389b1994897Sopenharmony_ci
390b1994897Sopenharmony_ci    bool IsDynamic() const
391b1994897Sopenharmony_ci    {
392b1994897Sopenharmony_ci        return !IsStaticFlag::Decode(properties_);
393b1994897Sopenharmony_ci    }
394b1994897Sopenharmony_ci    unsigned GetIndex() const
395b1994897Sopenharmony_ci    {
396b1994897Sopenharmony_ci        return IndexField::Decode(properties_);
397b1994897Sopenharmony_ci    }
398b1994897Sopenharmony_ci    unsigned GetSize() const
399b1994897Sopenharmony_ci    {
400b1994897Sopenharmony_ci        return SizeField::Decode(properties_);
401b1994897Sopenharmony_ci    }
402b1994897Sopenharmony_ci
403b1994897Sopenharmony_ci    VirtualRegister GetVirtualRegister() const
404b1994897Sopenharmony_ci    {
405b1994897Sopenharmony_ci        ASSERT(IsDynamic());
406b1994897Sopenharmony_ci        return VirtualRegister(VregField::Decode(properties_), IsAccFlag::Decode(properties_));
407b1994897Sopenharmony_ci    }
408b1994897Sopenharmony_ci
409b1994897Sopenharmony_ci    void SetVirtualRegister(VirtualRegister reg)
410b1994897Sopenharmony_ci    {
411b1994897Sopenharmony_ci        static_assert(sizeof(reg) <= sizeof(uintptr_t), "Consider passing the register by reference");
412b1994897Sopenharmony_ci        ASSERT(IsDynamic());
413b1994897Sopenharmony_ci        VregField::Set(reg.Value(), &properties_);
414b1994897Sopenharmony_ci        IsAccFlag::Set(reg.IsAccumulator(), &properties_);
415b1994897Sopenharmony_ci    }
416b1994897Sopenharmony_ci
417b1994897Sopenharmony_ci    uint32_t GetBbNum() const
418b1994897Sopenharmony_ci    {
419b1994897Sopenharmony_ci        ASSERT(IsDynamic());
420b1994897Sopenharmony_ci        return BbNumField::Decode(properties_);
421b1994897Sopenharmony_ci    }
422b1994897Sopenharmony_ci
423b1994897Sopenharmony_ci    void SetBbNum(uint32_t bb_num)
424b1994897Sopenharmony_ci    {
425b1994897Sopenharmony_ci        ASSERT(IsDynamic());
426b1994897Sopenharmony_ci        BbNumField::Set(bb_num, &properties_);
427b1994897Sopenharmony_ci    }
428b1994897Sopenharmony_ci
429b1994897Sopenharmony_ci    auto GetNext() const
430b1994897Sopenharmony_ci    {
431b1994897Sopenharmony_ci        return next_;
432b1994897Sopenharmony_ci    }
433b1994897Sopenharmony_ci
434b1994897Sopenharmony_ci    auto GetPrev() const
435b1994897Sopenharmony_ci    {
436b1994897Sopenharmony_ci        return prev_;
437b1994897Sopenharmony_ci    }
438b1994897Sopenharmony_ci
439b1994897Sopenharmony_ci    void SetNext(User *next)
440b1994897Sopenharmony_ci    {
441b1994897Sopenharmony_ci        next_ = next;
442b1994897Sopenharmony_ci    }
443b1994897Sopenharmony_ci
444b1994897Sopenharmony_ci    void SetPrev(User *prev)
445b1994897Sopenharmony_ci    {
446b1994897Sopenharmony_ci        prev_ = prev;
447b1994897Sopenharmony_ci    }
448b1994897Sopenharmony_ci
449b1994897Sopenharmony_ci    void Remove()
450b1994897Sopenharmony_ci    {
451b1994897Sopenharmony_ci        if (prev_ != nullptr) {
452b1994897Sopenharmony_ci            prev_->next_ = next_;
453b1994897Sopenharmony_ci        }
454b1994897Sopenharmony_ci        if (next_ != nullptr) {
455b1994897Sopenharmony_ci            next_->prev_ = prev_;
456b1994897Sopenharmony_ci        }
457b1994897Sopenharmony_ci    }
458b1994897Sopenharmony_ci
459b1994897Sopenharmony_ciprivate:
460b1994897Sopenharmony_ci    static constexpr unsigned BITS_FOR_INDEX = 21;
461b1994897Sopenharmony_ci    static constexpr unsigned BITS_FOR_SIZE = BITS_FOR_INDEX;
462b1994897Sopenharmony_ci    static constexpr unsigned BITS_FOR_BB_NUM = 20;
463b1994897Sopenharmony_ci    using IndexField = BitField<unsigned, 0, BITS_FOR_INDEX>;
464b1994897Sopenharmony_ci    using SizeField = IndexField::NextField<unsigned, BITS_FOR_SIZE>;
465b1994897Sopenharmony_ci    using IsStaticFlag = SizeField::NextFlag;
466b1994897Sopenharmony_ci
467b1994897Sopenharmony_ci    using BbNumField = IsStaticFlag::NextField<uint32_t, BITS_FOR_BB_NUM>;
468b1994897Sopenharmony_ci
469b1994897Sopenharmony_ci    using VregField = IsStaticFlag::NextField<unsigned, VirtualRegister::BITS_FOR_VREG>;
470b1994897Sopenharmony_ci    using IsAccFlag = VregField::NextFlag;
471b1994897Sopenharmony_ci
472b1994897Sopenharmony_ci    uint64_t properties_ {0};
473b1994897Sopenharmony_ci    User *next_ {nullptr};
474b1994897Sopenharmony_ci    User *prev_ {nullptr};
475b1994897Sopenharmony_ci};
476b1994897Sopenharmony_ci
477b1994897Sopenharmony_ci/**
478b1994897Sopenharmony_ci * List of users. Intended for range loop.
479b1994897Sopenharmony_ci * @tparam T should be User or const User
480b1994897Sopenharmony_ci */
481b1994897Sopenharmony_citemplate <typename T>
482b1994897Sopenharmony_ciclass UserList {
483b1994897Sopenharmony_ci    template <typename U>
484b1994897Sopenharmony_ci    struct UserIterator {
485b1994897Sopenharmony_ci        UserIterator() = default;
486b1994897Sopenharmony_ci        explicit UserIterator(U *u) : user_(u) {}
487b1994897Sopenharmony_ci
488b1994897Sopenharmony_ci        UserIterator &operator++()
489b1994897Sopenharmony_ci        {
490b1994897Sopenharmony_ci            user_ = user_->GetNext();
491b1994897Sopenharmony_ci            return *this;
492b1994897Sopenharmony_ci        }
493b1994897Sopenharmony_ci        bool operator!=(const UserIterator &other)
494b1994897Sopenharmony_ci        {
495b1994897Sopenharmony_ci            return user_ != other.user_;
496b1994897Sopenharmony_ci        }
497b1994897Sopenharmony_ci        U &operator*()
498b1994897Sopenharmony_ci        {
499b1994897Sopenharmony_ci            return *user_;
500b1994897Sopenharmony_ci        }
501b1994897Sopenharmony_ci        U *operator->()
502b1994897Sopenharmony_ci        {
503b1994897Sopenharmony_ci            return user_;
504b1994897Sopenharmony_ci        }
505b1994897Sopenharmony_ci
506b1994897Sopenharmony_ci    private:
507b1994897Sopenharmony_ci        U *user_ {nullptr};
508b1994897Sopenharmony_ci    };
509b1994897Sopenharmony_ci
510b1994897Sopenharmony_cipublic:
511b1994897Sopenharmony_ci    using Iterator = UserIterator<T>;
512b1994897Sopenharmony_ci    using ConstIterator = UserIterator<const T>;
513b1994897Sopenharmony_ci    using PointerType = std::conditional_t<std::is_const_v<T>, T *const *, T **>;
514b1994897Sopenharmony_ci
515b1994897Sopenharmony_ci    explicit UserList(PointerType head) : head_(head) {}
516b1994897Sopenharmony_ci
517b1994897Sopenharmony_ci    // NOLINTNEXTLINE(readability-identifier-naming)
518b1994897Sopenharmony_ci    Iterator begin()
519b1994897Sopenharmony_ci    {
520b1994897Sopenharmony_ci        return Iterator(*head_);
521b1994897Sopenharmony_ci    }
522b1994897Sopenharmony_ci    // NOLINTNEXTLINE(readability-identifier-naming)
523b1994897Sopenharmony_ci    Iterator end()
524b1994897Sopenharmony_ci    {
525b1994897Sopenharmony_ci        return Iterator(nullptr);
526b1994897Sopenharmony_ci    }
527b1994897Sopenharmony_ci    // NOLINTNEXTLINE(readability-identifier-naming)
528b1994897Sopenharmony_ci    ConstIterator begin() const
529b1994897Sopenharmony_ci    {
530b1994897Sopenharmony_ci        return ConstIterator(*head_);
531b1994897Sopenharmony_ci    }
532b1994897Sopenharmony_ci    // NOLINTNEXTLINE(readability-identifier-naming)
533b1994897Sopenharmony_ci    ConstIterator end() const
534b1994897Sopenharmony_ci    {
535b1994897Sopenharmony_ci        return ConstIterator(nullptr);
536b1994897Sopenharmony_ci    }
537b1994897Sopenharmony_ci    bool Empty() const
538b1994897Sopenharmony_ci    {
539b1994897Sopenharmony_ci        return *head_ == nullptr;
540b1994897Sopenharmony_ci    }
541b1994897Sopenharmony_ci    T &Front()
542b1994897Sopenharmony_ci    {
543b1994897Sopenharmony_ci        return **head_;
544b1994897Sopenharmony_ci    }
545b1994897Sopenharmony_ci    const T &Front() const
546b1994897Sopenharmony_ci    {
547b1994897Sopenharmony_ci        return **head_;
548b1994897Sopenharmony_ci    }
549b1994897Sopenharmony_ci
550b1994897Sopenharmony_ciprivate:
551b1994897Sopenharmony_ci    PointerType head_ {nullptr};
552b1994897Sopenharmony_ci};
553b1994897Sopenharmony_ci
554b1994897Sopenharmony_ciinline bool operator==(const User &lhs, const User &rhs)
555b1994897Sopenharmony_ci{
556b1994897Sopenharmony_ci    return lhs.GetInst() == rhs.GetInst();
557b1994897Sopenharmony_ci}
558b1994897Sopenharmony_ci
559b1994897Sopenharmony_ci/**
560b1994897Sopenharmony_ci * Operands class for instructions with fixed inputs count.
561b1994897Sopenharmony_ci * Actually, this class do absolutely nothing except that we can get sizeof of it when allocating memory.
562b1994897Sopenharmony_ci */
563b1994897Sopenharmony_citemplate <int N>
564b1994897Sopenharmony_cistruct Operands {
565b1994897Sopenharmony_ci    static_assert(N < MAX_STATIC_INPUTS, "Invalid inputs number");
566b1994897Sopenharmony_ci
567b1994897Sopenharmony_ci    std::array<User, N> users;
568b1994897Sopenharmony_ci    std::array<Input, N> inputs;
569b1994897Sopenharmony_ci};
570b1994897Sopenharmony_ci
571b1994897Sopenharmony_ci/**
572b1994897Sopenharmony_ci * Specialized version for instructions with variable inputs count.
573b1994897Sopenharmony_ci * Users and inputs are stored outside of this class.
574b1994897Sopenharmony_ci */
575b1994897Sopenharmony_ciclass DynamicOperands {
576b1994897Sopenharmony_cipublic:
577b1994897Sopenharmony_ci    explicit DynamicOperands(ArenaAllocator *allocator) : allocator_(allocator) {}
578b1994897Sopenharmony_ci
579b1994897Sopenharmony_ci    User *Users()
580b1994897Sopenharmony_ci    {
581b1994897Sopenharmony_ci        return users_;
582b1994897Sopenharmony_ci    }
583b1994897Sopenharmony_ci
584b1994897Sopenharmony_ci    Input *Inputs()
585b1994897Sopenharmony_ci    {
586b1994897Sopenharmony_ci        // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
587b1994897Sopenharmony_ci        return reinterpret_cast<Input *>(users_ + capacity_) + 1;
588b1994897Sopenharmony_ci    }
589b1994897Sopenharmony_ci
590b1994897Sopenharmony_ci    /// Append new input (and user accordingly)
591b1994897Sopenharmony_ci    unsigned Append(Inst *inst);
592b1994897Sopenharmony_ci
593b1994897Sopenharmony_ci    /// Remove input and user with index `index`.
594b1994897Sopenharmony_ci    void Remove(unsigned index);
595b1994897Sopenharmony_ci
596b1994897Sopenharmony_ci    /// Reallocate inputs/users storage to a new one with specified capacity.
597b1994897Sopenharmony_ci    void Reallocate(size_t new_capacity = 0);
598b1994897Sopenharmony_ci
599b1994897Sopenharmony_ci    /// Get instruction to which these operands belongs to.
600b1994897Sopenharmony_ci    Inst *GetOwnerInst() const
601b1994897Sopenharmony_ci    {
602b1994897Sopenharmony_ci        // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
603b1994897Sopenharmony_ci        return reinterpret_cast<Inst *>(const_cast<DynamicOperands *>(this) + 1);
604b1994897Sopenharmony_ci    }
605b1994897Sopenharmony_ci
606b1994897Sopenharmony_ci    User *GetUser(unsigned index)
607b1994897Sopenharmony_ci    {
608b1994897Sopenharmony_ci        CHECK_GE(capacity_ - 1, index);
609b1994897Sopenharmony_ci        // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
610b1994897Sopenharmony_ci        return &users_[capacity_ - index - 1];
611b1994897Sopenharmony_ci    }
612b1994897Sopenharmony_ci
613b1994897Sopenharmony_ci    Input *GetInput(unsigned index)
614b1994897Sopenharmony_ci    {
615b1994897Sopenharmony_ci        // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
616b1994897Sopenharmony_ci        return &Inputs()[index];
617b1994897Sopenharmony_ci    }
618b1994897Sopenharmony_ci
619b1994897Sopenharmony_ci    void SetInput(unsigned index, Input input)
620b1994897Sopenharmony_ci    {
621b1994897Sopenharmony_ci        // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
622b1994897Sopenharmony_ci        Inputs()[index] = input;
623b1994897Sopenharmony_ci    }
624b1994897Sopenharmony_ci
625b1994897Sopenharmony_ci    size_t Size() const
626b1994897Sopenharmony_ci    {
627b1994897Sopenharmony_ci        return size_;
628b1994897Sopenharmony_ci    }
629b1994897Sopenharmony_ci
630b1994897Sopenharmony_ciprivate:
631b1994897Sopenharmony_ci    User *users_ {nullptr};
632b1994897Sopenharmony_ci    size_t size_ {0};
633b1994897Sopenharmony_ci    size_t capacity_ {0};
634b1994897Sopenharmony_ci    ArenaAllocator *allocator_ {nullptr};
635b1994897Sopenharmony_ci};
636b1994897Sopenharmony_ci
637b1994897Sopenharmony_ci/**
638b1994897Sopenharmony_ci * Base class for all instructions, should not be instantiated directly
639b1994897Sopenharmony_ci */
640b1994897Sopenharmony_ciclass InstBase {
641b1994897Sopenharmony_ci    NO_COPY_SEMANTIC(InstBase);
642b1994897Sopenharmony_ci    NO_MOVE_SEMANTIC(InstBase);
643b1994897Sopenharmony_ci
644b1994897Sopenharmony_cipublic:
645b1994897Sopenharmony_ci    virtual ~InstBase() = default;
646b1994897Sopenharmony_ci
647b1994897Sopenharmony_cipublic:
648b1994897Sopenharmony_ci    ALWAYS_INLINE void operator delete([[maybe_unused]] void *unused, [[maybe_unused]] size_t size)
649b1994897Sopenharmony_ci    {
650b1994897Sopenharmony_ci        UNREACHABLE();
651b1994897Sopenharmony_ci    }
652b1994897Sopenharmony_ci    ALWAYS_INLINE void *operator new([[maybe_unused]] size_t size, void *ptr) noexcept
653b1994897Sopenharmony_ci    {
654b1994897Sopenharmony_ci        return ptr;
655b1994897Sopenharmony_ci    }
656b1994897Sopenharmony_ci    ALWAYS_INLINE void operator delete([[maybe_unused]] void *unused1, [[maybe_unused]] void *unused2) noexcept {}
657b1994897Sopenharmony_ci
658b1994897Sopenharmony_ci    void *operator new([[maybe_unused]] size_t size) = delete;
659b1994897Sopenharmony_ci
660b1994897Sopenharmony_ciprotected:
661b1994897Sopenharmony_ci    InstBase() = default;
662b1994897Sopenharmony_ci};
663b1994897Sopenharmony_ci
664b1994897Sopenharmony_ci/**
665b1994897Sopenharmony_ci * Base instruction class
666b1994897Sopenharmony_ci */
667b1994897Sopenharmony_ciclass Inst : public MarkerSet, public InstBase {
668b1994897Sopenharmony_cipublic:
669b1994897Sopenharmony_ci    /**
670b1994897Sopenharmony_ci     * Create new instruction. All instructions must be created with this method.
671b1994897Sopenharmony_ci     * It allocates additional space before Inst object for def-use structures.
672b1994897Sopenharmony_ci     *
673b1994897Sopenharmony_ci     * @tparam InstType - concrete type of instruction, shall be derived from Inst
674b1994897Sopenharmony_ci     * @tparam Args - constructor arguments types
675b1994897Sopenharmony_ci     * @param allocator - allocator for memory allocating
676b1994897Sopenharmony_ci     * @param args - constructor arguments
677b1994897Sopenharmony_ci     * @return - new instruction
678b1994897Sopenharmony_ci     */
679b1994897Sopenharmony_ci    template <typename InstType, typename... Args>
680b1994897Sopenharmony_ci    [[nodiscard]] static InstType *New(ArenaAllocator *allocator, Args &&... args);
681b1994897Sopenharmony_ci
682b1994897Sopenharmony_ci    // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
683b1994897Sopenharmony_ci#define INST_DEF(opcode, base, ...) inline const base *CastTo##opcode() const;
684b1994897Sopenharmony_ci    OPCODE_LIST(INST_DEF)
685b1994897Sopenharmony_ci#undef INST_DEF
686b1994897Sopenharmony_ci
687b1994897Sopenharmony_ci    // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
688b1994897Sopenharmony_ci#define INST_DEF(opcode, base, ...) inline base *CastTo##opcode();
689b1994897Sopenharmony_ci    OPCODE_LIST(INST_DEF)
690b1994897Sopenharmony_ci#undef INST_DEF
691b1994897Sopenharmony_ci
692b1994897Sopenharmony_ci    // Methods for instruction chaining inside basic blocks.
693b1994897Sopenharmony_ci    Inst *GetNext()
694b1994897Sopenharmony_ci    {
695b1994897Sopenharmony_ci        return next_;
696b1994897Sopenharmony_ci    }
697b1994897Sopenharmony_ci    const Inst *GetNext() const
698b1994897Sopenharmony_ci    {
699b1994897Sopenharmony_ci        return next_;
700b1994897Sopenharmony_ci    }
701b1994897Sopenharmony_ci    Inst *GetPrev()
702b1994897Sopenharmony_ci    {
703b1994897Sopenharmony_ci        return prev_;
704b1994897Sopenharmony_ci    }
705b1994897Sopenharmony_ci    const Inst *GetPrev() const
706b1994897Sopenharmony_ci    {
707b1994897Sopenharmony_ci        return prev_;
708b1994897Sopenharmony_ci    }
709b1994897Sopenharmony_ci    void SetNext(Inst *next)
710b1994897Sopenharmony_ci    {
711b1994897Sopenharmony_ci        next_ = next;
712b1994897Sopenharmony_ci    }
713b1994897Sopenharmony_ci    void SetPrev(Inst *prev)
714b1994897Sopenharmony_ci    {
715b1994897Sopenharmony_ci        prev_ = prev;
716b1994897Sopenharmony_ci    }
717b1994897Sopenharmony_ci
718b1994897Sopenharmony_ci    // Id accessors
719b1994897Sopenharmony_ci    auto GetId() const
720b1994897Sopenharmony_ci    {
721b1994897Sopenharmony_ci        return id_;
722b1994897Sopenharmony_ci    }
723b1994897Sopenharmony_ci    void SetId(int id)
724b1994897Sopenharmony_ci    {
725b1994897Sopenharmony_ci        id_ = id;
726b1994897Sopenharmony_ci    }
727b1994897Sopenharmony_ci
728b1994897Sopenharmony_ci    auto GetLinearNumber() const
729b1994897Sopenharmony_ci    {
730b1994897Sopenharmony_ci        return linear_number_;
731b1994897Sopenharmony_ci    }
732b1994897Sopenharmony_ci    void SetLinearNumber(LinearNumber number)
733b1994897Sopenharmony_ci    {
734b1994897Sopenharmony_ci        linear_number_ = number;
735b1994897Sopenharmony_ci    }
736b1994897Sopenharmony_ci
737b1994897Sopenharmony_ci    auto GetCloneNumber() const
738b1994897Sopenharmony_ci    {
739b1994897Sopenharmony_ci        return clone_number_;
740b1994897Sopenharmony_ci    }
741b1994897Sopenharmony_ci    void SetCloneNumber(int32_t number)
742b1994897Sopenharmony_ci    {
743b1994897Sopenharmony_ci        clone_number_ = number;
744b1994897Sopenharmony_ci    }
745b1994897Sopenharmony_ci
746b1994897Sopenharmony_ci    // Opcode accessors
747b1994897Sopenharmony_ci    Opcode GetOpcode() const
748b1994897Sopenharmony_ci    {
749b1994897Sopenharmony_ci        return opcode_;
750b1994897Sopenharmony_ci    }
751b1994897Sopenharmony_ci    void SetOpcode(Opcode opcode)
752b1994897Sopenharmony_ci    {
753b1994897Sopenharmony_ci        opcode_ = opcode;
754b1994897Sopenharmony_ci        SetField<FieldFlags>(inst_flags::GetFlagsMask(opcode));
755b1994897Sopenharmony_ci    }
756b1994897Sopenharmony_ci    const char *GetOpcodeStr() const
757b1994897Sopenharmony_ci    {
758b1994897Sopenharmony_ci        return GetOpcodeString(GetOpcode());
759b1994897Sopenharmony_ci    }
760b1994897Sopenharmony_ci
761b1994897Sopenharmony_ci    // Bytecode PC accessors
762b1994897Sopenharmony_ci    uint32_t GetPc() const
763b1994897Sopenharmony_ci    {
764b1994897Sopenharmony_ci        return pc_;
765b1994897Sopenharmony_ci    }
766b1994897Sopenharmony_ci    void SetPc(uint32_t pc)
767b1994897Sopenharmony_ci    {
768b1994897Sopenharmony_ci        pc_ = pc;
769b1994897Sopenharmony_ci    }
770b1994897Sopenharmony_ci
771b1994897Sopenharmony_ci    // Type accessors
772b1994897Sopenharmony_ci    DataType::Type GetType() const
773b1994897Sopenharmony_ci    {
774b1994897Sopenharmony_ci        return FieldType::Get(bit_fields_);
775b1994897Sopenharmony_ci    }
776b1994897Sopenharmony_ci    void SetType(DataType::Type type)
777b1994897Sopenharmony_ci    {
778b1994897Sopenharmony_ci        FieldType::Set(type, &bit_fields_);
779b1994897Sopenharmony_ci    }
780b1994897Sopenharmony_ci    bool HasType() const
781b1994897Sopenharmony_ci    {
782b1994897Sopenharmony_ci        return GetType() != DataType::Type::NO_TYPE;
783b1994897Sopenharmony_ci    }
784b1994897Sopenharmony_ci
785b1994897Sopenharmony_ci    // Parent basic block accessors
786b1994897Sopenharmony_ci    BasicBlock *GetBasicBlock()
787b1994897Sopenharmony_ci    {
788b1994897Sopenharmony_ci        return bb_;
789b1994897Sopenharmony_ci    }
790b1994897Sopenharmony_ci    const BasicBlock *GetBasicBlock() const
791b1994897Sopenharmony_ci    {
792b1994897Sopenharmony_ci        return bb_;
793b1994897Sopenharmony_ci    }
794b1994897Sopenharmony_ci    void SetBasicBlock(BasicBlock *bb)
795b1994897Sopenharmony_ci    {
796b1994897Sopenharmony_ci        bb_ = bb;
797b1994897Sopenharmony_ci    }
798b1994897Sopenharmony_ci
799b1994897Sopenharmony_ci    // Instruction properties getters
800b1994897Sopenharmony_ci    bool IsControlFlow() const
801b1994897Sopenharmony_ci    {
802b1994897Sopenharmony_ci        return GetFlag(inst_flags::CF);
803b1994897Sopenharmony_ci    }
804b1994897Sopenharmony_ci
805b1994897Sopenharmony_ci    bool IsIntrinsic() const
806b1994897Sopenharmony_ci    {
807b1994897Sopenharmony_ci        return GetOpcode() == Opcode::Intrinsic;
808b1994897Sopenharmony_ci    }
809b1994897Sopenharmony_ci
810b1994897Sopenharmony_ci    bool IsCall() const
811b1994897Sopenharmony_ci    {
812b1994897Sopenharmony_ci        return GetFlag(inst_flags::CALL);
813b1994897Sopenharmony_ci    }
814b1994897Sopenharmony_ci
815b1994897Sopenharmony_ci    bool IsSpillFill() const
816b1994897Sopenharmony_ci    {
817b1994897Sopenharmony_ci        return GetOpcode() == Opcode::SpillFill;
818b1994897Sopenharmony_ci    }
819b1994897Sopenharmony_ci
820b1994897Sopenharmony_ci    bool IsAccRead() const;
821b1994897Sopenharmony_ci    bool IsAccWrite() const;
822b1994897Sopenharmony_ci    bool CanThrow() const
823b1994897Sopenharmony_ci    {
824b1994897Sopenharmony_ci        return GetFlag(inst_flags::CAN_THROW);
825b1994897Sopenharmony_ci    }
826b1994897Sopenharmony_ci    bool RequireState() const
827b1994897Sopenharmony_ci    {
828b1994897Sopenharmony_ci        return GetFlag(inst_flags::REQUIRE_STATE);
829b1994897Sopenharmony_ci    }
830b1994897Sopenharmony_ci    // Returns true if the instruction not removable in DCE
831b1994897Sopenharmony_ci    bool IsNotRemovable() const
832b1994897Sopenharmony_ci    {
833b1994897Sopenharmony_ci        return GetFlag(inst_flags::NO_DCE);
834b1994897Sopenharmony_ci    }
835b1994897Sopenharmony_ci
836b1994897Sopenharmony_ci    // Returns true if the instruction doesn't have destination register
837b1994897Sopenharmony_ci    bool NoDest() const
838b1994897Sopenharmony_ci    {
839b1994897Sopenharmony_ci        return GetFlag(inst_flags::PSEUDO_DST) || GetFlag(inst_flags::NO_DST) || GetType() == DataType::VOID;
840b1994897Sopenharmony_ci    }
841b1994897Sopenharmony_ci
842b1994897Sopenharmony_ci    bool HasPseudoDestination() const
843b1994897Sopenharmony_ci    {
844b1994897Sopenharmony_ci        return GetFlag(inst_flags::PSEUDO_DST);
845b1994897Sopenharmony_ci    }
846b1994897Sopenharmony_ci
847b1994897Sopenharmony_ci    bool HasImplicitRuntimeCall() const
848b1994897Sopenharmony_ci    {
849b1994897Sopenharmony_ci        return GetFlag(inst_flags::IMPLICIT_RUNTIME_CALL);
850b1994897Sopenharmony_ci    }
851b1994897Sopenharmony_ci
852b1994897Sopenharmony_ci    bool CanDeoptimize() const
853b1994897Sopenharmony_ci    {
854b1994897Sopenharmony_ci        return GetFlag(inst_flags::CAN_DEOPTIMIZE);
855b1994897Sopenharmony_ci    }
856b1994897Sopenharmony_ci
857b1994897Sopenharmony_ci    // Returns true if the instruction is low-level
858b1994897Sopenharmony_ci    bool IsLowLevel() const
859b1994897Sopenharmony_ci    {
860b1994897Sopenharmony_ci        return GetFlag(inst_flags::LOW_LEVEL);
861b1994897Sopenharmony_ci    }
862b1994897Sopenharmony_ci
863b1994897Sopenharmony_ci    // Returns true if the instruction not hoistable
864b1994897Sopenharmony_ci    bool IsNotHoistable() const
865b1994897Sopenharmony_ci    {
866b1994897Sopenharmony_ci        return GetFlag(inst_flags::NO_HOIST);
867b1994897Sopenharmony_ci    }
868b1994897Sopenharmony_ci
869b1994897Sopenharmony_ci    // Returns true Cse can't be applied to the instruction
870b1994897Sopenharmony_ci    bool IsNotCseApplicable() const
871b1994897Sopenharmony_ci    {
872b1994897Sopenharmony_ci        return GetFlag(inst_flags::NO_CSE);
873b1994897Sopenharmony_ci    }
874b1994897Sopenharmony_ci
875b1994897Sopenharmony_ci    // Returns true if opcode can not be moved throught runtime calls (REFERENCE type only)
876b1994897Sopenharmony_ci    bool IsRefSpecial() const
877b1994897Sopenharmony_ci    {
878b1994897Sopenharmony_ci        bool result = GetFlag(inst_flags::REF_SPECIAL);
879b1994897Sopenharmony_ci        ASSERT(!result || GetType() == DataType::Type::REFERENCE);
880b1994897Sopenharmony_ci        return result;
881b1994897Sopenharmony_ci    }
882b1994897Sopenharmony_ci
883b1994897Sopenharmony_ci    // Returns true if the instruction is a commutative
884b1994897Sopenharmony_ci    bool IsCommutative() const
885b1994897Sopenharmony_ci    {
886b1994897Sopenharmony_ci        return GetFlag(inst_flags::COMMUTATIVE);
887b1994897Sopenharmony_ci    }
888b1994897Sopenharmony_ci
889b1994897Sopenharmony_ci    // Returns true if the instruction can be used in if-conversion
890b1994897Sopenharmony_ci    bool IsIfConvertable() const
891b1994897Sopenharmony_ci    {
892b1994897Sopenharmony_ci        return GetFlag(inst_flags::IFCVT);
893b1994897Sopenharmony_ci    }
894b1994897Sopenharmony_ci
895b1994897Sopenharmony_ci    virtual bool IsPropagateLiveness() const;
896b1994897Sopenharmony_ci
897b1994897Sopenharmony_ci    bool RequireRegMap() const;
898b1994897Sopenharmony_ci
899b1994897Sopenharmony_ci    ObjectTypeInfo GetObjectTypeInfo() const
900b1994897Sopenharmony_ci    {
901b1994897Sopenharmony_ci        return object_type_info_;
902b1994897Sopenharmony_ci    }
903b1994897Sopenharmony_ci
904b1994897Sopenharmony_ci    bool HasObjectTypeInfo() const
905b1994897Sopenharmony_ci    {
906b1994897Sopenharmony_ci        return object_type_info_.IsValid();
907b1994897Sopenharmony_ci    }
908b1994897Sopenharmony_ci
909b1994897Sopenharmony_ci    Inst *GetDataFlowInput(int index) const
910b1994897Sopenharmony_ci    {
911b1994897Sopenharmony_ci        return GetDataFlowInput(GetInput(index).GetInst());
912b1994897Sopenharmony_ci    }
913b1994897Sopenharmony_ci    Inst *GetDataFlowInput(Inst *input_inst) const;
914b1994897Sopenharmony_ci
915b1994897Sopenharmony_ci    bool IsPrecedingInSameBlock(const Inst *other) const;
916b1994897Sopenharmony_ci
917b1994897Sopenharmony_ci    bool IsDominate(const Inst *other) const;
918b1994897Sopenharmony_ci
919b1994897Sopenharmony_ci    bool InSameBlockOrDominate(const Inst *other) const;
920b1994897Sopenharmony_ci
921b1994897Sopenharmony_ci    const SaveStateInst *GetSaveState() const
922b1994897Sopenharmony_ci    {
923b1994897Sopenharmony_ci        return const_cast<Inst *>(this)->GetSaveState();
924b1994897Sopenharmony_ci    }
925b1994897Sopenharmony_ci
926b1994897Sopenharmony_ci    SaveStateInst *GetSaveState()
927b1994897Sopenharmony_ci    {
928b1994897Sopenharmony_ci        if (!RequireState()) {
929b1994897Sopenharmony_ci            return nullptr;
930b1994897Sopenharmony_ci        }
931b1994897Sopenharmony_ci        if (GetInputsCount() == 0) {
932b1994897Sopenharmony_ci            return nullptr;
933b1994897Sopenharmony_ci        }
934b1994897Sopenharmony_ci        auto ss = GetInput(GetInputsCount() - 1).GetInst();
935b1994897Sopenharmony_ci        if (ss->GetOpcode() != Opcode::SaveState) {
936b1994897Sopenharmony_ci            return nullptr;
937b1994897Sopenharmony_ci        }
938b1994897Sopenharmony_ci        return ss->CastToSaveState();
939b1994897Sopenharmony_ci    }
940b1994897Sopenharmony_ci
941b1994897Sopenharmony_ci    void SetSaveState(Inst *inst)
942b1994897Sopenharmony_ci    {
943b1994897Sopenharmony_ci        ASSERT(RequireState());
944b1994897Sopenharmony_ci        SetInput(GetInputsCount() - 1, inst);
945b1994897Sopenharmony_ci    }
946b1994897Sopenharmony_ci
947b1994897Sopenharmony_ci    bool IsZeroRegInst() const;
948b1994897Sopenharmony_ci
949b1994897Sopenharmony_ci    /**
950b1994897Sopenharmony_ci     * Return instruction clone
951b1994897Sopenharmony_ci     */
952b1994897Sopenharmony_ci    virtual Inst *Clone(const Graph *targetGraph) const;
953b1994897Sopenharmony_ci
954b1994897Sopenharmony_ci    uintptr_t GetFlagsMask() const
955b1994897Sopenharmony_ci    {
956b1994897Sopenharmony_ci        return GetField<FieldFlags>();
957b1994897Sopenharmony_ci    }
958b1994897Sopenharmony_ci
959b1994897Sopenharmony_ci    bool GetFlag(inst_flags::Flags flag) const
960b1994897Sopenharmony_ci    {
961b1994897Sopenharmony_ci        return (GetFlagsMask() & flag) != 0;
962b1994897Sopenharmony_ci    }
963b1994897Sopenharmony_ci
964b1994897Sopenharmony_ci    void SetFlag(inst_flags::Flags flag)
965b1994897Sopenharmony_ci    {
966b1994897Sopenharmony_ci        SetField<FieldFlags>(GetFlagsMask() | flag);
967b1994897Sopenharmony_ci    }
968b1994897Sopenharmony_ci
969b1994897Sopenharmony_ci    void ClearFlag(inst_flags::Flags flag)
970b1994897Sopenharmony_ci    {
971b1994897Sopenharmony_ci        SetField<FieldFlags>(GetFlagsMask() & ~static_cast<uintptr_t>(flag));
972b1994897Sopenharmony_ci    }
973b1994897Sopenharmony_ci
974b1994897Sopenharmony_ci#ifndef NDEBUG
975b1994897Sopenharmony_ci    uint8_t GetModesMask() const
976b1994897Sopenharmony_ci    {
977b1994897Sopenharmony_ci        return inst_modes::GetModesMask(opcode_);
978b1994897Sopenharmony_ci    }
979b1994897Sopenharmony_ci
980b1994897Sopenharmony_ci    bool SupportsMode(inst_modes::Mode mode) const
981b1994897Sopenharmony_ci    {
982b1994897Sopenharmony_ci        return (GetModesMask() & mode) != 0;
983b1994897Sopenharmony_ci    }
984b1994897Sopenharmony_ci#endif
985b1994897Sopenharmony_ci
986b1994897Sopenharmony_ci    void SetTerminator()
987b1994897Sopenharmony_ci    {
988b1994897Sopenharmony_ci        SetFlag(inst_flags::Flags::TERMINATOR);
989b1994897Sopenharmony_ci    }
990b1994897Sopenharmony_ci
991b1994897Sopenharmony_ci    void InsertBefore(Inst *inst);
992b1994897Sopenharmony_ci    void InsertAfter(Inst *inst);
993b1994897Sopenharmony_ci
994b1994897Sopenharmony_ci    /**
995b1994897Sopenharmony_ci     * Return true if instruction has dynamic operands storage.
996b1994897Sopenharmony_ci     */
997b1994897Sopenharmony_ci    bool IsOperandsDynamic() const
998b1994897Sopenharmony_ci    {
999b1994897Sopenharmony_ci        return GetField<InputsCount>() == MAX_STATIC_INPUTS;
1000b1994897Sopenharmony_ci    }
1001b1994897Sopenharmony_ci
1002b1994897Sopenharmony_ci    /**
1003b1994897Sopenharmony_ci     * Add user to the instruction.
1004b1994897Sopenharmony_ci     * @param user - pointer to User object
1005b1994897Sopenharmony_ci     */
1006b1994897Sopenharmony_ci    void AddUser(User *user)
1007b1994897Sopenharmony_ci    {
1008b1994897Sopenharmony_ci        ASSERT(user && user->GetInst());
1009b1994897Sopenharmony_ci        user->SetNext(first_user_);
1010b1994897Sopenharmony_ci        user->SetPrev(nullptr);
1011b1994897Sopenharmony_ci        if (first_user_ != nullptr) {
1012b1994897Sopenharmony_ci            ASSERT(first_user_->GetPrev() == nullptr);
1013b1994897Sopenharmony_ci            first_user_->SetPrev(user);
1014b1994897Sopenharmony_ci        }
1015b1994897Sopenharmony_ci        first_user_ = user;
1016b1994897Sopenharmony_ci    }
1017b1994897Sopenharmony_ci
1018b1994897Sopenharmony_ci    /**
1019b1994897Sopenharmony_ci     * Remove instruction from users.
1020b1994897Sopenharmony_ci     * @param user - pointer to User object
1021b1994897Sopenharmony_ci     */
1022b1994897Sopenharmony_ci    void RemoveUser(User *user)
1023b1994897Sopenharmony_ci    {
1024b1994897Sopenharmony_ci        ASSERT(user);
1025b1994897Sopenharmony_ci        ASSERT(HasUsers());
1026b1994897Sopenharmony_ci        if (user == first_user_) {
1027b1994897Sopenharmony_ci            first_user_ = user->GetNext();
1028b1994897Sopenharmony_ci        }
1029b1994897Sopenharmony_ci        user->Remove();
1030b1994897Sopenharmony_ci    }
1031b1994897Sopenharmony_ci
1032b1994897Sopenharmony_ci    /**
1033b1994897Sopenharmony_ci     * Set input instruction in specified index.
1034b1994897Sopenharmony_ci     * Old input will be removed.
1035b1994897Sopenharmony_ci     * @param index - index of input to be set
1036b1994897Sopenharmony_ci     * @param inst - new input instruction TODO sherstennikov: currently it can be nullptr, is it correct?
1037b1994897Sopenharmony_ci     */
1038b1994897Sopenharmony_ci    void SetInput(unsigned index, Inst *inst)
1039b1994897Sopenharmony_ci    {
1040b1994897Sopenharmony_ci        CHECK_LT(index, GetInputsCount());
1041b1994897Sopenharmony_ci        auto &input = GetInputs()[index];
1042b1994897Sopenharmony_ci        auto user = GetUser(index);
1043b1994897Sopenharmony_ci        if (input.GetInst() != nullptr && input.GetInst()->HasUsers()) {
1044b1994897Sopenharmony_ci            input.GetInst()->RemoveUser(user);
1045b1994897Sopenharmony_ci        }
1046b1994897Sopenharmony_ci        if (inst != nullptr) {
1047b1994897Sopenharmony_ci            inst->AddUser(user);
1048b1994897Sopenharmony_ci        }
1049b1994897Sopenharmony_ci        input = Input(inst);
1050b1994897Sopenharmony_ci    }
1051b1994897Sopenharmony_ci
1052b1994897Sopenharmony_ci    /**
1053b1994897Sopenharmony_ci     * Replace all inputs that points to specified instruction by new one.
1054b1994897Sopenharmony_ci     * @param old_input - instruction that should be replaced
1055b1994897Sopenharmony_ci     * @param new_input - new input instruction
1056b1994897Sopenharmony_ci     */
1057b1994897Sopenharmony_ci    void ReplaceInput(Inst *old_input, Inst *new_input)
1058b1994897Sopenharmony_ci    {
1059b1994897Sopenharmony_ci        unsigned index = 0;
1060b1994897Sopenharmony_ci        for (auto input : GetInputs()) {
1061b1994897Sopenharmony_ci            if (input.GetInst() == old_input) {
1062b1994897Sopenharmony_ci                SetInput(index, new_input);
1063b1994897Sopenharmony_ci            }
1064b1994897Sopenharmony_ci            index++;
1065b1994897Sopenharmony_ci        }
1066b1994897Sopenharmony_ci    }
1067b1994897Sopenharmony_ci
1068b1994897Sopenharmony_ci    /**
1069b1994897Sopenharmony_ci     * Replace inputs that point to this instruction by given instruction.
1070b1994897Sopenharmony_ci     * @param inst - new input instruction
1071b1994897Sopenharmony_ci     */
1072b1994897Sopenharmony_ci    void ReplaceUsers(Inst *inst)
1073b1994897Sopenharmony_ci    {
1074b1994897Sopenharmony_ci        ASSERT(inst != this);
1075b1994897Sopenharmony_ci        ASSERT(inst != nullptr);
1076b1994897Sopenharmony_ci        for (auto it = GetUsers().begin(); it != GetUsers().end(); it = GetUsers().begin()) {
1077b1994897Sopenharmony_ci            it->GetInst()->SetInput(it->GetIndex(), inst);
1078b1994897Sopenharmony_ci        }
1079b1994897Sopenharmony_ci    }
1080b1994897Sopenharmony_ci
1081b1994897Sopenharmony_ci    /**
1082b1994897Sopenharmony_ci     * Append input instruction.
1083b1994897Sopenharmony_ci     * Available only for variadic inputs instructions, such as PHI.
1084b1994897Sopenharmony_ci     * @param input - input instruction
1085b1994897Sopenharmony_ci     * @return index in inputs container where new input is placed
1086b1994897Sopenharmony_ci     */
1087b1994897Sopenharmony_ci    unsigned AppendInput(Inst *input)
1088b1994897Sopenharmony_ci    {
1089b1994897Sopenharmony_ci        CHECK_NOT_NULL(input);
1090b1994897Sopenharmony_ci        ASSERT(IsOperandsDynamic());
1091b1994897Sopenharmony_ci        DynamicOperands *operands = GetDynamicOperands();
1092b1994897Sopenharmony_ci        return operands->Append(input);
1093b1994897Sopenharmony_ci    }
1094b1994897Sopenharmony_ci
1095b1994897Sopenharmony_ci    unsigned AppendInput(Input input)
1096b1994897Sopenharmony_ci    {
1097b1994897Sopenharmony_ci        static_assert(sizeof(Input) <= sizeof(uintptr_t));  // Input become larger, so pass it by reference then
1098b1994897Sopenharmony_ci        return AppendInput(input.GetInst());
1099b1994897Sopenharmony_ci    }
1100b1994897Sopenharmony_ci
1101b1994897Sopenharmony_ci    /**
1102b1994897Sopenharmony_ci     * Remove input from inputs container
1103b1994897Sopenharmony_ci     * Available only for variadic inputs instructions, such as PHI.
1104b1994897Sopenharmony_ci     * @param index - index of input in inputs container
1105b1994897Sopenharmony_ci     */
1106b1994897Sopenharmony_ci    virtual void RemoveInput(unsigned index)
1107b1994897Sopenharmony_ci    {
1108b1994897Sopenharmony_ci        ASSERT(IsOperandsDynamic());
1109b1994897Sopenharmony_ci        DynamicOperands *operands = GetDynamicOperands();
1110b1994897Sopenharmony_ci        ASSERT(index < operands->Size());
1111b1994897Sopenharmony_ci        operands->Remove(index);
1112b1994897Sopenharmony_ci    }
1113b1994897Sopenharmony_ci
1114b1994897Sopenharmony_ci    /**
1115b1994897Sopenharmony_ci     * Remove all inputs
1116b1994897Sopenharmony_ci     */
1117b1994897Sopenharmony_ci    void RemoveInputs()
1118b1994897Sopenharmony_ci    {
1119b1994897Sopenharmony_ci        if (UNLIKELY(IsOperandsDynamic())) {
1120b1994897Sopenharmony_ci            for (auto inputs_count = GetInputsCount(); inputs_count != 0; --inputs_count) {
1121b1994897Sopenharmony_ci                RemoveInput(inputs_count - 1);
1122b1994897Sopenharmony_ci            }
1123b1994897Sopenharmony_ci        } else {
1124b1994897Sopenharmony_ci            for (size_t i = 0; i < GetInputsCount(); ++i) {
1125b1994897Sopenharmony_ci                SetInput(i, nullptr);
1126b1994897Sopenharmony_ci            }
1127b1994897Sopenharmony_ci        }
1128b1994897Sopenharmony_ci    }
1129b1994897Sopenharmony_ci
1130b1994897Sopenharmony_ci    /**
1131b1994897Sopenharmony_ci     * Remove all users
1132b1994897Sopenharmony_ci     */
1133b1994897Sopenharmony_ci    template <bool with_inputs = false>
1134b1994897Sopenharmony_ci    void RemoveUsers()
1135b1994897Sopenharmony_ci    {
1136b1994897Sopenharmony_ci        auto users = GetUsers();
1137b1994897Sopenharmony_ci        while (!users.Empty()) {
1138b1994897Sopenharmony_ci            // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
1139b1994897Sopenharmony_ci            if constexpr (with_inputs) {
1140b1994897Sopenharmony_ci                auto &user = users.Front();
1141b1994897Sopenharmony_ci                user.GetInst()->RemoveInput(user.GetIndex());
1142b1994897Sopenharmony_ci                // NOLINTNEXTLINE(readability-misleading-indentation)
1143b1994897Sopenharmony_ci            } else {
1144b1994897Sopenharmony_ci                RemoveUser(&users.Front());
1145b1994897Sopenharmony_ci            }
1146b1994897Sopenharmony_ci        }
1147b1994897Sopenharmony_ci    }
1148b1994897Sopenharmony_ci
1149b1994897Sopenharmony_ci    /**
1150b1994897Sopenharmony_ci     * Get input by index
1151b1994897Sopenharmony_ci     * @param index - index of input
1152b1994897Sopenharmony_ci     * @return input instruction
1153b1994897Sopenharmony_ci     */
1154b1994897Sopenharmony_ci    Input GetInput(unsigned index)
1155b1994897Sopenharmony_ci    {
1156b1994897Sopenharmony_ci        ASSERT(index < GetInputsCount());
1157b1994897Sopenharmony_ci        return GetInputs()[index];
1158b1994897Sopenharmony_ci    }
1159b1994897Sopenharmony_ci
1160b1994897Sopenharmony_ci    Input GetInput(unsigned index) const
1161b1994897Sopenharmony_ci    {
1162b1994897Sopenharmony_ci        ASSERT(index < GetInputsCount());
1163b1994897Sopenharmony_ci        return GetInputs()[index];
1164b1994897Sopenharmony_ci    }
1165b1994897Sopenharmony_ci
1166b1994897Sopenharmony_ci    Span<Input> GetInputs()
1167b1994897Sopenharmony_ci    {
1168b1994897Sopenharmony_ci        if (UNLIKELY(IsOperandsDynamic())) {
1169b1994897Sopenharmony_ci            DynamicOperands *operands = GetDynamicOperands();
1170b1994897Sopenharmony_ci            return Span<Input>(operands->Inputs(), operands->Size());
1171b1994897Sopenharmony_ci        }
1172b1994897Sopenharmony_ci
1173b1994897Sopenharmony_ci        auto inputs_count {GetField<InputsCount>()};
1174b1994897Sopenharmony_ci        return Span<Input>(
1175b1994897Sopenharmony_ci            reinterpret_cast<Input *>(reinterpret_cast<uintptr_t>(this) -
1176b1994897Sopenharmony_ci                                      (inputs_count + Input::GetPadding(RUNTIME_ARCH, inputs_count)) * sizeof(Input)),
1177b1994897Sopenharmony_ci            inputs_count);
1178b1994897Sopenharmony_ci    }
1179b1994897Sopenharmony_ci    Span<const Input> GetInputs() const
1180b1994897Sopenharmony_ci    {
1181b1994897Sopenharmony_ci        return Span<const Input>(const_cast<Inst *>(this)->GetInputs());
1182b1994897Sopenharmony_ci    }
1183b1994897Sopenharmony_ci
1184b1994897Sopenharmony_ci    virtual DataType::Type GetInputType([[maybe_unused]] size_t index) const
1185b1994897Sopenharmony_ci    {
1186b1994897Sopenharmony_ci        ASSERT(index < GetInputsCount());
1187b1994897Sopenharmony_ci        return GetType();
1188b1994897Sopenharmony_ci    }
1189b1994897Sopenharmony_ci
1190b1994897Sopenharmony_ci    UserList<User> GetUsers()
1191b1994897Sopenharmony_ci    {
1192b1994897Sopenharmony_ci        return UserList<User>(&first_user_);
1193b1994897Sopenharmony_ci    }
1194b1994897Sopenharmony_ci    UserList<const User> GetUsers() const
1195b1994897Sopenharmony_ci    {
1196b1994897Sopenharmony_ci        return UserList<const User>(&first_user_);
1197b1994897Sopenharmony_ci    }
1198b1994897Sopenharmony_ci
1199b1994897Sopenharmony_ci    size_t GetInputsCount() const
1200b1994897Sopenharmony_ci    {
1201b1994897Sopenharmony_ci        if (UNLIKELY(IsOperandsDynamic())) {
1202b1994897Sopenharmony_ci            return GetDynamicOperands()->Size();
1203b1994897Sopenharmony_ci        }
1204b1994897Sopenharmony_ci        return GetInputs().Size();
1205b1994897Sopenharmony_ci    }
1206b1994897Sopenharmony_ci
1207b1994897Sopenharmony_ci    bool HasUsers() const
1208b1994897Sopenharmony_ci    {
1209b1994897Sopenharmony_ci        return first_user_ != nullptr;
1210b1994897Sopenharmony_ci    };
1211b1994897Sopenharmony_ci
1212b1994897Sopenharmony_ci    bool HasSingleUser() const
1213b1994897Sopenharmony_ci    {
1214b1994897Sopenharmony_ci        return first_user_ != nullptr && first_user_->GetNext() == nullptr;
1215b1994897Sopenharmony_ci    }
1216b1994897Sopenharmony_ci
1217b1994897Sopenharmony_ci    /// Reserve space in dataflow storage for specified inputs count
1218b1994897Sopenharmony_ci    void ReserveInputs(size_t capacity);
1219b1994897Sopenharmony_ci
1220b1994897Sopenharmony_ci    virtual void SetLocation([[maybe_unused]] size_t index, [[maybe_unused]] Location location) {}
1221b1994897Sopenharmony_ci
1222b1994897Sopenharmony_ci    virtual Location GetLocation([[maybe_unused]] size_t index) const
1223b1994897Sopenharmony_ci    {
1224b1994897Sopenharmony_ci        return Location::RequireRegister();
1225b1994897Sopenharmony_ci    }
1226b1994897Sopenharmony_ci
1227b1994897Sopenharmony_ci    virtual Location GetDstLocation() const
1228b1994897Sopenharmony_ci    {
1229b1994897Sopenharmony_ci        return Location::MakeRegister(GetDstReg(), GetType());
1230b1994897Sopenharmony_ci    }
1231b1994897Sopenharmony_ci
1232b1994897Sopenharmony_ci    template <typename Accessor>
1233b1994897Sopenharmony_ci    typename Accessor::ValueType GetField() const
1234b1994897Sopenharmony_ci    {
1235b1994897Sopenharmony_ci        return Accessor::Get(bit_fields_);
1236b1994897Sopenharmony_ci    }
1237b1994897Sopenharmony_ci
1238b1994897Sopenharmony_ci    template <typename Accessor>
1239b1994897Sopenharmony_ci    void SetField(typename Accessor::ValueType value)
1240b1994897Sopenharmony_ci    {
1241b1994897Sopenharmony_ci        Accessor::Set(value, &bit_fields_);
1242b1994897Sopenharmony_ci    }
1243b1994897Sopenharmony_ci
1244b1994897Sopenharmony_ci    uint64_t GetAllFields() const
1245b1994897Sopenharmony_ci    {
1246b1994897Sopenharmony_ci        return bit_fields_;
1247b1994897Sopenharmony_ci    }
1248b1994897Sopenharmony_ci
1249b1994897Sopenharmony_ci    bool IsPhi() const
1250b1994897Sopenharmony_ci    {
1251b1994897Sopenharmony_ci        return opcode_ == Opcode::Phi;
1252b1994897Sopenharmony_ci    }
1253b1994897Sopenharmony_ci
1254b1994897Sopenharmony_ci    bool IsCatchPhi() const
1255b1994897Sopenharmony_ci    {
1256b1994897Sopenharmony_ci        return opcode_ == Opcode::CatchPhi;
1257b1994897Sopenharmony_ci    }
1258b1994897Sopenharmony_ci
1259b1994897Sopenharmony_ci    bool IsConst() const
1260b1994897Sopenharmony_ci    {
1261b1994897Sopenharmony_ci        return opcode_ == Opcode::Constant;
1262b1994897Sopenharmony_ci    }
1263b1994897Sopenharmony_ci
1264b1994897Sopenharmony_ci    bool IsParameter() const
1265b1994897Sopenharmony_ci    {
1266b1994897Sopenharmony_ci        return opcode_ == Opcode::Parameter;
1267b1994897Sopenharmony_ci    }
1268b1994897Sopenharmony_ci
1269b1994897Sopenharmony_ci    virtual bool IsBoolConst() const
1270b1994897Sopenharmony_ci    {
1271b1994897Sopenharmony_ci        return false;
1272b1994897Sopenharmony_ci    }
1273b1994897Sopenharmony_ci
1274b1994897Sopenharmony_ci    bool IsSaveState() const
1275b1994897Sopenharmony_ci    {
1276b1994897Sopenharmony_ci        return opcode_ == Opcode::SaveState;
1277b1994897Sopenharmony_ci    }
1278b1994897Sopenharmony_ci
1279b1994897Sopenharmony_ci    bool IsTry() const
1280b1994897Sopenharmony_ci    {
1281b1994897Sopenharmony_ci        return opcode_ == Opcode::Try;
1282b1994897Sopenharmony_ci    }
1283b1994897Sopenharmony_ci
1284b1994897Sopenharmony_ci    virtual void SetVnObject([[maybe_unused]] VnObject *vn_obj) {}
1285b1994897Sopenharmony_ci
1286b1994897Sopenharmony_ci    Register GetDstReg() const
1287b1994897Sopenharmony_ci    {
1288b1994897Sopenharmony_ci        return dst_reg_;
1289b1994897Sopenharmony_ci    }
1290b1994897Sopenharmony_ci
1291b1994897Sopenharmony_ci    void SetDstReg(Register reg)
1292b1994897Sopenharmony_ci    {
1293b1994897Sopenharmony_ci        dst_reg_ = reg;
1294b1994897Sopenharmony_ci    }
1295b1994897Sopenharmony_ci
1296b1994897Sopenharmony_ci    uint32_t GetVN() const
1297b1994897Sopenharmony_ci    {
1298b1994897Sopenharmony_ci        return vn_;
1299b1994897Sopenharmony_ci    }
1300b1994897Sopenharmony_ci
1301b1994897Sopenharmony_ci    void SetVN(uint32_t vn)
1302b1994897Sopenharmony_ci    {
1303b1994897Sopenharmony_ci        vn_ = vn;
1304b1994897Sopenharmony_ci    }
1305b1994897Sopenharmony_ci    void Dump(std::ostream *out, bool new_line = true) const;
1306b1994897Sopenharmony_ci    virtual bool DumpInputs(std::ostream *out) const;
1307b1994897Sopenharmony_ci    virtual void DumpOpcode(std::ostream *out) const;
1308b1994897Sopenharmony_ci
1309b1994897Sopenharmony_ci    virtual void SetDstReg([[maybe_unused]] unsigned index, Register reg)
1310b1994897Sopenharmony_ci    {
1311b1994897Sopenharmony_ci        ASSERT(index == 0);
1312b1994897Sopenharmony_ci        SetDstReg(reg);
1313b1994897Sopenharmony_ci    }
1314b1994897Sopenharmony_ci
1315b1994897Sopenharmony_ci    virtual Register GetDstReg([[maybe_unused]] unsigned index) const
1316b1994897Sopenharmony_ci    {
1317b1994897Sopenharmony_ci        ASSERT(index == 0);
1318b1994897Sopenharmony_ci        return GetDstReg();
1319b1994897Sopenharmony_ci    }
1320b1994897Sopenharmony_ci
1321b1994897Sopenharmony_ci    virtual size_t GetDstCount() const
1322b1994897Sopenharmony_ci    {
1323b1994897Sopenharmony_ci        return 1;
1324b1994897Sopenharmony_ci    }
1325b1994897Sopenharmony_ci
1326b1994897Sopenharmony_ci    virtual uint32_t GetSrcRegIndex() const
1327b1994897Sopenharmony_ci    {
1328b1994897Sopenharmony_ci        return 0;
1329b1994897Sopenharmony_ci    }
1330b1994897Sopenharmony_ci
1331b1994897Sopenharmony_ci    virtual void SetSrcReg([[maybe_unused]] unsigned index, [[maybe_unused]] Register reg) {}
1332b1994897Sopenharmony_ci
1333b1994897Sopenharmony_ci    virtual Register GetSrcReg([[maybe_unused]] unsigned index) const
1334b1994897Sopenharmony_ci    {
1335b1994897Sopenharmony_ci        return INVALID_REG;
1336b1994897Sopenharmony_ci    }
1337b1994897Sopenharmony_ci
1338b1994897Sopenharmony_ci    User *GetFirstUser() const
1339b1994897Sopenharmony_ci    {
1340b1994897Sopenharmony_ci        return first_user_;
1341b1994897Sopenharmony_ci    }
1342b1994897Sopenharmony_ci
1343b1994897Sopenharmony_ciprotected:
1344b1994897Sopenharmony_ci    using InstBase::InstBase;
1345b1994897Sopenharmony_ci    static constexpr int INPUT_COUNT = 0;
1346b1994897Sopenharmony_ci
1347b1994897Sopenharmony_ci    Inst() = default;
1348b1994897Sopenharmony_ci
1349b1994897Sopenharmony_ci    explicit Inst(Opcode opcode) : Inst(opcode, DataType::Type::NO_TYPE, INVALID_PC) {}
1350b1994897Sopenharmony_ci
1351b1994897Sopenharmony_ci    explicit Inst(Opcode opcode, DataType::Type type, uint32_t pc) : pc_(pc), opcode_(opcode)
1352b1994897Sopenharmony_ci    {
1353b1994897Sopenharmony_ci        bit_fields_ = inst_flags::GetFlagsMask(opcode);
1354b1994897Sopenharmony_ci        SetField<FieldType>(type);
1355b1994897Sopenharmony_ci    }
1356b1994897Sopenharmony_ci
1357b1994897Sopenharmony_ciprotected:
1358b1994897Sopenharmony_ci    using FieldFlags = BitField<uint32_t, 0, MinimumBitsToStore(1U << inst_flags::FLAGS_COUNT)>;
1359b1994897Sopenharmony_ci    using FieldType = FieldFlags::NextField<DataType::Type, MinimumBitsToStore(DataType::LAST)>;
1360b1994897Sopenharmony_ci    using InputsCount = FieldType::NextField<uint32_t, BITS_PER_INPUTS_NUM>;
1361b1994897Sopenharmony_ci    using LastField = InputsCount;
1362b1994897Sopenharmony_ci
1363b1994897Sopenharmony_ci    DynamicOperands *GetDynamicOperands() const
1364b1994897Sopenharmony_ci    {
1365b1994897Sopenharmony_ci        return reinterpret_cast<DynamicOperands *>(reinterpret_cast<uintptr_t>(this) - sizeof(DynamicOperands));
1366b1994897Sopenharmony_ci    }
1367b1994897Sopenharmony_ci
1368b1994897Sopenharmony_ciprivate:
1369b1994897Sopenharmony_ci    User *GetUser(unsigned index)
1370b1994897Sopenharmony_ci    {
1371b1994897Sopenharmony_ci        if (UNLIKELY(IsOperandsDynamic())) {
1372b1994897Sopenharmony_ci            return GetDynamicOperands()->GetUser(index);
1373b1994897Sopenharmony_ci        }
1374b1994897Sopenharmony_ci        auto inputs_count {GetField<InputsCount>()};
1375b1994897Sopenharmony_ci        // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1376b1994897Sopenharmony_ci        return reinterpret_cast<User *>(reinterpret_cast<Input *>(this) -
1377b1994897Sopenharmony_ci                                        // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1378b1994897Sopenharmony_ci                                        (inputs_count + Input::GetPadding(RUNTIME_ARCH, inputs_count))) -
1379b1994897Sopenharmony_ci               // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1380b1994897Sopenharmony_ci               index - 1;
1381b1994897Sopenharmony_ci    }
1382b1994897Sopenharmony_ci
1383b1994897Sopenharmony_ci    size_t OperandsStorageSize() const
1384b1994897Sopenharmony_ci    {
1385b1994897Sopenharmony_ci        if (UNLIKELY(IsOperandsDynamic())) {
1386b1994897Sopenharmony_ci            return sizeof(DynamicOperands);
1387b1994897Sopenharmony_ci        }
1388b1994897Sopenharmony_ci
1389b1994897Sopenharmony_ci        auto inputs_count {GetField<InputsCount>()};
1390b1994897Sopenharmony_ci        return inputs_count * (sizeof(Input) + sizeof(User)) +
1391b1994897Sopenharmony_ci               Input::GetPadding(RUNTIME_ARCH, inputs_count) * sizeof(Input);
1392b1994897Sopenharmony_ci    }
1393b1994897Sopenharmony_ci
1394b1994897Sopenharmony_ciprivate:
1395b1994897Sopenharmony_ci    /// Basic block this instruction belongs to
1396b1994897Sopenharmony_ci    BasicBlock *bb_ {nullptr};
1397b1994897Sopenharmony_ci
1398b1994897Sopenharmony_ci    /// Next instruction within basic block
1399b1994897Sopenharmony_ci    Inst *next_ {nullptr};
1400b1994897Sopenharmony_ci
1401b1994897Sopenharmony_ci    /// Previous instruction within basic block
1402b1994897Sopenharmony_ci    Inst *prev_ {nullptr};
1403b1994897Sopenharmony_ci
1404b1994897Sopenharmony_ci    /// First user in users chain
1405b1994897Sopenharmony_ci    User *first_user_ {nullptr};
1406b1994897Sopenharmony_ci
1407b1994897Sopenharmony_ci    /// This value hold properties of the instruction. It accessed via BitField types(f.e. FieldType).
1408b1994897Sopenharmony_ci    uint64_t bit_fields_ {0};
1409b1994897Sopenharmony_ci
1410b1994897Sopenharmony_ci    /// Unique id of instruction
1411b1994897Sopenharmony_ci    uint32_t id_ {INVALID_ID};
1412b1994897Sopenharmony_ci
1413b1994897Sopenharmony_ci    /// Unique id of instruction
1414b1994897Sopenharmony_ci    uint32_t vn_ {INVALID_VN};
1415b1994897Sopenharmony_ci
1416b1994897Sopenharmony_ci    /// Bytecode pc
1417b1994897Sopenharmony_ci    uint32_t pc_ {INVALID_PC};
1418b1994897Sopenharmony_ci
1419b1994897Sopenharmony_ci    /// Number used in cloning
1420b1994897Sopenharmony_ci    uint32_t clone_number_ {0};
1421b1994897Sopenharmony_ci
1422b1994897Sopenharmony_ci    /// Instruction number getting while visiting graph
1423b1994897Sopenharmony_ci    LinearNumber linear_number_ {INVALID_LINEAR_NUM};
1424b1994897Sopenharmony_ci
1425b1994897Sopenharmony_ci    ObjectTypeInfo object_type_info_ {};
1426b1994897Sopenharmony_ci
1427b1994897Sopenharmony_ci    /// Opcode, see opcodes.def
1428b1994897Sopenharmony_ci    Opcode opcode_ {Opcode::INVALID};
1429b1994897Sopenharmony_ci
1430b1994897Sopenharmony_ci    // Destination register type - defined in FieldType
1431b1994897Sopenharmony_ci    Register dst_reg_ {INVALID_REG};
1432b1994897Sopenharmony_ci};
1433b1994897Sopenharmony_ci
1434b1994897Sopenharmony_ci/**
1435b1994897Sopenharmony_ci * Proxy class that injects new field - type of the source operands - into property field of the instruction.
1436b1994897Sopenharmony_ci * Should be used when instruction has sources of the same type and type of the instruction is not match to type of
1437b1994897Sopenharmony_ci * sources. Examples: Cmp, Compare
1438b1994897Sopenharmony_ci * @tparam T Base instruction class after which this mixin is injected
1439b1994897Sopenharmony_ci */
1440b1994897Sopenharmony_citemplate <typename T>
1441b1994897Sopenharmony_ciclass InstWithOperandsType : public T {
1442b1994897Sopenharmony_cipublic:
1443b1994897Sopenharmony_ci    using T::T;
1444b1994897Sopenharmony_ci
1445b1994897Sopenharmony_ci    void SetOperandsType(DataType::Type type)
1446b1994897Sopenharmony_ci    {
1447b1994897Sopenharmony_ci        T::template SetField<FieldOperandsType>(type);
1448b1994897Sopenharmony_ci    }
1449b1994897Sopenharmony_ci    virtual DataType::Type GetOperandsType() const
1450b1994897Sopenharmony_ci    {
1451b1994897Sopenharmony_ci        return T::template GetField<FieldOperandsType>();
1452b1994897Sopenharmony_ci    }
1453b1994897Sopenharmony_ci
1454b1994897Sopenharmony_ciprotected:
1455b1994897Sopenharmony_ci    using FieldOperandsType =
1456b1994897Sopenharmony_ci        typename T::LastField::template NextField<DataType::Type, MinimumBitsToStore(DataType::LAST)>;
1457b1994897Sopenharmony_ci    using LastField = FieldOperandsType;
1458b1994897Sopenharmony_ci};
1459b1994897Sopenharmony_ci
1460b1994897Sopenharmony_ci/**
1461b1994897Sopenharmony_ci * Mixin for NeedBarrier flag.
1462b1994897Sopenharmony_ci * @tparam T Base instruction class after which this mixin is injected
1463b1994897Sopenharmony_ci */
1464b1994897Sopenharmony_citemplate <typename T>
1465b1994897Sopenharmony_ciclass NeedBarrierMixin : public T {
1466b1994897Sopenharmony_cipublic:
1467b1994897Sopenharmony_ci    using T::T;
1468b1994897Sopenharmony_ci
1469b1994897Sopenharmony_ci    void SetNeedBarrier(bool v)
1470b1994897Sopenharmony_ci    {
1471b1994897Sopenharmony_ci        T::template SetField<NeedBarrierFlag>(v);
1472b1994897Sopenharmony_ci    }
1473b1994897Sopenharmony_ci    bool GetNeedBarrier() const
1474b1994897Sopenharmony_ci    {
1475b1994897Sopenharmony_ci        return T::template GetField<NeedBarrierFlag>();
1476b1994897Sopenharmony_ci    }
1477b1994897Sopenharmony_ci
1478b1994897Sopenharmony_ciprotected:
1479b1994897Sopenharmony_ci    using NeedBarrierFlag = typename T::LastField::NextFlag;
1480b1994897Sopenharmony_ci    using LastField = NeedBarrierFlag;
1481b1994897Sopenharmony_ci};
1482b1994897Sopenharmony_ci
1483b1994897Sopenharmony_ci/**
1484b1994897Sopenharmony_ci * This mixin aims to implement type id accessors.
1485b1994897Sopenharmony_ci */
1486b1994897Sopenharmony_ciclass TypeIdMixin {
1487b1994897Sopenharmony_cipublic:
1488b1994897Sopenharmony_ci    TypeIdMixin() = default;
1489b1994897Sopenharmony_ci    NO_COPY_SEMANTIC(TypeIdMixin);
1490b1994897Sopenharmony_ci    NO_MOVE_SEMANTIC(TypeIdMixin);
1491b1994897Sopenharmony_ci    virtual ~TypeIdMixin() = default;
1492b1994897Sopenharmony_ci
1493b1994897Sopenharmony_ci    void SetTypeId(uint32_t id)
1494b1994897Sopenharmony_ci    {
1495b1994897Sopenharmony_ci        type_id_ = id;
1496b1994897Sopenharmony_ci    }
1497b1994897Sopenharmony_ci
1498b1994897Sopenharmony_ci    auto GetTypeId() const
1499b1994897Sopenharmony_ci    {
1500b1994897Sopenharmony_ci        return type_id_;
1501b1994897Sopenharmony_ci    }
1502b1994897Sopenharmony_ci
1503b1994897Sopenharmony_ci    void SetMethod(RuntimeInterface::MethodPtr method)
1504b1994897Sopenharmony_ci    {
1505b1994897Sopenharmony_ci        method_ = method;
1506b1994897Sopenharmony_ci    }
1507b1994897Sopenharmony_ci    auto GetMethod() const
1508b1994897Sopenharmony_ci    {
1509b1994897Sopenharmony_ci        return method_;
1510b1994897Sopenharmony_ci    }
1511b1994897Sopenharmony_ci
1512b1994897Sopenharmony_ciprivate:
1513b1994897Sopenharmony_ci    uint32_t type_id_ {0};
1514b1994897Sopenharmony_ci    // The pointer to the method in which this instruction is executed(inlined method)
1515b1994897Sopenharmony_ci    RuntimeInterface::MethodPtr method_ {nullptr};
1516b1994897Sopenharmony_ci};
1517b1994897Sopenharmony_ci
1518b1994897Sopenharmony_ci/**
1519b1994897Sopenharmony_ci * Mixin for Inlined calls/returns.
1520b1994897Sopenharmony_ci */
1521b1994897Sopenharmony_citemplate <typename T>
1522b1994897Sopenharmony_ciclass InlinedInstMixin : public T {
1523b1994897Sopenharmony_cipublic:
1524b1994897Sopenharmony_ci    using T::T;
1525b1994897Sopenharmony_ci
1526b1994897Sopenharmony_ci    void SetInlined(bool v)
1527b1994897Sopenharmony_ci    {
1528b1994897Sopenharmony_ci        T::template SetField<IsInlinedFlag>(v);
1529b1994897Sopenharmony_ci    }
1530b1994897Sopenharmony_ci    bool IsInlined() const
1531b1994897Sopenharmony_ci    {
1532b1994897Sopenharmony_ci        return T::template GetField<IsInlinedFlag>();
1533b1994897Sopenharmony_ci    }
1534b1994897Sopenharmony_ci
1535b1994897Sopenharmony_ciprotected:
1536b1994897Sopenharmony_ci    using IsInlinedFlag = typename T::LastField::NextFlag;
1537b1994897Sopenharmony_ci    using LastField = IsInlinedFlag;
1538b1994897Sopenharmony_ci};
1539b1994897Sopenharmony_ci
1540b1994897Sopenharmony_ci/**
1541b1994897Sopenharmony_ci * Mixin for instructions with immediate constant value
1542b1994897Sopenharmony_ci */
1543b1994897Sopenharmony_ciclass ImmediateMixin {
1544b1994897Sopenharmony_cipublic:
1545b1994897Sopenharmony_ci    explicit ImmediateMixin(uint64_t immediate) : immediate_(immediate) {}
1546b1994897Sopenharmony_ci
1547b1994897Sopenharmony_ci    NO_COPY_SEMANTIC(ImmediateMixin);
1548b1994897Sopenharmony_ci    NO_MOVE_SEMANTIC(ImmediateMixin);
1549b1994897Sopenharmony_ci    virtual ~ImmediateMixin() = default;
1550b1994897Sopenharmony_ci
1551b1994897Sopenharmony_ci    void SetImm(uint64_t immediate)
1552b1994897Sopenharmony_ci    {
1553b1994897Sopenharmony_ci        immediate_ = immediate;
1554b1994897Sopenharmony_ci    }
1555b1994897Sopenharmony_ci    auto GetImm() const
1556b1994897Sopenharmony_ci    {
1557b1994897Sopenharmony_ci        return immediate_;
1558b1994897Sopenharmony_ci    }
1559b1994897Sopenharmony_ci
1560b1994897Sopenharmony_ciprotected:
1561b1994897Sopenharmony_ci    ImmediateMixin() = default;
1562b1994897Sopenharmony_ci
1563b1994897Sopenharmony_ciprivate:
1564b1994897Sopenharmony_ci    uint64_t immediate_ {0};
1565b1994897Sopenharmony_ci};
1566b1994897Sopenharmony_ci
1567b1994897Sopenharmony_ci/**
1568b1994897Sopenharmony_ci * Mixin for instructions with ConditionCode
1569b1994897Sopenharmony_ci */
1570b1994897Sopenharmony_citemplate <typename T>
1571b1994897Sopenharmony_ciclass ConditionMixin : public T {
1572b1994897Sopenharmony_cipublic:
1573b1994897Sopenharmony_ci    enum class Prediction { NONE, LIKELY, UNLIKELY, SIZE = UNLIKELY };
1574b1994897Sopenharmony_ci
1575b1994897Sopenharmony_ci    using T::T;
1576b1994897Sopenharmony_ci    explicit ConditionMixin(ConditionCode cc)
1577b1994897Sopenharmony_ci    {
1578b1994897Sopenharmony_ci        T::template SetField<CcFlag>(cc);
1579b1994897Sopenharmony_ci    }
1580b1994897Sopenharmony_ci    NO_COPY_SEMANTIC(ConditionMixin);
1581b1994897Sopenharmony_ci    NO_MOVE_SEMANTIC(ConditionMixin);
1582b1994897Sopenharmony_ci    ~ConditionMixin() override = default;
1583b1994897Sopenharmony_ci
1584b1994897Sopenharmony_ci    auto GetCc() const
1585b1994897Sopenharmony_ci    {
1586b1994897Sopenharmony_ci        return T::template GetField<CcFlag>();
1587b1994897Sopenharmony_ci    }
1588b1994897Sopenharmony_ci    void SetCc(ConditionCode cc)
1589b1994897Sopenharmony_ci    {
1590b1994897Sopenharmony_ci        T::template SetField<CcFlag>(cc);
1591b1994897Sopenharmony_ci    }
1592b1994897Sopenharmony_ci    void InverseConditionCode()
1593b1994897Sopenharmony_ci    {
1594b1994897Sopenharmony_ci        SetCc(GetInverseConditionCode(GetCc()));
1595b1994897Sopenharmony_ci        if (IsLikely()) {
1596b1994897Sopenharmony_ci            SetUnlikely();
1597b1994897Sopenharmony_ci        } else if (IsUnlikely()) {
1598b1994897Sopenharmony_ci            SetLikely();
1599b1994897Sopenharmony_ci        }
1600b1994897Sopenharmony_ci    }
1601b1994897Sopenharmony_ci
1602b1994897Sopenharmony_ci    bool IsLikely() const
1603b1994897Sopenharmony_ci    {
1604b1994897Sopenharmony_ci        return T::template GetField<PredictionFlag>() == Prediction::LIKELY;
1605b1994897Sopenharmony_ci    }
1606b1994897Sopenharmony_ci    bool IsUnlikely() const
1607b1994897Sopenharmony_ci    {
1608b1994897Sopenharmony_ci        return T::template GetField<PredictionFlag>() == Prediction::UNLIKELY;
1609b1994897Sopenharmony_ci    }
1610b1994897Sopenharmony_ci    void SetLikely()
1611b1994897Sopenharmony_ci    {
1612b1994897Sopenharmony_ci        T::template SetField<PredictionFlag>(Prediction::LIKELY);
1613b1994897Sopenharmony_ci    }
1614b1994897Sopenharmony_ci    void SetUnlikely()
1615b1994897Sopenharmony_ci    {
1616b1994897Sopenharmony_ci        T::template SetField<PredictionFlag>(Prediction::UNLIKELY);
1617b1994897Sopenharmony_ci    }
1618b1994897Sopenharmony_ci
1619b1994897Sopenharmony_ciprotected:
1620b1994897Sopenharmony_ci    ConditionMixin() = default;
1621b1994897Sopenharmony_ci
1622b1994897Sopenharmony_ci    using CcFlag = typename T::LastField::template NextField<ConditionCode, MinimumBitsToStore(ConditionCode::CC_LAST)>;
1623b1994897Sopenharmony_ci    using PredictionFlag = typename CcFlag::template NextField<Prediction, MinimumBitsToStore(Prediction::SIZE)>;
1624b1994897Sopenharmony_ci    using LastField = PredictionFlag;
1625b1994897Sopenharmony_ci};
1626b1994897Sopenharmony_ci
1627b1994897Sopenharmony_ci/**
1628b1994897Sopenharmony_ci * Instruction with fixed number of inputs.
1629b1994897Sopenharmony_ci * Shall not be instantiated directly, only through derived classes.
1630b1994897Sopenharmony_ci */
1631b1994897Sopenharmony_citemplate <size_t N>
1632b1994897Sopenharmony_ciclass FixedInputsInst : public Inst {
1633b1994897Sopenharmony_cipublic:
1634b1994897Sopenharmony_ci    using Inst::Inst;
1635b1994897Sopenharmony_ci
1636b1994897Sopenharmony_ci    static constexpr int INPUT_COUNT = N;
1637b1994897Sopenharmony_ci
1638b1994897Sopenharmony_ci    void SetSrcReg(unsigned index, Register reg) override
1639b1994897Sopenharmony_ci    {
1640b1994897Sopenharmony_ci        ASSERT(index < N);
1641b1994897Sopenharmony_ci        src_regs_[index] = reg;
1642b1994897Sopenharmony_ci    }
1643b1994897Sopenharmony_ci
1644b1994897Sopenharmony_ci    Register GetSrcReg(unsigned index) const override
1645b1994897Sopenharmony_ci    {
1646b1994897Sopenharmony_ci        ASSERT(index < N);
1647b1994897Sopenharmony_ci        return src_regs_[index];
1648b1994897Sopenharmony_ci    }
1649b1994897Sopenharmony_ci
1650b1994897Sopenharmony_ci    Location GetLocation(size_t index) const override
1651b1994897Sopenharmony_ci    {
1652b1994897Sopenharmony_ci        return Location::MakeRegister(GetSrcReg(index), GetInputType(index));
1653b1994897Sopenharmony_ci    }
1654b1994897Sopenharmony_ci
1655b1994897Sopenharmony_ci    void SetLocation(size_t index, Location location) override
1656b1994897Sopenharmony_ci    {
1657b1994897Sopenharmony_ci        SetSrcReg(index, location.GetValue());
1658b1994897Sopenharmony_ci    }
1659b1994897Sopenharmony_ci
1660b1994897Sopenharmony_ci    void SetDstLocation(Location location)
1661b1994897Sopenharmony_ci    {
1662b1994897Sopenharmony_ci        SetDstReg(location.GetValue());
1663b1994897Sopenharmony_ci    }
1664b1994897Sopenharmony_ci
1665b1994897Sopenharmony_ci    Inst *Clone(const Graph *targetGraph) const override;
1666b1994897Sopenharmony_ci
1667b1994897Sopenharmony_ciprivate:
1668b1994897Sopenharmony_ci    template <typename T, std::size_t... Is>
1669b1994897Sopenharmony_ci    constexpr auto CreateArray(T value, [[maybe_unused]] std::index_sequence<Is...> unused)
1670b1994897Sopenharmony_ci    {
1671b1994897Sopenharmony_ci        return std::array<T, sizeof...(Is)> {(static_cast<void>(Is), value)...};
1672b1994897Sopenharmony_ci    }
1673b1994897Sopenharmony_ci
1674b1994897Sopenharmony_ci    std::array<Register, N> src_regs_ = CreateArray(INVALID_REG, std::make_index_sequence<INPUT_COUNT>());
1675b1994897Sopenharmony_ci};
1676b1994897Sopenharmony_ci
1677b1994897Sopenharmony_citemplate <size_t N>
1678b1994897Sopenharmony_ciInst *FixedInputsInst<N>::Clone(const Graph *targetGraph) const
1679b1994897Sopenharmony_ci{
1680b1994897Sopenharmony_ci    auto clone = static_cast<FixedInputsInst *>(Inst::Clone(targetGraph));
1681b1994897Sopenharmony_ci#ifndef NDEBUG
1682b1994897Sopenharmony_ci    for (size_t i = 0; i < INPUT_COUNT; ++i) {
1683b1994897Sopenharmony_ci        clone->SetSrcReg(i, GetSrcReg(i));
1684b1994897Sopenharmony_ci    }
1685b1994897Sopenharmony_ci#endif
1686b1994897Sopenharmony_ci    return clone;
1687b1994897Sopenharmony_ci}
1688b1994897Sopenharmony_ci
1689b1994897Sopenharmony_ci/**
1690b1994897Sopenharmony_ci * Instructions with fixed static inputs
1691b1994897Sopenharmony_ci * We need to explicitly declare these proxy classes because some code can't work with the templated inst classes, for
1692b1994897Sopenharmony_ci * example DEFINE_INST macro.
1693b1994897Sopenharmony_ci */
1694b1994897Sopenharmony_ciclass FixedInputsInst0 : public FixedInputsInst<0> {
1695b1994897Sopenharmony_cipublic:
1696b1994897Sopenharmony_ci    using FixedInputsInst::FixedInputsInst;
1697b1994897Sopenharmony_ci
1698b1994897Sopenharmony_ci    NO_COPY_SEMANTIC(FixedInputsInst0);
1699b1994897Sopenharmony_ci    NO_MOVE_SEMANTIC(FixedInputsInst0);
1700b1994897Sopenharmony_ci    ~FixedInputsInst0() override = default;
1701b1994897Sopenharmony_ci};
1702b1994897Sopenharmony_ci
1703b1994897Sopenharmony_ciclass FixedInputsInst1 : public FixedInputsInst<1> {
1704b1994897Sopenharmony_cipublic:
1705b1994897Sopenharmony_ci    using FixedInputsInst::FixedInputsInst;
1706b1994897Sopenharmony_ci
1707b1994897Sopenharmony_ci    NO_COPY_SEMANTIC(FixedInputsInst1);
1708b1994897Sopenharmony_ci    NO_MOVE_SEMANTIC(FixedInputsInst1);
1709b1994897Sopenharmony_ci    ~FixedInputsInst1() override = default;
1710b1994897Sopenharmony_ci};
1711b1994897Sopenharmony_ci
1712b1994897Sopenharmony_ciclass FixedInputsInst2 : public FixedInputsInst<2U> {
1713b1994897Sopenharmony_cipublic:
1714b1994897Sopenharmony_ci    using FixedInputsInst::FixedInputsInst;
1715b1994897Sopenharmony_ci
1716b1994897Sopenharmony_ci    NO_COPY_SEMANTIC(FixedInputsInst2);
1717b1994897Sopenharmony_ci    NO_MOVE_SEMANTIC(FixedInputsInst2);
1718b1994897Sopenharmony_ci    ~FixedInputsInst2() override = default;
1719b1994897Sopenharmony_ci};
1720b1994897Sopenharmony_ci
1721b1994897Sopenharmony_ci/**
1722b1994897Sopenharmony_ci * Instruction with variable inputs count
1723b1994897Sopenharmony_ci */
1724b1994897Sopenharmony_ciclass DynamicInputsInst : public Inst {
1725b1994897Sopenharmony_cipublic:
1726b1994897Sopenharmony_ci    using Inst::Inst;
1727b1994897Sopenharmony_ci
1728b1994897Sopenharmony_ci    static constexpr int INPUT_COUNT = MAX_STATIC_INPUTS;
1729b1994897Sopenharmony_ci
1730b1994897Sopenharmony_ci    Location GetLocation(size_t index) const override
1731b1994897Sopenharmony_ci    {
1732b1994897Sopenharmony_ci        if (locations_ == nullptr) {
1733b1994897Sopenharmony_ci            return Location::Invalid();
1734b1994897Sopenharmony_ci        }
1735b1994897Sopenharmony_ci        return locations_->GetLocation(index);
1736b1994897Sopenharmony_ci    }
1737b1994897Sopenharmony_ci
1738b1994897Sopenharmony_ci    Location GetDstLocation() const override
1739b1994897Sopenharmony_ci    {
1740b1994897Sopenharmony_ci        if (locations_ == nullptr) {
1741b1994897Sopenharmony_ci            return Location::Invalid();
1742b1994897Sopenharmony_ci        }
1743b1994897Sopenharmony_ci        return locations_->GetDstLocation();
1744b1994897Sopenharmony_ci    }
1745b1994897Sopenharmony_ci
1746b1994897Sopenharmony_ci    void SetLocation(size_t index, Location location) override
1747b1994897Sopenharmony_ci    {
1748b1994897Sopenharmony_ci        ASSERT(locations_ != nullptr);
1749b1994897Sopenharmony_ci        locations_->SetLocation(index, location);
1750b1994897Sopenharmony_ci    }
1751b1994897Sopenharmony_ci
1752b1994897Sopenharmony_ci    void SetDstLocation(Location location)
1753b1994897Sopenharmony_ci    {
1754b1994897Sopenharmony_ci        ASSERT(locations_ != nullptr);
1755b1994897Sopenharmony_ci        locations_->SetDstLocation(location);
1756b1994897Sopenharmony_ci    }
1757b1994897Sopenharmony_ci
1758b1994897Sopenharmony_ci    void SetLocationsInfo(LocationsInfo *info)
1759b1994897Sopenharmony_ci    {
1760b1994897Sopenharmony_ci        locations_ = info;
1761b1994897Sopenharmony_ci    }
1762b1994897Sopenharmony_ci
1763b1994897Sopenharmony_ci    Register GetSrcReg(unsigned index) const override
1764b1994897Sopenharmony_ci    {
1765b1994897Sopenharmony_ci        return GetLocation(index).GetValue();
1766b1994897Sopenharmony_ci    }
1767b1994897Sopenharmony_ci
1768b1994897Sopenharmony_ci    void SetSrcReg(unsigned index, Register reg) override
1769b1994897Sopenharmony_ci    {
1770b1994897Sopenharmony_ci        SetLocation(index, Location::MakeRegister(reg, GetInputType(index)));
1771b1994897Sopenharmony_ci    }
1772b1994897Sopenharmony_ci
1773b1994897Sopenharmony_ciprivate:
1774b1994897Sopenharmony_ci    LocationsInfo *locations_ {nullptr};
1775b1994897Sopenharmony_ci};
1776b1994897Sopenharmony_ci
1777b1994897Sopenharmony_ciclass SpillFillInst;
1778b1994897Sopenharmony_ci
1779b1994897Sopenharmony_ci/**
1780b1994897Sopenharmony_ci * Mixin to hold location data
1781b1994897Sopenharmony_ci */
1782b1994897Sopenharmony_ciclass LocationDataMixin {
1783b1994897Sopenharmony_cipublic:
1784b1994897Sopenharmony_ci    void SetLocationData(SpillFillData location_data)
1785b1994897Sopenharmony_ci    {
1786b1994897Sopenharmony_ci        location_data_ = location_data;
1787b1994897Sopenharmony_ci    }
1788b1994897Sopenharmony_ci
1789b1994897Sopenharmony_ci    auto GetLocationData() const
1790b1994897Sopenharmony_ci    {
1791b1994897Sopenharmony_ci        return location_data_;
1792b1994897Sopenharmony_ci    }
1793b1994897Sopenharmony_ci
1794b1994897Sopenharmony_ci    auto &GetLocationData()
1795b1994897Sopenharmony_ci    {
1796b1994897Sopenharmony_ci        return location_data_;
1797b1994897Sopenharmony_ci    }
1798b1994897Sopenharmony_ci
1799b1994897Sopenharmony_ciprotected:
1800b1994897Sopenharmony_ci    LocationDataMixin() = default;
1801b1994897Sopenharmony_ci    NO_COPY_SEMANTIC(LocationDataMixin);
1802b1994897Sopenharmony_ci    NO_MOVE_SEMANTIC(LocationDataMixin);
1803b1994897Sopenharmony_ci    virtual ~LocationDataMixin() = default;
1804b1994897Sopenharmony_ci
1805b1994897Sopenharmony_ciprivate:
1806b1994897Sopenharmony_ci    SpillFillData location_data_ {};
1807b1994897Sopenharmony_ci};
1808b1994897Sopenharmony_ci
1809b1994897Sopenharmony_ci/**
1810b1994897Sopenharmony_ci * Mixin to hold input types of call instruction
1811b1994897Sopenharmony_ci */
1812b1994897Sopenharmony_ciclass InputTypesMixin {
1813b1994897Sopenharmony_cipublic:
1814b1994897Sopenharmony_ci    InputTypesMixin() = default;
1815b1994897Sopenharmony_ci    NO_COPY_SEMANTIC(InputTypesMixin);
1816b1994897Sopenharmony_ci    NO_MOVE_SEMANTIC(InputTypesMixin);
1817b1994897Sopenharmony_ci    virtual ~InputTypesMixin() = default;
1818b1994897Sopenharmony_ci
1819b1994897Sopenharmony_ci    void AllocateInputTypes(ArenaAllocator *allocator, size_t capacity)
1820b1994897Sopenharmony_ci    {
1821b1994897Sopenharmony_ci        ASSERT(allocator != nullptr);
1822b1994897Sopenharmony_ci        ASSERT(input_types_ == nullptr);
1823b1994897Sopenharmony_ci        input_types_ = allocator->New<ArenaVector<DataType::Type>>(allocator->Adapter());
1824b1994897Sopenharmony_ci        ASSERT(input_types_ != nullptr);
1825b1994897Sopenharmony_ci        input_types_->reserve(capacity);
1826b1994897Sopenharmony_ci        ASSERT(input_types_->capacity() >= capacity);
1827b1994897Sopenharmony_ci    }
1828b1994897Sopenharmony_ci    void AddInputType(DataType::Type type)
1829b1994897Sopenharmony_ci    {
1830b1994897Sopenharmony_ci        ASSERT(input_types_ != nullptr);
1831b1994897Sopenharmony_ci        input_types_->push_back(type);
1832b1994897Sopenharmony_ci    }
1833b1994897Sopenharmony_ci    ArenaVector<DataType::Type> *GetInputTypes()
1834b1994897Sopenharmony_ci    {
1835b1994897Sopenharmony_ci        return input_types_;
1836b1994897Sopenharmony_ci    }
1837b1994897Sopenharmony_ci    void CloneTypes(ArenaAllocator *allocator, InputTypesMixin *target_inst) const
1838b1994897Sopenharmony_ci    {
1839b1994897Sopenharmony_ci        if (UNLIKELY(input_types_ == nullptr)) {
1840b1994897Sopenharmony_ci            return;
1841b1994897Sopenharmony_ci        }
1842b1994897Sopenharmony_ci        target_inst->AllocateInputTypes(allocator, input_types_->size());
1843b1994897Sopenharmony_ci        for (auto input_type : *input_types_) {
1844b1994897Sopenharmony_ci            target_inst->AddInputType(input_type);
1845b1994897Sopenharmony_ci        }
1846b1994897Sopenharmony_ci    }
1847b1994897Sopenharmony_ci
1848b1994897Sopenharmony_ciprotected:
1849b1994897Sopenharmony_ci    // NOLINTNEXTLINE(misc-non-private-member-variables-in-classes)
1850b1994897Sopenharmony_ci    ArenaVector<DataType::Type> *input_types_ {nullptr};
1851b1994897Sopenharmony_ci};
1852b1994897Sopenharmony_ci
1853b1994897Sopenharmony_ci/**
1854b1994897Sopenharmony_ci * Compare instruction
1855b1994897Sopenharmony_ci */
1856b1994897Sopenharmony_ci// NOLINTNEXTLINE(fuchsia-multiple-inheritance)
1857b1994897Sopenharmony_ciclass CompareInst : public InstWithOperandsType<ConditionMixin<FixedInputsInst2>> {
1858b1994897Sopenharmony_cipublic:
1859b1994897Sopenharmony_ci    using BaseInst = InstWithOperandsType<ConditionMixin<FixedInputsInst2>>;
1860b1994897Sopenharmony_ci    using BaseInst::BaseInst;
1861b1994897Sopenharmony_ci
1862b1994897Sopenharmony_ci    CompareInst(Opcode opcode, DataType::Type type, uint32_t pc, ConditionCode cc) : BaseInst(opcode, type, pc)
1863b1994897Sopenharmony_ci    {
1864b1994897Sopenharmony_ci        SetCc(cc);
1865b1994897Sopenharmony_ci    }
1866b1994897Sopenharmony_ci
1867b1994897Sopenharmony_ci    DataType::Type GetInputType([[maybe_unused]] size_t index) const override
1868b1994897Sopenharmony_ci    {
1869b1994897Sopenharmony_ci        ASSERT(index < GetInputsCount());
1870b1994897Sopenharmony_ci        return GetOperandsType();
1871b1994897Sopenharmony_ci    }
1872b1994897Sopenharmony_ci    void DumpOpcode(std::ostream *out) const override;
1873b1994897Sopenharmony_ci
1874b1994897Sopenharmony_ci    void SetVnObject(VnObject *vn_obj) override;
1875b1994897Sopenharmony_ci
1876b1994897Sopenharmony_ci    Inst *Clone(const Graph *targetGraph) const override;
1877b1994897Sopenharmony_ci};
1878b1994897Sopenharmony_ci
1879b1994897Sopenharmony_ci/**
1880b1994897Sopenharmony_ci * Mixin for AnyTypeMixin instructions
1881b1994897Sopenharmony_ci */
1882b1994897Sopenharmony_citemplate <typename T>
1883b1994897Sopenharmony_ciclass AnyTypeMixin : public T {
1884b1994897Sopenharmony_cipublic:
1885b1994897Sopenharmony_ci    using T::T;
1886b1994897Sopenharmony_ci
1887b1994897Sopenharmony_ci    void SetAnyType(AnyBaseType any_type)
1888b1994897Sopenharmony_ci    {
1889b1994897Sopenharmony_ci        T::template SetField<AnyBaseTypeField>(any_type);
1890b1994897Sopenharmony_ci    }
1891b1994897Sopenharmony_ci
1892b1994897Sopenharmony_ci    AnyBaseType GetAnyType() const
1893b1994897Sopenharmony_ci    {
1894b1994897Sopenharmony_ci        return T::template GetField<AnyBaseTypeField>();
1895b1994897Sopenharmony_ci    }
1896b1994897Sopenharmony_ci
1897b1994897Sopenharmony_ciprotected:
1898b1994897Sopenharmony_ci    using AnyBaseTypeField =
1899b1994897Sopenharmony_ci        typename T::LastField::template NextField<AnyBaseType, MinimumBitsToStore(AnyBaseType::COUNT)>;
1900b1994897Sopenharmony_ci    using LastField = AnyBaseTypeField;
1901b1994897Sopenharmony_ci};
1902b1994897Sopenharmony_ci
1903b1994897Sopenharmony_ci/**
1904b1994897Sopenharmony_ci * CompareAnyTypeInst instruction
1905b1994897Sopenharmony_ci */
1906b1994897Sopenharmony_ciclass CompareAnyTypeInst : public AnyTypeMixin<FixedInputsInst1> {
1907b1994897Sopenharmony_cipublic:
1908b1994897Sopenharmony_ci    using BaseInst = AnyTypeMixin<FixedInputsInst1>;
1909b1994897Sopenharmony_ci    using BaseInst::BaseInst;
1910b1994897Sopenharmony_ci
1911b1994897Sopenharmony_ci    CompareAnyTypeInst(Opcode opcode, uint32_t pc, AnyBaseType any_type) : BaseInst(opcode, DataType::Type::BOOL, pc)
1912b1994897Sopenharmony_ci    {
1913b1994897Sopenharmony_ci        SetAnyType(any_type);
1914b1994897Sopenharmony_ci    }
1915b1994897Sopenharmony_ci
1916b1994897Sopenharmony_ci    DataType::Type GetInputType(size_t index) const override
1917b1994897Sopenharmony_ci    {
1918b1994897Sopenharmony_ci        ASSERT(index < GetInputsCount());
1919b1994897Sopenharmony_ci        return GetInput(index).GetInst()->GetType();
1920b1994897Sopenharmony_ci    }
1921b1994897Sopenharmony_ci
1922b1994897Sopenharmony_ci    void DumpOpcode(std::ostream *out) const override;
1923b1994897Sopenharmony_ci
1924b1994897Sopenharmony_ci    Inst *Clone(const Graph *targetGraph) const override
1925b1994897Sopenharmony_ci    {
1926b1994897Sopenharmony_ci        auto clone = FixedInputsInst::Clone(targetGraph);
1927b1994897Sopenharmony_ci        clone->CastToCompareAnyType()->SetAnyType(GetAnyType());
1928b1994897Sopenharmony_ci        return clone;
1929b1994897Sopenharmony_ci    }
1930b1994897Sopenharmony_ci};
1931b1994897Sopenharmony_ci
1932b1994897Sopenharmony_ci/**
1933b1994897Sopenharmony_ci * CastAnyTypeValueInst instruction
1934b1994897Sopenharmony_ci */
1935b1994897Sopenharmony_ciclass CastAnyTypeValueInst : public AnyTypeMixin<FixedInputsInst1> {
1936b1994897Sopenharmony_cipublic:
1937b1994897Sopenharmony_ci    using BaseInst = AnyTypeMixin<FixedInputsInst1>;
1938b1994897Sopenharmony_ci    using BaseInst::BaseInst;
1939b1994897Sopenharmony_ci
1940b1994897Sopenharmony_ci    CastAnyTypeValueInst(Opcode opcode, uint32_t pc, AnyBaseType any_type)
1941b1994897Sopenharmony_ci        : BaseInst(opcode, AnyBaseTypeToDataType(any_type), pc)
1942b1994897Sopenharmony_ci    {
1943b1994897Sopenharmony_ci        SetAnyType(any_type);
1944b1994897Sopenharmony_ci    }
1945b1994897Sopenharmony_ci
1946b1994897Sopenharmony_ci    DataType::Type GetInputType(size_t index) const override
1947b1994897Sopenharmony_ci    {
1948b1994897Sopenharmony_ci        ASSERT(index < GetInputsCount());
1949b1994897Sopenharmony_ci        return GetInput(index).GetInst()->GetType();
1950b1994897Sopenharmony_ci    }
1951b1994897Sopenharmony_ci
1952b1994897Sopenharmony_ci    DataType::Type GetDeducedType() const
1953b1994897Sopenharmony_ci    {
1954b1994897Sopenharmony_ci        return AnyBaseTypeToDataType(GetAnyType());
1955b1994897Sopenharmony_ci    }
1956b1994897Sopenharmony_ci
1957b1994897Sopenharmony_ci    void DumpOpcode(std::ostream *out) const override;
1958b1994897Sopenharmony_ci
1959b1994897Sopenharmony_ci    Inst *Clone(const Graph *targetGraph) const override
1960b1994897Sopenharmony_ci    {
1961b1994897Sopenharmony_ci        auto targetGraphClone = FixedInputsInst::Clone(targetGraph);
1962b1994897Sopenharmony_ci        CHECK_NOT_NULL(targetGraphClone);
1963b1994897Sopenharmony_ci        auto clone = targetGraphClone->CastToCastAnyTypeValue();
1964b1994897Sopenharmony_ci        AnyBaseType any_type = GetAnyType();
1965b1994897Sopenharmony_ci        clone->SetAnyType(any_type);
1966b1994897Sopenharmony_ci        clone->SetType(GetType());
1967b1994897Sopenharmony_ci        return clone;
1968b1994897Sopenharmony_ci    }
1969b1994897Sopenharmony_ci};
1970b1994897Sopenharmony_ci
1971b1994897Sopenharmony_ci/**
1972b1994897Sopenharmony_ci * CastValueToAnyTypeInst instruction
1973b1994897Sopenharmony_ci */
1974b1994897Sopenharmony_ciclass CastValueToAnyTypeInst : public AnyTypeMixin<FixedInputsInst1> {
1975b1994897Sopenharmony_cipublic:
1976b1994897Sopenharmony_ci    using BaseInst = AnyTypeMixin<FixedInputsInst1>;
1977b1994897Sopenharmony_ci    using BaseInst::BaseInst;
1978b1994897Sopenharmony_ci
1979b1994897Sopenharmony_ci    CastValueToAnyTypeInst(Opcode opcode, uint32_t pc) : BaseInst(opcode, DataType::ANY, pc) {}
1980b1994897Sopenharmony_ci
1981b1994897Sopenharmony_ci    DataType::Type GetInputType(size_t index) const override
1982b1994897Sopenharmony_ci    {
1983b1994897Sopenharmony_ci        ASSERT(index < GetInputsCount());
1984b1994897Sopenharmony_ci        return GetInput(index).GetInst()->GetType();
1985b1994897Sopenharmony_ci    }
1986b1994897Sopenharmony_ci
1987b1994897Sopenharmony_ci    void DumpOpcode(std::ostream *out) const override;
1988b1994897Sopenharmony_ci
1989b1994897Sopenharmony_ci    Inst *Clone(const Graph *targetGraph) const override
1990b1994897Sopenharmony_ci    {
1991b1994897Sopenharmony_ci        auto clone = FixedInputsInst::Clone(targetGraph)->CastToCastValueToAnyType();
1992b1994897Sopenharmony_ci        auto any_type = GetAnyType();
1993b1994897Sopenharmony_ci        clone->SetAnyType(any_type);
1994b1994897Sopenharmony_ci        clone->SetType(GetType());
1995b1994897Sopenharmony_ci        return clone;
1996b1994897Sopenharmony_ci    }
1997b1994897Sopenharmony_ci};
1998b1994897Sopenharmony_ci
1999b1994897Sopenharmony_ci/**
2000b1994897Sopenharmony_ci * ConstantInst represent constant value.
2001b1994897Sopenharmony_ci *
2002b1994897Sopenharmony_ci * Available types: INT64, FLOAT32, FLOAT64, ANY. All integer types are stored as INT64 value.
2003b1994897Sopenharmony_ci * Once type of constant is set, it can't be changed anymore.
2004b1994897Sopenharmony_ci */
2005b1994897Sopenharmony_ciclass ConstantInst : public Inst {
2006b1994897Sopenharmony_cipublic:
2007b1994897Sopenharmony_ci    using Inst::Inst;
2008b1994897Sopenharmony_ci
2009b1994897Sopenharmony_ci    template <typename T>
2010b1994897Sopenharmony_ci    explicit ConstantInst(Opcode /* unused */, T value, bool support_int32 = false) : Inst(Opcode::Constant)
2011b1994897Sopenharmony_ci    {
2012b1994897Sopenharmony_ci        ASSERT(GetTypeFromCType<T>() != DataType::NO_TYPE);
2013b1994897Sopenharmony_ci        // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-branch-clone)
2014b1994897Sopenharmony_ci        if constexpr (GetTypeFromCType<T>() == DataType::FLOAT64) {
2015b1994897Sopenharmony_ci            value_ = bit_cast<uint64_t, double>(value);
2016b1994897Sopenharmony_ci            // NOLINTNEXTLINE(readability-braces-around-statements, readability-misleading-indentation)
2017b1994897Sopenharmony_ci        } else if constexpr (GetTypeFromCType<T>() == DataType::FLOAT32) {
2018b1994897Sopenharmony_ci            value_ = bit_cast<uint32_t, float>(value);
2019b1994897Sopenharmony_ci            // NOLINTNEXTLINE(readability-braces-around-statements, readability-misleading-indentation)
2020b1994897Sopenharmony_ci        } else if constexpr (GetTypeFromCType<T>() == DataType::ANY) {
2021b1994897Sopenharmony_ci            value_ = value.Raw();
2022b1994897Sopenharmony_ci            // NOLINTNEXTLINE(readability-braces-around-statements, readability-misleading-indentation)
2023b1994897Sopenharmony_ci        } else if (GetTypeFromCType<T>(support_int32) == DataType::INT32) {
2024b1994897Sopenharmony_ci            value_ = static_cast<int32_t>(value);
2025b1994897Sopenharmony_ci            // NOLINTNEXTLINE(readability-braces-around-statements, readability-misleading-indentation)
2026b1994897Sopenharmony_ci        } else {
2027b1994897Sopenharmony_ci            value_ = value;
2028b1994897Sopenharmony_ci        }
2029b1994897Sopenharmony_ci
2030b1994897Sopenharmony_ci        SetType(GetTypeFromCType<T>(support_int32));
2031b1994897Sopenharmony_ci    }
2032b1994897Sopenharmony_ci
2033b1994897Sopenharmony_ci    uint64_t GetRawValue() const
2034b1994897Sopenharmony_ci    {
2035b1994897Sopenharmony_ci        return value_;
2036b1994897Sopenharmony_ci    }
2037b1994897Sopenharmony_ci
2038b1994897Sopenharmony_ci    uint32_t GetInt32Value() const
2039b1994897Sopenharmony_ci    {
2040b1994897Sopenharmony_ci        ASSERT(GetType() == DataType::INT32);
2041b1994897Sopenharmony_ci        return static_cast<uint32_t>(value_);
2042b1994897Sopenharmony_ci    }
2043b1994897Sopenharmony_ci
2044b1994897Sopenharmony_ci    uint64_t GetInt64Value() const
2045b1994897Sopenharmony_ci    {
2046b1994897Sopenharmony_ci        ASSERT(GetType() == DataType::INT64);
2047b1994897Sopenharmony_ci        return value_;
2048b1994897Sopenharmony_ci    }
2049b1994897Sopenharmony_ci
2050b1994897Sopenharmony_ci    uint64_t GetIntValue() const
2051b1994897Sopenharmony_ci    {
2052b1994897Sopenharmony_ci        ASSERT(GetType() == DataType::INT64 || GetType() == DataType::INT32);
2053b1994897Sopenharmony_ci        return value_;
2054b1994897Sopenharmony_ci    }
2055b1994897Sopenharmony_ci
2056b1994897Sopenharmony_ci    float GetFloatValue() const
2057b1994897Sopenharmony_ci    {
2058b1994897Sopenharmony_ci        ASSERT(GetType() == DataType::FLOAT32);
2059b1994897Sopenharmony_ci        return bit_cast<float, uint32_t>(static_cast<uint32_t>(value_));
2060b1994897Sopenharmony_ci    }
2061b1994897Sopenharmony_ci
2062b1994897Sopenharmony_ci    double GetDoubleValue() const
2063b1994897Sopenharmony_ci    {
2064b1994897Sopenharmony_ci        ASSERT(GetType() == DataType::FLOAT64);
2065b1994897Sopenharmony_ci        return bit_cast<double, uint64_t>(value_);
2066b1994897Sopenharmony_ci    }
2067b1994897Sopenharmony_ci
2068b1994897Sopenharmony_ci    ConstantInst *GetNextConst()
2069b1994897Sopenharmony_ci    {
2070b1994897Sopenharmony_ci        return next_const_;
2071b1994897Sopenharmony_ci    }
2072b1994897Sopenharmony_ci    void SetNextConst(ConstantInst *next_const)
2073b1994897Sopenharmony_ci    {
2074b1994897Sopenharmony_ci        next_const_ = next_const;
2075b1994897Sopenharmony_ci    }
2076b1994897Sopenharmony_ci
2077b1994897Sopenharmony_ci    template <typename T>
2078b1994897Sopenharmony_ci    static constexpr DataType::Type GetTypeFromCType(bool support_int32 = false)
2079b1994897Sopenharmony_ci    {
2080b1994897Sopenharmony_ci        // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-branch-clone)
2081b1994897Sopenharmony_ci        if constexpr (std::is_integral_v<T>) {
2082b1994897Sopenharmony_ci            if (support_int32 && sizeof(T) == sizeof(uint32_t)) {
2083b1994897Sopenharmony_ci                return DataType::INT32;
2084b1994897Sopenharmony_ci            }
2085b1994897Sopenharmony_ci            return DataType::INT64;
2086b1994897Sopenharmony_ci            // NOLINTNEXTLINE(readability-braces-around-statements, readability-misleading-indentation)
2087b1994897Sopenharmony_ci        } else if constexpr (std::is_same_v<T, float>) {
2088b1994897Sopenharmony_ci            return DataType::FLOAT32;
2089b1994897Sopenharmony_ci            // NOLINTNEXTLINE(readability-braces-around-statements, readability-misleading-indentation)
2090b1994897Sopenharmony_ci        } else if constexpr (std::is_same_v<T, double>) {
2091b1994897Sopenharmony_ci            return DataType::FLOAT64;
2092b1994897Sopenharmony_ci            // NOLINTNEXTLINE(readability-braces-around-statements, readability-misleading-indentation)
2093b1994897Sopenharmony_ci        } else if constexpr (std::is_same_v<T, DataType::Any>) {
2094b1994897Sopenharmony_ci            return DataType::ANY;
2095b1994897Sopenharmony_ci        }
2096b1994897Sopenharmony_ci        return DataType::NO_TYPE;
2097b1994897Sopenharmony_ci    }
2098b1994897Sopenharmony_ci
2099b1994897Sopenharmony_ci    inline bool IsEqualConst(double value, [[maybe_unused]] bool support_int32 = false)
2100b1994897Sopenharmony_ci    {
2101b1994897Sopenharmony_ci        return IsEqualConst(DataType::FLOAT64, bit_cast<uint64_t, double>(value));
2102b1994897Sopenharmony_ci    }
2103b1994897Sopenharmony_ci    inline bool IsEqualConst(float value, [[maybe_unused]] bool support_int32 = false)
2104b1994897Sopenharmony_ci    {
2105b1994897Sopenharmony_ci        return IsEqualConst(DataType::FLOAT32, bit_cast<uint32_t, float>(value));
2106b1994897Sopenharmony_ci    }
2107b1994897Sopenharmony_ci    inline bool IsEqualConst(DataType::Any value, [[maybe_unused]] bool support_int32 = false)
2108b1994897Sopenharmony_ci    {
2109b1994897Sopenharmony_ci        return IsEqualConst(DataType::ANY, value.Raw());
2110b1994897Sopenharmony_ci    }
2111b1994897Sopenharmony_ci    inline bool IsEqualConst(DataType::Type type, uint64_t value)
2112b1994897Sopenharmony_ci    {
2113b1994897Sopenharmony_ci        return GetType() == type && value_ == value;
2114b1994897Sopenharmony_ci    }
2115b1994897Sopenharmony_ci    template <typename T>
2116b1994897Sopenharmony_ci    inline bool IsEqualConst(T value, bool support_int32 = false)
2117b1994897Sopenharmony_ci    {
2118b1994897Sopenharmony_ci        static_assert(GetTypeFromCType<T>() == DataType::INT64);
2119b1994897Sopenharmony_ci        if (support_int32 && sizeof(T) == sizeof(uint32_t)) {
2120b1994897Sopenharmony_ci            return (GetType() == DataType::INT32 && static_cast<int32_t>(value_) == static_cast<int32_t>(value));
2121b1994897Sopenharmony_ci        }
2122b1994897Sopenharmony_ci        return (GetType() == DataType::INT64 && value_ == static_cast<uint64_t>(value));
2123b1994897Sopenharmony_ci    }
2124b1994897Sopenharmony_ci
2125b1994897Sopenharmony_ci    inline bool IsEqualConstAllTypes(int64_t value, bool support_int32 = false)
2126b1994897Sopenharmony_ci    {
2127b1994897Sopenharmony_ci        return IsEqualConst(value, support_int32) || IsEqualConst(static_cast<float>(value)) ||
2128b1994897Sopenharmony_ci               IsEqualConst(static_cast<double>(value));
2129b1994897Sopenharmony_ci    }
2130b1994897Sopenharmony_ci
2131b1994897Sopenharmony_ci    bool IsBoolConst() const override
2132b1994897Sopenharmony_ci    {
2133b1994897Sopenharmony_ci        ASSERT(IsConst());
2134b1994897Sopenharmony_ci        return GetType() == DataType::INT64 && (GetIntValue() == 0 || GetIntValue() == 1);
2135b1994897Sopenharmony_ci    }
2136b1994897Sopenharmony_ci
2137b1994897Sopenharmony_ci    void SetImmTableSlot(ImmTableSlot imm_slot)
2138b1994897Sopenharmony_ci    {
2139b1994897Sopenharmony_ci        imm_slot_ = imm_slot;
2140b1994897Sopenharmony_ci    }
2141b1994897Sopenharmony_ci
2142b1994897Sopenharmony_ci    auto GetImmTableSlot() const
2143b1994897Sopenharmony_ci    {
2144b1994897Sopenharmony_ci        return imm_slot_;
2145b1994897Sopenharmony_ci    }
2146b1994897Sopenharmony_ci
2147b1994897Sopenharmony_ci    bool DumpInputs(std::ostream *out) const override;
2148b1994897Sopenharmony_ci
2149b1994897Sopenharmony_ci    Inst *Clone(const Graph *targetGraph) const override;
2150b1994897Sopenharmony_ci
2151b1994897Sopenharmony_ciprivate:
2152b1994897Sopenharmony_ci    uint64_t value_ {0};
2153b1994897Sopenharmony_ci    ConstantInst *next_const_ {nullptr};
2154b1994897Sopenharmony_ci    ImmTableSlot imm_slot_ {INVALID_IMM_TABLE_SLOT};
2155b1994897Sopenharmony_ci};
2156b1994897Sopenharmony_ci
2157b1994897Sopenharmony_ci// Type describing the purpose of the SpillFillInst.
2158b1994897Sopenharmony_ci// RegAlloc may use this information to preserve correct order of several SpillFillInst
2159b1994897Sopenharmony_ci// instructions placed along each other in the graph.
2160b1994897Sopenharmony_cienum SpillFillType {
2161b1994897Sopenharmony_ci    UNKNOWN,
2162b1994897Sopenharmony_ci    INPUT_FILL,
2163b1994897Sopenharmony_ci    CONNECT_SPLIT_SIBLINGS,
2164b1994897Sopenharmony_ci    SPLIT_MOVE,
2165b1994897Sopenharmony_ci};
2166b1994897Sopenharmony_ci
2167b1994897Sopenharmony_ciclass SpillFillInst : public FixedInputsInst0 {
2168b1994897Sopenharmony_cipublic:
2169b1994897Sopenharmony_ci    explicit SpillFillInst(ArenaAllocator *allocator, Opcode opcode)
2170b1994897Sopenharmony_ci        : FixedInputsInst0(opcode), spill_fills_(allocator->Adapter())
2171b1994897Sopenharmony_ci    {
2172b1994897Sopenharmony_ci    }
2173b1994897Sopenharmony_ci
2174b1994897Sopenharmony_ci    void AddMove(Register src, Register dst, DataType::Type type)
2175b1994897Sopenharmony_ci    {
2176b1994897Sopenharmony_ci        AddSpillFill(Location::MakeRegister(src, type), Location::MakeRegister(dst, type), type);
2177b1994897Sopenharmony_ci    }
2178b1994897Sopenharmony_ci
2179b1994897Sopenharmony_ci    void AddSpill(Register src, StackSlot dst, DataType::Type type)
2180b1994897Sopenharmony_ci    {
2181b1994897Sopenharmony_ci        AddSpillFill(Location::MakeRegister(src, type), Location::MakeStackSlot(dst), type);
2182b1994897Sopenharmony_ci    }
2183b1994897Sopenharmony_ci
2184b1994897Sopenharmony_ci    void AddFill(StackSlot src, Register dst, DataType::Type type)
2185b1994897Sopenharmony_ci    {
2186b1994897Sopenharmony_ci        AddSpillFill(Location::MakeStackSlot(src), Location::MakeRegister(dst, type), type);
2187b1994897Sopenharmony_ci    }
2188b1994897Sopenharmony_ci
2189b1994897Sopenharmony_ci    void AddMemCopy(StackSlot src, StackSlot dst, DataType::Type type)
2190b1994897Sopenharmony_ci    {
2191b1994897Sopenharmony_ci        AddSpillFill(Location::MakeStackSlot(src), Location::MakeStackSlot(dst), type);
2192b1994897Sopenharmony_ci    }
2193b1994897Sopenharmony_ci
2194b1994897Sopenharmony_ci    void AddSpillFill(const SpillFillData &spill_fill)
2195b1994897Sopenharmony_ci    {
2196b1994897Sopenharmony_ci        spill_fills_.emplace_back(spill_fill);
2197b1994897Sopenharmony_ci    }
2198b1994897Sopenharmony_ci
2199b1994897Sopenharmony_ci    void AddSpillFill(const Location &src, const Location &dst, DataType::Type type)
2200b1994897Sopenharmony_ci    {
2201b1994897Sopenharmony_ci        spill_fills_.emplace_back(SpillFillData {src.GetKind(), dst.GetKind(), src.GetValue(), dst.GetValue(), type});
2202b1994897Sopenharmony_ci    }
2203b1994897Sopenharmony_ci
2204b1994897Sopenharmony_ci    const ArenaVector<SpillFillData> &GetSpillFills() const
2205b1994897Sopenharmony_ci    {
2206b1994897Sopenharmony_ci        return spill_fills_;
2207b1994897Sopenharmony_ci    }
2208b1994897Sopenharmony_ci
2209b1994897Sopenharmony_ci    ArenaVector<SpillFillData> &GetSpillFills()
2210b1994897Sopenharmony_ci    {
2211b1994897Sopenharmony_ci        return spill_fills_;
2212b1994897Sopenharmony_ci    }
2213b1994897Sopenharmony_ci
2214b1994897Sopenharmony_ci    const SpillFillData &GetSpillFill(size_t n) const
2215b1994897Sopenharmony_ci    {
2216b1994897Sopenharmony_ci        ASSERT(n < spill_fills_.size());
2217b1994897Sopenharmony_ci        return spill_fills_[n];
2218b1994897Sopenharmony_ci    }
2219b1994897Sopenharmony_ci
2220b1994897Sopenharmony_ci    SpillFillData &GetSpillFill(size_t n)
2221b1994897Sopenharmony_ci    {
2222b1994897Sopenharmony_ci        ASSERT(n < spill_fills_.size());
2223b1994897Sopenharmony_ci        return spill_fills_[n];
2224b1994897Sopenharmony_ci    }
2225b1994897Sopenharmony_ci
2226b1994897Sopenharmony_ci    void RemoveSpillFill(size_t n)
2227b1994897Sopenharmony_ci    {
2228b1994897Sopenharmony_ci        ASSERT(n < spill_fills_.size());
2229b1994897Sopenharmony_ci        spill_fills_.erase(spill_fills_.begin() + n);
2230b1994897Sopenharmony_ci    }
2231b1994897Sopenharmony_ci
2232b1994897Sopenharmony_ci    // Get register number, holded by n-th spill-fill
2233b1994897Sopenharmony_ci    Register GetInputReg(size_t n) const
2234b1994897Sopenharmony_ci    {
2235b1994897Sopenharmony_ci        ASSERT(n < spill_fills_.size());
2236b1994897Sopenharmony_ci        ASSERT(spill_fills_[n].SrcType() == LocationType::REGISTER);
2237b1994897Sopenharmony_ci        return spill_fills_[n].SrcValue();
2238b1994897Sopenharmony_ci    }
2239b1994897Sopenharmony_ci
2240b1994897Sopenharmony_ci    void ClearSpillFills()
2241b1994897Sopenharmony_ci    {
2242b1994897Sopenharmony_ci        spill_fills_.clear();
2243b1994897Sopenharmony_ci    }
2244b1994897Sopenharmony_ci
2245b1994897Sopenharmony_ci    SpillFillType GetSpillFillType() const
2246b1994897Sopenharmony_ci    {
2247b1994897Sopenharmony_ci        return sf_type_;
2248b1994897Sopenharmony_ci    }
2249b1994897Sopenharmony_ci
2250b1994897Sopenharmony_ci    void SetSpillFillType(SpillFillType type)
2251b1994897Sopenharmony_ci    {
2252b1994897Sopenharmony_ci        sf_type_ = type;
2253b1994897Sopenharmony_ci    }
2254b1994897Sopenharmony_ci
2255b1994897Sopenharmony_ci    bool DumpInputs(std::ostream *out) const override;
2256b1994897Sopenharmony_ci
2257b1994897Sopenharmony_ci    Inst *Clone(const Graph *targetGraph) const override;
2258b1994897Sopenharmony_ci
2259b1994897Sopenharmony_ciprivate:
2260b1994897Sopenharmony_ci    ArenaVector<SpillFillData> spill_fills_;
2261b1994897Sopenharmony_ci    SpillFillType sf_type_ {UNKNOWN};
2262b1994897Sopenharmony_ci};
2263b1994897Sopenharmony_ci
2264b1994897Sopenharmony_ci// NOLINTNEXTLINE(fuchsia-multiple-inheritance)
2265b1994897Sopenharmony_ciclass ParameterInst : public Inst, public LocationDataMixin {
2266b1994897Sopenharmony_cipublic:
2267b1994897Sopenharmony_ci    using Inst::Inst;
2268b1994897Sopenharmony_ci
2269b1994897Sopenharmony_ci    explicit ParameterInst(Opcode /* unused */, uint16_t arg_number) : Inst(Opcode::Parameter), arg_number_(arg_number)
2270b1994897Sopenharmony_ci    {
2271b1994897Sopenharmony_ci    }
2272b1994897Sopenharmony_ci    uint16_t GetArgNumber() const
2273b1994897Sopenharmony_ci    {
2274b1994897Sopenharmony_ci        return arg_number_;
2275b1994897Sopenharmony_ci    }
2276b1994897Sopenharmony_ci
2277b1994897Sopenharmony_ci    void SetArgNumber(uint16_t arg_number)
2278b1994897Sopenharmony_ci    {
2279b1994897Sopenharmony_ci        arg_number_ = arg_number;
2280b1994897Sopenharmony_ci    }
2281b1994897Sopenharmony_ci
2282b1994897Sopenharmony_ci    bool DumpInputs(std::ostream *out) const override;
2283b1994897Sopenharmony_ci
2284b1994897Sopenharmony_ci    Inst *Clone(const Graph *targetGraph) const override;
2285b1994897Sopenharmony_ci
2286b1994897Sopenharmony_ciprivate:
2287b1994897Sopenharmony_ci    uint16_t arg_number_ {0};
2288b1994897Sopenharmony_ci};
2289b1994897Sopenharmony_ci
2290b1994897Sopenharmony_ciinline bool IsZeroConstant(const Inst *inst)
2291b1994897Sopenharmony_ci{
2292b1994897Sopenharmony_ci    return inst->IsConst() && inst->GetType() == DataType::INT64 && inst->CastToConstant()->GetIntValue() == 0;
2293b1994897Sopenharmony_ci}
2294b1994897Sopenharmony_ci
2295b1994897Sopenharmony_ciinline bool IsZeroConstantOrNullPtr(const Inst *inst)
2296b1994897Sopenharmony_ci{
2297b1994897Sopenharmony_ci    return IsZeroConstant(inst);
2298b1994897Sopenharmony_ci}
2299b1994897Sopenharmony_ci
2300b1994897Sopenharmony_ci/**
2301b1994897Sopenharmony_ci * Phi instruction
2302b1994897Sopenharmony_ci */
2303b1994897Sopenharmony_ciclass PhiInst : public AnyTypeMixin<DynamicInputsInst> {
2304b1994897Sopenharmony_cipublic:
2305b1994897Sopenharmony_ci    using BaseInst = AnyTypeMixin<DynamicInputsInst>;
2306b1994897Sopenharmony_ci    using BaseInst::BaseInst;
2307b1994897Sopenharmony_ci    /// Get basic block corresponding to given input index. Returned pointer to basic block, can't be nullptr
2308b1994897Sopenharmony_ci    BasicBlock *GetPhiInputBb(unsigned index);
2309b1994897Sopenharmony_ci    const BasicBlock *GetPhiInputBb(unsigned index) const
2310b1994897Sopenharmony_ci    {
2311b1994897Sopenharmony_ci        return (const_cast<PhiInst *>(this))->GetPhiInputBb(index);
2312b1994897Sopenharmony_ci    }
2313b1994897Sopenharmony_ci
2314b1994897Sopenharmony_ci    uint32_t GetPhiInputBbNum(unsigned index) const
2315b1994897Sopenharmony_ci    {
2316b1994897Sopenharmony_ci        ASSERT(index < GetInputsCount());
2317b1994897Sopenharmony_ci        return GetDynamicOperands()->GetUser(index)->GetBbNum();
2318b1994897Sopenharmony_ci    }
2319b1994897Sopenharmony_ci
2320b1994897Sopenharmony_ci    void SetPhiInputBbNum(unsigned index, uint32_t bb_num)
2321b1994897Sopenharmony_ci    {
2322b1994897Sopenharmony_ci        ASSERT(index < GetInputsCount());
2323b1994897Sopenharmony_ci        GetDynamicOperands()->GetUser(index)->SetBbNum(bb_num);
2324b1994897Sopenharmony_ci    }
2325b1994897Sopenharmony_ci
2326b1994897Sopenharmony_ci    Inst *Clone(const Graph *targetGraph) const override
2327b1994897Sopenharmony_ci    {
2328b1994897Sopenharmony_ci        auto clone = DynamicInputsInst::Clone(targetGraph);
2329b1994897Sopenharmony_ci        clone->CastToPhi()->SetAnyType(GetAnyType());
2330b1994897Sopenharmony_ci        return clone;
2331b1994897Sopenharmony_ci    }
2332b1994897Sopenharmony_ci
2333b1994897Sopenharmony_ci    AnyBaseType GetAssumedAnyType()
2334b1994897Sopenharmony_ci    {
2335b1994897Sopenharmony_ci        return GetAnyType();
2336b1994897Sopenharmony_ci    }
2337b1994897Sopenharmony_ci
2338b1994897Sopenharmony_ci    /// Get input instruction corresponding to the given basic block, can't be null.
2339b1994897Sopenharmony_ci    Inst *GetPhiInput(BasicBlock *bb);
2340b1994897Sopenharmony_ci    Inst *GetPhiDataflowInput(BasicBlock *bb);
2341b1994897Sopenharmony_ci    bool DumpInputs(std::ostream *out) const override;
2342b1994897Sopenharmony_ci
2343b1994897Sopenharmony_ci    // Get index of the given block in phi inputs
2344b1994897Sopenharmony_ci    size_t GetPredBlockIndex(const BasicBlock *block) const;
2345b1994897Sopenharmony_ci
2346b1994897Sopenharmony_ciprotected:
2347b1994897Sopenharmony_ci    using FlagIsLive = LastField::NextFlag;
2348b1994897Sopenharmony_ci    using LastField = FlagIsLive;
2349b1994897Sopenharmony_ci};
2350b1994897Sopenharmony_ci
2351b1994897Sopenharmony_ci/**
2352b1994897Sopenharmony_ci * Immediate for SavaState:
2353b1994897Sopenharmony_ci * value - constant value to be stored
2354b1994897Sopenharmony_ci * vreg - virtual register number
2355b1994897Sopenharmony_ci */
2356b1994897Sopenharmony_cistruct SaveStateImm {
2357b1994897Sopenharmony_ci    uint64_t value;
2358b1994897Sopenharmony_ci    uint16_t vreg;
2359b1994897Sopenharmony_ci    DataType::Type type;
2360b1994897Sopenharmony_ci    bool is_acc;
2361b1994897Sopenharmony_ci};
2362b1994897Sopenharmony_ci
2363b1994897Sopenharmony_ci/**
2364b1994897Sopenharmony_ci * Frame state saving instruction
2365b1994897Sopenharmony_ci * Aims to save pbc registers before calling something that can raise exception
2366b1994897Sopenharmony_ci */
2367b1994897Sopenharmony_ci// NOLINTNEXTLINE(fuchsia-multiple-inheritance)
2368b1994897Sopenharmony_ciclass SaveStateInst : public DynamicInputsInst {
2369b1994897Sopenharmony_cipublic:
2370b1994897Sopenharmony_ci    using DynamicInputsInst::DynamicInputsInst;
2371b1994897Sopenharmony_ci
2372b1994897Sopenharmony_ci    bool DumpInputs(std::ostream *out) const override;
2373b1994897Sopenharmony_ci
2374b1994897Sopenharmony_ci    void SetVirtualRegister(size_t index, VirtualRegister reg)
2375b1994897Sopenharmony_ci    {
2376b1994897Sopenharmony_ci        static_assert(sizeof(reg) <= sizeof(uintptr_t), "Consider passing the register by reference");
2377b1994897Sopenharmony_ci        ASSERT(index < GetInputsCount());
2378b1994897Sopenharmony_ci        GetDynamicOperands()->GetUser(index)->SetVirtualRegister(reg);
2379b1994897Sopenharmony_ci    }
2380b1994897Sopenharmony_ci
2381b1994897Sopenharmony_ci    VirtualRegister GetVirtualRegister(size_t index) const
2382b1994897Sopenharmony_ci    {
2383b1994897Sopenharmony_ci        ASSERT(index < GetInputsCount());
2384b1994897Sopenharmony_ci        return GetDynamicOperands()->GetUser(index)->GetVirtualRegister();
2385b1994897Sopenharmony_ci    }
2386b1994897Sopenharmony_ci
2387b1994897Sopenharmony_ci    bool Verify() const
2388b1994897Sopenharmony_ci    {
2389b1994897Sopenharmony_ci        for (size_t i {0}; i < GetInputsCount(); ++i) {
2390b1994897Sopenharmony_ci            if (static_cast<uint16_t>(GetVirtualRegister(i)) == VirtualRegister::INVALID) {
2391b1994897Sopenharmony_ci                return false;
2392b1994897Sopenharmony_ci            }
2393b1994897Sopenharmony_ci        }
2394b1994897Sopenharmony_ci        return true;
2395b1994897Sopenharmony_ci    }
2396b1994897Sopenharmony_ci
2397b1994897Sopenharmony_ci    bool RemoveNumericInputs()
2398b1994897Sopenharmony_ci    {
2399b1994897Sopenharmony_ci        size_t idx = 0;
2400b1994897Sopenharmony_ci        size_t inputs_count = GetInputsCount();
2401b1994897Sopenharmony_ci        bool removed = false;
2402b1994897Sopenharmony_ci        while (idx < inputs_count) {
2403b1994897Sopenharmony_ci            auto input_inst = GetInput(idx).GetInst();
2404b1994897Sopenharmony_ci            if (DataType::IsTypeNumeric(input_inst->GetType())) {
2405b1994897Sopenharmony_ci                RemoveInput(idx);
2406b1994897Sopenharmony_ci                inputs_count--;
2407b1994897Sopenharmony_ci                removed = true;
2408b1994897Sopenharmony_ci            } else {
2409b1994897Sopenharmony_ci                idx++;
2410b1994897Sopenharmony_ci            }
2411b1994897Sopenharmony_ci        }
2412b1994897Sopenharmony_ci        return removed;
2413b1994897Sopenharmony_ci    }
2414b1994897Sopenharmony_ci
2415b1994897Sopenharmony_ci    DataType::Type GetInputType([[maybe_unused]] size_t index) const override
2416b1994897Sopenharmony_ci    {
2417b1994897Sopenharmony_ci        ASSERT(index < GetInputsCount());
2418b1994897Sopenharmony_ci        return DataType::NO_TYPE;
2419b1994897Sopenharmony_ci    }
2420b1994897Sopenharmony_ci    auto GetMethod() const
2421b1994897Sopenharmony_ci    {
2422b1994897Sopenharmony_ci        return method_;
2423b1994897Sopenharmony_ci    }
2424b1994897Sopenharmony_ci    auto SetMethod(void *method)
2425b1994897Sopenharmony_ci    {
2426b1994897Sopenharmony_ci        method_ = method;
2427b1994897Sopenharmony_ci    }
2428b1994897Sopenharmony_ci
2429b1994897Sopenharmony_ci    void AppendImmediate(uint64_t imm, uint16_t vreg, DataType::Type type, bool is_acc);
2430b1994897Sopenharmony_ci
2431b1994897Sopenharmony_ci    const ArenaVector<SaveStateImm> *GetImmediates() const
2432b1994897Sopenharmony_ci    {
2433b1994897Sopenharmony_ci        return immediates_;
2434b1994897Sopenharmony_ci    }
2435b1994897Sopenharmony_ci
2436b1994897Sopenharmony_ci    const SaveStateImm &GetImmediate(size_t index) const
2437b1994897Sopenharmony_ci    {
2438b1994897Sopenharmony_ci        ASSERT(immediates_ != nullptr && index < immediates_->size());
2439b1994897Sopenharmony_ci        return (*immediates_)[index];
2440b1994897Sopenharmony_ci    }
2441b1994897Sopenharmony_ci
2442b1994897Sopenharmony_ci    void AllocateImmediates(ArenaAllocator *allocator, size_t size = 0);
2443b1994897Sopenharmony_ci
2444b1994897Sopenharmony_ci    size_t GetImmediatesCount() const
2445b1994897Sopenharmony_ci    {
2446b1994897Sopenharmony_ci        if (immediates_ == nullptr) {
2447b1994897Sopenharmony_ci            return 0;
2448b1994897Sopenharmony_ci        }
2449b1994897Sopenharmony_ci        return immediates_->size();
2450b1994897Sopenharmony_ci    }
2451b1994897Sopenharmony_ci
2452b1994897Sopenharmony_ci    void SetRootsRegMaskBit(size_t reg)
2453b1994897Sopenharmony_ci    {
2454b1994897Sopenharmony_ci        ASSERT(reg < roots_regs_mask_.size());
2455b1994897Sopenharmony_ci        roots_regs_mask_.set(reg);
2456b1994897Sopenharmony_ci    }
2457b1994897Sopenharmony_ci
2458b1994897Sopenharmony_ci    void SetRootsStackMaskBit(size_t slot)
2459b1994897Sopenharmony_ci    {
2460b1994897Sopenharmony_ci        if (roots_stack_mask_ != nullptr) {
2461b1994897Sopenharmony_ci            roots_stack_mask_->SetBit(slot);
2462b1994897Sopenharmony_ci        }
2463b1994897Sopenharmony_ci    }
2464b1994897Sopenharmony_ci
2465b1994897Sopenharmony_ci    ArenaBitVector *GetRootsStackMask()
2466b1994897Sopenharmony_ci    {
2467b1994897Sopenharmony_ci        return roots_stack_mask_;
2468b1994897Sopenharmony_ci    }
2469b1994897Sopenharmony_ci
2470b1994897Sopenharmony_ci    auto &GetRootsRegsMask()
2471b1994897Sopenharmony_ci    {
2472b1994897Sopenharmony_ci        return roots_regs_mask_;
2473b1994897Sopenharmony_ci    }
2474b1994897Sopenharmony_ci
2475b1994897Sopenharmony_ci    void CreateRootsStackMask(ArenaAllocator *allocator)
2476b1994897Sopenharmony_ci    {
2477b1994897Sopenharmony_ci        ASSERT(roots_stack_mask_ == nullptr);
2478b1994897Sopenharmony_ci        roots_stack_mask_ = allocator->New<ArenaBitVector>(allocator);
2479b1994897Sopenharmony_ci        CHECK_NOT_NULL(roots_stack_mask_);
2480b1994897Sopenharmony_ci        roots_stack_mask_->Reset();
2481b1994897Sopenharmony_ci    }
2482b1994897Sopenharmony_ci
2483b1994897Sopenharmony_ci    Inst *Clone(const Graph *targetGraph) const override;
2484b1994897Sopenharmony_ci#ifndef NDEBUG
2485b1994897Sopenharmony_ci    void SetInputsWereDeleted()
2486b1994897Sopenharmony_ci    {
2487b1994897Sopenharmony_ci        SetField<FlagInputsWereDeleted>(true);
2488b1994897Sopenharmony_ci    }
2489b1994897Sopenharmony_ci
2490b1994897Sopenharmony_ci    bool GetInputsWereDeleted()
2491b1994897Sopenharmony_ci    {
2492b1994897Sopenharmony_ci        return GetField<FlagInputsWereDeleted>();
2493b1994897Sopenharmony_ci    }
2494b1994897Sopenharmony_ci#endif
2495b1994897Sopenharmony_ci
2496b1994897Sopenharmony_ciprotected:
2497b1994897Sopenharmony_ci#ifndef NDEBUG
2498b1994897Sopenharmony_ci    using FlagInputsWereDeleted = LastField::NextFlag;
2499b1994897Sopenharmony_ci    using LastField = FlagInputsWereDeleted;
2500b1994897Sopenharmony_ci#endif
2501b1994897Sopenharmony_ci
2502b1994897Sopenharmony_ciprivate:
2503b1994897Sopenharmony_ci    ArenaVector<SaveStateImm> *immediates_ {nullptr};
2504b1994897Sopenharmony_ci    void *method_ {nullptr};
2505b1994897Sopenharmony_ci    /// If instruction is in the inlined graph, this variable points to the inliner's call instruction.
2506b1994897Sopenharmony_ci    ArenaBitVector *roots_stack_mask_ {nullptr};
2507b1994897Sopenharmony_ci    std::bitset<BITS_PER_UINT32> roots_regs_mask_ {0};
2508b1994897Sopenharmony_ci};
2509b1994897Sopenharmony_ci
2510b1994897Sopenharmony_ci// NOLINTNEXTLINE(fuchsia-multiple-inheritance)
2511b1994897Sopenharmony_ciclass IntrinsicInst : public InlinedInstMixin<DynamicInputsInst>, public InputTypesMixin {
2512b1994897Sopenharmony_cipublic:
2513b1994897Sopenharmony_ci    using Base = InlinedInstMixin<DynamicInputsInst>;
2514b1994897Sopenharmony_ci    using Base::Base;
2515b1994897Sopenharmony_ci    using IntrinsicId = RuntimeInterface::IntrinsicId;
2516b1994897Sopenharmony_ci
2517b1994897Sopenharmony_ci    IntrinsicInst(Opcode opcode, IntrinsicId intrinsic_id) : Base(opcode), intrinsic_id_(intrinsic_id) {}
2518b1994897Sopenharmony_ci
2519b1994897Sopenharmony_ci    IntrinsicInst(Opcode opcode, DataType::Type type, uint32_t pc, IntrinsicId intrinsic_id)
2520b1994897Sopenharmony_ci        : Base(opcode, type, pc), intrinsic_id_(intrinsic_id) {}
2521b1994897Sopenharmony_ci
2522b1994897Sopenharmony_ci    IntrinsicId GetIntrinsicId() const
2523b1994897Sopenharmony_ci    {
2524b1994897Sopenharmony_ci        return intrinsic_id_;
2525b1994897Sopenharmony_ci    }
2526b1994897Sopenharmony_ci
2527b1994897Sopenharmony_ci    void SetIntrinsicId(IntrinsicId intrinsic_id)
2528b1994897Sopenharmony_ci    {
2529b1994897Sopenharmony_ci        intrinsic_id_ = intrinsic_id;
2530b1994897Sopenharmony_ci    }
2531b1994897Sopenharmony_ci
2532b1994897Sopenharmony_ci    DataType::Type GetInputType(size_t index) const override
2533b1994897Sopenharmony_ci    {
2534b1994897Sopenharmony_ci        ASSERT(input_types_ != nullptr);
2535b1994897Sopenharmony_ci        ASSERT(index < input_types_->size());
2536b1994897Sopenharmony_ci        ASSERT(index < GetInputsCount());
2537b1994897Sopenharmony_ci        return (*input_types_)[index];
2538b1994897Sopenharmony_ci    }
2539b1994897Sopenharmony_ci
2540b1994897Sopenharmony_ci    const ArenaVector<uint32_t> &GetImms()
2541b1994897Sopenharmony_ci    {
2542b1994897Sopenharmony_ci        return *imms_;
2543b1994897Sopenharmony_ci    }
2544b1994897Sopenharmony_ci
2545b1994897Sopenharmony_ci    const ArenaVector<uint32_t> &GetImms() const
2546b1994897Sopenharmony_ci    {
2547b1994897Sopenharmony_ci        return *imms_;
2548b1994897Sopenharmony_ci    }
2549b1994897Sopenharmony_ci
2550b1994897Sopenharmony_ci    bool HasImms() const
2551b1994897Sopenharmony_ci    {
2552b1994897Sopenharmony_ci        return imms_ != nullptr;
2553b1994897Sopenharmony_ci    }
2554b1994897Sopenharmony_ci
2555b1994897Sopenharmony_ci    void AddImm(ArenaAllocator *allocator, uint32_t imm)
2556b1994897Sopenharmony_ci    {
2557b1994897Sopenharmony_ci        if (imms_ == nullptr) {
2558b1994897Sopenharmony_ci            imms_ = allocator->New<ArenaVector<uint32_t>>(allocator->Adapter());
2559b1994897Sopenharmony_ci            CHECK_NOT_NULL(imms_);
2560b1994897Sopenharmony_ci        }
2561b1994897Sopenharmony_ci        imms_->push_back(imm);
2562b1994897Sopenharmony_ci    }
2563b1994897Sopenharmony_ci
2564b1994897Sopenharmony_ci    bool IsNativeCall() const;
2565b1994897Sopenharmony_ci
2566b1994897Sopenharmony_ci    bool HasArgumentsOnStack() const
2567b1994897Sopenharmony_ci    {
2568b1994897Sopenharmony_ci        return GetField<ArgumentsOnStack>();
2569b1994897Sopenharmony_ci    }
2570b1994897Sopenharmony_ci
2571b1994897Sopenharmony_ci    void SetArgumentsOnStack()
2572b1994897Sopenharmony_ci    {
2573b1994897Sopenharmony_ci        SetField<ArgumentsOnStack>(true);
2574b1994897Sopenharmony_ci    }
2575b1994897Sopenharmony_ci
2576b1994897Sopenharmony_ci    Inst *Clone(const Graph *targetGraph) const override;
2577b1994897Sopenharmony_ci
2578b1994897Sopenharmony_ci    bool CanBeInlined()
2579b1994897Sopenharmony_ci    {
2580b1994897Sopenharmony_ci        return IsInlined();
2581b1994897Sopenharmony_ci    }
2582b1994897Sopenharmony_ci
2583b1994897Sopenharmony_ci    void SetRelocate()
2584b1994897Sopenharmony_ci    {
2585b1994897Sopenharmony_ci        SetField<Relocate>(true);
2586b1994897Sopenharmony_ci    }
2587b1994897Sopenharmony_ci
2588b1994897Sopenharmony_ci    bool GetRelocate() const
2589b1994897Sopenharmony_ci    {
2590b1994897Sopenharmony_ci        return GetField<Relocate>();
2591b1994897Sopenharmony_ci    }
2592b1994897Sopenharmony_ci
2593b1994897Sopenharmony_ci    void DumpOpcode(std::ostream *out) const override;
2594b1994897Sopenharmony_ci
2595b1994897Sopenharmony_ciprotected:
2596b1994897Sopenharmony_ci    using ArgumentsOnStack = LastField::NextFlag;
2597b1994897Sopenharmony_ci    using Relocate = ArgumentsOnStack::NextFlag;
2598b1994897Sopenharmony_ci    using LastField = Relocate;
2599b1994897Sopenharmony_ci
2600b1994897Sopenharmony_ciprivate:
2601b1994897Sopenharmony_ci    std::string GetIntrinsicOpcodeName() const;
2602b1994897Sopenharmony_ci
2603b1994897Sopenharmony_ci    IntrinsicId intrinsic_id_ {RuntimeInterface::IntrinsicId::COUNT};
2604b1994897Sopenharmony_ci    ArenaVector<uint32_t> *imms_ {nullptr};  // record imms appeared in intrinsics
2605b1994897Sopenharmony_ci};
2606b1994897Sopenharmony_ci
2607b1994897Sopenharmony_ci#include <ecma_intrinsics_enum.inl>
2608b1994897Sopenharmony_ci
2609b1994897Sopenharmony_ci/**
2610b1994897Sopenharmony_ci * Cmp instruction
2611b1994897Sopenharmony_ci */
2612b1994897Sopenharmony_ciclass CmpInst : public InstWithOperandsType<FixedInputsInst2> {
2613b1994897Sopenharmony_cipublic:
2614b1994897Sopenharmony_ci    using BaseInst = InstWithOperandsType<FixedInputsInst2>;
2615b1994897Sopenharmony_ci    using BaseInst::BaseInst;
2616b1994897Sopenharmony_ci
2617b1994897Sopenharmony_ci    bool IsFcmpg() const
2618b1994897Sopenharmony_ci    {
2619b1994897Sopenharmony_ci        ASSERT(DataType::IsFloatType(GetOperandsType()));
2620b1994897Sopenharmony_ci        return GetField<Fcmpg>();
2621b1994897Sopenharmony_ci    }
2622b1994897Sopenharmony_ci    bool IsFcmpl() const
2623b1994897Sopenharmony_ci    {
2624b1994897Sopenharmony_ci        ASSERT(DataType::IsFloatType(GetOperandsType()));
2625b1994897Sopenharmony_ci        return !GetField<Fcmpg>();
2626b1994897Sopenharmony_ci    }
2627b1994897Sopenharmony_ci    void SetFcmpg()
2628b1994897Sopenharmony_ci    {
2629b1994897Sopenharmony_ci        ASSERT(DataType::IsFloatType(GetOperandsType()));
2630b1994897Sopenharmony_ci        SetField<Fcmpg>(true);
2631b1994897Sopenharmony_ci    }
2632b1994897Sopenharmony_ci    void SetFcmpg(bool v)
2633b1994897Sopenharmony_ci    {
2634b1994897Sopenharmony_ci        ASSERT(DataType::IsFloatType(GetOperandsType()));
2635b1994897Sopenharmony_ci        SetField<Fcmpg>(v);
2636b1994897Sopenharmony_ci    }
2637b1994897Sopenharmony_ci    void SetFcmpl()
2638b1994897Sopenharmony_ci    {
2639b1994897Sopenharmony_ci        ASSERT(DataType::IsFloatType(GetOperandsType()));
2640b1994897Sopenharmony_ci        SetField<Fcmpg>(false);
2641b1994897Sopenharmony_ci    }
2642b1994897Sopenharmony_ci    void SetFcmpl(bool v)
2643b1994897Sopenharmony_ci    {
2644b1994897Sopenharmony_ci        ASSERT(DataType::IsFloatType(GetOperandsType()));
2645b1994897Sopenharmony_ci        SetField<Fcmpg>(!v);
2646b1994897Sopenharmony_ci    }
2647b1994897Sopenharmony_ci
2648b1994897Sopenharmony_ci    DataType::Type GetInputType([[maybe_unused]] size_t index) const override
2649b1994897Sopenharmony_ci    {
2650b1994897Sopenharmony_ci        ASSERT(index < GetInputsCount());
2651b1994897Sopenharmony_ci        return GetOperandsType();
2652b1994897Sopenharmony_ci    }
2653b1994897Sopenharmony_ci
2654b1994897Sopenharmony_ci    void SetVnObject(VnObject *vn_obj) override;
2655b1994897Sopenharmony_ci
2656b1994897Sopenharmony_ci    void DumpOpcode(std::ostream *out) const override;
2657b1994897Sopenharmony_ci
2658b1994897Sopenharmony_ci    Inst *Clone(const Graph *targetGraph) const override;
2659b1994897Sopenharmony_ci
2660b1994897Sopenharmony_ciprotected:
2661b1994897Sopenharmony_ci    using Fcmpg = LastField::NextFlag;
2662b1994897Sopenharmony_ci    using LastField = Fcmpg;
2663b1994897Sopenharmony_ci};
2664b1994897Sopenharmony_ci
2665b1994897Sopenharmony_ci// NOLINTNEXTLINE(fuchsia-multiple-inheritance)
2666b1994897Sopenharmony_ciclass LoadFromPool : public NeedBarrierMixin<FixedInputsInst1>, public TypeIdMixin {
2667b1994897Sopenharmony_cipublic:
2668b1994897Sopenharmony_ci    using Base = NeedBarrierMixin<FixedInputsInst1>;
2669b1994897Sopenharmony_ci    using Base::Base;
2670b1994897Sopenharmony_ci
2671b1994897Sopenharmony_ci    DataType::Type GetInputType([[maybe_unused]] size_t index) const override
2672b1994897Sopenharmony_ci    {
2673b1994897Sopenharmony_ci        ASSERT(index < GetInputsCount());
2674b1994897Sopenharmony_ci        return DataType::NO_TYPE;
2675b1994897Sopenharmony_ci    }
2676b1994897Sopenharmony_ci
2677b1994897Sopenharmony_ci    void DumpOpcode(std::ostream *out) const override;
2678b1994897Sopenharmony_ci
2679b1994897Sopenharmony_ci    Inst *Clone(const Graph *targetGraph) const override
2680b1994897Sopenharmony_ci    {
2681b1994897Sopenharmony_ci        auto clone = FixedInputsInst::Clone(targetGraph);
2682b1994897Sopenharmony_ci        static_cast<LoadFromPool *>(clone)->SetTypeId(GetTypeId());
2683b1994897Sopenharmony_ci        static_cast<LoadFromPool *>(clone)->SetMethod(GetMethod());
2684b1994897Sopenharmony_ci        return clone;
2685b1994897Sopenharmony_ci    }
2686b1994897Sopenharmony_ci};
2687b1994897Sopenharmony_ci
2688b1994897Sopenharmony_ci/**
2689b1994897Sopenharmony_ci * Conditional jump instruction
2690b1994897Sopenharmony_ci */
2691b1994897Sopenharmony_ci// NOLINTNEXTLINE(fuchsia-multiple-inheritance)
2692b1994897Sopenharmony_ciclass IfInst : public InstWithOperandsType<ConditionMixin<FixedInputsInst2>> {
2693b1994897Sopenharmony_cipublic:
2694b1994897Sopenharmony_ci    using Base = InstWithOperandsType<ConditionMixin<FixedInputsInst2>>;
2695b1994897Sopenharmony_ci    using Base::Base;
2696b1994897Sopenharmony_ci
2697b1994897Sopenharmony_ci    IfInst(Opcode opcode, DataType::Type type, uint32_t pc, ConditionCode cc) : Base(opcode, type, pc)
2698b1994897Sopenharmony_ci    {
2699b1994897Sopenharmony_ci        SetCc(cc);
2700b1994897Sopenharmony_ci    }
2701b1994897Sopenharmony_ci
2702b1994897Sopenharmony_ci    DataType::Type GetInputType([[maybe_unused]] size_t index) const override
2703b1994897Sopenharmony_ci    {
2704b1994897Sopenharmony_ci        ASSERT(index < GetInputsCount());
2705b1994897Sopenharmony_ci        return GetOperandsType();
2706b1994897Sopenharmony_ci    }
2707b1994897Sopenharmony_ci
2708b1994897Sopenharmony_ci    void DumpOpcode(std::ostream *out) const override;
2709b1994897Sopenharmony_ci
2710b1994897Sopenharmony_ci    void SetVnObject(VnObject *vn_obj) override;
2711b1994897Sopenharmony_ci
2712b1994897Sopenharmony_ci    Inst *Clone(const Graph *targetGraph) const override;
2713b1994897Sopenharmony_ci
2714b1994897Sopenharmony_ci    void SetMethod(RuntimeInterface::MethodPtr method)
2715b1994897Sopenharmony_ci    {
2716b1994897Sopenharmony_ci        method_ = method;
2717b1994897Sopenharmony_ci    }
2718b1994897Sopenharmony_ci
2719b1994897Sopenharmony_ci    RuntimeInterface::MethodPtr GetMethod() const
2720b1994897Sopenharmony_ci    {
2721b1994897Sopenharmony_ci        return method_;
2722b1994897Sopenharmony_ci    }
2723b1994897Sopenharmony_ci
2724b1994897Sopenharmony_ciprivate:
2725b1994897Sopenharmony_ci    RuntimeInterface::MethodPtr method_ {nullptr};
2726b1994897Sopenharmony_ci};
2727b1994897Sopenharmony_ci
2728b1994897Sopenharmony_ci/**
2729b1994897Sopenharmony_ci * IfImm instruction with immediate
2730b1994897Sopenharmony_ci */
2731b1994897Sopenharmony_ci// NOLINTNEXTLINE(fuchsia-multiple-inheritance)
2732b1994897Sopenharmony_ciclass IfImmInst : public InstWithOperandsType<ConditionMixin<FixedInputsInst1>>, public ImmediateMixin {
2733b1994897Sopenharmony_cipublic:
2734b1994897Sopenharmony_ci    using Base = InstWithOperandsType<ConditionMixin<FixedInputsInst1>>;
2735b1994897Sopenharmony_ci    using Base::Base;
2736b1994897Sopenharmony_ci
2737b1994897Sopenharmony_ci    IfImmInst(Opcode opcode, DataType::Type type, uint32_t pc, ConditionCode cc, uint64_t imm)
2738b1994897Sopenharmony_ci        : Base(opcode, type, pc), ImmediateMixin(imm)
2739b1994897Sopenharmony_ci    {
2740b1994897Sopenharmony_ci        SetCc(cc);
2741b1994897Sopenharmony_ci    }
2742b1994897Sopenharmony_ci
2743b1994897Sopenharmony_ci    DataType::Type GetInputType([[maybe_unused]] size_t index) const override
2744b1994897Sopenharmony_ci    {
2745b1994897Sopenharmony_ci        ASSERT(index < GetInputsCount());
2746b1994897Sopenharmony_ci        return GetOperandsType();
2747b1994897Sopenharmony_ci    }
2748b1994897Sopenharmony_ci
2749b1994897Sopenharmony_ci    void DumpOpcode(std::ostream *out) const override;
2750b1994897Sopenharmony_ci    bool DumpInputs(std::ostream *out) const override;
2751b1994897Sopenharmony_ci    void SetVnObject(VnObject *vn_obj) override;
2752b1994897Sopenharmony_ci
2753b1994897Sopenharmony_ci    Inst *Clone(const Graph *targetGraph) const override
2754b1994897Sopenharmony_ci    {
2755b1994897Sopenharmony_ci        auto clone = FixedInputsInst::Clone(targetGraph);
2756b1994897Sopenharmony_ci        clone->CastToIfImm()->SetCc(GetCc());
2757b1994897Sopenharmony_ci        clone->CastToIfImm()->SetImm(GetImm());
2758b1994897Sopenharmony_ci        clone->CastToIfImm()->SetOperandsType(GetOperandsType());
2759b1994897Sopenharmony_ci        clone->CastToIfImm()->SetMethod(GetMethod());
2760b1994897Sopenharmony_ci        return clone;
2761b1994897Sopenharmony_ci    }
2762b1994897Sopenharmony_ci
2763b1994897Sopenharmony_ci    BasicBlock *GetEdgeIfInputTrue();
2764b1994897Sopenharmony_ci    BasicBlock *GetEdgeIfInputFalse();
2765b1994897Sopenharmony_ci
2766b1994897Sopenharmony_ci    void SetMethod(RuntimeInterface::MethodPtr method)
2767b1994897Sopenharmony_ci    {
2768b1994897Sopenharmony_ci        method_ = method;
2769b1994897Sopenharmony_ci    }
2770b1994897Sopenharmony_ci
2771b1994897Sopenharmony_ci    RuntimeInterface::MethodPtr GetMethod() const
2772b1994897Sopenharmony_ci    {
2773b1994897Sopenharmony_ci        return method_;
2774b1994897Sopenharmony_ci    }
2775b1994897Sopenharmony_ci
2776b1994897Sopenharmony_ciprivate:
2777b1994897Sopenharmony_ci    size_t GetTrueInputEdgeIdx();
2778b1994897Sopenharmony_ci    RuntimeInterface::MethodPtr method_ {nullptr};
2779b1994897Sopenharmony_ci};
2780b1994897Sopenharmony_ci
2781b1994897Sopenharmony_ci/**
2782b1994897Sopenharmony_ci * CatchPhiInst instruction
2783b1994897Sopenharmony_ci */
2784b1994897Sopenharmony_ciclass CatchPhiInst : public DynamicInputsInst {
2785b1994897Sopenharmony_cipublic:
2786b1994897Sopenharmony_ci    using DynamicInputsInst::DynamicInputsInst;
2787b1994897Sopenharmony_ci
2788b1994897Sopenharmony_ci    const ArenaVector<const Inst *> *GetThrowableInsts() const
2789b1994897Sopenharmony_ci    {
2790b1994897Sopenharmony_ci        return throw_insts_;
2791b1994897Sopenharmony_ci    }
2792b1994897Sopenharmony_ci
2793b1994897Sopenharmony_ci    const Inst *GetThrowableInst(size_t i) const
2794b1994897Sopenharmony_ci    {
2795b1994897Sopenharmony_ci        ASSERT(throw_insts_ != nullptr && i < throw_insts_->size());
2796b1994897Sopenharmony_ci        return throw_insts_->at(i);
2797b1994897Sopenharmony_ci    }
2798b1994897Sopenharmony_ci
2799b1994897Sopenharmony_ci    void AppendThrowableInst(const Inst *inst);
2800b1994897Sopenharmony_ci    void ReplaceThrowableInst(const Inst *old_inst, const Inst *new_inst);
2801b1994897Sopenharmony_ci    void RemoveInput(unsigned index) override;
2802b1994897Sopenharmony_ci
2803b1994897Sopenharmony_ci    bool IsAcc() const
2804b1994897Sopenharmony_ci    {
2805b1994897Sopenharmony_ci        return GetField<IsAccFlag>();
2806b1994897Sopenharmony_ci    }
2807b1994897Sopenharmony_ci
2808b1994897Sopenharmony_ci    void SetIsAcc()
2809b1994897Sopenharmony_ci    {
2810b1994897Sopenharmony_ci        SetField<IsAccFlag>(true);
2811b1994897Sopenharmony_ci    }
2812b1994897Sopenharmony_ci
2813b1994897Sopenharmony_ciprotected:
2814b1994897Sopenharmony_ci    using IsAccFlag = LastField::NextFlag;
2815b1994897Sopenharmony_ci    using LastField = IsAccFlag;
2816b1994897Sopenharmony_ci
2817b1994897Sopenharmony_ciprivate:
2818b1994897Sopenharmony_ci    size_t GetThrowableInstIndex(const Inst *inst)
2819b1994897Sopenharmony_ci    {
2820b1994897Sopenharmony_ci        ASSERT(throw_insts_ != nullptr);
2821b1994897Sopenharmony_ci        auto it = std::find(throw_insts_->begin(), throw_insts_->end(), inst);
2822b1994897Sopenharmony_ci        ASSERT(it != throw_insts_->end());
2823b1994897Sopenharmony_ci        return std::distance(throw_insts_->begin(), it);
2824b1994897Sopenharmony_ci    }
2825b1994897Sopenharmony_ci
2826b1994897Sopenharmony_ciprivate:
2827b1994897Sopenharmony_ci    ArenaVector<const Inst *> *throw_insts_ {nullptr};
2828b1994897Sopenharmony_ci};
2829b1994897Sopenharmony_ci
2830b1994897Sopenharmony_ciclass TryInst : public FixedInputsInst0 {
2831b1994897Sopenharmony_cipublic:
2832b1994897Sopenharmony_ci    using FixedInputsInst0::FixedInputsInst0;
2833b1994897Sopenharmony_ci
2834b1994897Sopenharmony_ci    void AppendCatchTypeId(uint32_t id, uint32_t catch_edge_index);
2835b1994897Sopenharmony_ci
2836b1994897Sopenharmony_ci    const ArenaVector<uint32_t> *GetCatchTypeIds() const
2837b1994897Sopenharmony_ci    {
2838b1994897Sopenharmony_ci        return catch_type_ids_;
2839b1994897Sopenharmony_ci    }
2840b1994897Sopenharmony_ci
2841b1994897Sopenharmony_ci    const ArenaVector<uint32_t> *GetCatchEdgeIndexes() const
2842b1994897Sopenharmony_ci    {
2843b1994897Sopenharmony_ci        return catch_edge_indexes_;
2844b1994897Sopenharmony_ci    }
2845b1994897Sopenharmony_ci
2846b1994897Sopenharmony_ci    size_t GetCatchTypeIdsCount() const
2847b1994897Sopenharmony_ci    {
2848b1994897Sopenharmony_ci        return (catch_type_ids_ == nullptr ? 0 : catch_type_ids_->size());
2849b1994897Sopenharmony_ci    }
2850b1994897Sopenharmony_ci
2851b1994897Sopenharmony_ci    Inst *Clone(const Graph *targetGraph) const override;
2852b1994897Sopenharmony_ci
2853b1994897Sopenharmony_ci    void SetTryEndBlock(BasicBlock *try_end_bb)
2854b1994897Sopenharmony_ci    {
2855b1994897Sopenharmony_ci        try_end_bb_ = try_end_bb;
2856b1994897Sopenharmony_ci    }
2857b1994897Sopenharmony_ci
2858b1994897Sopenharmony_ci    BasicBlock *GetTryEndBlock() const
2859b1994897Sopenharmony_ci    {
2860b1994897Sopenharmony_ci        return try_end_bb_;
2861b1994897Sopenharmony_ci    }
2862b1994897Sopenharmony_ci
2863b1994897Sopenharmony_ciprivate:
2864b1994897Sopenharmony_ci    ArenaVector<uint32_t> *catch_type_ids_ {nullptr};
2865b1994897Sopenharmony_ci    ArenaVector<uint32_t> *catch_edge_indexes_ {nullptr};
2866b1994897Sopenharmony_ci    BasicBlock *try_end_bb_ {nullptr};
2867b1994897Sopenharmony_ci};
2868b1994897Sopenharmony_ci
2869b1994897Sopenharmony_ciTryInst *GetTryBeginInst(const BasicBlock *try_begin_bb);
2870b1994897Sopenharmony_ci
2871b1994897Sopenharmony_citemplate <typename InstType, typename... Args>
2872b1994897Sopenharmony_ciInstType *Inst::New(ArenaAllocator *allocator, Args &&... args)
2873b1994897Sopenharmony_ci{
2874b1994897Sopenharmony_ci    static_assert(alignof(InstType) >= alignof(uintptr_t));
2875b1994897Sopenharmony_ci    // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-branch-clone)
2876b1994897Sopenharmony_ci    if constexpr (std::is_same_v<InstType, SpillFillInst>) {
2877b1994897Sopenharmony_ci        auto data = reinterpret_cast<uintptr_t>(allocator->Alloc(sizeof(InstType), DEFAULT_ALIGNMENT));
2878b1994897Sopenharmony_ci        CHECK(data != 0);
2879b1994897Sopenharmony_ci        return new (reinterpret_cast<void *>(data)) InstType(allocator, std::forward<Args>(args)...);
2880b1994897Sopenharmony_ci        // NOLINTNEXTLINE(readability-braces-around-statements, readability-misleading-indentation)
2881b1994897Sopenharmony_ci    } else if constexpr (InstType::INPUT_COUNT == 0) {
2882b1994897Sopenharmony_ci        auto data = reinterpret_cast<uintptr_t>(allocator->Alloc(sizeof(InstType), DEFAULT_ALIGNMENT));
2883b1994897Sopenharmony_ci        CHECK(data != 0);
2884b1994897Sopenharmony_ci        return new (reinterpret_cast<void *>(data)) InstType(std::forward<Args>(args)...);
2885b1994897Sopenharmony_ci        // NOLINTNEXTLINE(readability-braces-around-statements, readability-misleading-indentation)
2886b1994897Sopenharmony_ci    } else if constexpr (InstType::INPUT_COUNT == MAX_STATIC_INPUTS) {
2887b1994897Sopenharmony_ci        constexpr size_t OPERANDS_SIZE = sizeof(DynamicOperands);
2888b1994897Sopenharmony_ci        static_assert((OPERANDS_SIZE % alignof(InstType)) == 0);
2889b1994897Sopenharmony_ci        auto data = reinterpret_cast<uintptr_t>(allocator->Alloc(OPERANDS_SIZE + sizeof(InstType), DEFAULT_ALIGNMENT));
2890b1994897Sopenharmony_ci        CHECK(data != 0);
2891b1994897Sopenharmony_ci        auto inst = new (reinterpret_cast<void *>(data + OPERANDS_SIZE)) InstType(std::forward<Args>(args)...);
2892b1994897Sopenharmony_ci        [[maybe_unused]] auto operands = new (reinterpret_cast<void *>(data)) DynamicOperands(allocator);
2893b1994897Sopenharmony_ci        static_cast<Inst *>(inst)->SetField<InputsCount>(InstType::INPUT_COUNT);
2894b1994897Sopenharmony_ci        return inst;
2895b1994897Sopenharmony_ci    } else {  // NOLINT(readability-misleading-indentation)
2896b1994897Sopenharmony_ci        constexpr size_t OPERANDS_SIZE = sizeof(Operands<InstType::INPUT_COUNT>);
2897b1994897Sopenharmony_ci        constexpr auto ALIGNMENT {GetLogAlignment(alignof(Operands<InstType::INPUT_COUNT>))};
2898b1994897Sopenharmony_ci        static_assert((OPERANDS_SIZE % alignof(InstType)) == 0);
2899b1994897Sopenharmony_ci        auto data = reinterpret_cast<uintptr_t>(allocator->Alloc(OPERANDS_SIZE + sizeof(InstType), ALIGNMENT));
2900b1994897Sopenharmony_ci        CHECK(data != 0);
2901b1994897Sopenharmony_ci        auto inst = new (reinterpret_cast<void *>(data + OPERANDS_SIZE)) InstType(std::forward<Args>(args)...);
2902b1994897Sopenharmony_ci        auto operands = new (reinterpret_cast<void *>(data)) Operands<InstType::INPUT_COUNT>;
2903b1994897Sopenharmony_ci        static_cast<Inst *>(inst)->SetField<InputsCount>(InstType::INPUT_COUNT);
2904b1994897Sopenharmony_ci        unsigned idx = InstType::INPUT_COUNT - 1;
2905b1994897Sopenharmony_ci        for (auto &user : operands->users) {
2906b1994897Sopenharmony_ci            new (&user) User(true, idx--, InstType::INPUT_COUNT);
2907b1994897Sopenharmony_ci        }
2908b1994897Sopenharmony_ci        return inst;
2909b1994897Sopenharmony_ci    }
2910b1994897Sopenharmony_ci}
2911b1994897Sopenharmony_ci
2912b1994897Sopenharmony_ciinline Inst *User::GetInput()
2913b1994897Sopenharmony_ci{
2914b1994897Sopenharmony_ci    return GetInst()->GetInput(GetIndex()).GetInst();
2915b1994897Sopenharmony_ci}
2916b1994897Sopenharmony_ci
2917b1994897Sopenharmony_ciinline const Inst *User::GetInput() const
2918b1994897Sopenharmony_ci{
2919b1994897Sopenharmony_ci    return GetInst()->GetInput(GetIndex()).GetInst();
2920b1994897Sopenharmony_ci}
2921b1994897Sopenharmony_ci
2922b1994897Sopenharmony_ciinline std::ostream &operator<<(std::ostream &os, const Inst &inst)
2923b1994897Sopenharmony_ci{
2924b1994897Sopenharmony_ci    inst.Dump(&os, false);
2925b1994897Sopenharmony_ci    return os;
2926b1994897Sopenharmony_ci}
2927b1994897Sopenharmony_ci
2928b1994897Sopenharmony_ci// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
2929b1994897Sopenharmony_ci#define INST_DEF(opcode, base, ...)                 \
2930b1994897Sopenharmony_ci    inline const base *Inst::CastTo##opcode() const \
2931b1994897Sopenharmony_ci    {                                               \
2932b1994897Sopenharmony_ci        ASSERT(GetOpcode() == Opcode::opcode);      \
2933b1994897Sopenharmony_ci        return static_cast<const base *>(this);     \
2934b1994897Sopenharmony_ci    }
2935b1994897Sopenharmony_ciOPCODE_LIST(INST_DEF)
2936b1994897Sopenharmony_ci#undef INST_DEF
2937b1994897Sopenharmony_ci
2938b1994897Sopenharmony_ci// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
2939b1994897Sopenharmony_ci#define INST_DEF(opcode, base, ...)            \
2940b1994897Sopenharmony_ci    inline base *Inst::CastTo##opcode()        \
2941b1994897Sopenharmony_ci    {                                          \
2942b1994897Sopenharmony_ci        ASSERT(GetOpcode() == Opcode::opcode); \
2943b1994897Sopenharmony_ci        return static_cast<base *>(this);      \
2944b1994897Sopenharmony_ci    }
2945b1994897Sopenharmony_ciOPCODE_LIST(INST_DEF)
2946b1994897Sopenharmony_ci#undef INST_DEF
2947b1994897Sopenharmony_ci}  // namespace panda::compiler
2948b1994897Sopenharmony_ci
2949b1994897Sopenharmony_ci#endif  // COMPILER_OPTIMIZER_IR_INST_H
2950