diff options
Diffstat (limited to 'source/slang/bytecode.cpp')
| -rw-r--r-- | source/slang/bytecode.cpp | 555 |
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); } |
