summaryrefslogtreecommitdiffstats
path: root/source/slang/slang-vm-bytecode.h
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2025-04-28 11:42:22 -0700
committerGitHub <noreply@github.com>2025-04-28 11:42:22 -0700
commitc39c29bf4c52a85d7c83cc8b66ae45e265f9e078 (patch)
tree969339828d49d7db92ed9294a17bd34cc021db84 /source/slang/slang-vm-bytecode.h
parent8f6c6e333c06ae1c3b9f00396563c14a2ae09b4d (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.h259
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