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