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