summaryrefslogtreecommitdiffstats
path: root/source/slang/bytecode.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang/bytecode.cpp')
-rw-r--r--source/slang/bytecode.cpp555
1 files changed, 380 insertions, 175 deletions
diff --git a/source/slang/bytecode.cpp b/source/slang/bytecode.cpp
index e412a5b94..854d9bf34 100644
--- a/source/slang/bytecode.cpp
+++ b/source/slang/bytecode.cpp
@@ -19,8 +19,8 @@ struct SharedBytecodeGenerationContext;
template<typename T>
struct BytecodeGenerationPtr
{
- SharedBytecodeGenerationContext* sharedContext;
UInt offset;
+ SharedBytecodeGenerationContext* sharedContext;
BytecodeGenerationPtr()
: sharedContext(nullptr)
@@ -49,31 +49,40 @@ struct BytecodeGenerationPtr
, offset(ptr.offset)
{}
- operator BCPtr<T>()
+ template<typename U>
+ BytecodeGenerationPtr<U> bitCast() const
+ {
+ return BytecodeGenerationPtr<U>(sharedContext, offset);
+ }
+
+ operator BCPtr<T>() const
{
return BCPtr<T>(getPtr());
}
- T* operator->()
+ T* operator->() const
{
return getPtr();
}
- T& operator*()
+ T& operator*() const
{
return *getPtr();
}
- T& operator[](UInt index)
+ T& operator[](UInt index) const
{
return getPtr()[index];
}
- BytecodeGenerationPtr<T> operator+(Int index)
+ BytecodeGenerationPtr<T> operator+(Int index) const
{
+ UInt size = sizeof(T);
+ Int delta = index * sizeof(T);
+ UInt newOffset = offset + delta;
return BytecodeGenerationPtr<T>(
sharedContext,
- offset + index*sizeof(T));
+ newOffset);
}
T* getPtr() const;
@@ -93,14 +102,27 @@ struct SharedBytecodeGenerationContext
// The final generated bytecode stream
List<uint8_t> bytecode;
- // Map from a global symbol to its global ID
- Dictionary<IRInst*, Int> mapGlobalSymbolToGLobalID;
+ // Map from an IR value to a global entity
+ // that encodes it:
+ Dictionary<IRValue*, BCConst> mapValueToGlobal;
+
+ // Types that have been emitted
+ List<BytecodeGenerationPtr<BCType>> bcTypes;
+ Dictionary<Type*, UInt> mapTypeToID;
+
+ // Compile-time constant values that need
+ // to be emitted...
+ List<IRValue*> 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;
@@ -110,11 +132,7 @@ struct BytecodeGenerationContext
// Map an instruction to its ID for use local
// to the current context
- Dictionary<IRInst*, Int> mapInstToLocalID;
-
- // Map an instruction to the ID for its auxiliary
- // symbol data
- Dictionary<IRInst*, UInt> mapInstToNestedID;
+ Dictionary<IRValue*, Int> mapInstToLocalID;
};
template<typename T>
@@ -169,7 +187,7 @@ void encodeUInt8(
BytecodeGenerationContext* context,
uint8_t value)
{
- context->shared->bytecode.Add(value);
+ context->currentBytecode.Add(value);
}
void encodeUInt(
@@ -220,50 +238,98 @@ void encodeSInt(
encodeUInt(context, uValue);
}
-Int getLocalID(
+BCConst getGlobalValue(
BytecodeGenerationContext* context,
- IRInst* inst)
+ IRValue* value)
{
- Int localID = 0;
- if( context->mapInstToLocalID.TryGetValue(inst, localID) )
- {
- return localID;
- }
+ 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.
- Int globalID = 0;
- if( context->shared->mapGlobalSymbolToGLobalID.TryGetValue(inst, globalID) )
+ switch( value->op )
{
- BCConst bcConst;
- bcConst.globalID = globalID;
+ case kIROp_IntLit:
+ {
+ UInt constID = context->shared->constants.Count();
+ context->shared->constants.Add(value);
- UInt remappedSymbolIndex = context->remappedGlobalSymbols.Count();
- context->remappedGlobalSymbols.Add(bcConst);
+ BCConst bcConst;
+ bcConst.flavor = kBCConstFlavor_Constant;
+ bcConst.id = constID;
- localID = ~remappedSymbolIndex;
- context->mapInstToLocalID.Add(inst, localID);
- return localID;
+ context->shared->mapValueToGlobal.Add(value, bcConst);
+
+ return bcConst;
+ }
+ break;
+
+ default:
+ break;
}
SLANG_UNEXPECTED("no ID for inst");
- return -9999;
+ bcConst.flavor = (BCConstFlavor) -1;
+ bcConst.id = -9999;
+ return bcConst;
+}
+
+Int getLocalID(
+ BytecodeGenerationContext* context,
+ IRValue* 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)
+ IRValue* operand)
{
auto id = getLocalID(context, operand);
encodeSInt(context, id);
}
-bool opHasResult(IRInst* inst)
+uint32_t getTypeID(
+ BytecodeGenerationContext* context,
+ Type* type);
+
+void encodeOperand(
+ BytecodeGenerationContext* context,
+ IRType* type)
+{
+ encodeUInt(context, getTypeID(context, type));
+}
+
+bool opHasResult(IRValue* inst)
{
auto type = inst->getType();
- if( !type || type->op != kIROp_VoidType )
+ 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 (auto basicType = dynamic_cast<BasicExpressionType*>(type))
{
- return true;
+ if (basicType->baseType == BaseType::Void)
+ return false;
}
- return false;
+
+ return true;
}
void generateBytecodeForInst(
@@ -282,15 +348,16 @@ void generateBytecodeForInst(
//
auto argCount = inst->getArgCount();
+ auto type = inst->getType();
encodeUInt(context, inst->op);
+ encodeOperand(context, inst->getType());
encodeUInt(context, argCount);
for( UInt aa = 0; aa < argCount; ++aa )
{
encodeOperand(context, inst->getArg(aa));
}
- auto type = inst->getType();
- if( type && type->op == kIROp_VoidType )
+ if (!opHasResult(inst))
{
// This instructions has no type, so don't emit a destination
}
@@ -354,6 +421,7 @@ void generateBytecodeForInst(
}
break;
+#if 0
case kIROp_Func:
{
encodeUInt(context, inst->op);
@@ -368,6 +436,7 @@ void generateBytecodeForInst(
encodeOperand(context, inst);
}
break;
+#endif
case kIROp_Store:
{
@@ -375,9 +444,9 @@ void generateBytecodeForInst(
// We need to encode the type being stored, to make
// our lives easier.
- encodeOperand(context, inst->getArg(2)->getType());
+ encodeOperand(context, inst->getArg(1)->getType());
+ encodeOperand(context, inst->getArg(0));
encodeOperand(context, inst->getArg(1));
- encodeOperand(context, inst->getArg(2));
}
break;
@@ -385,33 +454,166 @@ void generateBytecodeForInst(
{
encodeUInt(context, inst->op);
encodeOperand(context, inst->getType());
- encodeOperand(context, inst->getArg(1));
+ encodeOperand(context, inst->getArg(0));
encodeOperand(context, inst);
}
break;
}
}
-Int getIDForGlobalSymbol(
+BytecodeGenerationPtr<BCType> emitBCType(
+ BytecodeGenerationContext* context,
+ Type* 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 = 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 = id;
+
+ return bcType;
+}
+
+BytecodeGenerationPtr<BCType> emitBCVarArgType(
+ BytecodeGenerationContext* context,
+ Type* type,
+ IROp op,
+ List<BytecodeGenerationPtr<uint8_t>> args)
+{
+ return emitBCType(context, type, op, args.Buffer(), args.Count());
+}
+
+BytecodeGenerationPtr<BCType> emitBCType(
BytecodeGenerationContext* context,
- IRInst* inst)
+ Type* type,
+ IROp op)
+{
+ return emitBCType(context, type, op, nullptr, 0);
+}
+
+BytecodeGenerationPtr<BCType> emitBCType(
+ BytecodeGenerationContext* context,
+ Type* type);
+
+// Emit a `BCType` representation for the given `Type`
+BytecodeGenerationPtr<BCType> emitBCTypeImpl(
+ BytecodeGenerationContext* context,
+ Type* type)
+{
+ // A NULL type is interpreted as equivalent to `Void` for now.
+ if( !type )
+ {
+ return emitBCType(context, type, kIROp_VoidType);
+ }
+
+ if( auto basicType = type->As<BasicExpressionType>() )
+ {
+ switch(basicType->baseType)
+ {
+ case BaseType::Void: return emitBCType(context, type, kIROp_VoidType);
+ case BaseType::Bool: return emitBCType(context, type, kIROp_BoolType);
+ case BaseType::Int: return emitBCType(context, type, kIROp_Int32Type);
+ case BaseType::UInt: return emitBCType(context, type, kIROp_UInt32Type);
+ case BaseType::UInt64: return emitBCType(context, type, kIROp_UInt64Type);
+ case BaseType::Half: return emitBCType(context, type, kIROp_Float16Type);
+ case BaseType::Float: return emitBCType(context, type, kIROp_Float32Type);
+ case BaseType::Double: return emitBCType(context, type, kIROp_Float64Type);
+
+ default:
+ break;
+ }
+ }
+ else if( auto funcType = type->As<FuncType>() )
+ {
+ List<BytecodeGenerationPtr<uint8_t>> operands;
+
+ operands.Add(emitBCType(context, funcType->resultType).bitCast<uint8_t>());
+ UInt paramCount = funcType->getParamCount();
+ for(UInt pp = 0; pp < paramCount; ++pp)
+ {
+ operands.Add(emitBCType(context, funcType->getParamType(pp)).bitCast<uint8_t>());
+ }
+
+ return emitBCVarArgType(context, type, kIROp_FuncType, operands);
+ }
+ else if( auto ptrType = type->As<PtrType>() )
+ {
+ List<BytecodeGenerationPtr<uint8_t>> operands;
+ operands.Add(emitBCType(context, ptrType->getValueType()).bitCast<uint8_t>());
+ return emitBCVarArgType(context, type, kIROp_PtrType, operands);
+ }
+ else if( auto rwStructuredBufferType = type->As<HLSLRWStructuredBufferType>() )
+ {
+ List<BytecodeGenerationPtr<uint8_t>> operands;
+ operands.Add(emitBCType(context, rwStructuredBufferType->elementType).bitCast<uint8_t>());
+ return emitBCVarArgType(context, type, kIROp_readWriteStructuredBufferType, operands);
+ }
+ else if( auto structuredBufferType = type->As<HLSLStructuredBufferType>() )
+ {
+ List<BytecodeGenerationPtr<uint8_t>> operands;
+ operands.Add(emitBCType(context, structuredBufferType->elementType).bitCast<uint8_t>());
+ return emitBCVarArgType(context, type, kIROp_structuredBufferType, operands);
+ }
+
+
+ SLANG_UNEXPECTED("unimplemented");
+ return BytecodeGenerationPtr<BCType>();
+}
+
+BytecodeGenerationPtr<BCType> emitBCType(
+ BytecodeGenerationContext* context,
+ Type* type)
{
- Int globalID;
- if(context->shared->mapGlobalSymbolToGLobalID.TryGetValue(inst, globalID))
- return globalID;
+ auto canonical = type->GetCanonicalType();
+ UInt id = 0;
+ if(context->shared->mapTypeToID.TryGetValue(canonical, id))
+ {
+ return context->shared->bcTypes[id];
+ }
- SLANG_UNEXPECTED("no such ID");
+ BytecodeGenerationPtr<BCType> bcType = emitBCTypeImpl(context, canonical);
+ return bcType;
}
-uint32_t getTypeForGlobalSymbol(
+uint32_t getTypeID(
BytecodeGenerationContext* context,
- IRInst* inst)
+ Type* 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,
+ IRValue* inst)
{
auto type = inst->getType();
if(!type)
return 0;
- return getIDForGlobalSymbol(context, type);
+ return getTypeID(context, type);
}
BytecodeGenerationPtr<char> allocateString(
@@ -442,7 +644,7 @@ BytecodeGenerationPtr<char> allocateString(
BytecodeGenerationPtr<char> tryGenerateNameForSymbol(
BytecodeGenerationContext* context,
- IRInst* inst)
+ IRGlobalValue* inst)
{
// TODO: this is gross, and the IR should probably have
// a more direct means of querying a name for a symbol.
@@ -462,9 +664,10 @@ BytecodeGenerationPtr<char> tryGenerateNameForSymbol(
return BytecodeGenerationPtr<char>();
}
+// Generate a `BCSymbol` that can represent a global value.
BytecodeGenerationPtr<BCSymbol> generateBytecodeSymbolForInst(
BytecodeGenerationContext* context,
- IRInst* inst)
+ IRGlobalValue* inst)
{
switch( inst->op )
{
@@ -474,7 +677,7 @@ BytecodeGenerationPtr<BCSymbol> generateBytecodeSymbolForInst(
BytecodeGenerationPtr<BCFunc> bcFunc = allocate<BCFunc>(context);
bcFunc->op = inst->op;
- bcFunc->typeGlobalID = getTypeForGlobalSymbol(context, inst);
+ bcFunc->typeID = getTypeIDForGlobalSymbol(context, inst);
BytecodeGenerationContext subContextStorage;
BytecodeGenerationContext* subContext = &subContextStorage;
@@ -515,7 +718,17 @@ BytecodeGenerationPtr<BCSymbol> generateBytecodeSymbolForInst(
{
UInt blockID = blockCounter++;
UInt paramCount = 0;
- for( auto ii = bb->firstChild; ii; ii = ii->nextInst )
+
+ for( auto pp = bb->getFirstParam(); pp; pp = pp->getNextParam() )
+ {
+ // A parameter always uses a register.
+ regCounter++;
+ //
+ // We also want to keep a count of the parameters themselves.
+ paramCount++;
+ }
+
+ for( auto ii = bb->getFirstInst(); ii; ii = ii->nextInst )
{
switch( ii->op )
{
@@ -528,15 +741,6 @@ BytecodeGenerationPtr<BCSymbol> generateBytecodeSymbolForInst(
}
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
@@ -573,30 +777,25 @@ BytecodeGenerationPtr<BCSymbol> generateBytecodeSymbolForInst(
// are always the first N registers in the overall list.
//
bcBlocks[blockID].params = bcRegs + regCounter;
- for( auto ii = bb->firstChild; ii; ii = ii->nextInst )
+ for( auto pp = bb->getFirstParam(); pp; pp = pp->getNextParam() )
{
- if(ii->op != kIROp_Param)
- continue;
-
Int localID = regCounter++;
- subContext->mapInstToLocalID.Add(ii, localID);
+ subContext->mapInstToLocalID.Add(pp, localID);
- bcRegs[localID].op = ii->op;
- bcRegs[localID].name = tryGenerateNameForSymbol(context, ii);
+ bcRegs[localID].op = pp->op;
+#if 0
+ bcRegs[localID].name = tryGenerateNameForSymbol(context, pp);
+#endif
bcRegs[localID].previousVarIndexPlusOne = localID;
- bcRegs[localID].typeGlobalID = getTypeForGlobalSymbol(context, ii);
+ bcRegs[localID].typeID = getTypeIDForGlobalSymbol(context, pp);
}
// Now loop over the non-parameter instructions and
// allocate actual register locations to them.
- for( auto ii = bb->firstChild; ii; ii = ii->nextInst )
+ for( auto ii = bb->getFirstInst(); ii; ii = ii->nextInst )
{
switch(ii->op)
{
- case kIROp_Param:
- // Already handled.
- break;
-
default:
// For an ordinary instruction with a result,
// allocate it here.
@@ -606,9 +805,11 @@ BytecodeGenerationPtr<BCSymbol> generateBytecodeSymbolForInst(
subContext->mapInstToLocalID.Add(ii, localID);
bcRegs[localID].op = ii->op;
+#if 0
bcRegs[localID].name = tryGenerateNameForSymbol(context, ii);
+#endif
bcRegs[localID].previousVarIndexPlusOne = localID;
- bcRegs[localID].typeGlobalID = getTypeForGlobalSymbol(context, ii);
+ bcRegs[localID].typeID = getTypeIDForGlobalSymbol(context, ii);
}
break;
@@ -624,30 +825,39 @@ BytecodeGenerationPtr<BCSymbol> generateBytecodeSymbolForInst(
subContext->mapInstToLocalID.Add(ii, localID);
bcRegs[localID].op = ii->op;
+#if 0
bcRegs[localID].name = tryGenerateNameForSymbol(context, ii);
+#endif
bcRegs[localID].previousVarIndexPlusOne = localID;
- bcRegs[localID].typeGlobalID = getTypeForGlobalSymbol(context, ii);
+ bcRegs[localID].typeID = getTypeIDForGlobalSymbol(context, ii);
bcRegs[localID+1].op = ii->op;
bcRegs[localID+1].previousVarIndexPlusOne = localID+1;
- bcRegs[localID+1].typeGlobalID = getIDForGlobalSymbol(context,
- ((IRPtrType*) ii->getType())->getValueType());
+ bcRegs[localID+1].typeID = getTypeID(context,
+ (ii->getType()->As<PtrType>())->getValueType());
}
break;
}
}
}
+ assert(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() )
{
UInt blockID = blockCounter++;
- bcBlocks[blockID].code = getPtr<BCOp>(context);
+ // Get local bytecode offset for current block.
+ UInt blockOffset = subContext->currentBytecode.Count();
+ blockOffsets.Add( blockOffset );
- for( auto ii = bb->firstChild; ii; ii = ii->nextInst )
+ for( auto ii = bb->getFirstInst(); ii; ii = ii->nextInst )
{
// What we do with each instruction depends a bit on the
// kind of instruction it is.
@@ -671,6 +881,22 @@ BytecodeGenerationPtr<BCSymbol> generateBytecodeSymbolForInst(
}
}
+
+ // 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.
@@ -689,6 +915,17 @@ BytecodeGenerationPtr<BCSymbol> generateBytecodeSymbolForInst(
}
break;
+ case kIROp_global_var:
+ {
+ auto bcVar = allocate<BCSymbol>(context);
+
+ bcVar->op = inst->op;
+ bcVar->typeID = getTypeID(context, inst->type);
+
+ return bcVar;
+ }
+ break;
+
default:
// Most instructions don't need a custom representation.
return BytecodeGenerationPtr<BCSymbol>();
@@ -699,126 +936,98 @@ BytecodeGenerationPtr<BCModule> generateBytecodeForModule(
BytecodeGenerationContext* context,
IRModule* irModule)
{
- // The module will get encoded much like a function,
- // and then that function will be "invoked" to load
- // the module.
+ // A module in the bytecode is mostly just a list of the
+ // global symbols in the module.
//
- auto bcModule = allocate<BCModule>(context);
- bcModule->op = irModule->op;
- bcModule->typeGlobalID = 0;
-
- // The logical function that the module representats
- // will only have a single block, so we can allocate it now.
+ // 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.
//
- auto bcBlock = allocate<BCBlock>(context);
- bcBlock->paramCount = 0;
- bcBlock->params = BytecodeGenerationPtr<BCReg>();
-
- bcModule->blockCount = 1;
- bcModule->blocks = bcBlock;
-
- // Because the module is the top-most level, there is
- // no need for it to have "constants" that represent
- // values imported from the next outer scope.
+ // 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.
//
- bcModule->constCount = 0;
- bcModule->consts = BytecodeGenerationPtr<BCConst>();
+ 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 regCount = 0;
- for( auto inst = irModule->firstChild; inst; inst = inst->nextInst )
+ UInt symbolCount = 0;
+ for( auto gv : irModule->globalValues )
{
- if(!opHasResult(inst))
- continue;
-
- Int globalID = Int(regCount++);
+ Int globalID = Int(symbolCount++);
- context->shared->mapGlobalSymbolToGLobalID.Add(inst, globalID);
+ // Ensure that local code inside functions can see these symbols
+ BCConst bcConst;
+ bcConst.flavor = kBCConstFlavor_GlobalSymbol;
+ bcConst.id = globalID;
+ context->shared->mapValueToGlobal.Add(gv, bcConst);
// In the global scope, global IDs are also the local IDs
- context->mapInstToLocalID.Add(inst, globalID);
+ context->mapInstToLocalID.Add(gv, globalID);
}
- auto bcRegs = allocateArray<BCReg>(context, regCount);
+ auto bcSymbols = allocateArray<BCPtr<BCSymbol>>(context, symbolCount);
- bcModule->regCount = regCount;
- bcModule->regs = bcRegs;
+ bcModule->symbolCount = symbolCount;
+ bcModule->symbols = bcSymbols;
- // Now lets walk through and initialize all those bytecode
- // register representations so that we can use them.
- UInt regCounter= 0;
- for( auto inst = irModule->firstChild; inst; inst = inst->nextInst )
+ for( auto gv : irModule->globalValues )
{
- if(!opHasResult(inst))
- continue;
-
- UInt regIndex = *context->mapInstToLocalID.TryGetValue(inst);
+ UInt symbolIndex = *context->mapInstToLocalID.TryGetValue(gv);
- BytecodeGenerationPtr<char> name = tryGenerateNameForSymbol(context, inst);
-
- bcRegs[regIndex].op = inst->op;
- bcRegs[regIndex].name = name;
- bcRegs[regIndex].typeGlobalID = getTypeForGlobalSymbol(context, inst);
- bcRegs[regIndex].previousVarIndexPlusOne = regIndex;
- }
-
- // Some instructions represent "nested" symbols that will need
- // custom handling, and we will represent those here.
- List<BytecodeGenerationPtr<BCSymbol>> nestedSymbols;
- for( auto inst = irModule->firstChild; inst; inst = inst->nextInst )
- {
- UInt regIndex = *context->mapInstToLocalID.TryGetValue(inst);
-
- auto bcSymbol = generateBytecodeSymbolForInst(context, inst);
+ auto bcSymbol = generateBytecodeSymbolForInst(context, gv);
if (!bcSymbol.getPtr())
continue;
- UInt nestedSymbolID = nestedSymbols.Count();
- nestedSymbols.Add(bcSymbol);
-
- context->mapInstToNestedID.Add(inst, nestedSymbolID);
+ auto name = tryGenerateNameForSymbol(context, gv);
+ bcSymbol->name = name;
- bcSymbol->name = bcRegs[regIndex].name;
+ bcSymbols[symbolIndex] = bcSymbol;
}
- auto nestedSymbolCount = nestedSymbols.Count();
- auto bcNestedSymbols = allocateArray<BCPtr<BCSymbol>>(context, nestedSymbolCount);
+ // 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 = constantCount;
+ bcModule->constants = bcConstants;
- bcModule->nestedSymbolCount = nestedSymbolCount;
- bcModule->nestedSymbols = bcNestedSymbols;
- for (UInt ii = 0; ii < nestedSymbolCount; ++ii)
+ for(UInt cc = 0; cc < constantCount; ++cc)
{
- bcNestedSymbols[ii] = nestedSymbols[ii];
- }
-
+ auto irConstant = (IRConstant*) context->shared->constants[cc];
+ bcConstants[cc].op = irConstant->op;
+ bcConstants[cc].typeID = getTypeID(context, irConstant->type);
- // Finally, we can go through and emit the actual code for
- // the initialization step.
- bcBlock->code = getPtr<BCOp>(context);
- for( auto inst = irModule->firstChild; inst; inst = inst->nextInst )
- {
- // Generate bytecode for global-scope inst
- generateBytecodeForInst(context, inst);
- }
- // Need to encode a terminator here, just to keep the encoding valid
- encodeUInt(context, kIROp_ReturnVoid);
+ switch(irConstant->op)
+ {
+ case kIROp_IntLit:
+ {
+ auto ptr = allocate<IRIntegerValue>(context);
+ *ptr = irConstant->u.intVal;
+ bcConstants[cc].ptr = ptr.bitCast<uint8_t>();
+ }
+ break;
-#if 0
+ default:
+ break;
+ }
- // Now we can go through and generate the bytecode object
- // that will represent each of these global symbols
+ }
- List<BytecodeGenerationPtr<BCSymbol>> globalSymbols;
+ // 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 = typeCount;
+ bcModule->types = bcTypes;
- for( auto inst = irModule->firstChild; inst; inst = inst->nextInst )
+ for(UInt tt = 0; tt < typeCount; ++tt)
{
- // Generate bytecode for global-scope inst
- auto globalSymbol = generateBytecodeForGlobalSymbol(context, inst);
- globalSymbols.Add(globalSymbol);
+ bcTypes[tt] = context->shared->bcTypes[tt];
}
-#endif
+
return bcModule;
}
@@ -833,10 +1042,6 @@ void generateBytecodeStream(
memcpy(header->magic, "slang\0bc", sizeof(header->magic));
header->version = 0;
- // HACK: ensure that a NULL pointer in an operand field can
- // be encoded.
- context->shared->mapGlobalSymbolToGLobalID.Add(nullptr, -1);
-
header->module = generateBytecodeForModule(context, irModule);
}