• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef PANDA_ASSEMBLER_ASSEMBLY_INS_H
17 #define PANDA_ASSEMBLER_ASSEMBLY_INS_H
18 
19 #include <array>
20 #include <string>
21 #include <string_view>
22 #include <unordered_map>
23 #include <variant>
24 #include <vector>
25 
26 #include "assembly-debug.h"
27 #include "bytecode_emitter.h"
28 #include "file_items.h"
29 #include "isa.h"
30 #include "lexer.h"
31 
32 namespace ark::pandasm {
33 
34 enum class Opcode {
35 // CC-OFFNXT(G.PRE.02) opcode is class member
36 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
37 #define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs, prof_size) opcode,
38     PANDA_INSTRUCTION_LIST(OPLIST)
39 #undef OPLIST
40         INVALID,
41     NUM_OPCODES = INVALID
42 };
43 
44 enum InstFlags {
45     NONE = 0,
46     JUMP = (1U << 0U),
47     COND = (1U << 1U),
48     CALL = (1U << 2U),
49     RETURN = (1U << 3U),
50     ACC_READ = (1U << 4U),
51     ACC_WRITE = (1U << 5U),
52     PSEUDO = (1U << 6U),
53     THROWING = (1U << 7U),
54     METHOD_ID = (1U << 8U),
55     FIELD_ID = (1U << 9U),
56     TYPE_ID = (1U << 10U),
57     STRING_ID = (1U << 11U),
58     LITERALARRAY_ID = (1U << 12U),
59     CALL_RANGE = (1U << 13U),
60     STATIC_FIELD_ID = (1U << 14U),
61     STATIC_METHOD_ID = (1U << 15U)
62 };
63 
64 constexpr int INVALID_REG_IDX = -1;
65 
66 constexpr InstFlags operator|(InstFlags a, InstFlags b)
67 {
68     using Utype = std::underlying_type_t<InstFlags>;
69     return static_cast<InstFlags>(static_cast<Utype>(a) | static_cast<Utype>(b));
70 }
71 
72 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
73 #define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs, prof_size) (flags),
74 constexpr std::array<unsigned, static_cast<size_t>(Opcode::NUM_OPCODES)> INST_FLAGS_TABLE = {
75     PANDA_INSTRUCTION_LIST(OPLIST)};
76 #undef OPLIST
77 
78 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
79 #define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs, prof_size) (width),
80 constexpr std::array<size_t, static_cast<size_t>(Opcode::NUM_OPCODES)> INST_WIDTH_TABLE = {
81     PANDA_INSTRUCTION_LIST(OPLIST)};
82 #undef OPLIST
83 
84 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
85 #define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs, prof_size) (def_idx),
86 constexpr std::array<int, static_cast<size_t>(Opcode::NUM_OPCODES)> DEF_IDX_TABLE = {PANDA_INSTRUCTION_LIST(OPLIST)};
87 #undef OPLIST
88 
89 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
90 #define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs, prof_size) (use_idxs),
91 constexpr std::array<std::array<int, MAX_NUMBER_OF_SRC_REGS>, static_cast<size_t>(Opcode::NUM_OPCODES)> USE_IDXS_TABLE =
92     {PANDA_INSTRUCTION_LIST(OPLIST)};  // CC-OFF(G.FMT.03) any style changes will worsen readability
93 #undef OPLIST
94 
95 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
96 #define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs, prof_size) (prof_size),
97 // clang-format off
98 constexpr std::array<unsigned, static_cast<size_t>(Opcode::NUM_OPCODES) + 1> INST_PROFILE_SIZES =
99     {PANDA_INSTRUCTION_LIST(OPLIST) 0};  // CC-OFF(G.FMT.03) any style changes will worsen readability
100 // clang-format on
101 #undef OPLIST
102 
103 // NOLINTBEGIN(misc-non-private-member-variables-in-classes)
104 struct Ins {
105     using IType = std::variant<int64_t, double>;
106 
107     constexpr static uint16_t ACCUMULATOR = -1;
108     constexpr static size_t MAX_CALL_SHORT_ARGS = 2;
109     constexpr static size_t MAX_CALL_ARGS = 4;
110     constexpr static uint16_t MAX_NON_RANGE_CALL_REG = 15;
111     constexpr static uint16_t MAX_RANGE_CALL_START_REG = 255;
112 
113     Opcode opcode = Opcode::INVALID; /* operation type */
114     std::vector<uint16_t> regs;      /* list of arguments - registers */
115     std::vector<std::string> ids;    /* list of arguments - identifiers */
116     std::vector<IType> imms;         /* list of arguments - immediates */
117     std::string label;               /* label at the beginning of a line */
118     bool setLabel = false;           /* whether this label is defined */
119     debuginfo::Ins insDebug;
120     uint16_t profileId {0}; /* Index in the profile vector */
121 
122     PANDA_PUBLIC_API std::string ToString(const std::string &endline = "", bool printArgs = false,
123                                           size_t firstArgIdx = 0) const;
124 
125     // CC-OFFNXT(G.FUN.01-CPP) solid logic
126     bool Emit(BytecodeEmitter &emitter, panda_file::MethodItem *method,
127               const std::unordered_map<std::string, panda_file::BaseMethodItem *> &methods,
128               const std::unordered_map<std::string, panda_file::BaseMethodItem *> &staticMethods,
129               const std::unordered_map<std::string, panda_file::BaseFieldItem *> &fields,
130               const std::unordered_map<std::string, panda_file::BaseFieldItem *> &staticFields,
131               const std::unordered_map<std::string, panda_file::BaseClassItem *> &classes,
132               const std::unordered_map<std::string_view, panda_file::StringItem *> &strings,
133               const std::unordered_map<std::string, panda_file::LiteralArrayItem *> &literalarrays,
134               const std::unordered_map<std::string_view, ark::Label> &labels) const;
135 
OperandListLengthIns136     size_t OperandListLength() const
137     {
138         return regs.size() + ids.size() + imms.size();
139     }
140 
HasFlagIns141     bool HasFlag(InstFlags flag) const
142     {
143         if (opcode == Opcode::INVALID) {  // NOTE(mbolshov): introduce 'label' opcode for labels
144             return false;
145         }
146         return (INST_FLAGS_TABLE[static_cast<size_t>(opcode)] & flag) != 0;
147     }
148 
CanThrowIns149     bool CanThrow() const
150     {
151         return HasFlag(InstFlags::THROWING) || HasFlag(InstFlags::METHOD_ID) || HasFlag(InstFlags::STATIC_METHOD_ID) ||
152                HasFlag(InstFlags::FIELD_ID) || HasFlag(InstFlags::STATIC_FIELD_ID) || HasFlag(InstFlags::TYPE_ID) ||
153                HasFlag(InstFlags::STRING_ID);
154     }
155 
IsJumpIns156     bool IsJump() const
157     {
158         return HasFlag(InstFlags::JUMP);
159     }
160 
IsConditionalJumpIns161     bool IsConditionalJump() const
162     {
163         return IsJump() && HasFlag(InstFlags::COND);
164     }
165 
IsCallIns166     bool IsCall() const
167     {  // Non-range call
168         return HasFlag(InstFlags::CALL);
169     }
170 
IsCallRangeIns171     bool IsCallRange() const
172     {  // Range call
173         return HasFlag(InstFlags::CALL_RANGE);
174     }
175 
IsPseudoCallIns176     bool IsPseudoCall() const
177     {
178         return HasFlag(InstFlags::PSEUDO) && HasFlag(InstFlags::CALL);
179     }
180 
IsReturnIns181     bool IsReturn() const
182     {
183         return HasFlag(InstFlags::RETURN);
184     }
185 
MaxRegEncodingWidthIns186     size_t MaxRegEncodingWidth() const
187     {
188         if (opcode == Opcode::INVALID) {
189             return 0;
190         }
191         return INST_WIDTH_TABLE[static_cast<size_t>(opcode)];
192     }
193 
UsesIns194     std::vector<uint16_t> Uses() const
195     {
196         if (IsPseudoCall()) {
197             return regs;
198         }
199 
200         if (opcode == Opcode::INVALID) {
201             return {};
202         }
203 
204         auto useIdxs = USE_IDXS_TABLE[static_cast<size_t>(opcode)];
205         std::vector<uint16_t> res(MAX_NUMBER_OF_SRC_REGS + 1);
206         if (HasFlag(InstFlags::ACC_READ)) {
207             res.push_back(Ins::ACCUMULATOR);
208         }
209         for (auto idx : useIdxs) {
210             if (idx == INVALID_REG_IDX) {
211                 break;
212             }
213             ASSERT(static_cast<size_t>(idx) < regs.size());
214             res.emplace_back(regs[idx]);
215         }
216         return res;
217     }
218 
DefIns219     std::optional<size_t> Def() const
220     {
221         if (opcode == Opcode::INVALID) {
222             return {};
223         }
224         auto defIdx = DEF_IDX_TABLE[static_cast<size_t>(opcode)];
225         if (defIdx != INVALID_REG_IDX) {
226             return regs[defIdx];
227         }
228         if (HasFlag(InstFlags::ACC_WRITE)) {
229             return Ins::ACCUMULATOR;
230         }
231         return {};
232     }
233 
IsValidToEmitIns234     bool IsValidToEmit() const
235     {
236         const auto invalidRegNum = 1U << MaxRegEncodingWidth();
237         for (auto reg : regs) {
238             if (reg >= invalidRegNum) {
239                 return false;
240             }
241         }
242         return true;
243     }
244 
HasDebugInfoIns245     bool HasDebugInfo() const
246     {
247         return insDebug.lineNumber != 0;
248     }
249 
250 private:
251     std::string OperandsToString(bool printArgs = false, size_t firstArgIdx = 0) const;
252     std::string RegsToString(bool &first, bool printArgs = false, size_t firstArgIdx = 0) const;
253     std::string ImmsToString(bool &first) const;
254     std::string IdsToString(bool &first) const;
255 
256     std::string IdToString(size_t idx, bool isFirst) const;
257     std::string ImmToString(size_t idx, bool isFirst) const;
258     std::string RegToString(size_t idx, bool isFirst, bool printArgs = false, size_t firstArgIdx = 0) const;
259 };
260 // NOLINTEND(misc-non-private-member-variables-in-classes)
261 
262 }  // namespace ark::pandasm
263 
264 #endif  // PANDA_ASSEMBLER_ASSEMBLY_INS_H
265