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 ASSEMBLER_ASSEMBLY_INS_H
17b1994897Sopenharmony_ci#define ASSEMBLER_ASSEMBLY_INS_H
18b1994897Sopenharmony_ci
19b1994897Sopenharmony_ci#include <array>
20b1994897Sopenharmony_ci#include <string>
21b1994897Sopenharmony_ci#include <string_view>
22b1994897Sopenharmony_ci#include <unordered_map>
23b1994897Sopenharmony_ci#include <variant>
24b1994897Sopenharmony_ci#include <vector>
25b1994897Sopenharmony_ci
26b1994897Sopenharmony_ci#include "assembly-debug.h"
27b1994897Sopenharmony_ci#include "bytecode_emitter.h"
28b1994897Sopenharmony_ci#include "file_items.h"
29b1994897Sopenharmony_ci#include "isa.h"
30b1994897Sopenharmony_ci#include "lexer.h"
31b1994897Sopenharmony_ci
32b1994897Sopenharmony_cinamespace panda::pandasm {
33b1994897Sopenharmony_ci
34b1994897Sopenharmony_cienum class Opcode {
35b1994897Sopenharmony_ci#define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs) opcode,
36b1994897Sopenharmony_ci    PANDA_INSTRUCTION_LIST(OPLIST)
37b1994897Sopenharmony_ci#undef OPLIST
38b1994897Sopenharmony_ci        INVALID,
39b1994897Sopenharmony_ci    NUM_OPCODES = INVALID
40b1994897Sopenharmony_ci};
41b1994897Sopenharmony_ci
42b1994897Sopenharmony_cienum InstFlags {
43b1994897Sopenharmony_ci    NONE = 0,
44b1994897Sopenharmony_ci    JUMP = (1U << 0U),
45b1994897Sopenharmony_ci    COND = (1U << 1U),
46b1994897Sopenharmony_ci    CALL = (1U << 2U),
47b1994897Sopenharmony_ci    RETURN = (1U << 3U),
48b1994897Sopenharmony_ci    ACC_READ = (1U << 4U),
49b1994897Sopenharmony_ci    ACC_WRITE = (1U << 5U),
50b1994897Sopenharmony_ci    PSEUDO = (1U << 6U),
51b1994897Sopenharmony_ci    THROWING = (1U << 7U),
52b1994897Sopenharmony_ci    METHOD_ID = (1U << 8U),
53b1994897Sopenharmony_ci    FIELD_ID = (1U << 9U),
54b1994897Sopenharmony_ci    TYPE_ID = (1U << 10U),
55b1994897Sopenharmony_ci    STRING_ID = (1U << 11U),
56b1994897Sopenharmony_ci    LITERALARRAY_ID = (1U << 12U),
57b1994897Sopenharmony_ci    CALL_RANGE = (1U << 13U)
58b1994897Sopenharmony_ci};
59b1994897Sopenharmony_ci
60b1994897Sopenharmony_ciconstexpr int INVALID_REG_IDX = -1;
61b1994897Sopenharmony_ci
62b1994897Sopenharmony_ciconstexpr size_t MAX_NUMBER_OF_SRC_REGS = 4;  // TODO(mbolshov): auto-generate
63b1994897Sopenharmony_ci
64b1994897Sopenharmony_ciconstexpr InstFlags operator|(InstFlags a, InstFlags b)
65b1994897Sopenharmony_ci{
66b1994897Sopenharmony_ci    using utype = std::underlying_type_t<InstFlags>;
67b1994897Sopenharmony_ci    return static_cast<InstFlags>(static_cast<utype>(a) | static_cast<utype>(b));
68b1994897Sopenharmony_ci}
69b1994897Sopenharmony_ci
70b1994897Sopenharmony_ci#define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs) flags,
71b1994897Sopenharmony_ciconstexpr std::array<unsigned, static_cast<size_t>(Opcode::NUM_OPCODES)> INST_FLAGS_TABLE = {
72b1994897Sopenharmony_ci    PANDA_INSTRUCTION_LIST(OPLIST)};
73b1994897Sopenharmony_ci#undef OPLIST
74b1994897Sopenharmony_ci
75b1994897Sopenharmony_ci#define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs) width,
76b1994897Sopenharmony_ciconstexpr std::array<size_t, static_cast<size_t>(Opcode::NUM_OPCODES)> INST_WIDTH_TABLE = {
77b1994897Sopenharmony_ci    PANDA_INSTRUCTION_LIST(OPLIST)};
78b1994897Sopenharmony_ci#undef OPLIST
79b1994897Sopenharmony_ci
80b1994897Sopenharmony_ci#define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs) def_idx,
81b1994897Sopenharmony_ciconstexpr std::array<int, static_cast<size_t>(Opcode::NUM_OPCODES)> DEF_IDX_TABLE = {PANDA_INSTRUCTION_LIST(OPLIST)};
82b1994897Sopenharmony_ci#undef OPLIST
83b1994897Sopenharmony_ci
84b1994897Sopenharmony_ci#define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs) use_idxs,
85b1994897Sopenharmony_ci// clang-format off
86b1994897Sopenharmony_ciconstexpr std::array<std::array<int, MAX_NUMBER_OF_SRC_REGS>,
87b1994897Sopenharmony_ci                     static_cast<size_t>(Opcode::NUM_OPCODES)> USE_IDXS_TABLE = {PANDA_INSTRUCTION_LIST(OPLIST)};
88b1994897Sopenharmony_ci// clang-format on
89b1994897Sopenharmony_ci#undef OPLIST
90b1994897Sopenharmony_ci
91b1994897Sopenharmony_cistruct Ins {
92b1994897Sopenharmony_ci    using IType = std::variant<int64_t, double>;
93b1994897Sopenharmony_ci
94b1994897Sopenharmony_ci    constexpr static uint16_t ACCUMULATOR = -1;
95b1994897Sopenharmony_ci    constexpr static size_t MAX_CALL_SHORT_ARGS = 2;
96b1994897Sopenharmony_ci    constexpr static size_t MAX_CALL_ARGS = 4;
97b1994897Sopenharmony_ci    constexpr static uint16_t MAX_NON_RANGE_CALL_REG = 15;
98b1994897Sopenharmony_ci    constexpr static uint16_t MAX_RANGE_CALL_START_REG = 255;
99b1994897Sopenharmony_ci
100b1994897Sopenharmony_ci    Opcode opcode = Opcode::INVALID; /* operation type */
101b1994897Sopenharmony_ci    std::vector<uint16_t> regs;      /* list of arguments - registers */
102b1994897Sopenharmony_ci    std::vector<std::string> ids;    /* list of arguments - identifiers */
103b1994897Sopenharmony_ci    std::vector<IType> imms;         /* list of arguments - immediates */
104b1994897Sopenharmony_ci    std::string label;               /* label at the beginning of a line */
105b1994897Sopenharmony_ci    bool set_label = false;          /* whether this label is defined */
106b1994897Sopenharmony_ci    debuginfo::Ins ins_debug;
107b1994897Sopenharmony_ci
108b1994897Sopenharmony_ci    std::string ToString(std::string endline = "", bool print_args = false, size_t first_arg_idx = 0) const;
109b1994897Sopenharmony_ci
110b1994897Sopenharmony_ci    bool Emit(BytecodeEmitter &emitter, panda_file::MethodItem *method,
111b1994897Sopenharmony_ci              const std::unordered_map<std::string, panda_file::BaseMethodItem *> &methods,
112b1994897Sopenharmony_ci              const std::unordered_map<std::string, panda_file::BaseFieldItem *> &fields,
113b1994897Sopenharmony_ci              const std::unordered_map<std::string, panda_file::BaseClassItem *> &classes,
114b1994897Sopenharmony_ci              const std::unordered_map<std::string, panda_file::StringItem *> &strings,
115b1994897Sopenharmony_ci              const std::unordered_map<std::string, panda_file::LiteralArrayItem *> &literalarrays,
116b1994897Sopenharmony_ci              const std::unordered_map<std::string_view, panda::Label> &labels) const;
117b1994897Sopenharmony_ci
118b1994897Sopenharmony_ci    size_t OperandListLength() const
119b1994897Sopenharmony_ci    {
120b1994897Sopenharmony_ci        return regs.size() + ids.size() + imms.size();
121b1994897Sopenharmony_ci    }
122b1994897Sopenharmony_ci
123b1994897Sopenharmony_ci    bool HasFlag(InstFlags flag) const
124b1994897Sopenharmony_ci    {
125b1994897Sopenharmony_ci        if (opcode == Opcode::INVALID) {  // TODO(mbolshov): introduce 'label' opcode for labels
126b1994897Sopenharmony_ci            return false;
127b1994897Sopenharmony_ci        }
128b1994897Sopenharmony_ci        return (INST_FLAGS_TABLE[static_cast<size_t>(opcode)] & flag) != 0;
129b1994897Sopenharmony_ci    }
130b1994897Sopenharmony_ci
131b1994897Sopenharmony_ci    bool CanThrow() const
132b1994897Sopenharmony_ci    {
133b1994897Sopenharmony_ci        return HasFlag(InstFlags::THROWING) || HasFlag(InstFlags::METHOD_ID) || HasFlag(InstFlags::FIELD_ID) ||
134b1994897Sopenharmony_ci               HasFlag(InstFlags::TYPE_ID) || HasFlag(InstFlags::STRING_ID);
135b1994897Sopenharmony_ci    }
136b1994897Sopenharmony_ci
137b1994897Sopenharmony_ci    bool IsJump() const
138b1994897Sopenharmony_ci    {
139b1994897Sopenharmony_ci        return HasFlag(InstFlags::JUMP);
140b1994897Sopenharmony_ci    }
141b1994897Sopenharmony_ci
142b1994897Sopenharmony_ci    bool IsConditionalJump() const
143b1994897Sopenharmony_ci    {
144b1994897Sopenharmony_ci        return IsJump() && HasFlag(InstFlags::COND);
145b1994897Sopenharmony_ci    }
146b1994897Sopenharmony_ci
147b1994897Sopenharmony_ci    bool IsCall() const
148b1994897Sopenharmony_ci    {  // Non-range call
149b1994897Sopenharmony_ci        return HasFlag(InstFlags::CALL);
150b1994897Sopenharmony_ci    }
151b1994897Sopenharmony_ci
152b1994897Sopenharmony_ci    bool IsCallRange() const
153b1994897Sopenharmony_ci    {  // Range call
154b1994897Sopenharmony_ci        return HasFlag(InstFlags::CALL_RANGE);
155b1994897Sopenharmony_ci    }
156b1994897Sopenharmony_ci
157b1994897Sopenharmony_ci    bool IsPseudoCall() const
158b1994897Sopenharmony_ci    {
159b1994897Sopenharmony_ci        return HasFlag(InstFlags::PSEUDO) && HasFlag(InstFlags::CALL);
160b1994897Sopenharmony_ci    }
161b1994897Sopenharmony_ci
162b1994897Sopenharmony_ci    bool IsReturn() const
163b1994897Sopenharmony_ci    {
164b1994897Sopenharmony_ci        return HasFlag(InstFlags::RETURN);
165b1994897Sopenharmony_ci    }
166b1994897Sopenharmony_ci
167b1994897Sopenharmony_ci    size_t MaxRegEncodingWidth() const
168b1994897Sopenharmony_ci    {
169b1994897Sopenharmony_ci        if (opcode == Opcode::INVALID) {
170b1994897Sopenharmony_ci            return 0;
171b1994897Sopenharmony_ci        }
172b1994897Sopenharmony_ci        return INST_WIDTH_TABLE[static_cast<size_t>(opcode)];
173b1994897Sopenharmony_ci    }
174b1994897Sopenharmony_ci
175b1994897Sopenharmony_ci    std::vector<uint16_t> Uses() const
176b1994897Sopenharmony_ci    {
177b1994897Sopenharmony_ci        if (IsPseudoCall()) {
178b1994897Sopenharmony_ci            return regs;
179b1994897Sopenharmony_ci        }
180b1994897Sopenharmony_ci
181b1994897Sopenharmony_ci        if (opcode == Opcode::INVALID) {
182b1994897Sopenharmony_ci            return {};
183b1994897Sopenharmony_ci        }
184b1994897Sopenharmony_ci
185b1994897Sopenharmony_ci        auto use_idxs = USE_IDXS_TABLE[static_cast<size_t>(opcode)];
186b1994897Sopenharmony_ci        std::vector<uint16_t> res(MAX_NUMBER_OF_SRC_REGS + 1);
187b1994897Sopenharmony_ci        if (HasFlag(InstFlags::ACC_READ)) {
188b1994897Sopenharmony_ci            res.push_back(Ins::ACCUMULATOR);
189b1994897Sopenharmony_ci        }
190b1994897Sopenharmony_ci        for (auto idx : use_idxs) {
191b1994897Sopenharmony_ci            if (idx == INVALID_REG_IDX) {
192b1994897Sopenharmony_ci                break;
193b1994897Sopenharmony_ci            }
194b1994897Sopenharmony_ci            ASSERT(static_cast<size_t>(idx) < regs.size());
195b1994897Sopenharmony_ci            res.emplace_back(regs[idx]);
196b1994897Sopenharmony_ci        }
197b1994897Sopenharmony_ci        return res;
198b1994897Sopenharmony_ci    }
199b1994897Sopenharmony_ci
200b1994897Sopenharmony_ci    std::optional<size_t> Def() const
201b1994897Sopenharmony_ci    {
202b1994897Sopenharmony_ci        if (opcode == Opcode::INVALID) {
203b1994897Sopenharmony_ci            return {};
204b1994897Sopenharmony_ci        }
205b1994897Sopenharmony_ci        auto def_idx = DEF_IDX_TABLE[static_cast<size_t>(opcode)];
206b1994897Sopenharmony_ci        if (def_idx != INVALID_REG_IDX) {
207b1994897Sopenharmony_ci            return regs[def_idx];
208b1994897Sopenharmony_ci        }
209b1994897Sopenharmony_ci        if (HasFlag(InstFlags::ACC_WRITE)) {
210b1994897Sopenharmony_ci            return Ins::ACCUMULATOR;
211b1994897Sopenharmony_ci        }
212b1994897Sopenharmony_ci        return {};
213b1994897Sopenharmony_ci    }
214b1994897Sopenharmony_ci
215b1994897Sopenharmony_ci    bool IsValidToEmit() const
216b1994897Sopenharmony_ci    {
217b1994897Sopenharmony_ci        const auto INVALID_REG_NUM = 1U << MaxRegEncodingWidth();
218b1994897Sopenharmony_ci        for (auto reg : regs) {
219b1994897Sopenharmony_ci            if (reg >= INVALID_REG_NUM) {
220b1994897Sopenharmony_ci                return false;
221b1994897Sopenharmony_ci            }
222b1994897Sopenharmony_ci        }
223b1994897Sopenharmony_ci        return true;
224b1994897Sopenharmony_ci    }
225b1994897Sopenharmony_ci
226b1994897Sopenharmony_ci    bool HasDebugInfo() const
227b1994897Sopenharmony_ci    {
228b1994897Sopenharmony_ci        return ins_debug.line_number != 0;
229b1994897Sopenharmony_ci    }
230b1994897Sopenharmony_ci
231b1994897Sopenharmony_ciprivate:
232b1994897Sopenharmony_ci    std::string OperandsToString(bool print_args = false, size_t first_arg_idx = 0) const;
233b1994897Sopenharmony_ci    std::string RegsToString(bool &first, bool print_args = false, size_t first_arg_idx = 0) const;
234b1994897Sopenharmony_ci    std::string ImmsToString(bool &first) const;
235b1994897Sopenharmony_ci    std::string IdsToString(bool &first) const;
236b1994897Sopenharmony_ci
237b1994897Sopenharmony_ci    std::string IdToString(size_t idx, bool is_first) const;
238b1994897Sopenharmony_ci    std::string ImmToString(size_t idx, bool is_first) const;
239b1994897Sopenharmony_ci    std::string RegToString(size_t idx, bool is_first, bool print_args = false, size_t first_arg_idx = 0) const;
240b1994897Sopenharmony_ci};
241b1994897Sopenharmony_ci}  // namespace panda::pandasm
242b1994897Sopenharmony_ci
243b1994897Sopenharmony_ci#endif  // ASSEMBLER_ASSEMBLY_INS_H
244