chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file tvm/runtime/vm/bytecode.h
|
||||
* \brief The bytecode for the virtual machine.
|
||||
*/
|
||||
#ifndef TVM_RUNTIME_VM_BYTECODE_H_
|
||||
#define TVM_RUNTIME_VM_BYTECODE_H_
|
||||
|
||||
#include <tvm/ffi/dtype.h>
|
||||
#include <tvm/ffi/error.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
namespace tvm {
|
||||
namespace runtime {
|
||||
namespace vm {
|
||||
|
||||
/*!
|
||||
* \brief The storage type for the bytecode in the VM.
|
||||
*/
|
||||
using ExecWord = int64_t;
|
||||
|
||||
/*! \brief A register name. */
|
||||
using RegName = ExecWord;
|
||||
|
||||
/*!
|
||||
* \brief An alias for the integer type used ubiquitously in the VM.
|
||||
*/
|
||||
using Index = ExecWord;
|
||||
|
||||
/*!
|
||||
* \brief An enumeration of Relax's opcodes.
|
||||
*
|
||||
* The opcode is used to implement instruction
|
||||
* as a tagged union.
|
||||
*/
|
||||
enum class Opcode {
|
||||
Call = 1U,
|
||||
Ret = 2U,
|
||||
Goto = 3U,
|
||||
If = 4U,
|
||||
};
|
||||
|
||||
/*! \brief A single virtual machine instruction.
|
||||
*
|
||||
* The representation of the instruction is as
|
||||
* a tagged union.
|
||||
*
|
||||
* The first field represents which instruction,
|
||||
* and by extension which field of the union
|
||||
* is active.
|
||||
*/
|
||||
struct Instruction {
|
||||
/*! \brief The number of bit for storing value. */
|
||||
static constexpr ExecWord kKindBit = 8;
|
||||
/*! \brief The number of bit for storing value. */
|
||||
static constexpr ExecWord kValueBit = sizeof(ExecWord) * 8 - kKindBit;
|
||||
/*! \brief The bit mask of the value part. */
|
||||
static constexpr ExecWord kValueMask = (static_cast<ExecWord>(1) << kValueBit) - 1;
|
||||
/*! \brief Maximum possible value, use 1 bit for sign. */
|
||||
static constexpr ExecWord kValueMaxLimit = (static_cast<ExecWord>(1) << (kValueBit - 1)) - 1;
|
||||
/*! \brief Minimum possible value, remove 1 slot to keep things symmetric. */
|
||||
static constexpr ExecWord kValueMinLimit = -kValueMaxLimit;
|
||||
/*! \brief Beginning of special register section. */
|
||||
static constexpr RegName kBeginSpecialReg = static_cast<ExecWord>(1) << 54;
|
||||
/*! \brief Random magic number that represents void argument, indicate null value */
|
||||
static constexpr RegName kVoidRegister = kBeginSpecialReg + 0;
|
||||
/*! \brief Random magic number that represents the VM context */
|
||||
static constexpr RegName kVMRegister = kBeginSpecialReg + 1;
|
||||
/*!
|
||||
* \brief The kind of instruction's argument.
|
||||
*/
|
||||
enum class ArgKind : int { kRegister = 0, kImmediate = 1, kConstIdx = 2, kFuncIdx = 3 };
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const ArgKind& kind) {
|
||||
switch (kind) {
|
||||
case ArgKind::kRegister:
|
||||
os << "kRegister";
|
||||
break;
|
||||
case ArgKind::kImmediate:
|
||||
os << "kImmediate";
|
||||
break;
|
||||
case ArgKind::kConstIdx:
|
||||
os << "kConstIdx";
|
||||
break;
|
||||
case ArgKind::kFuncIdx:
|
||||
os << "kFuncIdx";
|
||||
break;
|
||||
default:
|
||||
TVM_FFI_THROW(InternalError)
|
||||
<< "Internal error: "
|
||||
<< "Invalid ArgKind with integer value " << static_cast<int>(kind);
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief The auxiliary data structure for instruction argument.
|
||||
*/
|
||||
class Arg {
|
||||
public:
|
||||
/*! \brief Construct a void argument. */
|
||||
Arg() : data_(Instruction::kVoidRegister) {}
|
||||
/*!
|
||||
* \brief construct Arg from data.
|
||||
* \param data The data repr.
|
||||
*/
|
||||
static Arg FromData(ExecWord data) { return Arg(data); }
|
||||
/*!
|
||||
* \brief construct a register Arg.
|
||||
* \param reg The register number.
|
||||
* \return The constructed arg.
|
||||
*/
|
||||
static Arg Register(RegName reg) { return Arg(ArgKind::kRegister, reg); }
|
||||
/*!
|
||||
* \brief construct a ConstIdx arg.
|
||||
* \param index The constant index.
|
||||
* \return The constructed arg.
|
||||
*/
|
||||
static Arg ConstIdx(Index index) { return Arg(ArgKind::kConstIdx, index); }
|
||||
/*!
|
||||
* \brief construct a immediate arg.
|
||||
* \param imm_value The immediate value.
|
||||
* \return The constructed arg.
|
||||
*/
|
||||
static Arg Immediate(int64_t imm_value) { return Arg(ArgKind::kImmediate, imm_value); }
|
||||
/*!
|
||||
* \brief construct a FuncIdx arg.
|
||||
* \param index The func index in the function table.
|
||||
* \return The constructed arg.
|
||||
*/
|
||||
static Arg FuncIdx(Index index) { return Arg(ArgKind::kFuncIdx, index); }
|
||||
/*!
|
||||
* \brief Get the kind of argument.
|
||||
* \return The kind of argument.
|
||||
*/
|
||||
ArgKind kind() const {
|
||||
uint8_t kind = (data_ >> kValueBit) & 0xFF;
|
||||
return Instruction::ArgKind(kind);
|
||||
}
|
||||
/*!
|
||||
* \brief Get the value of argument.
|
||||
* \return The value of argument.
|
||||
* \note We store both positive and negative values by sign extension.
|
||||
*/
|
||||
ExecWord value() const { return ((data_ & kValueMask) << kKindBit) >> kKindBit; }
|
||||
/*!
|
||||
* \brief Get the raw data repr of the arg.
|
||||
* \return The raw data.
|
||||
*/
|
||||
ExecWord data() const { return data_; }
|
||||
|
||||
private:
|
||||
/*! \brief Construct from the data. */
|
||||
explicit Arg(ExecWord data) : data_(data) {}
|
||||
/*! \brief Construct from the kind and value. */
|
||||
Arg(ArgKind kind, Index value) {
|
||||
TVM_FFI_ICHECK_LE(value, kValueMaxLimit);
|
||||
TVM_FFI_ICHECK_GE(value, kValueMinLimit);
|
||||
data_ = (static_cast<ExecWord>(kind) << kValueBit) | (value & kValueMask);
|
||||
}
|
||||
/*! \brief The underlying stored data. */
|
||||
ExecWord data_;
|
||||
};
|
||||
/*! \brief The instruction opcode. */
|
||||
Opcode op;
|
||||
union {
|
||||
struct /* Call */ {
|
||||
/*! \brief The destination register. */
|
||||
RegName dst;
|
||||
/*! \brief The index into the packed function table. */
|
||||
Index func_idx;
|
||||
/*! \brief The number of arguments to the packed function. */
|
||||
Index num_args;
|
||||
/*! \brief The arguments of the packed function. */
|
||||
Arg* args;
|
||||
};
|
||||
struct /* Ret */ {
|
||||
/*! \brief The return result. */
|
||||
RegName result;
|
||||
};
|
||||
struct /* Goto */ {
|
||||
/*! \brief The jump offset. */
|
||||
Index pc_offset;
|
||||
};
|
||||
struct /* If */ {
|
||||
/*! \brief The register containing the cond value. */
|
||||
RegName cond;
|
||||
/*! \brief The program counter offset for the false branch. */
|
||||
Index false_offset;
|
||||
};
|
||||
};
|
||||
/*!
|
||||
* \brief Construct a Call instruction.
|
||||
* \param func_idx The index of the function to call.
|
||||
* \param num_args The number of arguments.
|
||||
* \param args The input arguments.
|
||||
* \param dst The destination register.
|
||||
* \return The call instruction.
|
||||
*/
|
||||
static Instruction Call(Index func_idx, Index num_args, Arg* args, RegName dst);
|
||||
/*!
|
||||
* \brief Construct a return instruction.
|
||||
* \param result The register containing the return value.
|
||||
* \return The return instruction.
|
||||
*/
|
||||
static Instruction Ret(RegName result);
|
||||
/*!
|
||||
* \brief Construct a goto instruction.
|
||||
* \param pc_offset The register containing the jump offset.
|
||||
* \return The goto instruction.
|
||||
*/
|
||||
static Instruction Goto(RegName pc_offset);
|
||||
/*!
|
||||
* \brief Construct an If instruction.
|
||||
* \param cond The register containing the cond value.
|
||||
* \param false_offset The program counter offset for the false branch.
|
||||
* \return The If instruction.
|
||||
*/
|
||||
static Instruction If(RegName cond, Index false_offset);
|
||||
};
|
||||
|
||||
} // namespace vm
|
||||
} // namespace runtime
|
||||
} // namespace tvm
|
||||
|
||||
#endif // TVM_RUNTIME_VM_BYTECODE_H_
|
||||
Reference in New Issue
Block a user