• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 panda::pandasm {
33 
34 enum class Opcode {
35 #define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs) opcode,
36     PANDA_INSTRUCTION_LIST(OPLIST)
37 #undef OPLIST
38         INVALID,
39     NUM_OPCODES = INVALID
40 };
41 
42 enum InstFlags {
43     NONE = 0,
44     JUMP = (1U << 0U),
45     COND = (1U << 1U),
46     CALL = (1U << 2U),
47     RETURN = (1U << 3U),
48     ACC_READ = (1U << 4U),
49     ACC_WRITE = (1U << 5U),
50     PSEUDO = (1U << 6U),
51     THROWING = (1U << 7U),
52     METHOD_ID = (1U << 8U),
53     FIELD_ID = (1U << 9U),
54     TYPE_ID = (1U << 10U),
55     STRING_ID = (1U << 11U),
56     LITERALARRAY_ID = (1U << 12U)
57 };
58 
59 enum class PrintKind { DEFAULT, CALL, CALLI };
60 
61 constexpr int INVALID_REG_IDX = -1;
62 constexpr size_t MAX_NUMBER_OF_SRC_REGS = 5;
63 constexpr size_t NUM_OPCODES = static_cast<size_t>(Opcode::NUM_OPCODES);
64 
65 constexpr InstFlags operator|(InstFlags a, InstFlags b)
66 {
67     using utype = std::underlying_type_t<InstFlags>;
68     return static_cast<InstFlags>(static_cast<utype>(a) | static_cast<utype>(b));
69 }
70 
71 #define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs) flags,
72 constexpr std::array<unsigned, NUM_OPCODES> INST_FLAGS_TABLE = {PANDA_INSTRUCTION_LIST(OPLIST)};
73 #undef OPLIST
74 
75 #define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs) width,
76 constexpr std::array<size_t, NUM_OPCODES> INST_WIDTH_TABLE = {PANDA_INSTRUCTION_LIST(OPLIST)};
77 #undef OPLIST
78 
79 #define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs) def_idx,
80 constexpr std::array<int, NUM_OPCODES> DEF_IDX_TABLE = {PANDA_INSTRUCTION_LIST(OPLIST)};
81 #undef OPLIST
82 
83 #define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs) use_idxs,
84 constexpr std::array<std::array<int, MAX_NUMBER_OF_SRC_REGS>, NUM_OPCODES> USE_IDXS_TABLE = {
85     PANDA_INSTRUCTION_LIST(OPLIST)};
86 #undef OPLIST
87 
88 struct Ins {
89     using IType = std::variant<int64_t, double>;
90 
91     constexpr static uint16_t ACCUMULATOR = -1;
92     constexpr static size_t MAX_CALL_SHORT_ARGS = 2;
93     constexpr static size_t MAX_CALL_ARGS = 4;
94     constexpr static uint16_t MAX_NON_RANGE_CALL_REG = 15;
95     constexpr static uint16_t MAX_RANGE_CALL_START_REG = 255;
96 
97     Opcode opcode = Opcode::INVALID; /* operation type */
98     std::vector<uint16_t> regs;      /* list of arguments - registers */
99     std::vector<std::string> ids;    /* list of arguments - identifiers */
100     std::vector<IType> imms;         /* list of arguments - immediates */
101     std::string label;               /* label at the beginning of a line */
102     bool set_label = false;          /* whether this label is defined */
103     debuginfo::Ins ins_debug;
104 
105     std::string ToString(std::string endline = "", bool print_args = false, size_t first_arg_idx = 0) const;
106 
107     bool Emit(BytecodeEmitter &emitter, panda_file::MethodItem *method,
108               const std::unordered_map<std::string, panda_file::BaseMethodItem *> &methods,
109               const std::unordered_map<std::string, panda_file::BaseFieldItem *> &fields,
110               const std::unordered_map<std::string, panda_file::BaseClassItem *> &classes,
111               const std::unordered_map<std::string_view, panda_file::StringItem *> &strings,
112               const std::unordered_map<std::string, panda_file::LiteralArrayItem *> &literalarrays,
113               const std::unordered_map<std::string_view, panda::Label> &labels) const;
114 
OperandListLengthIns115     size_t OperandListLength() const
116     {
117         return regs.size() + ids.size() + imms.size();
118     }
119 
HasFlagIns120     bool HasFlag(InstFlags flag) const
121     {
122         if (opcode == Opcode::INVALID) {
123             return false;
124         }
125         return (INST_FLAGS_TABLE[static_cast<size_t>(opcode)] & flag) != 0;
126     }
127 
CanThrowIns128     bool CanThrow() const
129     {
130         return HasFlag(InstFlags::THROWING) || HasFlag(InstFlags::METHOD_ID) || HasFlag(InstFlags::FIELD_ID) ||
131                HasFlag(InstFlags::TYPE_ID) || HasFlag(InstFlags::STRING_ID);
132     }
133 
IsJumpIns134     bool IsJump() const
135     {
136         return HasFlag(InstFlags::JUMP);
137     }
138 
IsConditionalJumpIns139     bool IsConditionalJump() const
140     {
141         return IsJump() && HasFlag(InstFlags::COND);
142     }
143 
IsCallIns144     bool IsCall() const
145     {  // Non-range call
146         return HasFlag(InstFlags::CALL);
147     }
148 
IsPseudoCallIns149     bool IsPseudoCall() const
150     {
151         return HasFlag(InstFlags::PSEUDO) && HasFlag(InstFlags::CALL);
152     }
153 
IsReturnIns154     bool IsReturn() const
155     {
156         return HasFlag(InstFlags::RETURN);
157     }
158 
MaxRegEncodingWidthIns159     size_t MaxRegEncodingWidth() const
160     {
161         if (opcode == Opcode::INVALID) {
162             return 0;
163         }
164         return INST_WIDTH_TABLE[static_cast<size_t>(opcode)];
165     }
166 
UsesIns167     std::vector<uint16_t> Uses() const
168     {
169         if (IsPseudoCall()) {
170             return regs;
171         }
172 
173         if (opcode == Opcode::INVALID) {
174             return {};
175         }
176 
177         auto use_idxs = USE_IDXS_TABLE[static_cast<size_t>(opcode)];
178         std::vector<uint16_t> res;
179         for (auto idx : use_idxs) {
180             if (HasFlag(InstFlags::ACC_READ)) {
181                 res.push_back(Ins::ACCUMULATOR);
182             }
183             if (idx != INVALID_REG_IDX) {
184                 ASSERT(static_cast<size_t>(idx) < regs.size());
185                 res.push_back(regs[idx]);
186             }
187         }
188         return res;
189     }
190 
DefIns191     std::optional<size_t> Def() const
192     {
193         if (opcode == Opcode::INVALID) {
194             return {};
195         }
196         auto def_idx = DEF_IDX_TABLE[static_cast<size_t>(opcode)];
197         if (def_idx != INVALID_REG_IDX) {
198             return regs[def_idx];
199         }
200         if (HasFlag(InstFlags::ACC_WRITE)) {
201             return Ins::ACCUMULATOR;
202         }
203         return {};
204     }
205 
IsValidToEmitIns206     bool IsValidToEmit() const
207     {
208         const auto INVALID_REG_NUM = 1U << MaxRegEncodingWidth();
209         for (auto reg : regs) {
210             if (reg >= INVALID_REG_NUM) {
211                 return false;
212             }
213         }
214         return true;
215     }
216 
HasDebugInfoIns217     bool HasDebugInfo() const
218     {
219         return ins_debug.line_number != 0;
220     }
221 
222 private:
223     std::string OperandsToString(PrintKind print_kind = PrintKind::DEFAULT, bool print_args = false,
224                                  size_t first_arg_idx = 0) const;
225     std::string RegsToString(bool &first, bool print_args = false, size_t first_arg_idx = 0) const;
226     std::string ImmsToString(bool &first) const;
227     std::string IdsToString(bool &first) const;
228 };
229 }  // namespace panda::pandasm
230 
231 #endif  // PANDA_ASSEMBLER_ASSEMBLY_INS_H_
232