• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 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 ASSEMBLER_ASSEMBLY_INS_H
17 #define 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     CALL_RANGE = (1U << 13U)
58 };
59 
60 constexpr int INVALID_REG_IDX = -1;
61 
62 constexpr size_t MAX_NUMBER_OF_SRC_REGS = 4;  // TODO(mbolshov): auto-generate
63 
64 constexpr InstFlags operator|(InstFlags a, InstFlags b)
65 {
66     using utype = std::underlying_type_t<InstFlags>;
67     return static_cast<InstFlags>(static_cast<utype>(a) | static_cast<utype>(b));
68 }
69 
70 #define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs) flags,
71 constexpr std::array<unsigned, static_cast<size_t>(Opcode::NUM_OPCODES)> INST_FLAGS_TABLE = {
72     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, static_cast<size_t>(Opcode::NUM_OPCODES)> INST_WIDTH_TABLE = {
77     PANDA_INSTRUCTION_LIST(OPLIST)};
78 #undef OPLIST
79 
80 #define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs) def_idx,
81 constexpr std::array<int, static_cast<size_t>(Opcode::NUM_OPCODES)> DEF_IDX_TABLE = {PANDA_INSTRUCTION_LIST(OPLIST)};
82 #undef OPLIST
83 
84 #define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs) use_idxs,
85 // clang-format off
86 constexpr std::array<std::array<int, MAX_NUMBER_OF_SRC_REGS>, static_cast<size_t>(Opcode::NUM_OPCODES)> USE_IDXS_TABLE = {
87     PANDA_INSTRUCTION_LIST(OPLIST)};
88 // clang-format on
89 #undef OPLIST
90 
91 struct Ins {
92     using IType = std::variant<int64_t, double>;
93 
94     constexpr static uint16_t ACCUMULATOR = -1;
95     constexpr static size_t MAX_CALL_SHORT_ARGS = 2;
96     constexpr static size_t MAX_CALL_ARGS = 4;
97     constexpr static uint16_t MAX_NON_RANGE_CALL_REG = 15;
98     constexpr static uint16_t MAX_RANGE_CALL_START_REG = 255;
99 
100     Opcode opcode = Opcode::INVALID; /* operation type */
101     std::vector<uint16_t> regs;      /* list of arguments - registers */
102     std::vector<std::string> ids;    /* list of arguments - identifiers */
103     std::vector<IType> imms;         /* list of arguments - immediates */
104     std::string label;               /* label at the beginning of a line */
105     bool set_label = false;          /* whether this label is defined */
106     debuginfo::Ins ins_debug;
107 
108     std::string ToString(std::string endline = "", bool print_args = false, size_t first_arg_idx = 0) const;
109 
110     bool Emit(BytecodeEmitter &emitter, panda_file::MethodItem *method,
111               const std::unordered_map<std::string, panda_file::BaseMethodItem *> &methods,
112               const std::unordered_map<std::string, panda_file::BaseFieldItem *> &fields,
113               const std::unordered_map<std::string, panda_file::BaseClassItem *> &classes,
114               const std::unordered_map<std::string, panda_file::StringItem *> &strings,
115               const std::unordered_map<std::string, panda_file::LiteralArrayItem *> &literalarrays,
116               const std::unordered_map<std::string_view, panda::Label> &labels) const;
117 
OperandListLengthIns118     size_t OperandListLength() const
119     {
120         return regs.size() + ids.size() + imms.size();
121     }
122 
HasFlagIns123     bool HasFlag(InstFlags flag) const
124     {
125         if (opcode == Opcode::INVALID) {  // TODO(mbolshov): introduce 'label' opcode for labels
126             return false;
127         }
128         return (INST_FLAGS_TABLE[static_cast<size_t>(opcode)] & flag) != 0;
129     }
130 
CanThrowIns131     bool CanThrow() const
132     {
133         return HasFlag(InstFlags::THROWING) || HasFlag(InstFlags::METHOD_ID) || HasFlag(InstFlags::FIELD_ID) ||
134                HasFlag(InstFlags::TYPE_ID) || HasFlag(InstFlags::STRING_ID);
135     }
136 
IsJumpIns137     bool IsJump() const
138     {
139         return HasFlag(InstFlags::JUMP);
140     }
141 
IsConditionalJumpIns142     bool IsConditionalJump() const
143     {
144         return IsJump() && HasFlag(InstFlags::COND);
145     }
146 
IsCallIns147     bool IsCall() const
148     {  // Non-range call
149         return HasFlag(InstFlags::CALL);
150     }
151 
IsCallRangeIns152     bool IsCallRange() const
153     {  // Range call
154         return HasFlag(InstFlags::CALL_RANGE);
155     }
156 
IsPseudoCallIns157     bool IsPseudoCall() const
158     {
159         return HasFlag(InstFlags::PSEUDO) && HasFlag(InstFlags::CALL);
160     }
161 
IsReturnIns162     bool IsReturn() const
163     {
164         return HasFlag(InstFlags::RETURN);
165     }
166 
MaxRegEncodingWidthIns167     size_t MaxRegEncodingWidth() const
168     {
169         if (opcode == Opcode::INVALID) {
170             return 0;
171         }
172         return INST_WIDTH_TABLE[static_cast<size_t>(opcode)];
173     }
174 
UsesIns175     std::vector<uint16_t> Uses() const
176     {
177         if (IsPseudoCall()) {
178             return regs;
179         }
180 
181         if (opcode == Opcode::INVALID) {
182             return {};
183         }
184 
185         auto use_idxs = USE_IDXS_TABLE[static_cast<size_t>(opcode)];
186         std::vector<uint16_t> res(MAX_NUMBER_OF_SRC_REGS + 1);
187         if (HasFlag(InstFlags::ACC_READ)) {
188             res.push_back(Ins::ACCUMULATOR);
189         }
190         for (auto idx : use_idxs) {
191             if (idx == INVALID_REG_IDX) {
192                 break;
193             }
194             ASSERT(static_cast<size_t>(idx) < regs.size());
195             res.emplace_back(regs[idx]);
196         }
197         return res;
198     }
199 
DefIns200     std::optional<size_t> Def() const
201     {
202         if (opcode == Opcode::INVALID) {
203             return {};
204         }
205         auto def_idx = DEF_IDX_TABLE[static_cast<size_t>(opcode)];
206         if (def_idx != INVALID_REG_IDX) {
207             return regs[def_idx];
208         }
209         if (HasFlag(InstFlags::ACC_WRITE)) {
210             return Ins::ACCUMULATOR;
211         }
212         return {};
213     }
214 
IsValidToEmitIns215     bool IsValidToEmit() const
216     {
217         const auto INVALID_REG_NUM = 1U << MaxRegEncodingWidth();
218         for (auto reg : regs) {
219             if (reg >= INVALID_REG_NUM) {
220                 return false;
221             }
222         }
223         return true;
224     }
225 
HasDebugInfoIns226     bool HasDebugInfo() const
227     {
228         return ins_debug.line_number != 0;
229     }
230 
231 private:
232     std::string OperandsToString(bool print_args = false, size_t first_arg_idx = 0) const;
233     std::string RegsToString(bool &first, bool print_args = false, size_t first_arg_idx = 0) const;
234     std::string ImmsToString(bool &first) const;
235     std::string IdsToString(bool &first) const;
236 
237     std::string IdToString(size_t idx, bool is_first) const;
238     std::string ImmToString(size_t idx, bool is_first) const;
239     std::string RegToString(size_t idx, bool is_first, bool print_args = false, size_t first_arg_idx = 0) const;
240 };
241 }  // namespace panda::pandasm
242 
243 #endif  // ASSEMBLER_ASSEMBLY_INS_H
244