diff options
| author | Yong He <yonghe@outlook.com> | 2025-04-28 11:42:22 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-04-28 11:42:22 -0700 |
| commit | c39c29bf4c52a85d7c83cc8b66ae45e265f9e078 (patch) | |
| tree | 969339828d49d7db92ed9294a17bd34cc021db84 /source/slang/slang-vm-bytecode.h | |
| parent | 8f6c6e333c06ae1c3b9f00396563c14a2ae09b4d (diff) | |
Add Slang Byte Code generation and interpreter. (#6896)
* Add Slang Byte Code generation and interpreter.
* Fix compile issues.
* format code
* More compile fix.
* Fix clang issue.
* Fix more clang issues.
* Another clang fix.
* Fix clang issues.
* Fix another clang issue.
* Fix wasm build.
* Update building.md
* Fix test-server.
* Fix compile error.
* Fix bug.
---------
Co-authored-by: slangbot <186143334+slangbot@users.noreply.github.com>
Diffstat (limited to 'source/slang/slang-vm-bytecode.h')
| -rw-r--r-- | source/slang/slang-vm-bytecode.h | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/source/slang/slang-vm-bytecode.h b/source/slang/slang-vm-bytecode.h new file mode 100644 index 000000000..5d030ee3a --- /dev/null +++ b/source/slang/slang-vm-bytecode.h @@ -0,0 +1,259 @@ +#ifndef SLANG_VM_BYTE_CODE_H +#define SLANG_VM_BYTE_CODE_H + +#include "core/slang-basic.h" +#include "core/slang-riff.h" +#include "slang-com-ptr.h" + +namespace Slang +{ + +/* +Slang ByteCode Module File Format + +# Header + - (4 bytes) FourCC: 'S', 'V', 'M', 'C' (kSlangByteCodeFourCC) + - (4 bytes uint) Version: 100 + +# Function Section + - (4 bytes) FourCC: 'S', 'V', 'F', 'N' (kSlangByteCodeFunctionsFourCC) + - (4 bytes uint) Function Count: number of functions in the module + - (uint array) Function Offsets: + array of "Function Count" 32-bit uints, storing byte offsets from + start of file for each function. + +## Function i: + - (32 bytes `VMFuncHeader`) Function metadata, describing the name and other + info needed for execution. VMFuncHeader::name is a `VMOperand` whose + sectionId = kSlangByteCodeSectionConstants, pointing to the constant section for the + function name. + - (uint32 * parameterCount array): array of "parameterCount" 32-bit uints, storing byte offsets + from start of the function's working set for each parameter. + - (byte array) Code: array of `header.codeSize` bytes, containing the instruction stream for the + function. Each instruction starts with a `VMInstHeader`, followed by + `VMInstHeader::operandCount` `VMOperand` structs. + +# Kernel Blob Section: binary data for the kernel blob + - (4 bytes) FourCC: 'S', 'V', 'K', 'N' (kSlangByteCodeKernelBlobFourCC) + - (4 bytes uint) Kernel Blob Size: size of the kernel blob in bytes. + - (byte array) Kernel Blob: array of "Kernel Blob Size" bytes, containing the kernel blob data. + +# Constants Section + - (4 bytes) FourCC: 'S', 'V', 'C', 'S' (kSlangByteCodeConstantsFourCC) + - (4 bytes uint) Constant Count: number of constants in the module. + - (4 bytes uint) String Count: number of string literals in the constant section. + - (uint array) String offsets: array of "String Count" 32-bit uints, storing byte offsets from + start of the constant array blob (next item) for each string literal. + - (uint array) Constants: + array of "Constant Count" 32-bit uints, storing byte offsets from + start of file for each constant. +*/ + +static const int kSlangByteCodeVersion = 100; + +static const uint32_t kSlangByteCodeFourCC = SLANG_FOUR_CC('S', 'V', 'M', 'C'); +static const uint32_t kSlangByteCodeFunctionsFourCC = SLANG_FOUR_CC('S', 'V', 'F', 'N'); +static const uint32_t kSlangByteCodeKernelBlobFourCC = SLANG_FOUR_CC('S', 'V', 'K', 'N'); +static const uint32_t kSlangByteCodeConstantsFourCC = SLANG_FOUR_CC('S', 'V', 'C', 'S'); + +static const int kSlangByteCodeSectionWorkingSet = 0; +static const int kSlangByteCodeSectionConstants = 1; +static const int kSlangByteCodeSectionInsts = 2; +static const int kSlangByteCodeSectionImmediate = 3; +static const int kSlangByteCodeSectionFuncs = 4; +static const int kSlangByteCodeSectionStrings = 5; + + +enum class VMOp : uint32_t +{ + Nop, + Add, + Sub, + Mul, + Div, + Rem, + Neg, + And, + Or, + Not, + BitAnd, + BitOr, + BitNot, + BitXor, + Shl, + Shr, + Ret, + Less, + Leq, + Greater, + Geq, + Equal, + Neq, + Jump, + JumpIf, + Dispatch, + Load, + Store, + Copy, + GetWorkingSetPtr, + GetElementPtr, + OffsetPtr, + GetElement, + Swizzle, + Cast, + CallExt, + Call, + Print, +}; + +// Represents an operand in the VM bytecode. +// It consists of a section ID and a byte offset within that section. +struct VMOperand +{ + uint32_t sectionId; + uint32_t padding; // Padding to ensure section takes 8 bytes. sectionId will be replaced + // with actual pointers before execution. + uint32_t type : 8; // type of the operand data. + uint32_t size : 24; + uint32_t offset; + slang::OperandDataType getType() const { return slang::OperandDataType(type); } + void setType(slang::OperandDataType newType) { type = uint32_t(newType); } +}; + +struct VMInstHeader +{ + VMOp opcode; + uint32_t padding; // 32-bit padding, to ensure space are reserved to store function pointers for + // the opcode. + uint32_t opcodeExtension; + uint32_t operandCount; + VMOperand& getOperand(Index index) const { return *((VMOperand*)(this + 1) + index); } +}; + +struct VMFuncHeader +{ + VMOperand name; // Name of the function as a VMOperand, pointing to the constant section. + uint32_t workingSetSizeInBytes; // Size of the working set in bytes. + uint32_t codeSize; // Size of the code in bytes. + uint32_t parameterCount; // Number of parameters for the function. + uint32_t returnValueSizeInBytes; // Size of the return value in bytes. + uint32_t parameterSizeInBytes; // Size of the parameters in bytes. + uint32_t getParameterOffset(Index index) const { return *((uint32_t*)(this + 1) + index); } + uint8_t* getCode() const { return (uint8_t*)(this + 1) + parameterCount * sizeof(uint32_t); } +}; + +static const int kSlangByteCodeScalarTypeSignedInt = 0; +static const int kSlangByteCodeScalarTypeUnsignedInt = 1; +static const int kSlangByteCodeScalarTypeFloat = 2; + +struct ArithmeticExtCode +{ + uint32_t scalarType : 2; // 0: signed int, 1: unsigned int, 2: floating-point + uint32_t scalarBitWidth : 2; // 0: 8, 1: 16, 2: 32, 3: 64 + uint32_t vectorSize : 12; // number of elements in the vector. + uint32_t unused : 16; +}; + +template<typename TOperand, typename TInstHeader> +struct VMInstIterator +{ + uint8_t* codePtr; // Pointer to the current instruction. + + void moveNext() + { + // Read the instruction header + TInstHeader header; + memcpy(&header, codePtr, sizeof(header)); + codePtr += sizeof(header); + + // Calculate the size of operand list. + auto operandListSize = header.operandCount * sizeof(TOperand); + + // Advance the code pointer by the size of the header and operand list. + codePtr += operandListSize; + } + + VMInstIterator& operator++() + { + moveNext(); + return *this; + } + VMInstIterator operator++(int) + { + VMInstIterator rs = *this; + rs.moveNext(); + return rs; + } + + bool operator!=(const VMInstIterator& iter) const { return codePtr != iter.codePtr; } + bool operator==(const VMInstIterator& iter) const { return codePtr == iter.codePtr; } + TInstHeader* operator*() const { return reinterpret_cast<TInstHeader*>(codePtr); } +}; + +struct VMModuleView; + +struct VMFunctionView +{ + const char* name = nullptr; + VMFuncHeader* header; // Function header containing metadata. + uint32_t* paramOffsets; + uint8_t* functionCode; // Pointer to the function code. + uint8_t* functionCodeEnd; // Pointer to the end of the function code. + VMModuleView* moduleView; // Pointer to start of the module. + VMInstIterator<VMOperand, VMInstHeader> begin() const + { + VMInstIterator<VMOperand, VMInstHeader> iter; + iter.codePtr = functionCode; + return iter; + } + + VMInstIterator<VMOperand, VMInstHeader> end() const + { + VMInstIterator<VMOperand, VMInstHeader> iter; + iter.codePtr = functionCodeEnd; + return iter; + } +}; + +struct VMModuleView +{ + uint8_t* code; + uint32_t functionCount; + uint32_t* functionOffsets; + uint8_t* constants; + uint32_t constantBlobSize; + uint32_t stringCount; + uint32_t* stringOffsets; // Offsets to string literals in the constant section. + uint8_t* kernelBlob; + uint32_t kernelBlobSize; + + List<VMFunctionView> functionViews; + + VMFunctionView getFunction(Index index) const; + + template<typename T> + SlangResult getConstant(VMOperand operand, T& outValue) const + { + if (operand.sectionId != kSlangByteCodeSectionConstants) + { + return SLANG_FAIL; // Invalid section + } + if (operand.offset + sizeof(T) > constantBlobSize) + { + return SLANG_FAIL; // Out of bounds + } + memcpy(&outValue, constants + operand.offset, sizeof(T)); + return SLANG_OK; + } +}; + +SlangResult initVMModule(uint8_t* code, uint32_t codeSize, VMModuleView* moduleView); + +StringBuilder& operator<<(StringBuilder& sb, VMOp op); +StringBuilder& operator<<(StringBuilder& sb, VMModuleView& module); +void printVMInst(StringBuilder& sb, VMModuleView* moduleView, VMInstHeader* inst); + +} // namespace Slang + + +#endif |
