Path: blob/master/thirdparty/glslang/SPIRV/SpvBuilder.h
21958 views
//1// Copyright (C) 2014-2015 LunarG, Inc.2// Copyright (C) 2015-2020 Google, Inc.3// Copyright (C) 2017 ARM Limited.4// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved.5//6// All rights reserved.7//8// Redistribution and use in source and binary forms, with or without9// modification, are permitted provided that the following conditions10// are met:11//12// Redistributions of source code must retain the above copyright13// notice, this list of conditions and the following disclaimer.14//15// Redistributions in binary form must reproduce the above16// copyright notice, this list of conditions and the following17// disclaimer in the documentation and/or other materials provided18// with the distribution.19//20// Neither the name of 3Dlabs Inc. Ltd. nor the names of its21// contributors may be used to endorse or promote products derived22// from this software without specific prior written permission.23//24// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS25// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT26// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS27// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE28// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,29// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,30// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;31// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER32// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT33// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN34// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE35// POSSIBILITY OF SUCH DAMAGE.3637//38// "Builder" is an interface to fully build SPIR-V IR. Allocate one of39// these to build (a thread safe) internal SPIR-V representation (IR),40// and then dump it as a binary stream according to the SPIR-V specification.41//42// A Builder has a 1:1 relationship with a SPIR-V module.43//4445#pragma once46#ifndef SpvBuilder_H47#define SpvBuilder_H4849#include "Logger.h"50#define SPV_ENABLE_UTILITY_CODE51#include "spirv.hpp11"52#include "spvIR.h"53#include "spvUtil.h"5455namespace spv {56#include "GLSL.ext.KHR.h"57#include "GLSL.ext.EXT.h"58#include "NonSemanticShaderDebugInfo100.h"59}6061#include <algorithm>62#include <cstdint>63#include <map>64#include <memory>65#include <set>66#include <sstream>67#include <stack>68#include <unordered_map>69#include <unordered_set>70#include <map>7172namespace spv {7374typedef enum {75Spv_1_0 = (1 << 16),76Spv_1_1 = (1 << 16) | (1 << 8),77Spv_1_2 = (1 << 16) | (2 << 8),78Spv_1_3 = (1 << 16) | (3 << 8),79Spv_1_4 = (1 << 16) | (4 << 8),80Spv_1_5 = (1 << 16) | (5 << 8),81Spv_1_6 = (1 << 16) | (6 << 8),82} SpvVersion;8384struct StructMemberDebugInfo {85std::string name {};86int line {0};87int column {0};88// Set if the caller knows a better debug type than what is associated with the functional SPIR-V type.89spv::Id debugTypeOverride {0};90};9192class Builder {93public:94Builder(unsigned int spvVersion, unsigned int userNumber, SpvBuildLogger* logger);95virtual ~Builder();9697static const int maxMatrixSize = 4;9899unsigned int getSpvVersion() const { return spvVersion; }100101void setSource(spv::SourceLanguage lang, int version)102{103sourceLang = lang;104sourceVersion = version;105}106spv::Id getStringId(const std::string& str)107{108auto sItr = stringIds.find(str);109if (sItr != stringIds.end())110return sItr->second;111spv::Id strId = getUniqueId();112Instruction* fileString = new Instruction(strId, NoType, Op::OpString);113const char* file_c_str = str.c_str();114fileString->addStringOperand(file_c_str);115strings.push_back(std::unique_ptr<Instruction>(fileString));116module.mapInstruction(fileString);117stringIds[file_c_str] = strId;118return strId;119}120121spv::Id getMainFileId() const { return mainFileId; }122123// Initialize the main source file name124void setDebugMainSourceFile(const std::string& file)125{126if (trackDebugInfo) {127dirtyLineTracker = true;128mainFileId = getStringId(file);129currentFileId = mainFileId;130}131}132133// Set the debug source location tracker in the builder.134// The upcoming instructions in basic blocks will be associated to this location.135void setDebugSourceLocation(int line, const char* filename)136{137if (trackDebugInfo) {138dirtyLineTracker = true;139if (line != 0) {140// TODO: This is special handling of some AST nodes having (untracked) line 0.141// But they should have a valid line number.142currentLine = line;143if (filename) {144currentFileId = getStringId(filename);145}146}147}148}149150void setSourceText(const std::string& text) { sourceText = text; }151void addSourceExtension(const char* ext) { sourceExtensions.push_back(ext); }152void addModuleProcessed(const std::string& p) { moduleProcesses.push_back(p.c_str()); }153void setEmitSpirvDebugInfo()154{155trackDebugInfo = true;156emitSpirvDebugInfo = true;157}158void setEmitNonSemanticShaderDebugInfo(bool emitSourceText)159{160trackDebugInfo = true;161emitNonSemanticShaderDebugInfo = true;162importNonSemanticShaderDebugInfoInstructions();163164if (emitSourceText) {165emitNonSemanticShaderDebugSource = emitSourceText;166}167}168void addExtension(const char* ext) { extensions.insert(ext); }169void removeExtension(const char* ext)170{171extensions.erase(ext);172}173void addIncorporatedExtension(const char* ext, SpvVersion incorporatedVersion)174{175if (getSpvVersion() < static_cast<unsigned>(incorporatedVersion))176addExtension(ext);177}178void promoteIncorporatedExtension(const char* baseExt, const char* promoExt, SpvVersion incorporatedVersion)179{180removeExtension(baseExt);181addIncorporatedExtension(promoExt, incorporatedVersion);182}183void addInclude(const std::string& name, const std::string& text)184{185spv::Id incId = getStringId(name);186includeFiles[incId] = &text;187}188Id import(const char*);189void setMemoryModel(spv::AddressingModel addr, spv::MemoryModel mem)190{191addressModel = addr;192memoryModel = mem;193}194195void addCapability(spv::Capability cap) { capabilities.insert(cap); }196197// To get a new <id> for anything needing a new one.198Id getUniqueId() { return ++uniqueId; }199200// To get a set of new <id>s, e.g., for a set of function parameters201Id getUniqueIds(int numIds)202{203Id id = uniqueId + 1;204uniqueId += numIds;205return id;206}207208// Maps the given OpType Id to a Non-Semantic DebugType Id.209Id getDebugType(Id type) {210if (auto it = debugTypeIdLookup.find(type); it != debugTypeIdLookup.end()) {211return it->second;212}213214return NoType;215}216217// Maps the given OpFunction Id to a Non-Semantic DebugFunction Id.218Id getDebugFunction(Id func) {219if (auto it = debugFuncIdLookup.find(func); it != debugFuncIdLookup.end()) {220return it->second;221}222223return NoResult;224}225226// For creating new types (will return old type if the requested one was already made).227Id makeVoidType();228Id makeBoolType();229Id makePointer(StorageClass, Id pointee);230Id makeForwardPointer(StorageClass);231Id makePointerFromForwardPointer(StorageClass, Id forwardPointerType, Id pointee);232Id makeIntegerType(int width, bool hasSign); // generic233Id makeIntType(int width) { return makeIntegerType(width, true); }234Id makeUintType(int width) { return makeIntegerType(width, false); }235Id makeFloatType(int width);236Id makeBFloat16Type();237Id makeFloatE5M2Type();238Id makeFloatE4M3Type();239Id makeStructType(const std::vector<Id>& members, const std::vector<spv::StructMemberDebugInfo>& memberDebugInfo,240const char* name, bool const compilerGenerated = true);241Id makeStructResultType(Id type0, Id type1);242Id makeVectorType(Id component, int size);243Id makeMatrixType(Id component, int cols, int rows);244Id makeArrayType(Id element, Id sizeId, int stride); // 0 stride means no stride decoration245Id makeRuntimeArray(Id element);246Id makeFunctionType(Id returnType, const std::vector<Id>& paramTypes);247Id makeImageType(Id sampledType, Dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format, const char* debugNames);248Id makeSamplerType(const char* debugName);249Id makeSampledImageType(Id imageType, const char* debugName);250Id makeCooperativeMatrixTypeKHR(Id component, Id scope, Id rows, Id cols, Id use);251Id makeCooperativeMatrixTypeNV(Id component, Id scope, Id rows, Id cols);252Id makeCooperativeMatrixTypeWithSameShape(Id component, Id otherType);253Id makeCooperativeVectorTypeNV(Id componentType, Id components);254Id makeTensorTypeARM(Id elementType, Id rank);255Id makeGenericType(spv::Op opcode, std::vector<spv::IdImmediate>& operands);256257// SPIR-V NonSemantic Shader DebugInfo Instructions258Id makeDebugInfoNone();259Id makeBoolDebugType(int const size);260Id makeIntegerDebugType(int const width, bool const hasSign);261Id makeFloatDebugType(int const width);262Id makeSequentialDebugType(Id const baseType, Id const componentCount, NonSemanticShaderDebugInfo100Instructions const sequenceType);263Id makeArrayDebugType(Id const baseType, Id const componentCount);264Id makeVectorDebugType(Id const baseType, int const componentCount);265Id makeMatrixDebugType(Id const vectorType, int const vectorCount, bool columnMajor = true);266Id makeMemberDebugType(Id const memberType, StructMemberDebugInfo const& debugTypeLoc);267Id makeCompositeDebugType(std::vector<Id> const& memberTypes, std::vector<StructMemberDebugInfo> const& memberDebugInfo,268char const* const name, NonSemanticShaderDebugInfo100DebugCompositeType const tag);269Id makeOpaqueDebugType(char const* const name);270Id makePointerDebugType(StorageClass storageClass, Id const baseType);271Id makeForwardPointerDebugType(StorageClass storageClass);272Id makeDebugSource(const Id fileName);273Id makeDebugCompilationUnit();274Id createDebugGlobalVariable(Id const type, char const*const name, Id const variable);275Id createDebugLocalVariable(Id type, char const*const name, size_t const argNumber = 0);276Id makeDebugExpression();277Id makeDebugDeclare(Id const debugLocalVariable, Id const pointer);278Id makeDebugValue(Id const debugLocalVariable, Id const value);279Id makeDebugFunctionType(Id returnType, const std::vector<Id>& paramTypes);280Id makeDebugFunction(Function* function, Id nameId, Id funcTypeId);281Id makeDebugLexicalBlock(uint32_t line, uint32_t column);282std::string unmangleFunctionName(std::string const& name) const;283284// Initialize non-semantic debug information for a function, including those of:285// - The function definition286// - The function parameters287void setupFunctionDebugInfo(Function* function, const char* name, const std::vector<Id>& paramTypes,288const std::vector<char const*>& paramNames);289290// accelerationStructureNV type291Id makeAccelerationStructureType();292// rayQueryEXT type293Id makeRayQueryType();294// hitObjectNV type295Id makeHitObjectNVType();296// hitObjectEXT type297Id makeHitObjectEXTType();298299// For querying about types.300Id getTypeId(Id resultId) const { return module.getTypeId(resultId); }301Id getDerefTypeId(Id resultId) const;302Op getOpCode(Id id) const { return module.getInstruction(id)->getOpCode(); }303Op getTypeClass(Id typeId) const { return getOpCode(typeId); }304Op getMostBasicTypeClass(Id typeId) const;305unsigned int getNumComponents(Id resultId) const { return getNumTypeComponents(getTypeId(resultId)); }306unsigned int getNumTypeConstituents(Id typeId) const;307unsigned int getNumTypeComponents(Id typeId) const { return getNumTypeConstituents(typeId); }308Id getScalarTypeId(Id typeId) const;309Id getContainedTypeId(Id typeId) const;310Id getContainedTypeId(Id typeId, int) const;311StorageClass getTypeStorageClass(Id typeId) const { return module.getStorageClass(typeId); }312ImageFormat getImageTypeFormat(Id typeId) const313{ return (ImageFormat)module.getInstruction(typeId)->getImmediateOperand(6); }314Id getResultingAccessChainType() const;315Id getIdOperand(Id resultId, int idx) { return module.getInstruction(resultId)->getIdOperand(idx); }316Id getCooperativeVectorNumComponents(Id typeId) const { return module.getInstruction(typeId)->getIdOperand(1); }317318bool isPointer(Id resultId) const { return isPointerType(getTypeId(resultId)); }319bool isScalar(Id resultId) const { return isScalarType(getTypeId(resultId)); }320bool isVector(Id resultId) const { return isVectorType(getTypeId(resultId)); }321bool isMatrix(Id resultId) const { return isMatrixType(getTypeId(resultId)); }322bool isCooperativeMatrix(Id resultId)const { return isCooperativeMatrixType(getTypeId(resultId)); }323bool isCooperativeVector(Id resultId)const { return isCooperativeVectorType(getTypeId(resultId)); }324bool isAggregate(Id resultId) const { return isAggregateType(getTypeId(resultId)); }325bool isSampledImage(Id resultId) const { return isSampledImageType(getTypeId(resultId)); }326bool isTensorView(Id resultId)const { return isTensorViewType(getTypeId(resultId)); }327328bool isBoolType(Id typeId)329{ return groupedTypes[enumCast(Op::OpTypeBool)].size() > 0 && typeId == groupedTypes[enumCast(Op::OpTypeBool)].back()->getResultId(); }330bool isIntType(Id typeId) const331{ return getTypeClass(typeId) == Op::OpTypeInt && module.getInstruction(typeId)->getImmediateOperand(1) != 0; }332bool isUintType(Id typeId) const333{ return getTypeClass(typeId) == Op::OpTypeInt && module.getInstruction(typeId)->getImmediateOperand(1) == 0; }334bool isFloatType(Id typeId) const { return getTypeClass(typeId) == Op::OpTypeFloat; }335bool isPointerType(Id typeId) const { return getTypeClass(typeId) == Op::OpTypePointer; }336bool isScalarType(Id typeId) const337{ return getTypeClass(typeId) == Op::OpTypeFloat || getTypeClass(typeId) == Op::OpTypeInt ||338getTypeClass(typeId) == Op::OpTypeBool; }339bool isVectorType(Id typeId) const { return getTypeClass(typeId) == Op::OpTypeVector; }340bool isMatrixType(Id typeId) const { return getTypeClass(typeId) == Op::OpTypeMatrix; }341bool isStructType(Id typeId) const { return getTypeClass(typeId) == Op::OpTypeStruct; }342bool isArrayType(Id typeId) const { return getTypeClass(typeId) == Op::OpTypeArray; }343bool isCooperativeMatrixType(Id typeId)const344{345return getTypeClass(typeId) == Op::OpTypeCooperativeMatrixKHR || getTypeClass(typeId) == Op::OpTypeCooperativeMatrixNV;346}347bool isTensorViewType(Id typeId) const { return getTypeClass(typeId) == Op::OpTypeTensorViewNV; }348bool isCooperativeVectorType(Id typeId) const { return getTypeClass(typeId) == Op::OpTypeCooperativeVectorNV; }349bool isTensorTypeARM(Id typeId) const { return getTypeClass(typeId) == Op::OpTypeTensorARM; }350bool isAggregateType(Id typeId) const351{ return isArrayType(typeId) || isStructType(typeId) || isCooperativeMatrixType(typeId); }352bool isImageType(Id typeId) const { return getTypeClass(typeId) == Op::OpTypeImage; }353bool isSamplerType(Id typeId) const { return getTypeClass(typeId) == Op::OpTypeSampler; }354bool isSampledImageType(Id typeId) const { return getTypeClass(typeId) == Op::OpTypeSampledImage; }355bool containsType(Id typeId, Op typeOp, unsigned int width) const;356bool containsPhysicalStorageBufferOrArray(Id typeId) const;357358bool isConstantOpCode(Op opcode) const;359bool isSpecConstantOpCode(Op opcode) const;360bool isConstant(Id resultId) const { return isConstantOpCode(getOpCode(resultId)); }361bool isConstantScalar(Id resultId) const { return getOpCode(resultId) == Op::OpConstant; }362bool isSpecConstant(Id resultId) const { return isSpecConstantOpCode(getOpCode(resultId)); }363unsigned int getConstantScalar(Id resultId) const364{ return module.getInstruction(resultId)->getImmediateOperand(0); }365StorageClass getStorageClass(Id resultId) const { return getTypeStorageClass(getTypeId(resultId)); }366367bool isVariableOpCode(Op opcode) const { return opcode == Op::OpVariable; }368bool isVariable(Id resultId) const { return isVariableOpCode(getOpCode(resultId)); }369bool isGlobalStorage(Id resultId) const { return getStorageClass(resultId) != StorageClass::Function; }370bool isGlobalVariable(Id resultId) const { return isVariable(resultId) && isGlobalStorage(resultId); }371// See if a resultId is valid for use as an initializer.372bool isValidInitializer(Id resultId) const { return isConstant(resultId) || isGlobalVariable(resultId); }373374int getScalarTypeWidth(Id typeId) const375{376Id scalarTypeId = getScalarTypeId(typeId);377assert(getTypeClass(scalarTypeId) == Op::OpTypeInt || getTypeClass(scalarTypeId) == Op::OpTypeFloat);378return module.getInstruction(scalarTypeId)->getImmediateOperand(0);379}380381unsigned int getTypeNumColumns(Id typeId) const382{383assert(isMatrixType(typeId));384return getNumTypeConstituents(typeId);385}386unsigned int getNumColumns(Id resultId) const { return getTypeNumColumns(getTypeId(resultId)); }387unsigned int getTypeNumRows(Id typeId) const388{389assert(isMatrixType(typeId));390return getNumTypeComponents(getContainedTypeId(typeId));391}392unsigned int getNumRows(Id resultId) const { return getTypeNumRows(getTypeId(resultId)); }393394Dim getTypeDimensionality(Id typeId) const395{396assert(isImageType(typeId));397return (Dim)module.getInstruction(typeId)->getImmediateOperand(1);398}399Id getImageType(Id resultId) const400{401Id typeId = getTypeId(resultId);402assert(isImageType(typeId) || isSampledImageType(typeId));403return isSampledImageType(typeId) ? module.getInstruction(typeId)->getIdOperand(0) : typeId;404}405bool isArrayedImageType(Id typeId) const406{407assert(isImageType(typeId));408return module.getInstruction(typeId)->getImmediateOperand(3) != 0;409}410411// For making new constants (will return old constant if the requested one was already made).412Id makeNullConstant(Id typeId);413Id makeBoolConstant(bool b, bool specConstant = false);414Id makeIntConstant(Id typeId, unsigned value, bool specConstant);415Id makeInt64Constant(Id typeId, unsigned long long value, bool specConstant);416Id makeInt8Constant(int i, bool specConstant = false)417{ return makeIntConstant(makeIntType(8), (unsigned)i, specConstant); }418Id makeUint8Constant(unsigned u, bool specConstant = false)419{ return makeIntConstant(makeUintType(8), u, specConstant); }420Id makeInt16Constant(int i, bool specConstant = false)421{ return makeIntConstant(makeIntType(16), (unsigned)i, specConstant); }422Id makeUint16Constant(unsigned u, bool specConstant = false)423{ return makeIntConstant(makeUintType(16), u, specConstant); }424Id makeIntConstant(int i, bool specConstant = false)425{ return makeIntConstant(makeIntType(32), (unsigned)i, specConstant); }426Id makeUintConstant(unsigned u, bool specConstant = false)427{ return makeIntConstant(makeUintType(32), u, specConstant); }428Id makeUintConstant(Scope u, bool specConstant = false)429{ return makeUintConstant((unsigned)u, specConstant); }430Id makeUintConstant(StorageClass u, bool specConstant = false)431{ return makeUintConstant((unsigned)u, specConstant); }432Id makeUintConstant(MemorySemanticsMask u, bool specConstant = false)433{ return makeUintConstant((unsigned)u, specConstant); }434Id makeUintConstant(SourceLanguage u, bool specConstant = false)435{ return makeUintConstant((unsigned)u, specConstant); }436Id makeInt64Constant(long long i, bool specConstant = false)437{ return makeInt64Constant(makeIntType(64), (unsigned long long)i, specConstant); }438Id makeUint64Constant(unsigned long long u, bool specConstant = false)439{ return makeInt64Constant(makeUintType(64), u, specConstant); }440Id makeFloatConstant(float f, bool specConstant = false);441Id makeDoubleConstant(double d, bool specConstant = false);442Id makeFloat16Constant(float f16, bool specConstant = false);443Id makeBFloat16Constant(float bf16, bool specConstant = false);444Id makeFloatE5M2Constant(float fe5m2, bool specConstant = false);445Id makeFloatE4M3Constant(float fe4m3, bool specConstant = false);446Id makeFpConstant(Id type, double d, bool specConstant = false);447448Id importNonSemanticShaderDebugInfoInstructions();449450// Turn the array of constants into a proper spv constant of the requested type.451Id makeCompositeConstant(Id type, const std::vector<Id>& comps, bool specConst = false);452453// Methods for adding information outside the CFG.454Instruction* addEntryPoint(ExecutionModel, Function*, const char* name);455void addExecutionMode(Function*, ExecutionMode mode, int value1 = -1, int value2 = -1, int value3 = -1);456void addExecutionMode(Function*, ExecutionMode mode, const std::vector<unsigned>& literals);457void addExecutionModeId(Function*, ExecutionMode mode, const std::vector<Id>& operandIds);458void addName(Id, const char* name);459void addMemberName(Id, int member, const char* name);460void addDecoration(Id, Decoration, int num = -1);461void addDecoration(Id, Decoration, const char*);462void addDecoration(Id, Decoration, const std::vector<unsigned>& literals);463void addDecoration(Id, Decoration, const std::vector<const char*>& strings);464void addLinkageDecoration(Id id, const char* name, spv::LinkageType linkType);465void addDecorationId(Id id, Decoration, Id idDecoration);466void addDecorationId(Id id, Decoration, const std::vector<Id>& operandIds);467void addMemberDecoration(Id, unsigned int member, Decoration, int num = -1);468void addMemberDecoration(Id, unsigned int member, Decoration, const char*);469void addMemberDecoration(Id, unsigned int member, Decoration, const std::vector<unsigned>& literals);470void addMemberDecoration(Id, unsigned int member, Decoration, const std::vector<const char*>& strings);471472// At the end of what block do the next create*() instructions go?473// Also reset current last DebugScope and current source line to unknown474void setBuildPoint(Block* bp) {475buildPoint = bp;476dirtyLineTracker = true;477dirtyScopeTracker = true;478}479Block* getBuildPoint() const { return buildPoint; }480481// Append an instruction to the end of the current build point.482// Optionally, additional debug info instructions may also be prepended.483void addInstruction(std::unique_ptr<Instruction> inst);484485// Append an instruction to the end of the current build point without prepending any debug instructions.486// This is useful for insertion of some debug info instructions themselves or some control flow instructions487// that are attached to its predecessor instruction.488void addInstructionNoDebugInfo(std::unique_ptr<Instruction> inst);489490// Make the entry-point function. The returned pointer is only valid491// for the lifetime of this builder.492Function* makeEntryPoint(const char*);493494// Make a shader-style function, and create its entry block if entry is non-zero.495// Return the function, pass back the entry.496// The returned pointer is only valid for the lifetime of this builder.497Function* makeFunctionEntry(Decoration precision, Id returnType, const char* name, LinkageType linkType,498const std::vector<Id>& paramTypes,499const std::vector<std::vector<Decoration>>& precisions, Block** entry = nullptr);500501// Create a return. An 'implicit' return is one not appearing in the source502// code. In the case of an implicit return, no post-return block is inserted.503void makeReturn(bool implicit, Id retVal = 0);504505// Initialize state and generate instructions for new lexical scope506void enterLexicalBlock(uint32_t line, uint32_t column);507508// Set state and generate instructions to exit current lexical scope509void leaveLexicalBlock();510511// Prepare builder for generation of instructions for a function.512void enterFunction(Function const* function);513514// Generate all the code needed to finish up a function.515void leaveFunction();516517// Create block terminator instruction for certain statements like518// discard, terminate-invocation, terminateRayEXT, or ignoreIntersectionEXT519void makeStatementTerminator(spv::Op opcode, const char *name);520521// Create block terminator instruction for statements that have input operands522// such as OpEmitMeshTasksEXT523void makeStatementTerminator(spv::Op opcode, const std::vector<Id>& operands, const char* name);524525// Create a global/local constant. Because OpConstant is automatically emitted by getting the constant526// ids, this function only handles debug info.527void createConstVariable(Id type, const char* name, Id constant, bool isGlobal);528529// Create a global or function local or IO variable.530Id createVariable(Decoration precision, StorageClass storageClass, Id type, const char* name = nullptr,531Id initializer = NoResult, bool const compilerGenerated = true);532533// Create an intermediate with an undefined value.534Id createUndefined(Id type);535536// Store into an Id and return the l-value537void createStore(Id rValue, Id lValue, spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMask::MaskNone,538spv::Scope scope = spv::Scope::Max, unsigned int alignment = 0);539540// Load from an Id and return it541Id createLoad(Id lValue, spv::Decoration precision,542spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMask::MaskNone,543spv::Scope scope = spv::Scope::Max, unsigned int alignment = 0);544545// Create an OpAccessChain instruction546Id createAccessChain(StorageClass, Id base, const std::vector<Id>& offsets);547548// Create an OpArrayLength instruction549Id createArrayLength(Id base, unsigned int member, unsigned int bits);550551// Create an OpCooperativeMatrixLengthKHR instruction552Id createCooperativeMatrixLengthKHR(Id type);553// Create an OpCooperativeMatrixLengthNV instruction554Id createCooperativeMatrixLengthNV(Id type);555556// Create an OpCompositeExtract instruction557Id createCompositeExtract(Id composite, Id typeId, unsigned index);558Id createCompositeExtract(Id composite, Id typeId, const std::vector<unsigned>& indexes);559Id createCompositeInsert(Id object, Id composite, Id typeId, unsigned index);560Id createCompositeInsert(Id object, Id composite, Id typeId, const std::vector<unsigned>& indexes);561562Id createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex);563Id createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex);564565void createNoResultOp(Op);566void createNoResultOp(Op, Id operand);567void createNoResultOp(Op, const std::vector<Id>& operands);568void createNoResultOp(Op, const std::vector<IdImmediate>& operands);569void createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask);570void createMemoryBarrier(Scope executionScope, MemorySemanticsMask memorySemantics);571Id createUnaryOp(Op, Id typeId, Id operand);572Id createBinOp(Op, Id typeId, Id operand1, Id operand2);573Id createTriOp(Op, Id typeId, Id operand1, Id operand2, Id operand3);574Id createOp(Op, Id typeId, const std::vector<Id>& operands);575Id createOp(Op, Id typeId, const std::vector<IdImmediate>& operands);576Id createFunctionCall(spv::Function*, const std::vector<spv::Id>&);577Id createSpecConstantOp(Op, Id typeId, const std::vector<spv::Id>& operands, const std::vector<unsigned>& literals);578579// Take an rvalue (source) and a set of channels to extract from it to580// make a new rvalue, which is returned.581Id createRvalueSwizzle(Decoration precision, Id typeId, Id source, const std::vector<unsigned>& channels);582583// Take a copy of an lvalue (target) and a source of components, and set the584// source components into the lvalue where the 'channels' say to put them.585// An updated version of the target is returned.586// (No true lvalue or stores are used.)587Id createLvalueSwizzle(Id typeId, Id target, Id source, const std::vector<unsigned>& channels);588589// If both the id and precision are valid, the id590// gets tagged with the requested precision.591// The passed in id is always the returned id, to simplify use patterns.592Id setPrecision(Id id, Decoration precision)593{594if (precision != NoPrecision && id != NoResult)595addDecoration(id, precision);596597return id;598}599600// Can smear a scalar to a vector for the following forms:601// - promoteScalar(scalar, vector) // smear scalar to width of vector602// - promoteScalar(vector, scalar) // smear scalar to width of vector603// - promoteScalar(pointer, scalar) // smear scalar to width of what pointer points to604// - promoteScalar(scalar, scalar) // do nothing605// Other forms are not allowed.606//607// Generally, the type of 'scalar' does not need to be the same type as the components in 'vector'.608// The type of the created vector is a vector of components of the same type as the scalar.609//610// Note: One of the arguments will change, with the result coming back that way rather than611// through the return value.612void promoteScalar(Decoration precision, Id& left, Id& right);613614// Make a value by smearing the scalar to fill the type.615// vectorType should be the correct type for making a vector of scalarVal.616// (No conversions are done.)617Id smearScalar(Decoration precision, Id scalarVal, Id vectorType);618619// Create a call to a built-in function.620Id createBuiltinCall(Id resultType, Id builtins, int entryPoint, const std::vector<Id>& args);621622// List of parameters used to create a texture operation623struct TextureParameters {624Id sampler;625Id coords;626Id bias;627Id lod;628Id Dref;629Id offset;630Id offsets;631Id gradX;632Id gradY;633Id sample;634Id component;635Id texelOut;636Id lodClamp;637Id granularity;638Id coarse;639bool nonprivate;640bool volatil;641bool nontemporal;642};643644// Select the correct texture operation based on all inputs, and emit the correct instruction645Id createTextureCall(Decoration precision, Id resultType, bool sparse, bool fetch, bool proj, bool gather,646bool noImplicit, const TextureParameters&, ImageOperandsMask);647648// Emit the OpTextureQuery* instruction that was passed in.649// Figure out the right return value and type, and return it.650Id createTextureQueryCall(Op, const TextureParameters&, bool isUnsignedResult);651652Id createSamplePositionCall(Decoration precision, Id, Id);653654Id createBitFieldExtractCall(Decoration precision, Id, Id, Id, bool isSigned);655Id createBitFieldInsertCall(Decoration precision, Id, Id, Id, Id);656657// Reduction comparison for composites: For equal and not-equal resulting in a scalar.658Id createCompositeCompare(Decoration precision, Id, Id, bool /* true if for equal, false if for not-equal */);659660// OpCompositeConstruct661Id createCompositeConstruct(Id typeId, const std::vector<Id>& constituents);662663// vector or scalar constructor664Id createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId);665666// matrix constructor667Id createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id constructee);668669// coopmat conversion670Id createCooperativeMatrixConversion(Id typeId, Id source);671Id createCooperativeMatrixReduce(Op opcode, Id typeId, Id source, unsigned int mask, Id func);672Id createCooperativeMatrixPerElementOp(Id typeId, const std::vector<Id>& operands);673674// Helper to use for building nested control flow with if-then-else.675class If {676public:677If(Id condition, SelectionControlMask ctrl, Builder& builder);678~If() {}679680void makeBeginElse();681void makeEndIf();682683private:684If(const If&);685If& operator=(If&);686687Builder& builder;688Id condition;689SelectionControlMask control;690Function* function;691Block* headerBlock;692Block* thenBlock;693Block* elseBlock;694Block* mergeBlock;695};696697// Make a switch statement. A switch has 'numSegments' of pieces of code, not containing698// any case/default labels, all separated by one or more case/default labels. Each possible699// case value v is a jump to the caseValues[v] segment. The defaultSegment is also in this700// number space. How to compute the value is given by 'condition', as in switch(condition).701//702// The SPIR-V Builder will maintain the stack of post-switch merge blocks for nested switches.703//704// Use a defaultSegment < 0 if there is no default segment (to branch to post switch).705//706// Returns the right set of basic blocks to start each code segment with, so that the caller's707// recursion stack can hold the memory for it.708//709void makeSwitch(Id condition, SelectionControlMask control, int numSegments, const std::vector<int>& caseValues,710const std::vector<int>& valueToSegment, int defaultSegment, std::vector<Block*>& segmentBB);711712// Add a branch to the innermost switch's merge block.713void addSwitchBreak(bool implicit);714715// Move to the next code segment, passing in the return argument in makeSwitch()716void nextSwitchSegment(std::vector<Block*>& segmentBB, int segment);717718// Finish off the innermost switch.719void endSwitch(std::vector<Block*>& segmentBB);720721struct LoopBlocks {722LoopBlocks(Block& head, Block& body, Block& merge, Block& continue_target) :723head(head), body(body), merge(merge), continue_target(continue_target) { }724Block &head, &body, &merge, &continue_target;725private:726LoopBlocks();727LoopBlocks& operator=(const LoopBlocks&) = delete;728};729730// Start a new loop and prepare the builder to generate code for it. Until731// closeLoop() is called for this loop, createLoopContinue() and732// createLoopExit() will target its corresponding blocks.733LoopBlocks& makeNewLoop();734735// Create a new block in the function containing the build point. Memory is736// owned by the function object.737Block& makeNewBlock();738739// Add a branch to the continue_target of the current (innermost) loop.740void createLoopContinue();741742// Add an exit (e.g. "break") from the innermost loop that we're currently743// in.744void createLoopExit();745746// Close the innermost loop that you're in747void closeLoop();748749//750// Access chain design for an R-Value vs. L-Value:751//752// There is a single access chain the builder is building at753// any particular time. Such a chain can be used to either to a load or754// a store, when desired.755//756// Expressions can be r-values, l-values, or both, or only r-values:757// a[b.c].d = .... // l-value758// ... = a[b.c].d; // r-value, that also looks like an l-value759// ++a[b.c].d; // r-value and l-value760// (x + y)[2]; // r-value only, can't possibly be l-value761//762// Computing an r-value means generating code. Hence,763// r-values should only be computed when they are needed, not speculatively.764//765// Computing an l-value means saving away information for later use in the compiler,766// no code is generated until the l-value is later dereferenced. It is okay767// to speculatively generate an l-value, just not okay to speculatively dereference it.768//769// The base of the access chain (the left-most variable or expression770// from which everything is based) can be set either as an l-value771// or as an r-value. Most efficient would be to set an l-value if one772// is available. If an expression was evaluated, the resulting r-value773// can be set as the chain base.774//775// The users of this single access chain can save and restore if they776// want to nest or manage multiple chains.777//778779struct AccessChain {780Id base; // for l-values, pointer to the base object, for r-values, the base object781std::vector<Id> indexChain;782Id instr; // cache the instruction that generates this access chain783std::vector<unsigned> swizzle; // each std::vector element selects the next GLSL component number784Id component; // a dynamic component index, can coexist with a swizzle,785// done after the swizzle, NoResult if not present786Id preSwizzleBaseType; // dereferenced type, before swizzle or component is applied;787// NoType unless a swizzle or component is present788bool isRValue; // true if 'base' is an r-value, otherwise, base is an l-value789unsigned int alignment; // bitwise OR of alignment values passed in. Accumulates worst alignment.790// Only tracks base and (optional) component selection alignment.791792// Accumulate whether anything in the chain of structures has coherent decorations.793struct CoherentFlags {794CoherentFlags() { clear(); }795bool isVolatile() const { return volatil; }796bool isNonUniform() const { return nonUniform; }797bool anyCoherent() const {798return coherent || devicecoherent || queuefamilycoherent || workgroupcoherent ||799subgroupcoherent || shadercallcoherent;800}801802unsigned coherent : 1;803unsigned devicecoherent : 1;804unsigned queuefamilycoherent : 1;805unsigned workgroupcoherent : 1;806unsigned subgroupcoherent : 1;807unsigned shadercallcoherent : 1;808unsigned nonprivate : 1;809unsigned volatil : 1;810unsigned nontemporal : 1;811unsigned isImage : 1;812unsigned nonUniform : 1;813814void clear() {815coherent = 0;816devicecoherent = 0;817queuefamilycoherent = 0;818workgroupcoherent = 0;819subgroupcoherent = 0;820shadercallcoherent = 0;821nonprivate = 0;822volatil = 0;823nontemporal = 0;824isImage = 0;825nonUniform = 0;826}827828CoherentFlags operator |=(const CoherentFlags &other) {829coherent |= other.coherent;830devicecoherent |= other.devicecoherent;831queuefamilycoherent |= other.queuefamilycoherent;832workgroupcoherent |= other.workgroupcoherent;833subgroupcoherent |= other.subgroupcoherent;834shadercallcoherent |= other.shadercallcoherent;835nonprivate |= other.nonprivate;836volatil |= other.volatil;837nontemporal = other.nontemporal;838isImage |= other.isImage;839nonUniform |= other.nonUniform;840return *this;841}842};843CoherentFlags coherentFlags;844};845846//847// the SPIR-V builder maintains a single active chain that848// the following methods operate on849//850851// for external save and restore852AccessChain getAccessChain() { return accessChain; }853void setAccessChain(AccessChain newChain) { accessChain = newChain; }854855// clear accessChain856void clearAccessChain();857858// set new base as an l-value base859void setAccessChainLValue(Id lValue)860{861assert(isPointer(lValue));862accessChain.base = lValue;863}864865// set new base value as an r-value866void setAccessChainRValue(Id rValue)867{868accessChain.isRValue = true;869accessChain.base = rValue;870}871872// push offset onto the end of the chain873void accessChainPush(Id offset, AccessChain::CoherentFlags coherentFlags, unsigned int alignment)874{875accessChain.indexChain.push_back(offset);876accessChain.coherentFlags |= coherentFlags;877accessChain.alignment |= alignment;878}879880// push new swizzle onto the end of any existing swizzle, merging into a single swizzle881void accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType,882AccessChain::CoherentFlags coherentFlags, unsigned int alignment);883884// push a dynamic component selection onto the access chain, only applicable with a885// non-trivial swizzle or no swizzle886void accessChainPushComponent(Id component, Id preSwizzleBaseType, AccessChain::CoherentFlags coherentFlags,887unsigned int alignment)888{889if (accessChain.swizzle.size() != 1) {890accessChain.component = component;891if (accessChain.preSwizzleBaseType == NoType)892accessChain.preSwizzleBaseType = preSwizzleBaseType;893}894accessChain.coherentFlags |= coherentFlags;895accessChain.alignment |= alignment;896}897898// use accessChain and swizzle to store value899void accessChainStore(Id rvalue, Decoration nonUniform,900spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMask::MaskNone,901spv::Scope scope = spv::Scope::Max, unsigned int alignment = 0);902903// use accessChain and swizzle to load an r-value904Id accessChainLoad(Decoration precision, Decoration l_nonUniform, Decoration r_nonUniform, Id ResultType,905spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMask::MaskNone, spv::Scope scope = spv::Scope::Max,906unsigned int alignment = 0);907908// Return whether or not the access chain can be represented in SPIR-V909// as an l-value.910// E.g., a[3].yx cannot be, while a[3].y and a[3].y[x] can be.911bool isSpvLvalue() const { return accessChain.swizzle.size() <= 1; }912913// get the direct pointer for an l-value914Id accessChainGetLValue();915916// Get the inferred SPIR-V type of the result of the current access chain,917// based on the type of the base and the chain of dereferences.918Id accessChainGetInferredType();919920// Add capabilities, extensions, remove unneeded decorations, etc.,921// based on the resulting SPIR-V.922void postProcess(bool compileOnly);923924// Prune unreachable blocks in the CFG and remove unneeded decorations.925void postProcessCFG();926927// Add capabilities, extensions based on instructions in the module.928void postProcessFeatures();929// Hook to visit each instruction in a block in a function930void postProcess(Instruction&);931// Hook to visit each non-32-bit sized float/int operation in a block.932void postProcessType(const Instruction&, spv::Id typeId);933// move OpSampledImage instructions to be next to their users.934void postProcessSamplers();935936void dump(std::vector<unsigned int>&) const;937938// Add a branch to the target block.939// If set implicit, the branch instruction shouldn't have debug source location.940void createBranch(bool implicit, Block* block);941void createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock);942void createLoopMerge(Block* mergeBlock, Block* continueBlock, LoopControlMask control,943const std::vector<unsigned int>& operands);944945// Sets to generate opcode for specialization constants.946void setToSpecConstCodeGenMode() { generatingOpCodeForSpecConst = true; }947// Sets to generate opcode for non-specialization constants (normal mode).948void setToNormalCodeGenMode() { generatingOpCodeForSpecConst = false; }949// Check if the builder is generating code for spec constants.950bool isInSpecConstCodeGenMode() { return generatingOpCodeForSpecConst; }951952void setUseReplicatedComposites(bool use) { useReplicatedComposites = use; }953954private:955// Helper to get size of a scalar (in bytes)956unsigned int postProcessGetLargestScalarSize(const Instruction& type);957958protected:959Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value);960Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, unsigned v2);961Id findCompositeConstant(Op typeClass, Op opcode, Id typeId, const std::vector<Id>& comps, size_t numMembers);962Id findStructConstant(Id typeId, const std::vector<Id>& comps);963Id collapseAccessChain();964void remapDynamicSwizzle();965void transferAccessChainSwizzle(bool dynamic);966void simplifyAccessChainSwizzle();967void createAndSetNoPredecessorBlock(const char*);968void createSelectionMerge(Block* mergeBlock, SelectionControlMask control);969void dumpSourceInstructions(std::vector<unsigned int>&) const;970void dumpSourceInstructions(const spv::Id fileId, const std::string& text, std::vector<unsigned int>&) const;971template <class Range> void dumpInstructions(std::vector<unsigned int>& out, const Range& instructions) const;972void dumpModuleProcesses(std::vector<unsigned int>&) const;973spv::MemoryAccessMask sanitizeMemoryAccessForStorageClass(spv::MemoryAccessMask memoryAccess, StorageClass sc)974const;975struct DecorationInstructionLessThan {976bool operator()(const std::unique_ptr<Instruction>& lhs, const std::unique_ptr<Instruction>& rhs) const;977};978979unsigned int spvVersion; // the version of SPIR-V to emit in the header980SourceLanguage sourceLang;981int sourceVersion;982spv::Id nonSemanticShaderCompilationUnitId {0};983spv::Id nonSemanticShaderDebugInfo {0};984spv::Id debugInfoNone {0};985spv::Id debugExpression {0}; // Debug expression with zero operations.986std::string sourceText;987988// True if an new OpLine/OpDebugLine may need to be inserted. Either:989// 1. The current debug location changed990// 2. The current build point changed991bool dirtyLineTracker;992int currentLine = 0;993// OpString id of the current file name. Always 0 if debug info is off.994spv::Id currentFileId = 0;995// OpString id of the main file name. Always 0 if debug info is off.996spv::Id mainFileId = 0;997998// True if an new OpDebugScope may need to be inserted. Either:999// 1. A new lexical block is pushed1000// 2. The current build point changed1001bool dirtyScopeTracker;1002std::stack<spv::Id> currentDebugScopeId;10031004// This flag toggles tracking of debug info while building the SPIR-V.1005bool trackDebugInfo = false;1006// This flag toggles emission of SPIR-V debug instructions, like OpLine and OpSource.1007bool emitSpirvDebugInfo = false;1008// This flag toggles emission of Non-Semantic Debug extension debug instructions.1009bool emitNonSemanticShaderDebugInfo = false;1010bool restoreNonSemanticShaderDebugInfo = false;1011bool emitNonSemanticShaderDebugSource = false;10121013std::set<std::string> extensions;1014std::vector<const char*> sourceExtensions;1015std::vector<const char*> moduleProcesses;1016AddressingModel addressModel;1017MemoryModel memoryModel;1018std::set<spv::Capability> capabilities;1019int builderNumber;1020Module module;1021Block* buildPoint;1022Id uniqueId;1023Function* entryPointFunction;1024// This tracks the current function being built, or nullptr if not in a function.1025Function const* currentFunction { nullptr };1026bool generatingOpCodeForSpecConst;1027bool useReplicatedComposites { false };1028AccessChain accessChain;10291030// special blocks of instructions for output1031std::vector<std::unique_ptr<Instruction> > strings;1032std::vector<std::unique_ptr<Instruction> > imports;1033std::vector<std::unique_ptr<Instruction> > entryPoints;1034std::vector<std::unique_ptr<Instruction> > executionModes;1035std::vector<std::unique_ptr<Instruction> > names;1036std::set<std::unique_ptr<Instruction>, DecorationInstructionLessThan> decorations;1037std::vector<std::unique_ptr<Instruction> > constantsTypesGlobals;1038std::vector<std::unique_ptr<Instruction> > externals;1039std::vector<std::unique_ptr<Function> > functions;10401041// not output, internally used for quick & dirty canonical (unique) creation10421043// Key for scalar constants (handles both 32-bit and 64-bit)1044struct ScalarConstantKey {1045unsigned int typeClass; // OpTypeInt, OpTypeFloat, OpTypeBool1046unsigned int opcode; // OpConstant, OpSpecConstant, OpConstantTrue, etc.1047Id typeId; // The specific type1048unsigned value1; // First operand (or only operand)1049unsigned value2; // Second operand (0 for single-operand constants)10501051bool operator==(const ScalarConstantKey& other) const {1052return typeClass == other.typeClass &&1053opcode == other.opcode &&1054typeId == other.typeId &&1055value1 == other.value1 &&1056value2 == other.value2;1057}1058};10591060struct ScalarConstantKeyHash {1061// 64/32 bit mix function from MurmurHash31062inline std::size_t hash_mix(std::size_t h) const {1063if constexpr (sizeof(std::size_t) == 8) {1064h ^= h >> 33;1065h *= UINT64_C(0xff51afd7ed558ccd);1066h ^= h >> 33;1067h *= UINT64_C(0xc4ceb9fe1a85ec53);1068h ^= h >> 33;1069return h;1070} else {1071h ^= h >> 16;1072h *= UINT32_C(0x85ebca6b);1073h ^= h >> 13;1074h *= UINT32_C(0xc2b2ae35);1075h ^= h >> 16;1076return h;1077}1078}10791080// Hash combine from boost1081inline std::size_t hash_combine(std::size_t seed, std::size_t v) const {1082return hash_mix(seed + 0x9e3779b9 + v);1083}10841085std::size_t operator()(const ScalarConstantKey& k) const {1086size_t hash1 = hash_combine(std::hash<unsigned>{}(k.typeClass), std::hash<unsigned>{}(k.opcode));1087size_t hash2 = hash_combine(std::hash<Id>{}(k.value1), std::hash<unsigned>{}(k.value2));1088size_t hash3 = hash_combine(hash1, hash2);1089return hash_combine(hash3, std::hash<unsigned>{}(k.typeId));1090}1091};10921093// map type opcodes to constant inst.1094std::unordered_map<unsigned int, std::vector<Instruction*>> groupedCompositeConstants;1095// map struct-id to constant instructions1096std::unordered_map<unsigned int, std::vector<Instruction*>> groupedStructConstants;1097// map type opcodes to type instructions1098std::unordered_map<unsigned int, std::vector<Instruction*>> groupedTypes;1099// map type opcodes to debug type instructions1100std::unordered_map<unsigned int, std::vector<Instruction*>> groupedDebugTypes;1101// list of OpConstantNull instructions1102std::vector<Instruction*> nullConstants;1103// map scalar constants to result IDs1104std::unordered_map<ScalarConstantKey, Id, ScalarConstantKeyHash> groupedScalarConstantResultIDs;11051106// Track which types have explicit layouts, to avoid reusing in storage classes without layout.1107// Currently only tracks array types.1108std::unordered_set<unsigned int> explicitlyLaidOut;11091110// stack of switches1111std::stack<Block*> switchMerges;11121113// Our loop stack.1114std::stack<LoopBlocks> loops;11151116// map from strings to their string ids1117std::unordered_map<std::string, spv::Id> stringIds;11181119// map from include file name ids to their contents1120std::map<spv::Id, const std::string*> includeFiles;11211122// maps from OpTypeXXX id to DebugTypeXXX id1123std::unordered_map<spv::Id, spv::Id> debugTypeIdLookup;11241125// maps from OpFunction id to DebugFunction id1126std::unordered_map<spv::Id, spv::Id> debugFuncIdLookup;11271128// map from file name string id to DebugSource id1129std::unordered_map<spv::Id, spv::Id> debugSourceId;11301131// The stream for outputting warnings and errors.1132SpvBuildLogger* logger;1133}; // end Builder class11341135} // end spv namespace11361137#endif // SpvBuilder_H113811391140