summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
authorTim Foley <tfoleyNV@users.noreply.github.com>2018-12-10 12:42:15 -0800
committerGitHub <noreply@github.com>2018-12-10 12:42:15 -0800
commitb2997170df7cc2703de714a946a38dc35058e7f8 (patch)
treebbd19208ba07a2f45a2c25f28f6cf77be16f0b49 /source
parent32f57c30cfce1681f5fe617e4fe230e88eb7b840 (diff)
Remove the "VM" and "bytecode" features (#745)
* Remove the "VM" and "bytecode" features The "bytecode" in `bc.{h,cpp}` was an initial attempt at a serialized encoding for the Slang IR, but we now have the `ir-serialize.{h,cpp}` approach which was has been kept up to date much better. Similarly, the "VM" in `vm.{h,cpp}` was intended to be a system for interpreting Slang code in the bytecode format directly (so that you could load and evaluate code in a Slang module in a lightweight fashion). This never got used past a single test, which we eventually disabled. There are good ideas in some of this code, but at this point the implementations have bit-rotted to a point where trying to maintain it is more costly than it would be to re-created it if/when we ever decide these features are important again. * fixup: remove slang-eval-test from Makefile
Diffstat (limited to 'source')
-rw-r--r--source/slang/bytecode.cpp1071
-rw-r--r--source/slang/bytecode.h253
-rw-r--r--source/slang/compiler.cpp13
-rw-r--r--source/slang/ir.cpp15
-rw-r--r--source/slang/slang.vcxproj4
-rw-r--r--source/slang/slang.vcxproj.filters14
-rw-r--r--source/slang/vm.cpp1180
-rw-r--r--source/slang/vm.h19
8 files changed, 15 insertions, 2554 deletions
diff --git a/source/slang/bytecode.cpp b/source/slang/bytecode.cpp
deleted file mode 100644
index 7ceb06cdc..000000000
--- a/source/slang/bytecode.cpp
+++ /dev/null
@@ -1,1071 +0,0 @@
-#include "bytecode.h"
-
-// Implementation of the Slang bytecode (BC)
-// (most notably including conversion from IR to BC)
-
-#include "compiler.h"
-#include "ir.h"
-#include "ir-insts.h"
-#include "lower-to-ir.h"
-
-namespace Slang
-{
-struct SharedBytecodeGenerationContext;
-
-// Representation of a `BCPtr<T>` during actual bytecode generation.
-// This representation is to deal with the fact that the actual
-// storage for the bytecode data might get reallocated during emission
-// so that we need to be careful and not work with raw `BCPtr<T>`.
-template<typename T>
-struct BytecodeGenerationPtr
-{
- UInt offset;
- SharedBytecodeGenerationContext* sharedContext;
-
- BytecodeGenerationPtr()
- : sharedContext(nullptr)
- , offset(0)
- {}
-
-
- BytecodeGenerationPtr(
- SharedBytecodeGenerationContext* sharedContext,
- UInt offset)
- : sharedContext(sharedContext)
- , offset(offset)
- {}
-
- BytecodeGenerationPtr(
- BytecodeGenerationPtr<T> const& ptr)
- : sharedContext(ptr.sharedContext)
- , offset(ptr.offset)
- {}
-
- template<typename U>
- BytecodeGenerationPtr(
- BytecodeGenerationPtr<U> const& ptr,
- typename EnableIf<IsConvertible<T*, U*>::Value, void>::type * = 0)
- : sharedContext(ptr.sharedContext)
- , offset(ptr.offset)
- {}
-
- template<typename U>
- BytecodeGenerationPtr<U> bitCast() const
- {
- return BytecodeGenerationPtr<U>(sharedContext, offset);
- }
-
- operator BCPtr<T>() const
- {
- return BCPtr<T>(getPtr());
- }
-
- T* operator->() const
- {
- return getPtr();
- }
-
- T& operator*() const
- {
- return *getPtr();
- }
-
- T& operator[](UInt index) const
- {
- return getPtr()[index];
- }
-
- BytecodeGenerationPtr<T> operator+(Int index) const
- {
- Int delta = index * sizeof(T);
- UInt newOffset = offset + delta;
- return BytecodeGenerationPtr<T>(
- sharedContext,
- newOffset);
- }
-
- T* getPtr() const;
-};
-
-#if 0
-template<typename T>
-void BCPtr<T>::operator=(BytecodeGenerationPtr<T> const& ptr)
-{
- fprintf(stderr, "0x%p: operator=BGP 0x%p\n", this, ptr.getPtr());
- *this = ptr.getPtr();
-}
-#endif
-
-struct SharedBytecodeGenerationContext
-{
- // The final generated bytecode stream
- List<uint8_t> bytecode;
-
- // Map from an IR value to a global entity
- // that encodes it:
- Dictionary<IRInst*, BCConst> mapValueToGlobal;
-
- // Types that have been emitted
- List<BytecodeGenerationPtr<BCType>> bcTypes;
- Dictionary<IRType*, UInt> mapTypeToID;
-
- // Compile-time constant values that need
- // to be emitted...
- List<IRInst*> constants;
-};
-
-struct BytecodeGenerationContext
-{
- SharedBytecodeGenerationContext* shared;
-
- // The bytecode of the current symbol being
- // output.
- List<uint8_t> currentBytecode;
-
- // The function that is in scope for this context
- IRFunc* currentIRFunc;
-
- // Counter for global symbols that have been assigned
- // so that they can be used by this function
- List<BCConst> remappedGlobalSymbols;
-
- // Map an instruction to its ID for use local
- // to the current context
- Dictionary<IRInst*, Int> mapInstToLocalID;
-};
-
-template<typename T>
-T* BytecodeGenerationPtr<T>::getPtr() const
-{
- if(!sharedContext) return nullptr;
- return (T*)(sharedContext->bytecode.Buffer() + offset);
-}
-
-
-BCPtr<void>::RawVal allocateRaw(
- BytecodeGenerationContext* context,
- size_t size,
- size_t alignment)
-{
- size_t currentOffset = context->shared->bytecode.Count();
-
- size_t beginOffset = (currentOffset + (alignment-1)) & ~(alignment-1);
-
- size_t endOffset = beginOffset + size;
-
- for(size_t ii = currentOffset; ii < endOffset; ++ii)
- context->shared->bytecode.Add(0);
-
- return (BCPtr<void>::RawVal)beginOffset;
-}
-
-template<typename T>
-BytecodeGenerationPtr<T> allocate(
- BytecodeGenerationContext* context)
-{
- return BytecodeGenerationPtr<T>(context->shared, allocateRaw(context, sizeof(T), alignof(T)));
-}
-
-template<typename T>
-BytecodeGenerationPtr<T> allocateArray(
- BytecodeGenerationContext* context,
- UInt count)
-{
- return BytecodeGenerationPtr<T>(context->shared, allocateRaw(context, count * sizeof(T), alignof(T)));
-}
-
-template<typename T>
-BytecodeGenerationPtr<T> getPtr(
- BytecodeGenerationContext* context)
-{
- return BytecodeGenerationPtr<T>(context->shared, context->shared->bytecode.Count());
-}
-
-
-void encodeUInt8(
- BytecodeGenerationContext* context,
- uint8_t value)
-{
- context->currentBytecode.Add(value);
-}
-
-void encodeUInt(
- BytecodeGenerationContext* context,
- UInt value)
-{
- if( value < 128 )
- {
- encodeUInt8(context, (uint8_t)value);
- return;
- }
-
- uint8_t bytes[16];
- UInt count = 0;
-
- for(;;)
- {
- UInt index = count++;
- bytes[index] = value & 0x7F;
- value = value >> 7;
- if (!value)
- break;
-
- bytes[index] |= 0x80;
- }
-
- UInt index = count;
- while (index--)
- {
- encodeUInt8(context, bytes[index]);
- }
-}
-
-void encodeSInt(
- BytecodeGenerationContext* context,
- Int value)
-{
- UInt uValue;
- if( value < 0 )
- {
- uValue = (~UInt(value) << 1) | 1;
- }
- else
- {
- uValue = UInt(value) << 1;
- }
-
- encodeUInt(context, uValue);
-}
-
-BCConst getGlobalValue(
- BytecodeGenerationContext* context,
- IRInst* value)
-{
- {
- BCConst bcConst;
- if (context->shared->mapValueToGlobal.TryGetValue(value, bcConst))
- return bcConst;
- }
- // Next we need to check for things that can be mapped to
- // global IDs on the fly.
-
- switch( value->op )
- {
- case kIROp_IntLit:
- {
- UInt constID = context->shared->constants.Count();
- context->shared->constants.Add(value);
-
- BCConst bcConst;
- bcConst.flavor = kBCConstFlavor_Constant;
- bcConst.id = (uint32_t)constID;
-
- context->shared->mapValueToGlobal.Add(value, bcConst);
-
- return bcConst;
- }
- break;
-
- default:
- break;
- }
-
- SLANG_UNEXPECTED("no ID for inst");
- {
- UNREACHABLE(BCConst bcConst);
- UNREACHABLE(bcConst.flavor = (BCConstFlavor)-1);
- UNREACHABLE(bcConst.id = -9999);
- UNREACHABLE_RETURN(bcConst);
- }
-}
-
-Int getLocalID(
- BytecodeGenerationContext* context,
- IRInst* value)
-{
- Int localID = 0;
- if( context->mapInstToLocalID.TryGetValue(value, localID) )
- {
- return localID;
- }
-
- BCConst bcConst = getGlobalValue(context, value);
- UInt remappedSymbolIndex = context->remappedGlobalSymbols.Count();
- context->remappedGlobalSymbols.Add(bcConst);
-
- localID = ~remappedSymbolIndex;
- context->mapInstToLocalID.Add(value, localID);
- return localID;
-}
-
-void encodeOperand(
- BytecodeGenerationContext* context,
- IRInst* operand)
-{
- auto id = getLocalID(context, operand);
- encodeSInt(context, id);
-}
-
-uint32_t getTypeID(
- BytecodeGenerationContext* context,
- IRType* type);
-
-void encodeOperand(
- BytecodeGenerationContext* context,
- IRType* type)
-{
- encodeUInt(context, getTypeID(context, type));
-}
-
-bool opHasResult(IRInst* inst)
-{
- auto type = inst->getDataType();
- if (!type) return false;
-
- // As a bit of a hack right now, we need to check whether
- // the function returns the distinguished `Void` type,
- // since that is conceptually the same as "not returning
- // a value."
- if(type->op == kIROp_VoidType)
- return false;
-
- return true;
-}
-
-void generateBytecodeForInst(
- BytecodeGenerationContext* context,
- IRInst* inst)
-{
- // We are generating bytecode for a local instruction
- // inside a function or similar context.
- switch( inst->op )
- {
- default:
- {
- // As a default case, we will assume that bytecode ops
- // and the IR's internal opcodes are the same, and then
- // encode the necessary extra info:
- //
-
- auto operandCount = inst->getOperandCount();
- encodeUInt(context, inst->op);
- encodeOperand(context, inst->getDataType());
- encodeUInt(context, operandCount);
- for( UInt aa = 0; aa < operandCount; ++aa )
- {
- encodeOperand(context, inst->getOperand(aa));
- }
-
- if (!opHasResult(inst))
- {
- // This instructions has no type, so don't emit a destination
- }
- else
- {
- // The instruction can be encoded
- // as its own operand for the destination.
- encodeOperand(context, inst);
- }
- }
- break;
-
- case kIROp_ReturnVoid:
- // Trivial encoding here
- encodeUInt(context, inst->op);
- break;
-
- case kIROp_IntLit:
- {
- auto ii = (IRConstant*) inst;
- encodeUInt(context, ii->op);
- encodeOperand(context, ii->getDataType());
-
- // TODO: probably want distinct encodings
- // for signed vs. unsigned here.
- encodeUInt(context, UInt(ii->value.intVal));
-
- // destination:
- encodeOperand(context, inst);
- }
- break;
-
- case kIROp_FloatLit:
- {
- auto cInst = (IRConstant*) inst;
- encodeUInt(context, cInst->op);
- encodeOperand(context, cInst->getDataType());
-
- static const UInt size = sizeof(IRFloatingPointValue);
- unsigned char buffer[size];
- memcpy(buffer, &cInst->value.floatVal, sizeof(buffer));
-
- for(UInt ii = 0; ii < size; ++ii)
- {
- encodeUInt8(context, buffer[ii]);
- }
-
- // destination:
- encodeOperand(context, inst);
- }
- break;
-
- case kIROp_BoolLit:
- {
- auto ii = (IRConstant*) inst;
- encodeUInt(context, ii->op);
- encodeUInt(context, ii->value.intVal ? 1 : 0);
-
- // destination:
- encodeOperand(context, inst);
- }
- break;
-
-#if 0
- case kIROp_Func:
- {
- encodeUInt(context, inst->op);
-
- // We just want to encode the ID for the function
- // symbol data, and then do the rest on the decode side
- UInt nestedID = 0;
- context->mapInstToNestedID.TryGetValue(inst, nestedID);
- encodeUInt(context, nestedID);
-
- // destination:
- encodeOperand(context, inst);
- }
- break;
-#endif
-
- case kIROp_Store:
- {
- encodeUInt(context, inst->op);
-
- // We need to encode the type being stored, to make
- // our lives easier.
- encodeOperand(context, inst->getOperand(1)->getDataType());
- encodeOperand(context, inst->getOperand(0));
- encodeOperand(context, inst->getOperand(1));
- }
- break;
-
- case kIROp_Load:
- {
- encodeUInt(context, inst->op);
- encodeOperand(context, inst->getDataType());
- encodeOperand(context, inst->getOperand(0));
- encodeOperand(context, inst);
- }
- break;
- }
-}
-
-BytecodeGenerationPtr<BCType> emitBCType(
- BytecodeGenerationContext* context,
- IRType* type,
- IROp op,
- BytecodeGenerationPtr<uint8_t> const* args,
- UInt argCount)
-{
- UInt size = sizeof(BCType)
- + argCount * sizeof(BCPtr<void>);
-
- BytecodeGenerationPtr<uint8_t> bcAllocation(
- context->shared,
- allocateRaw(context, size, alignof(BCPtr<void>)));
-
- BytecodeGenerationPtr<BCType> bcType = bcAllocation.bitCast<BCType>();
- auto bcArgs = (bcType + 1).bitCast<BCPtr<uint8_t>>();
-
- bcType->op = op;
- bcType->argCount = (uint32_t)argCount;
-
- for(UInt aa = 0; aa < argCount; ++aa)
- {
- bcArgs[aa] = args[aa];
- }
-
- UInt id = context->shared->bcTypes.Count();
- context->shared->mapTypeToID.Add(type, id);
- context->shared->bcTypes.Add(bcType);
- bcType->id = (uint32_t)id;
-
- return bcType;
-}
-
-BytecodeGenerationPtr<BCType> emitBCVarArgType(
- BytecodeGenerationContext* context,
- IRType* type,
- IROp op,
- List<BytecodeGenerationPtr<uint8_t>> args)
-{
- return emitBCType(context, type, op, args.Buffer(), args.Count());
-}
-
-BytecodeGenerationPtr<BCType> emitBCType(
- BytecodeGenerationContext* context,
- IRType* type,
- IROp op)
-{
- return emitBCType(context, type, op, nullptr, 0);
-}
-
-BytecodeGenerationPtr<BCType> emitBCType(
- BytecodeGenerationContext* context,
- IRType* type);
-
-// Emit a `BCType` representation for the given `Type`
-BytecodeGenerationPtr<BCType> emitBCTypeImpl(
- BytecodeGenerationContext* context,
- IRType* type)
-{
- // A NULL type is interpreted as equivalent to `Void` for now.
- if( !type )
- {
- return emitBCType(context, type, kIROp_VoidType);
- }
-
- List<BytecodeGenerationPtr<uint8_t>> operands;
- UInt operandCount = type->getOperandCount();
- for (UInt ii = 0; ii < operandCount; ++ii)
- {
- operands.Add(emitBCType(context, (IRType*) type->getOperand(ii)).bitCast<uint8_t>());
- }
- return emitBCVarArgType(context, type, type->op, operands);
-}
-
-BytecodeGenerationPtr<BCType> emitBCType(
- BytecodeGenerationContext* context,
- IRType* type)
-{
- auto canonical = type->getCanonicalType();
- UInt id = 0;
- if(context->shared->mapTypeToID.TryGetValue(canonical, id))
- {
- return context->shared->bcTypes[id];
- }
-
- BytecodeGenerationPtr<BCType> bcType = emitBCTypeImpl(context, canonical);
- return bcType;
-}
-
-uint32_t getTypeID(
- BytecodeGenerationContext* context,
- IRType* type)
-{
- // We have a type, and we need to emit it (if we haven't
- // already) and return its index in the global type table.
- BytecodeGenerationPtr<BCType> bcType = emitBCType(context, type);
- return bcType->id;
-}
-
-uint32_t getTypeIDForGlobalSymbol(
- BytecodeGenerationContext* context,
- IRInst* inst)
-{
- auto type = inst->getDataType();
- if(!type)
- return 0;
-
- return getTypeID(context, type);
-}
-
-BytecodeGenerationPtr<char> allocateString(
- BytecodeGenerationContext* context,
- char const* data,
- UInt size)
-{
- BytecodeGenerationPtr<char> ptr = allocateArray<char>(context, size + 1);
- memcpy(ptr.getPtr(), data, size);
- return ptr;
-}
-
-BytecodeGenerationPtr<char> allocateString(
- BytecodeGenerationContext* context,
- String const& str)
-{
- return allocateString(context,
- str.Buffer(),
- str.Length());
-}
-
-BytecodeGenerationPtr<char> allocateString(
- BytecodeGenerationContext* context,
- Name* name)
-{
- return allocateString(context, name->text);
-}
-
-BytecodeGenerationPtr<char> tryGenerateNameForSymbol(
- BytecodeGenerationContext* context,
- IRGlobalValue* inst)
-{
- // TODO: this is gross, and the IR should probably have
- // a more direct means of querying a name for a symbol.
- if (auto highLevelDeclDecoration = inst->findDecoration<IRHighLevelDeclDecoration>())
- {
- auto decl = highLevelDeclDecoration->decl;
- if (auto reflectionNameMod = decl->FindModifier<ParameterGroupReflectionName>())
- {
- return allocateString(context, reflectionNameMod->name);
- }
- else if(auto name = decl->nameAndLoc.name)
- {
- return allocateString(context, name);
- }
- }
-
- return BytecodeGenerationPtr<char>();
-}
-
-// Generate a `BCSymbol` that can represent a global value.
-BytecodeGenerationPtr<BCSymbol> generateBytecodeSymbolForInst(
- BytecodeGenerationContext* context,
- IRGlobalValue* inst)
-{
- switch( inst->op )
- {
- case kIROp_Func:
- {
- auto irFunc = (IRFunc*) inst;
- BytecodeGenerationPtr<BCFunc> bcFunc = allocate<BCFunc>(context);
-
- bcFunc->op = inst->op;
- bcFunc->typeID = getTypeIDForGlobalSymbol(context, inst);
-
- BytecodeGenerationContext subContextStorage;
- BytecodeGenerationContext* subContext = &subContextStorage;
- subContext->shared = context->shared;
- subContext->currentIRFunc = irFunc;
-
- // First we need to enumerate our basic blocks, so that they
- // can reference one another (basic blocks can forward reference
- // blocks that haven't been seen yet).
- //
- // Note: we allow the IDs of blocks to overlap with ordinary
- // "register" numbers, because there is no case where an operand
- // could be either a block or an ordinary register.
- //
- UInt blockCounter = 0;
- for( auto bb = irFunc->getFirstBlock(); bb; bb = bb->getNextBlock() )
- {
- Int blockID = Int(blockCounter++);
- subContext->mapInstToLocalID.Add(bb, blockID);
- }
- UInt blockCount = blockCounter;
-
- // Allocate the array of block objects to be stored in the
- // bytecode file.
- auto bcBlocks = allocateArray<BCBlock>(context, blockCount);
- bcFunc->blockCount = (uint32_t)blockCount;
- bcFunc->blocks = bcBlocks;
-
- // Now loop through the blocks again, and allocate the storage
- // for any parameters, variables, or registers used inside
- // each block.
- //
- // We'll count in a first pass, and then fill things in
- // using a second pass
- Int regCounter = 0;
- blockCounter = 0;
- for( auto bb = irFunc->getFirstBlock(); bb; bb = bb->getNextBlock() )
- {
- UInt blockID = blockCounter++;
- UInt paramCount = 0;
-
- for( auto ii = bb->getFirstInst(); ii; ii = ii->getNextInst() )
- {
- switch( ii->op )
- {
- default:
- // Default behavior: if an op has a result,
- // then it needs a register to store it.
- if(opHasResult(ii))
- {
- regCounter++;
- }
- break;
-
- case kIROp_Param:
- // A parameter always uses a register.
- regCounter++;
- //
- // We also want to keep a count of the parameters themselves.
- paramCount++;
- break;
-
- case kIROp_Var:
- // A `var` (`alloca`) node needs two registers:
- // one to hold the actual storage, and another
- // to hold the pointer.
- regCounter += 2;
- break;
- }
- }
-
- bcBlocks[blockID].paramCount = (uint32_t)paramCount;
- }
-
- // Okay, we've counted how many registers we need for each block,
- // and now we can allocate the contiguous array we will use.
- UInt regCount = regCounter;
- auto bcRegs = allocateArray<BCReg>(context, regCount);
-
- bcFunc->regCount = (uint32_t)regCount;
- bcFunc->regs = bcRegs;
-
- // Now we will loop over things again to fill in the information
- // on all these registers.
-
- regCounter = 0;
- blockCounter = 0;
- for( auto bb = irFunc->getFirstBlock(); bb; bb = bb->getNextBlock() )
- {
- UInt blockID = blockCounter++;
-
- // Loop over the instruction in the block, to allocate registers
- // for them. The parameters of a block will always be the first
- // N instructions in the block, so they will always get the
- // first N registers in that block. Similarly, the entry block
- // is always the first block, so that the parameters of the function
- // will always be the first N registers.
- //
- bcBlocks[blockID].params = bcRegs + regCounter;
- for( auto ii = bb->getFirstInst(); ii; ii = ii->getNextInst() )
- {
- switch(ii->op)
- {
- default:
- // For a parameter, or an ordinary instruction with
- // a result, allocate it here.
- if( opHasResult(ii) )
- {
- Int localID = regCounter++;
- subContext->mapInstToLocalID.Add(ii, localID);
-
- bcRegs[localID].op = ii->op;
-#if 0
- bcRegs[localID].name = tryGenerateNameForSymbol(context, ii);
-#endif
- bcRegs[localID].previousVarIndexPlusOne = (uint32_t)localID;
- bcRegs[localID].typeID = getTypeIDForGlobalSymbol(context, ii);
- }
- break;
-
- case kIROp_Var:
- // As handled in the earlier loop, we are
- // allocating *two* locations for each `var`
- // instruction. The first of these will be
- // the actual pointer value, while the second
- // will be the storage for the variable value.
- {
- Int localID = regCounter;
- regCounter += 2;
-
- subContext->mapInstToLocalID.Add(ii, localID);
- bcRegs[localID].op = ii->op;
-#if 0
- bcRegs[localID].name = tryGenerateNameForSymbol(context, ii);
-#endif
- bcRegs[localID].previousVarIndexPlusOne = (uint32_t)localID;
- bcRegs[localID].typeID = getTypeIDForGlobalSymbol(context, ii);
-
- bcRegs[localID+1].op = ii->op;
- bcRegs[localID+1].previousVarIndexPlusOne = (uint32_t)localID+1;
- bcRegs[localID+1].typeID = getTypeID(context,
- (as<IRPtrType>(ii->getDataType()))->getValueType());
- }
- break;
- }
- }
- }
- assert((UInt)regCounter == regCount);
-
- // Now that we've allocated our blocks and our registers
- // we can go through the actual process of emitting instructions. Hooray!
- blockCounter = 0;
-
- // Offset of each basic block from the start of the code
- // for the current funciton.
- List<UInt> blockOffsets;
- for( auto bb = irFunc->getFirstBlock(); bb; bb = bb->getNextBlock() )
- {
- blockCounter++;
-
- // Get local bytecode offset for current block.
- UInt blockOffset = subContext->currentBytecode.Count();
- blockOffsets.Add( blockOffset );
-
- for( auto ii = bb->getFirstInst(); ii; ii = ii->getNextInst() )
- {
- // What we do with each instruction depends a bit on the
- // kind of instruction it is.
- switch( ii->op )
- {
- default:
- // For most instructions we just emit their bytecode
- // ops directly.
- generateBytecodeForInst(subContext, ii);
- break;
-
- case kIROp_Param:
- // Don't actually emit code for these, because
- // there isn't really anything to *execute*
- //
- // Note that we *do* allow the `var` nodes
- // to be executed, just because they need
- // to set up a register with the pointer value.
- break;
- }
- }
- }
-
-
- // We've collected bytecode for the instruction stream
- // into a sub-context, so we can now append that code.
- UInt byteCount = subContext->currentBytecode.Count();
- BytecodeGenerationPtr<uint8_t> bytes = allocateArray<uint8_t>(context, byteCount);
- memcpy(&bytes[0], subContext->currentBytecode.Buffer(), byteCount);
-
- // Now that we've allocated the storage, we can write
- // the bytecode pointers into the blocks.
- blockCounter = 0;
- for( auto bb = irFunc->getFirstBlock(); bb; bb = bb->getNextBlock() )
- {
- UInt blockID = blockCounter++;
- bcBlocks[blockID].code = bytes + blockOffsets[blockID];
- }
-
- // Finally, after emitting all the instructions we can
- // build a table of global symbols taht need to be
- // imported into the current function as constants.
- UInt constCount = subContext->remappedGlobalSymbols.Count();
- auto bcConsts = allocateArray<BCConst>(context, constCount);
-
- bcFunc->constCount = (uint32_t)constCount;
- bcFunc->consts = bcConsts;
-
- for( UInt cc = 0; cc < constCount; ++cc )
- {
- bcConsts[cc] = subContext->remappedGlobalSymbols[cc];
- }
-
- return bcFunc;
- }
- break;
-
- case kIROp_GlobalVar:
- case kIROp_GlobalConstant:
- {
- auto bcVar = allocate<BCSymbol>(context);
-
- bcVar->op = inst->op;
- bcVar->typeID = getTypeID(context, inst->getFullType());
-
- // TODO: actually need to intialize with body instructions
-
- return bcVar;
- }
- break;
-
- default:
- // Most instructions don't need a custom representation.
- return BytecodeGenerationPtr<BCSymbol>();
- }
-}
-
-BytecodeGenerationPtr<BCModule> generateBytecodeForModule(
- BytecodeGenerationContext* context,
- IRModule* irModule)
-{
- if (!irModule)
- {
- // Not IR module? Then return a null pointer.
- return BytecodeGenerationPtr<BCModule>();
- }
-
- // A module in the bytecode is mostly just a list of the
- // global symbols in the module.
- //
- // TODO: we need to be careful and recognize the distinction
- // between the global symbols in the *AST* module, vs. those
- // symbols which are effectively global in the *IR* module.
- //
- // We probably need to store these distinctly, since we
- // need the AST global symbols for reflection, and then
- // also to reconstruct the AST on load when importing a
- // serialized module. We then need the global IR symbols
- // to use when linking, to quickly resolve things without
- // needing any semantic knowledge of nesting at the AST level.
- //
- auto bcModule = allocate<BCModule>(context);
-
- // We need to compute how many "registers" to allocate
- // for the module, where the registers represent the
- // values being computed at the global scope.
- UInt symbolCount = 0;
- for(auto ii : irModule->getGlobalInsts())
- {
- auto gv = as<IRGlobalValue>(ii);
- if (!gv)
- continue;
-
- Int globalID = Int(symbolCount++);
-
- // Ensure that local code inside functions can see these symbols
- BCConst bcConst;
- bcConst.flavor = kBCConstFlavor_GlobalSymbol;
- bcConst.id = (uint32_t)globalID;
- context->shared->mapValueToGlobal.Add(gv, bcConst);
-
- // In the global scope, global IDs are also the local IDs
- context->mapInstToLocalID.Add(gv, globalID);
- }
-
- auto bcSymbols = allocateArray<BCPtr<BCSymbol>>(context, symbolCount);
-
- bcModule->symbolCount = (uint32_t)symbolCount;
- bcModule->symbols = bcSymbols;
-
- for(auto ii : irModule->getGlobalInsts())
- {
- auto gv = as<IRGlobalValue>(ii);
- if (!gv)
- continue;
-
- UInt symbolIndex = *context->mapInstToLocalID.TryGetValue(gv);
-
- auto bcSymbol = generateBytecodeSymbolForInst(context, gv);
- if (!bcSymbol.getPtr())
- continue;
-
- auto name = tryGenerateNameForSymbol(context, gv);
- bcSymbol->name = name;
-
- bcSymbols[symbolIndex] = bcSymbol;
- }
-
- // At this point we should have identified all the literals we need:
- UInt constantCount = context->shared->constants.Count();
- auto bcConstants = allocateArray<BCConstant>(context, constantCount);
- bcModule->constantCount = (uint32_t)constantCount;
- bcModule->constants = bcConstants;
-
- for(UInt cc = 0; cc < constantCount; ++cc)
- {
- auto irConstant = (IRConstant*) context->shared->constants[cc];
- bcConstants[cc].op = irConstant->op;
- bcConstants[cc].typeID = getTypeID(context, irConstant->getFullType());
-
- switch(irConstant->op)
- {
- case kIROp_IntLit:
- {
- auto ptr = allocate<IRIntegerValue>(context);
- *ptr = irConstant->value.intVal;
- bcConstants[cc].ptr = ptr.bitCast<uint8_t>();
- }
- break;
-
- default:
- break;
- }
-
- }
-
- // At this point we should have collected all the types we need:
- UInt typeCount = context->shared->bcTypes.Count();
- auto bcTypes = allocateArray<BCPtr<BCType>>(context, typeCount);
- bcModule->typeCount = (uint32_t)typeCount;
- bcModule->types = bcTypes;
-
- for(UInt tt = 0; tt < typeCount; ++tt)
- {
- bcTypes[tt] = context->shared->bcTypes[tt];
- }
-
-
- return bcModule;
-}
-
-void generateBytecodeContainer(
- BytecodeGenerationContext* context,
- CompileRequest* compileReq)
-{
- // Header must be the very first thing in the bytecode stream
- BytecodeGenerationPtr<BCHeader> header = allocate<BCHeader>(context);
-
- memcpy(header->magic, "slang\0bc", sizeof(header->magic));
- header->version = 0;
-
- // TODO: Need to generate BC representation of all the public/exported
- // declrations in the translation units, so that they can be used to
- // resolve depenencies downstream.
-
- // TODO: Need to dump BC representation of compiled kernel codes
- // for each specified code-generation target.
-
- List<BytecodeGenerationPtr<BCModule>> bcModulesList;
- for (auto translationUnitReq : compileReq->translationUnits)
- {
- auto bcModule = generateBytecodeForModule(context, translationUnitReq->irModule);
- bcModulesList.Add(bcModule);
- }
-
- UInt bcModuleCount = bcModulesList.Count();
- header->moduleCount = (uint32_t)bcModuleCount;
-
- auto bcModules = allocateArray<BCPtr<BCModule>>(context, bcModuleCount);
- header->modules = bcModules;
- for(UInt ii = 0; ii < bcModuleCount; ++ii)
- {
- bcModules[ii] = bcModulesList[ii];
- }
-}
-
-void generateBytecodeForCompileRequest(
- CompileRequest* compileReq)
-{
- SharedBytecodeGenerationContext sharedContext;
-
- BytecodeGenerationContext context;
- context.shared = &sharedContext;
-
- generateBytecodeContainer(&context, compileReq);
-
- compileReq->generatedBytecode = sharedContext.bytecode;
-}
-
-// TODO: Need to support IR emit at the whole-module/compile-request
-// level, and not just for individual entry points.
-#if 0
-List<uint8_t> emitSlangIRForEntryPoint(
- EntryPointRequest* entryPoint)
-{
- auto compileRequest = entryPoint->compileRequest;
- auto irModule = lowerEntryPointToIR(
- entryPoint,
- compileRequest->layout.Ptr(),
- // TODO: we need to pick the target more carefully here
- CodeGenTarget::HLSL);
-
-#if 0
- String irAsm = getSlangIRAssembly(irModule);
- fprintf(stderr, "%s\n", irAsm.Buffer());
-#endif
-
- // Now we need to encode that IR into a binary format
- // for transmission/serialization/etc.
-
- SharedBytecodeGenerationContext sharedContext;
-
- BytecodeGenerationContext context;
- context.shared = &sharedContext;
-
- generateBytecodeStream(&context, irModule);
-
- return sharedContext.bytecode;
-}
-#endif
-
-} // namespace Slang
diff --git a/source/slang/bytecode.h b/source/slang/bytecode.h
deleted file mode 100644
index f1ad52c32..000000000
--- a/source/slang/bytecode.h
+++ /dev/null
@@ -1,253 +0,0 @@
-// bytecode.h
-#ifndef SLANG_BYTECODE_H_INCLUDED
-#define SLANG_BYTECODE_H_INCLUDED
-
-// This file defines a "bytecode" format for storing shader code
-// that has been generated via the Slang IR. The bytecode has
-// two main goals, that can end up in a bit of conflict:
-//
-// 1) It is the official serialized form of the Slang IR, and
-// so it is of some importance that constructs in the IR be
-// able to round-trip through the bytecode.
-//
-// 2) It should support being directly executed/interpreted,
-// so that Slang code can be executed on CPUs when
-// performance isn't critical (or when a JIT just isn't
-// an option).
-//
-
-#include "../core/basic.h"
-
-namespace Slang
-{
-template<typename T>
-struct BytecodeGenerationPtr;
-
-// A "pointer" stored in a serialized bytecode file, which
-// is represented as a byte offset relative to itself.
-//
-template<typename T>
-struct BCPtr
-{
- typedef int32_t RawVal;
-
- RawVal rawVal;
-
- BCPtr() : rawVal(0) {}
-
- BCPtr(T* ptr)
- : rawVal(0)
- {
- *this = ptr;
- }
-
- BCPtr(BCPtr<T> const& ptr)
- : rawVal(0)
- {
- *this = ptr.getPtr();
- }
-
- void operator=(BCPtr<T> const& ptr)
- {
- *this = ptr.getPtr();
- }
-
- void operator=(T* ptr)
- {
- if (ptr)
- {
- rawVal = (RawVal)((char*)ptr - (char*)this);
- }
- else
- {
- rawVal = 0;
- }
- }
-
- operator T*() const { return getPtr(); }
- T* operator->() const { return getPtr(); }
-
- T* getPtr() const
- {
- if(!rawVal) return nullptr;
- return (T*)((char const*)this + rawVal);
- }
-};
-
-// Representation of a "type-level" value in
-// the bytecode fiel. This corresponds to
-// the AST-level notion of a `Val`
-struct BCVal
-{
- // The opcode used to define this value
- uint32_t op;
-
- // The ID of the type within its module
- uint32_t id;
-};
-
-struct BCType : BCVal
-{
- // TODO: avoid having to encode this?
- uint32_t argCount;
-
- // type-specific operands follow
-
- //
-
- BCPtr<BCVal>* getArgs() { return (BCPtr<BCVal>*) (this +1); }
-
- BCVal* getArg(UInt index) { return getArgs()[index]; }
-};
-
-struct BCPtrType : BCType
-{
- BCPtr<BCType> valueType;
-};
-
-struct BCFuncType : BCType
-{
- BCPtr<BCType> resultType;
- BCPtr<BCType> paramTypes[1];
-
- BCType* getResultType() { return resultType; }
-
- UInt getParamCount() { return argCount - 1; }
- BCType* getParamType(UInt index) { return paramTypes[index]; }
-};
-
-struct BCConstant : BCVal
-{
- uint32_t typeID;
- BCPtr<uint8_t> ptr;
-};
-
-struct BCSymbol
-{
- // The opcode that was used to define
- // this symbol; used to categorize things
- uint32_t op;
-
- // The index (in the module's type table)
- // of the type of the symbol:
- uint32_t typeID;
-
- // The name of this symbol (which might
- // be a mangled name at some point,
- // so it is really only meant to be
- // used for linkage...)
- BCPtr<char> name;
-};
-
-typedef uint8_t BCOp;
-
-struct BCReg : BCSymbol
-{
- // The index of the variable/register
- // that should be stored immediately
- // preceding this one.
- uint32_t previousVarIndexPlusOne;
-};
-
-enum BCConstFlavor
-{
- kBCConstFlavor_GlobalSymbol,
- kBCConstFlavor_Constant,
-};
-
-struct BCConst
-{
- // The flavor of bytecode constant we
- // are dealing with.
- uint32_t flavor;
- uint32_t id;
-};
-
-struct BCBlock
-{
- // The start of the bytecode for this block
- BCPtr<BCOp> code;
-
- // The list of parameters of the block
- uint32_t paramCount;
- BCPtr<BCReg> params;
-};
-
-struct BCFunc : BCSymbol
-{
- // A list of "registers" used to hold
- // intermediate values during execution
- // of this function.
- uint32_t regCount;
- BCPtr<BCReg> regs;
-
- // The basic blocks of the function
- uint32_t blockCount;
- BCPtr<BCBlock> blocks;
-
- // A list of "constants" which are values
- // from the global scope that this function
- // wants to be able to refer to. We could
- // just encode global values directly,
- // but this would make the encoding less dense.
- uint32_t constCount;
- BCPtr<BCConst> consts;
-};
-
-struct BCModule
-{
- // The symbols (functions, global variables, etc.)
- // that have been declared in the module.
- uint32_t symbolCount;
- BCPtr<BCPtr<BCSymbol>> symbols;
-
- // The types that are used by this module, stored
- // in a single array so that they can be conveniently
- // mapped to another representation in one go.
- //
- // Instructions in a bytecode instruction sequence
- // might reference these types by index.
- uint32_t typeCount;
- BCPtr<BCPtr<BCType>> types;
-
- // True compile-time constants go here:
- uint32_t constantCount;
- BCPtr<BCConstant> constants;
-};
-
-struct BCHeader
-{
- char magic[8];
- uint32_t version;
-
- // TODO: probably want a section-based file
- // format so that we can add/remove different
- // kinds of data without having to revise
- // the schema here.
-
- // TODO: should include AST declaration structure
- // here, which can be used for refleciton, and
- // also loaded to resolve dependencies when
- // compiling other modules.
-
- // TODO: Include the original entry point requests?
-
- // Zero or more IR modules, corresponding to
- // the translation units of the original compile
- // request.
- uint32_t moduleCount;
- BCPtr<BCPtr<BCModule>> modules;
-
- // TODO: should enumerate targets here, and
- // include reflection layout info + compiled
- // entry points for each target.
-};
-
-class CompileRequest;
-void generateBytecodeForCompileRequest(
- CompileRequest* compileReq);
-
-}
-
-
-#endif
diff --git a/source/slang/compiler.cpp b/source/slang/compiler.cpp
index 37e9827f8..0f333aa3d 100644
--- a/source/slang/compiler.cpp
+++ b/source/slang/compiler.cpp
@@ -5,7 +5,6 @@
#include "../core/slang-io.h"
#include "../core/slang-string-util.h"
-#include "bytecode.h"
#include "compiler.h"
#include "lexer.h"
#include "lower-to-ir.h"
@@ -1079,18 +1078,6 @@ SlangResult dissassembleDXILUsingDXC(
generateOutputForTarget(targetReq);
}
- // If we are being asked to generate code in a container
- // format, then we are now in a position to do so.
- switch (compileRequest->containerFormat)
- {
- default:
- break;
-
- case ContainerFormat::SlangModule:
- generateBytecodeForCompileRequest(compileRequest);
- break;
- }
-
// If we are in command-line mode, we might be expected to actually
// write output to one or more files here.
diff --git a/source/slang/ir.cpp b/source/slang/ir.cpp
index 2f16f4ebc..c0715fca3 100644
--- a/source/slang/ir.cpp
+++ b/source/slang/ir.cpp
@@ -2617,7 +2617,20 @@ namespace Slang
}
}
- bool opHasResult(IRInst* inst);
+ bool opHasResult(IRInst* inst)
+ {
+ auto type = inst->getDataType();
+ if (!type) return false;
+
+ // As a bit of a hack right now, we need to check whether
+ // the function returns the distinguished `Void` type,
+ // since that is conceptually the same as "not returning
+ // a value."
+ if(type->op == kIROp_VoidType)
+ return false;
+
+ return true;
+ }
bool instHasUses(IRInst* inst)
{
diff --git a/source/slang/slang.vcxproj b/source/slang/slang.vcxproj
index 6bcaac3da..c502780df 100644
--- a/source/slang/slang.vcxproj
+++ b/source/slang/slang.vcxproj
@@ -171,7 +171,6 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\..\slang.h" />
- <ClInclude Include="bytecode.h" />
<ClInclude Include="compiler.h" />
<ClInclude Include="core.meta.slang.h" />
<ClInclude Include="decl-defs.h" />
@@ -222,10 +221,8 @@
<ClInclude Include="type-system-shared.h" />
<ClInclude Include="val-defs.h" />
<ClInclude Include="visitor.h" />
- <ClInclude Include="vm.h" />
</ItemGroup>
<ItemGroup>
- <ClCompile Include="bytecode.cpp" />
<ClCompile Include="check.cpp" />
<ClCompile Include="compiler.cpp" />
<ClCompile Include="diagnostics.cpp" />
@@ -262,7 +259,6 @@
<ClCompile Include="token.cpp" />
<ClCompile Include="type-layout.cpp" />
<ClCompile Include="type-system-shared.cpp" />
- <ClCompile Include="vm.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="slang.natvis" />
diff --git a/source/slang/slang.vcxproj.filters b/source/slang/slang.vcxproj.filters
index ce76ec77e..dc5630504 100644
--- a/source/slang/slang.vcxproj.filters
+++ b/source/slang/slang.vcxproj.filters
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Header Files">
@@ -12,9 +12,6 @@
<ClInclude Include="..\..\slang.h">
<Filter>Header Files</Filter>
</ClInclude>
- <ClInclude Include="bytecode.h">
- <Filter>Header Files</Filter>
- </ClInclude>
<ClInclude Include="compiler.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -165,14 +162,8 @@
<ClInclude Include="visitor.h">
<Filter>Header Files</Filter>
</ClInclude>
- <ClInclude Include="vm.h">
- <Filter>Header Files</Filter>
- </ClInclude>
</ItemGroup>
<ItemGroup>
- <ClCompile Include="bytecode.cpp">
- <Filter>Source Files</Filter>
- </ClCompile>
<ClCompile Include="check.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -281,9 +272,6 @@
<ClCompile Include="type-system-shared.cpp">
<Filter>Source Files</Filter>
</ClCompile>
- <ClCompile Include="vm.cpp">
- <Filter>Source Files</Filter>
- </ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="slang.natvis">
diff --git a/source/slang/vm.cpp b/source/slang/vm.cpp
deleted file mode 100644
index 0f79c763b..000000000
--- a/source/slang/vm.cpp
+++ /dev/null
@@ -1,1180 +0,0 @@
-#include "vm.h"
-
-// Implementation of the Slang bytecode VM
-//
-
-#include "bytecode.h"
-#include "ir.h"
-
-#include "../../slang.h"
-
-namespace Slang
-{
-
-struct VMValImpl
-{
- // opcode used to construct the value
- uint32_t op;
-};
-
-// Representation of a type during VM execution
-struct VMTypeImpl : VMValImpl
-{
- // number of arguments to the type
- uint32_t argCount;
-
- // Size and alignment of instances of this
- // type.
- UInt size;
- UInt alignment;
-
- // operands follow
-};
-
-struct VMVal
-{
- VMValImpl* impl;
-
- VMValImpl* getImpl() { return impl; }
-};
-
-struct VMType : VMVal
-{
- VMTypeImpl* getImpl() { return (VMTypeImpl*) impl; }
- UInt getSize() { return getImpl()->size; }
- UInt getAlignment() { return getImpl()->alignment; }
-};
-
-struct VMPtrTypeImpl : VMTypeImpl
-{
- VMType base;
-};
-
-struct VMReg
-{
- // Type that the register is meant to hold
- VMType type;
-
- // offset of the variable inside the frame
- size_t offset;
-};
-
-struct VMConst
-{
- // Type of the constant
- VMType type;
-
- // Operand address to use
- void* ptr;
-};
-
-struct VMModule;
-
-// Information about a function after it has been
-// loaded into the VM.
-struct VMFunc
-{
- // The parent module that this function belongs to
- VMModule* module;
- BCFunc* bcFunc;
-
- VMReg* regs;
- VMConst* consts;
-
- size_t frameSize;
-};
-
-struct VMFrame
-{
- // The function from which this frame was spawned
- VMFunc* func;
-
- // The parent frame on the call stack of the
- // current thread.
- VMFrame* parent;
-
- // The instruction pointer within this frame
- BCOp* ip;
-
- // Registers are stored after this point.
-};
-
-struct VM;
-
-struct VMModule
-{
- BCModule* bcModule;
- VM* vm;
- void** symbols;
- VMType* types;
-};
-
-UInt decodeUInt(BCOp** ioPtr)
-{
- BCOp* ptr = *ioPtr;
-
- UInt value = *ptr++;
- if( value < 128 )
- {
- *ioPtr = ptr;
- return value;
- }
-
- // Slower path for variable-length encoding
-
- UInt result = 0;
- for(;;)
- {
- value = value & 0x7F;
- result = (result << 7) | value;
-
- if(value < 127)
- {
- *ioPtr = ptr;
- return value;
- }
-
- value = *ptr++;
- }
-}
-
-Int decodeSInt(BCOp** ioPtr)
-{
- UInt uVal = decodeUInt(ioPtr);
- if( uVal & 1 )
- {
- return Int(~(uVal >> 1));
- }
- else
- {
- return Int(uVal >> 1);
- }
-}
-
-void* getRegPtrImpl(VMFrame* frame, UInt id)
-{
- VMFunc* vmFunc = frame->func;
- VMReg* vmReg = &vmFunc->regs[id];
- size_t offset = vmReg->offset;
-
- return (void*)((char*)frame + offset);
-}
-
-void* getOperandPtrImpl(VMFrame* frame, Int id)
-{
- if( id >= 0 )
- {
- // This ID represents a local variable/register
- // of the current call frame, and should
- // be used to index into a table of such values.
-
- return getRegPtrImpl(frame, id);
- }
- else
- {
- // This ID represents a global value that has
- // been imported into the current func, and
- // should be looked up via indirection into
- // the current module.
-
- VMFunc* vmFunc = frame->func;
- VMConst* vmConst = &vmFunc->consts[~id];
- return vmConst->ptr;
- }
-}
-
-VMType getOperandTypeImpl(VMFrame* frame, Int id)
-{
- if( id >= 0 )
- {
- return frame->func->regs[id].type;
- }
- else
- {
- return frame->func->consts[~id].type;
- }
-}
-struct VMPtrAndType
-{
- void* ptr;
- VMType type;
-};
-
-VMPtrAndType decodeOperandPtrAndType(VMFrame* frame, BCOp** ioIP)
-{
- Int id = decodeSInt(ioIP);
-
- VMPtrAndType ptrAndType;
- ptrAndType.ptr = getOperandPtrImpl(frame, id);
- ptrAndType.type = getOperandTypeImpl(frame, id);
- return ptrAndType;
-}
-
-void* decodeOperandPtrImpl(VMFrame* frame, BCOp** ioIP)
-{
- Int id = decodeSInt(ioIP);
- return getOperandPtrImpl(frame, id);
-}
-
-
-template<typename T>
-T* decodeOperandPtr(VMFrame* frame, BCOp** ioIP)
-{
- return (T*)decodeOperandPtrImpl(frame, ioIP);
-}
-
-
-template<typename T>
-T& decodeOperand(VMFrame* frame, BCOp** ioIP)
-{
- return *decodeOperandPtr<T>(frame, ioIP);
-}
-
-VMType decodeType(VMFrame* frame, BCOp** ioIP)
-{
- UInt id = decodeUInt(ioIP);
- return frame->func->module->types[id];
-}
-
-VMFunc* loadVMFunc(
- BCFunc* bcFunc,
- VMModule* vmModule);
-
-struct VMSizeAlign
-{
- UInt size;
- UInt align;
-};
-
-VMSizeAlign getVMSymbolSize(BCSymbol* symbol)
-{
- VMSizeAlign result;
- result.size = sizeof(void*);
- result.align = sizeof(void*);
- switch( symbol->op )
- {
- default:
- SLANG_UNEXPECTED("op");
- break;
-
- case kIROp_TypeKind:
- break;
-
- case kIROp_Func:
- {
- BCFunc* func = (BCFunc*) symbol;
- result.size = sizeof(VMFunc)
- + func->regCount * sizeof(VMReg)
- + func->constCount * sizeof(VMConst);
- }
- break;
- }
-
- return result;
-}
-
-VMType getType(
- VMModule* vmModule,
- uint32_t typeID)
-{
- return vmModule->types[typeID];
-}
-
-void* getGlobalPtr(
- VMModule* vmModule,
- uint32_t globalID)
-{
- return vmModule->symbols[globalID];
-}
-
-VMType getGlobalType(
- VMModule* vmModule,
- uint32_t globalID)
-{
- return getType(vmModule, vmModule->bcModule->symbols[globalID]->typeID);
-}
-
-VMFunc* loadVMFunc(
- BCFunc* bcFunc,
- VMModule* vmModule)
-{
- UInt regCount = bcFunc->regCount;
- UInt constCount = bcFunc->constCount;
- UInt vmFuncSize = sizeof(VMFunc)
- + regCount * sizeof(VMReg)
- + constCount * sizeof(VMConst);
-
- VMFunc* vmFunc = (VMFunc*) malloc(vmFuncSize);
- VMReg* vmRegs = (VMReg*) (vmFunc + 1);
- VMConst* vmConsts = (VMConst*) (vmRegs + regCount);
-
- vmFunc->module = vmModule;
- vmFunc->bcFunc = bcFunc;
- vmFunc->regs = vmRegs;
- vmFunc->consts = vmConsts;
-
- UInt offset = sizeof(VMFrame);
- for( UInt rr = 0; rr < regCount; ++rr )
- {
- BCReg* bcReg = &bcFunc->regs[rr];
- auto bcTypeID = bcReg->typeID;
-
- // We expect the type to come from the outer module, so
- // that we can allocate space for it as we go.
- auto vmType = getType(vmModule, bcTypeID);
-
- auto regSize = vmType.getSize();
- auto regAlign = vmType.getAlignment();
-
- offset = (offset + (regAlign-1)) & ~(regAlign-1);
-
- size_t regOffset = offset;
- offset += regSize;
-
- vmRegs[rr].type = vmType;
- vmRegs[rr].offset = regOffset;
- }
- vmFunc->frameSize = offset;
-
- for( UInt cc = 0; cc < constCount; ++cc )
- {
- BCConst bcConst = bcFunc->consts[cc];
- switch( bcConst.flavor )
- {
- case kBCConstFlavor_GlobalSymbol:
- {
- auto globalID = bcConst.id;
- vmFunc->consts[cc].ptr = &vmModule->symbols[globalID];
- vmFunc->consts[cc].type = getGlobalType(vmModule, globalID);
- }
- break;
-
- case kBCConstFlavor_Constant:
- {
- auto constID = bcConst.id;
- auto constInfo = &vmModule->bcModule->constants[constID];
- vmFunc->consts[cc].ptr = constInfo->ptr;
- #if 0
- fprintf(stderr, "CONSANT[%d] : [%p]\n", (int)cc, vmFunc->consts[cc].ptr);
- fprintf(stderr, "BC [%p] : %d\n", &constInfo->ptr, (int)constInfo->ptr.rawVal);
- #endif
- vmFunc->consts[cc].type = getType(vmModule, constInfo->typeID);
- }
- break;
- }
-
-
- }
-
- return vmFunc;
-}
-
-VMFrame* createFrame(VMFunc* vmFunc)
-{
- VMFrame* vmFrame = (VMFrame*) malloc(vmFunc->frameSize);
- vmFrame->func = vmFunc;
- vmFrame->ip = vmFunc->bcFunc->blocks[0].code;
- return vmFrame;
-}
-
-void dumpVMFrame(VMFrame* vmFrame)
-{
- fflush(stderr);
-
- // We want to walk the VM frame and dump the
- // state of all of its logical registers.
- // For now this is made easier by having
- // no overlapping register assignments...
- VMFunc* vmFunc = vmFrame->func;
- BCFunc* bcFunc = vmFunc->bcFunc;
- UInt regCount = bcFunc->regCount;
-
- for (UInt rr = 0; rr < regCount; ++rr)
- {
- VMType regType = getOperandTypeImpl(vmFrame, rr);
- void* regData = getRegPtrImpl(vmFrame, rr);
-
- char const* name = bcFunc->regs[rr].name;
-
- // Use the type to print the data...
-
- fprintf(stderr, "0x%p: ", regData);
-
- fprintf(stderr, "%%%u ", (unsigned int) rr);
- if (name)
- {
- fprintf(stderr, "\"%s\" ", name);
- }
- if (regType.impl)
- {
- switch (regType.impl->op)
- {
- case kIROp_TypeKind:
- // TODO: we could recursively go and print types...
- fprintf(stderr, ": Type = ???");
- break;
-
- case kIROp_HLSLRWStructuredBufferType:
- fprintf(stderr, ": RWStructuredBuffer<??\?> = ???");
- break;
-
- case kIROp_HLSLStructuredBufferType:
- fprintf(stderr, ": StructuredBuffer<??\?> = ???");
- break;
-
- case kIROp_BoolType:
- fprintf(stderr, ": Bool = %s", *(bool*)regData ? "true" : "false");
- break;
-
- case kIROp_IntType:
- fprintf(stderr, ": Int32 = %d", *(int32_t*)regData);
- break;
-
- case kIROp_UIntType:
- fprintf(stderr, ": UInt32 = %u", *(uint32_t*)regData);
- break;
-
- case kIROp_PtrType:
- {
- fprintf(stderr, ": Ptr<?> = [%p]", *(void**)regData);
- }
- break;
-
- default:
- fprintf(stderr, "<unknown>");
- break;
- }
- }
- else
- {
- fprintf(stderr, ": <null>");
- }
- fprintf(stderr, "; // ");
- fprintf(stderr, "%s", getIROpInfo((IROp) bcFunc->regs[rr].op).name);
- fprintf(stderr, "\n");
-
- // Okay, now we need to use the type
- // stored in the VM register to tell
- // us how to print things.
- }
-
- IROp op = IROp(*vmFrame->ip);
- IROpInfo opInfo = getIROpInfo(op);
- fprintf(stderr, "NEXT op: %s\n", opInfo.name);
-
- fflush(stderr);
-}
-
-struct VM
-{
-};
-
-VM* createVM()
-{
- VM* vm = new VM();
- return vm;
-}
-
-struct VMThread
-{
- // The currently executing call frame
- VMFrame* frame;
-};
-
-void resumeThread(
- VMThread* vmThread);
-
-void computeTypeSizeAlign(
- VMTypeImpl* impl)
-{
- UInt size = 0;
- UInt alignment = 0;
- switch(impl->op)
- {
- case kIROp_VoidType:
- size = 0;
- break;
-
- case kIROp_BoolType:
- size = 1;
- break;
-
- case kIROp_IntType:
- case kIROp_UIntType:
- case kIROp_FloatType:
- size = 4;
- break;
-
- case kIROp_FuncType:
- case kIROp_PtrType:
- case kIROp_HLSLRWStructuredBufferType:
- case kIROp_HLSLStructuredBufferType:
- size = sizeof(void*);
- break;
-
- default:
- SLANG_UNIMPLEMENTED_X("type sizing");
- UNREACHABLE(impl->size = 0);
- break;
- }
-
- if(!alignment)
- alignment = size;
- if(!alignment)
- alignment = 1;
-
- impl->size = size;
- impl->alignment = alignment;
-}
-
-VMType getType(
- VM* /*vm*/,
- VMTypeImpl* typeImpl)
-{
- // TODO: need to look up an existing type that matches...
-
- UInt argCount = typeImpl->argCount;
- UInt size = sizeof(VMTypeImpl) + argCount*sizeof(VMType);
-
- VMTypeImpl* impl = (VMTypeImpl*) malloc(size);
- memcpy(impl, typeImpl, size);
-
- computeTypeSizeAlign(impl);
-
- VMType type;
- type.impl = impl;
- return type;
-}
-
-VMVal getVal(
- VMModule* vmModule,
- UInt index)
-{
- return vmModule->types[index];
-}
-
-VMType loadVMType(
- VMModule* vmModule,
- BCType* bcType)
-{
- // Need to load type from BC format to VM
- IROp op = (IROp) bcType->op;
- switch(bcType->op)
- {
- case kIROp_PtrType:
- {
- // TODO: need to do some caching!
- BCPtrType* bcPtrType = (BCPtrType*) bcType;
-
- VMPtrTypeImpl vmPtrTypeImpl;
- vmPtrTypeImpl.op = op;
- vmPtrTypeImpl.argCount = 1;
- vmPtrTypeImpl.size = sizeof(void*);
- vmPtrTypeImpl.alignment = sizeof(void*);
- vmPtrTypeImpl.base = getType(vmModule, bcPtrType->valueType->id);
-
- auto vmPtrType = getType(vmModule->vm, &vmPtrTypeImpl);
- return vmPtrType;
- }
- break;
-
- default:
- {
- UInt argCount = bcType->argCount;
-
- UInt size = sizeof(VMTypeImpl) + argCount * sizeof(VMVal);
-
- VMTypeImpl* impl = (VMTypeImpl*) alloca(size);
- memset(impl, 0, size);
- impl->op = bcType->op;
- impl->argCount = (uint32_t)argCount;
-
- VMVal* args = (VMVal*) (impl + 1);
- for(UInt aa = 0; aa < argCount; ++aa)
- {
- args[aa] = getVal(vmModule, bcType->getArg(aa)->id);
- }
-
- return getType(vmModule->vm, impl);
- }
-
- UNREACHABLE(SLANG_UNEXPECTED("unimplemented"));
- UNREACHABLE_RETURN(VMType());
- break;
- }
-}
-
-void* allocateImpl(VM* /*vm*/, UInt size, UInt /*align*/)
-{
- void* ptr = malloc(size);
- memset(ptr, 0, size);
- return ptr;
-}
-
-void* allocate(VM* vm, VMType type)
-{
- return allocateImpl(vm, type.getSize(), type.getAlignment());
-}
-
-template<typename T>
-T* allocate(VM* vm)
-{
- return allocateImpl(vm, sizeof(T), alignof(T));
-}
-
-void* loadVMSymbol(
- VMModule* vmModule,
- BCSymbol* bcSymbol)
-{
- // Need to load type from BC format to VM
-
- auto vm = vmModule->vm;
-
- switch(bcSymbol->op)
- {
- case kIROp_GlobalVar:
- {
- auto type = getType(vmModule, bcSymbol->typeID);
- assert(type.impl->op == kIROp_PtrType);
-
- VMPtrTypeImpl* ptrTypeImpl = (VMPtrTypeImpl*) type.impl;
- auto valueType = ptrTypeImpl->base;
-
- void* varValue = allocate(vm, valueType);
- void** varPtr = (void**) allocate(vm, type);
-
-
- *varPtr = varValue;
-
- return varPtr;
- }
- break;
-
- case kIROp_GlobalConstant:
- {
- auto type = getType(vmModule, bcSymbol->typeID);
- void* valPtr = allocate(vm, type);
- return valPtr;
- }
- break;
-
- case kIROp_Func:
- {
- auto bcFunc = (BCFunc*) bcSymbol;
- VMFunc* vmFunc = loadVMFunc(bcFunc, vmModule);
- return vmFunc;
- }
- break;
-
- default:
- return nullptr;
- }
-}
-
-VMModule* loadVMModuleInstance(
- VM* vm,
- void const* bytecode,
- size_t /*bytecodeSize*/)
-{
- BCHeader* bcHeader = (BCHeader*) bytecode;
-
- UInt bcModuleCount = bcHeader->moduleCount;
- if (bcModuleCount == 0)
- return nullptr;
-
- BCModule* bcModule = bcHeader->modules[0];
-
- UInt symbolCount = bcModule->symbolCount;
- UInt typeCount = bcModule->typeCount;
-
- UInt vmModuleSize = sizeof(VMModule)
- + symbolCount * sizeof(void*)
- + typeCount * sizeof(VMType);
-
- VMModule* vmModule = (VMModule*)malloc(vmModuleSize);
- memset(vmModule, 0, vmModuleSize);
-
- void** vmSymbols = (void**)(vmModule + 1);
- VMType* vmTypes = (VMType*)(vmSymbols + symbolCount);
-
- vmModule->bcModule = bcModule;
- vmModule->vm = vm;
- vmModule->symbols = vmSymbols;
- vmModule->types = vmTypes;
-
- // Initialize types before symbols, since the symbols
- // will all have types...
- for(UInt tt = 0; tt < typeCount; ++tt)
- {
- BCType* bcType = bcModule->types[tt];
- vmTypes[tt] = loadVMType(vmModule, bcType);
- }
-
- // Now we need to initialize all the VM-level symbols
- // from their BC-level equivalents.
- for(UInt ss = 0; ss < symbolCount; ++ss)
- {
- BCSymbol* bcSymbol = bcModule->symbols[ss];
- vmSymbols[ss] = loadVMSymbol(vmModule, bcSymbol);
- }
-
- return vmModule;
-}
-
-void* findGlobalSymbolPtr(
- VMModule* module,
- char const* name)
-{
- // Okay, we need to search through the available
- // symbols, looking for one that gives us a name
- // match.
-
- BCModule* bcModule = module->bcModule;
- UInt symbolCount = bcModule->symbolCount;
- for(UInt ss = 0; ss < symbolCount; ++ss)
- {
- BCSymbol* bcSymbol = bcModule->symbols[ss];
-
- char const* symbolName = bcSymbol->name;
- if (!symbolName)
- continue;
-
- if(strcmp(symbolName, name) == 0)
- return getGlobalPtr(module, (uint32_t)ss);
- }
-
- return nullptr;
-}
-
-VMThread* createThread(
- VM* /*vm*/)
-{
- VMThread* thread = new VMThread();
- thread->frame = nullptr;
- return thread;
-}
-
-void beginCall(
- VMThread* vmThread,
- VMFunc* vmFunc)
-{
- VMFrame* vmFrame = createFrame(vmFunc);
-
- vmFrame->parent = vmThread->frame;
- vmThread->frame = vmFrame;
-}
-
-void setArg(
- VMThread* vmThread,
- UInt argIndex,
- void const* data,
- size_t size)
-{
- // TODO: need all kinds of validation here...
-
- void* dest = getRegPtrImpl(vmThread->frame, argIndex);
- memcpy(dest, data, size);
-}
-
-void resumeThread(
- VMThread* vmThread)
-{
- auto frame = vmThread->frame;
- auto ip = frame->ip;
-
- for(;;)
- {
-#if 0
- // debugging:
- frame->ip = ip;
- dumpVMFrame(frame);
-#endif
-
- auto op = (IROp) decodeUInt(&ip);
- switch( op )
- {
- case kIROp_Var:
- {
- // This instruction represents the `alloca` for a variable of some type.
-
- VMType type = decodeType(frame, &ip);
- UInt argCount = decodeUInt(&ip);
- void* argPtrs[16] = { 0 };
- for( UInt aa = 0; aa < argCount; ++aa )
- {
- void* argPtr = decodeOperandPtr<void>(frame, &ip);
- argPtrs[aa] = argPtr;
- }
-
- void** destPtr = decodeOperandPtr<void*>(frame, &ip);
-
- // For now this is a bit silly and simple: the
- // storage for the variable we are "allocating"
- // should be right after outer destination, so we can
- // set it pretty easily.
-
- *destPtr = destPtr + 1;
- }
- break;
-
- case kIROp_Store:
- {
- // An ordinary memory store
- VMType type = decodeType(frame, &ip);
- void* dest = decodeOperand<void*>(frame, &ip);
- void* src = decodeOperandPtr<void>(frame, &ip);
-
-#if 0
- fprintf(stderr, "STORE *[%p] = [%p] // size: %d\n",
- dest,
- src,
- (int) type.getSize());
-#endif
-
- memcpy(dest, src, type.getSize());
- }
- break;
-
- case kIROp_Load:
- {
- // An ordinary memory store
- VMType type = decodeType(frame, &ip);
- void* src = decodeOperand<void*>(frame, &ip);
- void* dest = decodeOperandPtr<void>(frame, &ip);
-
- memcpy(dest, src, type.getSize());
- }
- break;
-
- case kIROp_Call:
- {
- VMType type = decodeType(frame, &ip);
- UInt operandCount = decodeUInt(&ip);
-
- // First operand is the callee function
- VMFunc* func = decodeOperand<VMFunc*>(frame, &ip);
-
- // Okay, we need to create a frame to prepare the call
- VMFrame* newFrame = createFrame(func);
- newFrame->parent = frame;
-
- // Remaining arguments should populate the
- // first N registers of the callee
- UInt argCount = operandCount - 1;
- for( UInt aa = 0; aa < argCount; ++aa )
- {
- void* argPtr = decodeOperandPtr<void>(frame, &ip);
- void* regPtr = getRegPtrImpl(newFrame, aa);
-
- VMType regType = func->regs[aa].type;
- memcpy(regPtr, argPtr, regType.getSize());
- }
-
- // Note that we do *not* try to read off
- // the destination operand, and instead
- // leave that to be done during the
- // return sequence.
- //
-
- // Save the IP we were using in teh current function.
- //
- frame->ip = ip;
-
- // Now switch over to the callee:
- //
- frame = newFrame;
- ip = newFrame->ip;
- }
- break;
-
- case kIROp_ReturnVoid:
- {
- // Easy case: just jump to the parent frame,
- // without having to worry about operands.
- VMFrame* newFrame = frame->parent;
- vmThread->frame = newFrame;
-
- // HACK: we need to know when we are done.
- // TODO: We should probably have the bottom
- // of the stack for a thread always point
- // to a special bytecode sequence that
- // forces a `yield` op that can handle
- // the exit from the interpreter, rather
- // than always take a branch here.
- if (!newFrame)
- return;
-
- frame = newFrame;
- ip = frame->ip;
-
- }
- break;
-
- case kIROp_ReturnVal:
- {
- VMType instType = decodeType(frame, &ip);
- /*UInt argCount =*/ decodeUInt(&ip);
- void* argPtr = decodeOperandPtr<void>(frame, &ip);
-
- VMFrame* newFrame = frame->parent;
- vmThread->frame = newFrame;
-
- // Note: see the comments above about
- // this branch.
- if (!newFrame)
- return;
-
- frame = newFrame;
- ip = frame->ip;
-
- auto destPtrAndType = decodeOperandPtrAndType(frame, &ip);
- void* destPtr = destPtrAndType.ptr;
- VMType type = destPtrAndType.type;
-
- memcpy(destPtr, argPtr, type.getSize());
- }
- break;
-
- case kIROp_loop:
- case kIROp_unconditionalBranch:
- {
- // For now our encoding is very regular, so we can decode without
- // knowing too much about an instruction...
-
- VMType type = decodeType(frame, &ip);
- UInt argCount = decodeUInt(&ip);
- Int destinationBlockIndex = decodeSInt(&ip);
-
- auto func = frame->func;
- auto& destinationBlock = func->bcFunc->blocks[destinationBlockIndex];
-
- // We may be passing arguments through to the destination
- // block, so any remaining operands of the branch instruction
- // need to be used to fill in the parameter registers of
- // the destination block.
-
- UInt paramCount = destinationBlock.paramCount;
-
- // There might be additional operands, because some branches
- // also include information on merge points and break/continue labels.
- UInt remainingArgCount = argCount - 1;
- assert(remainingArgCount >= paramCount);
-
- UInt extraArgCount = remainingArgCount - paramCount;
-
- for (UInt ee = 0; ee < extraArgCount; ++ee)
- {
- decodeOperandPtr<void>(frame, &ip);
- }
-
- auto baseRegIndex = destinationBlock.params - func->bcFunc->regs;
- for( UInt pp = 0; pp < paramCount; ++pp )
- {
- auto regIndex = baseRegIndex + pp;
-
- void* argPtr = decodeOperandPtr<void>(frame, &ip);
- void* regPtr = getRegPtrImpl(frame, regIndex);
-
- VMType regType = func->regs[regIndex].type;
- memcpy(regPtr, argPtr, regType.getSize());
- }
-
- // Now simply jump to the destination block.
- //
- ip = destinationBlock.code;
- }
- break;
-
- case kIROp_ifElse:
- case kIROp_conditionalBranch:
- {
- // For now our encoding is very regular, so we can decode without
- // knowing too much about an instruction...
-
- VMType type = decodeType(frame, &ip);
- UInt argCount = decodeUInt(&ip);
- bool* condition = decodeOperandPtr<bool>(frame, &ip);
- Int trueBlockID = decodeSInt(&ip);
- Int falseBlockID = decodeSInt(&ip);
- for( UInt aa = 4; aa < argCount; ++aa )
- {
- decodeOperandPtr<void>(frame, &ip);
- }
-
- Int destinationBlock = *condition ? trueBlockID : falseBlockID;
-
- // TODO: we need to deal with the case of
- // passing arguments to the block, which
- // means copying between the registers...
- //
- ip = frame->func->bcFunc->blocks[destinationBlock].code;
- }
- break;
-
- case kIROp_Greater:
- {
- // For now our encoding is very regular, so we can decode without
- // knowing too much about an instruction...
-
- VMType resultType = decodeType(frame, &ip);
- /*UInt argCount = */decodeUInt(&ip);
- //void* argPtrs[16] = { 0 };
- auto leftOpnd = decodeOperandPtrAndType(frame, &ip);
- auto type = leftOpnd.type;
- auto leftPtr = leftOpnd.ptr;
- void* rightPtr = decodeOperandPtr<void>(frame, &ip);
-
- bool* destPtr = decodeOperandPtr<bool>(frame, &ip);
-
- switch (type.impl->op)
- {
- case kIROp_IntType:
- *destPtr = *(int32_t*)leftPtr > *(int32_t*)rightPtr;
- break;
-
- default:
- SLANG_UNEXPECTED("comparison op case");
- break;
- }
- }
- break;
-
- case kIROp_Mul:
- {
- VMType type = decodeType(frame, &ip);
- /*UInt argCount = */decodeUInt(&ip);
- void* leftPtr = decodeOperandPtr<void>(frame, &ip);
- void* rightPtr = decodeOperandPtr<void>(frame, &ip);
-
- void* destPtr = decodeOperandPtr<void>(frame, &ip);
-
- switch (type.impl->op)
- {
- case kIROp_IntType:
- *(int32_t*)destPtr = *(int32_t*)leftPtr * *(int32_t*)rightPtr;
- break;
-
- default:
- SLANG_UNEXPECTED("comparison op case");
- break;
- }
- }
- break;
-
- case kIROp_Sub:
- {
- VMType type = decodeType(frame, &ip);
- /*UInt argCount = */decodeUInt(&ip);
- void* leftPtr = decodeOperandPtr<void>(frame, &ip);
- void* rightPtr = decodeOperandPtr<void>(frame, &ip);
-
- void* destPtr = decodeOperandPtr<void>(frame, &ip);
-
- switch (type.impl->op)
- {
- case kIROp_IntType:
- *(int32_t*)destPtr = *(int32_t*)leftPtr - *(int32_t*)rightPtr;
- break;
-
- default:
- SLANG_UNEXPECTED("comparison op case");
- break;
- }
- }
- break;
-
- default:
- {
- // For now our encoding is very regular, so we can decode without
- // knowing too much about an instruction...
-
- VMType type = decodeType(frame, &ip);
- UInt argCount = decodeUInt(&ip);
- void* argPtrs[16] = { 0 };
- for( UInt aa = 0; aa < argCount; ++aa )
- {
- void* argPtr = decodeOperandPtr<void>(frame, &ip);
- argPtrs[aa] = argPtr;
- }
-
- SLANG_UNEXPECTED("unknown bytecode op");
- return;
- }
- break;
- }
- }
-
-}
-
-
-
-
-SLANG_API void SlangVMThread_resume(
- SlangVMThread* thread)
-{
- Slang::resumeThread(
- (Slang::VMThread*) thread);
-}
-
-} // namespace Slang
-
-SLANG_API SlangVM* SlangVM_create()
-{
- return (SlangVM*) Slang::createVM();
-}
-
-SLANG_API SlangVMModule* SlangVMModule_load(
- SlangVM* vm,
- void const* bytecode,
- size_t bytecodeSize)
-{
- return (SlangVMModule*) Slang::loadVMModuleInstance(
- (Slang::VM*) vm,
- bytecode,
- bytecodeSize);
-}
-
-SLANG_API void* SlangVMModule_findGlobalSymbolPtr(
- SlangVMModule* module,
- char const* name)
-{
- return (SlangVMFunc*) Slang::findGlobalSymbolPtr(
- (Slang::VMModule*) module,
- name);
-}
-
-SLANG_API SlangVMThread* SlangVMThread_create(
- SlangVM* vm)
-{
- return (SlangVMThread*)Slang::createThread(
- (Slang::VM*) vm);
-}
-
-SLANG_API void SlangVMThread_beginCall(
- SlangVMThread* thread,
- SlangVMFunc* func)
-{
- Slang::beginCall(
- (Slang::VMThread*) thread,
- (Slang::VMFunc*) func);
-}
-
-SLANG_API void SlangVMThread_setArg(
- SlangVMThread* thread,
- SlangUInt argIndex,
- void const* data,
- size_t size)
-{
- Slang::setArg(
- (Slang::VMThread*) thread,
- argIndex,
- data,
- size);
-}
-
-SLANG_API void SlangVMThread_resume(
- SlangVMThread* thread)
-{
- Slang::resumeThread(
- (Slang::VMThread*) thread);
-}
diff --git a/source/slang/vm.h b/source/slang/vm.h
deleted file mode 100644
index e67fec43a..000000000
--- a/source/slang/vm.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// vm.h
-#ifndef SLANG_VM_H_INCLUDED
-#define SLANG_VM_H_INCLUDED
-
-// This file defines a virtual machine for executing
-// code that has been converted to Slang bytecode.
-//
-
-#include "../core/basic.h"
-
-namespace Slang
-{
-
-
-
-}
-
-
-#endif