mirror of
https://gitee.com/openharmony/arkcompiler_runtime_core
synced 2025-04-12 23:50:55 +00:00
244 lines
7.5 KiB
C++
244 lines
7.5 KiB
C++
/**
|
|
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#ifndef ASSEMBLER_ASSEMBLY_INS_H
|
|
#define ASSEMBLER_ASSEMBLY_INS_H
|
|
|
|
#include <array>
|
|
#include <string>
|
|
#include <string_view>
|
|
#include <unordered_map>
|
|
#include <variant>
|
|
#include <vector>
|
|
|
|
#include "assembly-debug.h"
|
|
#include "bytecode_emitter.h"
|
|
#include "file_items.h"
|
|
#include "isa.h"
|
|
#include "lexer.h"
|
|
|
|
namespace panda::pandasm {
|
|
|
|
enum class Opcode {
|
|
#define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs) opcode,
|
|
PANDA_INSTRUCTION_LIST(OPLIST)
|
|
#undef OPLIST
|
|
INVALID,
|
|
NUM_OPCODES = INVALID
|
|
};
|
|
|
|
enum InstFlags {
|
|
NONE = 0,
|
|
JUMP = (1U << 0U),
|
|
COND = (1U << 1U),
|
|
CALL = (1U << 2U),
|
|
RETURN = (1U << 3U),
|
|
ACC_READ = (1U << 4U),
|
|
ACC_WRITE = (1U << 5U),
|
|
PSEUDO = (1U << 6U),
|
|
THROWING = (1U << 7U),
|
|
METHOD_ID = (1U << 8U),
|
|
FIELD_ID = (1U << 9U),
|
|
TYPE_ID = (1U << 10U),
|
|
STRING_ID = (1U << 11U),
|
|
LITERALARRAY_ID = (1U << 12U),
|
|
CALL_RANGE = (1U << 13U)
|
|
};
|
|
|
|
constexpr int INVALID_REG_IDX = -1;
|
|
|
|
constexpr size_t MAX_NUMBER_OF_SRC_REGS = 4; // TODO(mbolshov): auto-generate
|
|
|
|
constexpr InstFlags operator|(InstFlags a, InstFlags b)
|
|
{
|
|
using utype = std::underlying_type_t<InstFlags>;
|
|
return static_cast<InstFlags>(static_cast<utype>(a) | static_cast<utype>(b));
|
|
}
|
|
|
|
#define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs) flags,
|
|
constexpr std::array<unsigned, static_cast<size_t>(Opcode::NUM_OPCODES)> INST_FLAGS_TABLE = {
|
|
PANDA_INSTRUCTION_LIST(OPLIST)};
|
|
#undef OPLIST
|
|
|
|
#define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs) width,
|
|
constexpr std::array<size_t, static_cast<size_t>(Opcode::NUM_OPCODES)> INST_WIDTH_TABLE = {
|
|
PANDA_INSTRUCTION_LIST(OPLIST)};
|
|
#undef OPLIST
|
|
|
|
#define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs) def_idx,
|
|
constexpr std::array<int, static_cast<size_t>(Opcode::NUM_OPCODES)> DEF_IDX_TABLE = {PANDA_INSTRUCTION_LIST(OPLIST)};
|
|
#undef OPLIST
|
|
|
|
#define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs) use_idxs,
|
|
// clang-format off
|
|
constexpr std::array<std::array<int, MAX_NUMBER_OF_SRC_REGS>,
|
|
static_cast<size_t>(Opcode::NUM_OPCODES)> USE_IDXS_TABLE = {PANDA_INSTRUCTION_LIST(OPLIST)};
|
|
// clang-format on
|
|
#undef OPLIST
|
|
|
|
struct Ins {
|
|
using IType = std::variant<int64_t, double>;
|
|
|
|
constexpr static uint16_t ACCUMULATOR = -1;
|
|
constexpr static size_t MAX_CALL_SHORT_ARGS = 2;
|
|
constexpr static size_t MAX_CALL_ARGS = 4;
|
|
constexpr static uint16_t MAX_NON_RANGE_CALL_REG = 15;
|
|
constexpr static uint16_t MAX_RANGE_CALL_START_REG = 255;
|
|
|
|
Opcode opcode = Opcode::INVALID; /* operation type */
|
|
std::vector<uint16_t> regs; /* list of arguments - registers */
|
|
std::vector<std::string> ids; /* list of arguments - identifiers */
|
|
std::vector<IType> imms; /* list of arguments - immediates */
|
|
std::string label; /* label at the beginning of a line */
|
|
bool set_label = false; /* whether this label is defined */
|
|
debuginfo::Ins ins_debug;
|
|
|
|
std::string ToString(std::string endline = "", bool print_args = false, size_t first_arg_idx = 0) const;
|
|
|
|
bool Emit(BytecodeEmitter &emitter, panda_file::MethodItem *method,
|
|
const std::unordered_map<std::string, panda_file::BaseMethodItem *> &methods,
|
|
const std::unordered_map<std::string, panda_file::BaseFieldItem *> &fields,
|
|
const std::unordered_map<std::string, panda_file::BaseClassItem *> &classes,
|
|
const std::unordered_map<std::string, panda_file::StringItem *> &strings,
|
|
const std::unordered_map<std::string, panda_file::LiteralArrayItem *> &literalarrays,
|
|
const std::unordered_map<std::string_view, panda::Label> &labels) const;
|
|
|
|
size_t OperandListLength() const
|
|
{
|
|
return regs.size() + ids.size() + imms.size();
|
|
}
|
|
|
|
bool HasFlag(InstFlags flag) const
|
|
{
|
|
if (opcode == Opcode::INVALID) { // TODO(mbolshov): introduce 'label' opcode for labels
|
|
return false;
|
|
}
|
|
return (INST_FLAGS_TABLE[static_cast<size_t>(opcode)] & flag) != 0;
|
|
}
|
|
|
|
bool CanThrow() const
|
|
{
|
|
return HasFlag(InstFlags::THROWING) || HasFlag(InstFlags::METHOD_ID) || HasFlag(InstFlags::FIELD_ID) ||
|
|
HasFlag(InstFlags::TYPE_ID) || HasFlag(InstFlags::STRING_ID);
|
|
}
|
|
|
|
bool IsJump() const
|
|
{
|
|
return HasFlag(InstFlags::JUMP);
|
|
}
|
|
|
|
bool IsConditionalJump() const
|
|
{
|
|
return IsJump() && HasFlag(InstFlags::COND);
|
|
}
|
|
|
|
bool IsCall() const
|
|
{ // Non-range call
|
|
return HasFlag(InstFlags::CALL);
|
|
}
|
|
|
|
bool IsCallRange() const
|
|
{ // Range call
|
|
return HasFlag(InstFlags::CALL_RANGE);
|
|
}
|
|
|
|
bool IsPseudoCall() const
|
|
{
|
|
return HasFlag(InstFlags::PSEUDO) && HasFlag(InstFlags::CALL);
|
|
}
|
|
|
|
bool IsReturn() const
|
|
{
|
|
return HasFlag(InstFlags::RETURN);
|
|
}
|
|
|
|
size_t MaxRegEncodingWidth() const
|
|
{
|
|
if (opcode == Opcode::INVALID) {
|
|
return 0;
|
|
}
|
|
return INST_WIDTH_TABLE[static_cast<size_t>(opcode)];
|
|
}
|
|
|
|
std::vector<uint16_t> Uses() const
|
|
{
|
|
if (IsPseudoCall()) {
|
|
return regs;
|
|
}
|
|
|
|
if (opcode == Opcode::INVALID) {
|
|
return {};
|
|
}
|
|
|
|
auto use_idxs = USE_IDXS_TABLE[static_cast<size_t>(opcode)];
|
|
std::vector<uint16_t> res(MAX_NUMBER_OF_SRC_REGS + 1);
|
|
if (HasFlag(InstFlags::ACC_READ)) {
|
|
res.push_back(Ins::ACCUMULATOR);
|
|
}
|
|
for (auto idx : use_idxs) {
|
|
if (idx == INVALID_REG_IDX) {
|
|
break;
|
|
}
|
|
ASSERT(static_cast<size_t>(idx) < regs.size());
|
|
res.emplace_back(regs[idx]);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
std::optional<size_t> Def() const
|
|
{
|
|
if (opcode == Opcode::INVALID) {
|
|
return {};
|
|
}
|
|
auto def_idx = DEF_IDX_TABLE[static_cast<size_t>(opcode)];
|
|
if (def_idx != INVALID_REG_IDX) {
|
|
return regs[def_idx];
|
|
}
|
|
if (HasFlag(InstFlags::ACC_WRITE)) {
|
|
return Ins::ACCUMULATOR;
|
|
}
|
|
return {};
|
|
}
|
|
|
|
bool IsValidToEmit() const
|
|
{
|
|
const auto INVALID_REG_NUM = 1U << MaxRegEncodingWidth();
|
|
for (auto reg : regs) {
|
|
if (reg >= INVALID_REG_NUM) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool HasDebugInfo() const
|
|
{
|
|
return ins_debug.line_number != 0;
|
|
}
|
|
|
|
private:
|
|
std::string OperandsToString(bool print_args = false, size_t first_arg_idx = 0) const;
|
|
std::string RegsToString(bool &first, bool print_args = false, size_t first_arg_idx = 0) const;
|
|
std::string ImmsToString(bool &first) const;
|
|
std::string IdsToString(bool &first) const;
|
|
|
|
std::string IdToString(size_t idx, bool is_first) const;
|
|
std::string ImmToString(size_t idx, bool is_first) const;
|
|
std::string RegToString(size_t idx, bool is_first, bool print_args = false, size_t first_arg_idx = 0) const;
|
|
};
|
|
} // namespace panda::pandasm
|
|
|
|
#endif // ASSEMBLER_ASSEMBLY_INS_H
|