diff options
| author | Ellie Hermaszewska <ellieh@nvidia.com> | 2024-10-29 14:49:26 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-10-29 14:49:26 +0800 |
| commit | f65d756bff8d4c5cbc15bd0322a2ae8e6b896a21 (patch) | |
| tree | ea1d61342cd29368e19135000ec2948813096205 /source/slang/slang-emit-spirv.cpp | |
| parent | a729c15e9dce9f5116a38afc66329ab2ca4cea54 (diff) | |
format
* format
* Minor test fixes
* enable checking cpp format in ci
Diffstat (limited to 'source/slang/slang-emit-spirv.cpp')
| -rw-r--r-- | source/slang/slang-emit-spirv.cpp | 3505 |
1 files changed, 1919 insertions, 1586 deletions
diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp index 3ba7cf43b..e134c579e 100644 --- a/source/slang/slang-emit-spirv.cpp +++ b/source/slang/slang-emit-spirv.cpp @@ -1,19 +1,19 @@ // slang-emit-spirv.cpp +#include "../core/slang-memory-arena.h" #include "slang-compiler.h" #include "slang-emit-base.h" - -#include "slang-ir-util.h" #include "slang-ir-call-graph.h" -#include "slang-ir.h" #include "slang-ir-insts.h" #include "slang-ir-layout.h" -#include "slang-ir-spirv-snippet.h" #include "slang-ir-spirv-legalize.h" -#include "slang-spirv-val.h" +#include "slang-ir-spirv-snippet.h" +#include "slang-ir-util.h" +#include "slang-ir.h" #include "slang-lookup-spirv.h" +#include "slang-spirv-val.h" #include "spirv/unified1/spirv.h" -#include "../core/slang-memory-arena.h" + #include <type_traits> namespace Slang @@ -70,7 +70,7 @@ namespace Slang // the enumeration of the ordering in Section 2.4 and use it to // define a list of *logical sections* that make up a SPIR-V module. - /// Logical sections of a SPIR-V module. +/// Logical sections of a SPIR-V module. enum class SpvLogicalSectionID { Capabilities, @@ -124,38 +124,38 @@ struct SpvInst; // earlier and instructions such as functions will be used // as parents. - /// Base type for SPIR-V instructions and logical sections of a module - /// - /// Holds and supports appending to a list of child instructions. +/// Base type for SPIR-V instructions and logical sections of a module +/// +/// Holds and supports appending to a list of child instructions. struct SpvInstParent { public: - /// Add an instruction to the end of the list of children + /// Add an instruction to the end of the list of children void addInst(SpvInst* inst); - /// Dump all children, recursively, to a flattened list of SPIR-V words + /// Dump all children, recursively, to a flattened list of SPIR-V words void dumpTo(List<SpvWord>& ioWords); - /// The first child, if any. + /// The first child, if any. SpvInst* m_firstChild = nullptr; - /// A pointer to the null pointer at the end of the linked list. - /// - /// If the list of children is empty this points to `m_firstChild`, - /// while if it is non-empty it points to the `nextSibling` field - /// of the last instruction. - /// + /// A pointer to the null pointer at the end of the linked list. + /// + /// If the list of children is empty this points to `m_firstChild`, + /// while if it is non-empty it points to the `nextSibling` field + /// of the last instruction. + /// SpvInst* m_lastChild = nullptr; }; // A SPIR-V instruction is then (in the general case) a potential // parent to other instructions. - /// A type to represent a SPIR-V instruction to be emitted. - /// - /// This type alows the instruction to be built up across - /// multiple steps in a mutable fashion. - /// +/// A type to represent a SPIR-V instruction to be emitted. +/// +/// This type alows the instruction to be built up across +/// multiple steps in a mutable fashion. +/// struct SpvInst : SpvInstParent { // [2.3: Physical Layout of a SPIR-V Module and Instruction] @@ -169,7 +169,7 @@ struct SpvInst : SpvInstParent // intermediate structure, and compute the word count on // the fly when writing an instruction to an output buffer. - /// The SPIR-V opcode for the instruction + /// The SPIR-V opcode for the instruction SpvOp opcode; // [2.3: Physical Layout of a SPIR-V Module and Instruction] @@ -190,9 +190,9 @@ struct SpvInst : SpvInstParent // cases where we needed to do post-processing, then we would // need to store a more refined representation here. - /// The additional words of the instruction after the opcode + /// The additional words of the instruction after the opcode SpvWord* operandWords = nullptr; - /// The amount of operand words + /// The amount of operand words uint32_t operandWordsCount = 0; // We will store the instructions in a given `SpvInstParent` @@ -200,15 +200,15 @@ struct SpvInst : SpvInstParent SpvInstParent* parent = nullptr; - /// The next instruction in the same `SpvInstParent` + /// The next instruction in the same `SpvInstParent` SpvInst* nextSibling = nullptr; SpvInst* prevSibling = nullptr; - - /// The result <id> produced by this instruction, or zero if it has no result. + + /// The result <id> produced by this instruction, or zero if it has no result. SpvWord id = 0; - /// Dump the instruction (and any children, recursively) into the flat array of SPIR-V words. + /// Dump the instruction (and any children, recursively) into the flat array of SPIR-V words. void dumpTo(List<SpvWord>& ioWords) { // [2.2: Terms] @@ -229,7 +229,7 @@ struct SpvInst : SpvInstParent // The operand words simply follow the opcode word. // ioWords.addRange(operandWords, operandWordsCount); - + // In our representation choice, the children of a // parent instruction will always follow the encoded // words of a parent: @@ -278,7 +278,7 @@ struct SpvInst : SpvInstParent } }; - /// A logical section of a SPIR-V module +/// A logical section of a SPIR-V module struct SpvLogicalSection : SpvInstParent { }; @@ -309,7 +309,7 @@ void SpvInstParent::addInst(SpvInst* inst) void SpvInstParent::dumpTo(List<SpvWord>& ioWords) { - for( auto child = m_firstChild; child; child = child->nextSibling ) + for (auto child = m_firstChild; child; child = child->nextSibling) { child->dumpTo(ioWords); } @@ -333,7 +333,10 @@ struct SpvLiteralInteger static SpvLiteralInteger from32(int32_t value) { return from32(uint32_t(value)); } static SpvLiteralInteger from32(uint32_t value) { return SpvLiteralInteger{{value}}; } static SpvLiteralInteger from64(int64_t value) { return from64(uint64_t(value)); } - static SpvLiteralInteger from64(uint64_t value) { return SpvLiteralInteger{{SpvWord(value), SpvWord(value >> 32)}}; } + static SpvLiteralInteger from64(uint64_t value) + { + return SpvLiteralInteger{{SpvWord(value), SpvWord(value >> 32)}}; + } List<SpvWord> value; // Words, stored low words to high (TODO, SmallArray or something here) }; @@ -341,7 +344,10 @@ struct SpvLiteralInteger struct SpvLiteralBits { static SpvLiteralBits from32(uint32_t value) { return SpvLiteralBits{{value}}; } - static SpvLiteralBits from64(uint64_t value) { return SpvLiteralBits{{SpvWord(value), SpvWord(value >> 32)}}; } + static SpvLiteralBits from64(uint64_t value) + { + return SpvLiteralBits{{SpvWord(value), SpvWord(value >> 32)}}; + } static SpvLiteralBits fromUnownedStringSlice(UnownedStringSlice text) { SpvLiteralBits result; @@ -392,20 +398,29 @@ struct OperandsOf { OperandsOf(IRInst* irInst) : irInst(irInst) - {} + { + } IRInst* irInst = nullptr; }; /// Helper type for not emitting an operand in this position -struct SkipThisOptionalOperand {}; +struct SkipThisOptionalOperand +{ +}; template<typename T> struct OptionalOperand { static_assert(std::is_trivial_v<T>); - OptionalOperand(SkipThisOptionalOperand) : present(false) {} - OptionalOperand(T value) : present(true), value(value) {} + OptionalOperand(SkipThisOptionalOperand) + : present(false) + { + } + OptionalOperand(T value) + : present(true), value(value) + { + } bool present; T value; }; @@ -443,12 +458,10 @@ constexpr bool isSingular = !isPlural<T>; // to defining the main context type that will drive SPIR-V // code generation. - /// Context used for translating a Slang IR module to SPIR-V -struct SPIRVEmitContext - : public SourceEmitterBase - , public SPIRVEmitSharedContext +/// Context used for translating a Slang IR module to SPIR-V +struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContext { - /// The Slang IR module being translated + /// The Slang IR module being translated IRModule* m_irModule; // [2.2: Terms] @@ -461,7 +474,8 @@ struct SPIRVEmitContext // // > Bound; where all <id>s in this module are guaranteed to satisfy // > 0 < id < Bound - // > Bound should be small, smaller is better, with all <id> in a module being densely packed and near 0. + // > Bound should be small, smaller is better, with all <id> in a module being densely packed + // and near 0. // // Instructions will be referred to by their <id>s. // We need to generate <id>s for instructions, and also @@ -474,14 +488,14 @@ struct SPIRVEmitContext // but we expect the amount of slop to be small (and // it can be cleaned up by other tools/passes). - /// The next destination `<id>` to allocate. + /// The next destination `<id>` to allocate. SpvWord m_nextID = 1; OrderedHashSet<IRPtrTypeBase*> m_forwardDeclaredPointers; SpvInst* m_nullDwarfExpr = nullptr; - // A hash set to prevent redecorating the same spv inst. + // A hash set to prevent redecorating the same spv inst. HashSet<SpvId> m_decoratedSpvInsts; SpvAddressingModel m_addressingMode = SpvAddressingModelLogical; @@ -490,26 +504,23 @@ struct SPIRVEmitContext // in a single array so that we can easily look up a // section by its `SpvLogicalSectionID`. - /// The logical sections of the SPIR-V module + /// The logical sections of the SPIR-V module SpvLogicalSection m_sections[int(SpvLogicalSectionID::Count)]; - /// Get a logical section based on its `SpvLogicalSectionID` - SpvLogicalSection* getSection(SpvLogicalSectionID id) - { - return &m_sections[int(id)]; - } + /// Get a logical section based on its `SpvLogicalSectionID` + SpvLogicalSection* getSection(SpvLogicalSectionID id) { return &m_sections[int(id)]; } // At the end of emission we need a single linear stream of words, // so we will eventually flatten `m_sections` into a single array. - /// The final array of SPIR-V words that defines the encoded module + /// The final array of SPIR-V words that defines the encoded module List<SpvWord> m_words; - /// Emit the concrete words that make up the binary SPIR-V module. - /// - /// This function fills in `m_words` based on the data in `m_sections`. - /// This function should only be called once. - /// + /// Emit the concrete words that make up the binary SPIR-V module. + /// + /// This function fills in `m_words` based on the data in `m_sections`. + /// This function should only be called once. + /// void emitPhysicalLayout() { // [2.3: Physical Layout of a SPIR-V Module and Instruction] @@ -543,8 +554,8 @@ struct SPIRVEmitContext // // Once we are done emitting the header, we emit all // the instructions in our logical sections. - // - for( int ii = 0; ii < int(SpvLogicalSectionID::Count); ++ii ) + // + for (int ii = 0; ii < int(SpvLogicalSectionID::Count); ++ii) { m_sections[ii].dumpTo(m_words); } @@ -559,7 +570,7 @@ struct SPIRVEmitContext // have been emitted, where a Slang IR instruction maps // to the corresponding SPIR-V instruction. - /// Map a Slang IR instruction to the corresponding SPIR-V instruction + /// Map a Slang IR instruction to the corresponding SPIR-V instruction Dictionary<IRInst*, SpvInst*> m_mapIRInstToSpvInst; // Sometimes we need to reserve an ID for an `IRInst` without actually @@ -568,10 +579,10 @@ struct SPIRVEmitContext // `IRInst` may not have been emitted. Dictionary<IRInst*, SpvWord> m_mapIRInstToSpvID; - // Map a Slang IR instruction to the corresponding SPIR-V debug instruction. + // Map a Slang IR instruction to the corresponding SPIR-V debug instruction. Dictionary<IRInst*, SpvInst*> m_mapIRInstToSpvDebugInst; - /// Register that `irInst` maps to `spvInst` + /// Register that `irInst` maps to `spvInst` void registerInst(IRInst* irInst, SpvInst* spvInst) { m_mapIRInstToSpvInst.add(irInst, spvInst); @@ -587,7 +598,7 @@ struct SPIRVEmitContext } } - /// Register that `irInst` has debug info represented by `spvDebugInst`. + /// Register that `irInst` has debug info represented by `spvDebugInst`. void registerDebugInst(IRInst* irInst, SpvInst* spvDebugInst) { m_mapIRInstToSpvDebugInst.add(irInst, spvDebugInst); @@ -607,7 +618,7 @@ struct SPIRVEmitContext return nullptr; } - /// Get or reserve a SpvID for an IR value. + /// Get or reserve a SpvID for an IR value. SpvWord getIRInstSpvID(IRInst* inst) { // If we have already emitted an SpvInst for `inst`, return its ID. @@ -631,16 +642,13 @@ struct SPIRVEmitContext // // We will allocate <id>s on emand as they are needed. - SpvWord freshID() - { - return m_nextID++; - } + SpvWord freshID() { return m_nextID++; } - /// Get the <id> for `inst`, or assign one if it doesn't have one yet + /// Get the <id> for `inst`, or assign one if it doesn't have one yet SpvWord getID(SpvInst* inst) { auto id = inst->id; - if( !id ) + if (!id) { id = freshID(); inst->id = id; @@ -670,26 +678,24 @@ struct SPIRVEmitContext { SLANG_FORCE_INLINE operator SpvInst*() const { return m_inst; } - InstConstructScope(SPIRVEmitContext* context, SpvOp opcode, IRInst* irInst = nullptr): - m_context(context) + InstConstructScope(SPIRVEmitContext* context, SpvOp opcode, IRInst* irInst = nullptr) + : m_context(context) { m_context->_beginInst(opcode, irInst, *this); } - ~InstConstructScope() - { - m_context->_endInst(*this); - } + ~InstConstructScope() { m_context->_endInst(*this); } - SpvInst* m_inst; ///< The instruction associated with this scope - SPIRVEmitContext* m_context; ///< The context - SpvInst* m_previousInst; ///< The previously live inst - Index m_operandsStartIndex; ///< The start index for operands of m_inst + SpvInst* m_inst; ///< The instruction associated with this scope + SPIRVEmitContext* m_context; ///< The context + SpvInst* m_previousInst; ///< The previously live inst + Index m_operandsStartIndex; ///< The start index for operands of m_inst }; // ...If we're speculatively adding them to see if we have a memoized results struct OperandMemoizeScope { - OperandMemoizeScope(SPIRVEmitContext* context) : m_context(context) + OperandMemoizeScope(SPIRVEmitContext* context) + : m_context(context) { m_tmpOperandStack.swapWith(m_context->m_operandStack); std::swap(m_tmpPeeking, m_context->m_peekingOperands); @@ -708,17 +714,17 @@ struct SPIRVEmitContext SpvInst* m_tmpInst = nullptr; }; - /// Holds memory for instructions and operands. + /// Holds memory for instructions and operands. MemoryArena m_memoryArena; - /// Begin emitting an instruction with the given SPIR-V `opcode`. - /// - /// If `irInst` is non-null, then the resulting SPIR-V instruction - /// will be registered as corresponding to `irInst`. - /// - /// The created instruction is stored in m_currentInst. - /// - /// Should not typically be called directly use InstConstructScope to scope construction + /// Begin emitting an instruction with the given SPIR-V `opcode`. + /// + /// If `irInst` is non-null, then the resulting SPIR-V instruction + /// will be registered as corresponding to `irInst`. + /// + /// The created instruction is stored in m_currentInst. + /// + /// Should not typically be called directly use InstConstructScope to scope construction void _beginInst(SpvOp opcode, IRInst* irInst, InstConstructScope& ioScope) { SLANG_ASSERT(this == ioScope.m_context); @@ -727,7 +733,7 @@ struct SPIRVEmitContext auto spvInst = new (m_memoryArena.allocate(sizeof(SpvInst))) SpvInst(); spvInst->opcode = opcode; - if(irInst) + if (irInst) { registerInst(irInst, spvInst); } @@ -741,8 +747,8 @@ struct SPIRVEmitContext m_currentInst = spvInst; } - /// End emitting an instruction - /// Should not typically be called directly use InstConstructScope to scope construction + /// End emitting an instruction + /// Should not typically be called directly use InstConstructScope to scope construction void _endInst(const InstConstructScope& scope) { SLANG_ASSERT(scope.m_inst == m_currentInst); @@ -751,11 +757,13 @@ struct SPIRVEmitContext // Work out how many operands were added const Index operandsCount = m_operandStack.getCount() - operandsStartIndex; - + if (operandsCount) { // Allocate the operands - m_currentInst->operandWords = m_memoryArena.allocateAndCopyArray(m_operandStack.getBuffer() + operandsStartIndex, operandsCount); + m_currentInst->operandWords = m_memoryArena.allocateAndCopyArray( + m_operandStack.getBuffer() + operandsStartIndex, + operandsCount); // Set the count m_currentInst->operandWordsCount = uint32_t(operandsCount); } @@ -795,7 +803,7 @@ struct SPIRVEmitContext // The simplest case is when an instruction takes an operand // that is just a literal SPIR-V word. - /// Emit a literal `word` as an operand to the current instruction + /// Emit a literal `word` as an operand to the current instruction void emitOperand(SpvWord word) { // Can only add operands if we are constructing an instruction (ie in _beginInst/_endInst) @@ -809,11 +817,8 @@ struct SPIRVEmitContext // the same. If we have a `SpvInst` we can look up or // generate an <id> for it. - /// Emit an operand to the current instruction, which references `src` by its <id> - void emitOperand(SpvInst* src) - { - emitOperand(getID(src)); - } + /// Emit an operand to the current instruction, which references `src` by its <id> + void emitOperand(SpvInst* src) { emitOperand(getID(src)); } // Commonly, we will have an operand in the form of an `IRInst` // which might either represent an instruction we've already @@ -821,7 +826,7 @@ struct SPIRVEmitContext // or which we have yet to emit (because it is a global-scope // instruction that has not been referenced before). - /// Emit an operand to the current instruction, which references `src` by its <id> + /// Emit an operand to the current instruction, which references `src` by its <id> void emitOperand(IRInst* src) { SpvInst* spvSrc = ensureInst(src); @@ -832,7 +837,7 @@ struct SPIRVEmitContext // which requires us to follow the SPIR-V rules to // encode the string into multiple operand words. - /// Emit an operand that is encoded as a literal string + /// Emit an operand that is encoded as a literal string void emitOperand(UnownedStringSlice const& text) { // Can only emitOperands if we are in an instruction @@ -850,7 +855,10 @@ struct SPIRVEmitContext // have access to the `SpvInst` that will get the <id>. // We will use a dummy `enum` type to support this case. - enum ResultIDToken { kResultID }; + enum ResultIDToken + { + kResultID + }; void emitOperand(ResultIDToken) { @@ -864,41 +872,41 @@ struct SPIRVEmitContext void emitOperand(const SpvLiteralBits& bits) { - for(const auto v : bits.value) + for (const auto v : bits.value) emitOperand(v); } void emitOperand(const SpvLiteralInteger& integer) { - for(const auto v : integer.value) + for (const auto v : integer.value) emitOperand(v); } template<typename T> void emitOperand(const List<T>& os) { - for(const auto& o : os) + for (const auto& o : os) emitOperand(o); } template<typename T> void emitOperand(const IROperandList<T>& os) { - for(const auto& o : os) + for (const auto& o : os) emitOperand(o); } template<typename T, Index N> void emitOperand(const Array<T, N>& os) { - for(const auto& o : os) + for (const auto& o : os) emitOperand(o); } template<typename T> void emitOperand(const ArrayView<T>& os) { - for(const auto& o : os) + for (const auto& o : os) emitOperand(o); } @@ -925,40 +933,40 @@ struct SPIRVEmitContext switch (type->getOp()) { case kIROp_DoubleType: - { - if (auto fval = as<IRFloatLit>(inst)) - return SpvLiteralBits::from64(DoubleAsInt64(fval->getValue())); - break; - } + { + if (auto fval = as<IRFloatLit>(inst)) + return SpvLiteralBits::from64(DoubleAsInt64(fval->getValue())); + break; + } case kIROp_HalfType: - { - if (auto fval = as<IRFloatLit>(inst)) - return SpvLiteralBits::from32(uint32_t(FloatToHalf((float)fval->getValue()))); - break; - } + { + if (auto fval = as<IRFloatLit>(inst)) + return SpvLiteralBits::from32(uint32_t(FloatToHalf((float)fval->getValue()))); + break; + } case kIROp_FloatType: - { - if (auto fval = as<IRFloatLit>(inst)) - return SpvLiteralBits::from32(FloatAsInt((float)fval->getValue())); - break; - } + { + if (auto fval = as<IRFloatLit>(inst)) + return SpvLiteralBits::from32(FloatAsInt((float)fval->getValue())); + break; + } case kIROp_Int64Type: case kIROp_UInt64Type: #if SLANG_PTR_IS_64 case kIROp_PtrType: case kIROp_UIntPtrType: #endif - { - if (auto val = as<IRIntLit>(inst)) - return SpvLiteralBits::from64(uint64_t(val->getValue())); - break; - } + { + if (auto val = as<IRIntLit>(inst)) + return SpvLiteralBits::from64(uint64_t(val->getValue())); + break; + } default: - { - if (auto val = as<IRIntLit>(inst)) - return SpvLiteralBits::from32(uint32_t(val->getValue())); - break; - } + { + if (auto val = as<IRIntLit>(inst)) + return SpvLiteralBits::from32(uint32_t(val->getValue())); + break; + } } return SpvLiteralBits::from32(0); } @@ -982,23 +990,15 @@ struct SPIRVEmitContext case kIROp_PtrType: case kIROp_UIntPtrType: #endif - { - result = emitOpConstant( - inst, - type, - SpvLiteralBits::from64(uint64_t(val)) - ); - break; - } + { + result = emitOpConstant(inst, type, SpvLiteralBits::from64(uint64_t(val))); + break; + } default: - { - result = emitOpConstant( - inst, - type, - SpvLiteralBits::from32(uint32_t(val)) - ); - break; - } + { + result = emitOpConstant(inst, type, SpvLiteralBits::from32(uint32_t(val))); + break; + } } m_spvIntConstants[key] = result; m_mapIRInstToSpvInst[inst] = result; @@ -1017,19 +1017,17 @@ struct SPIRVEmitContext } if (type->getOp() == kIROp_DoubleType) { - result = emitOpConstant( - inst, - type, - SpvLiteralBits::from64(uint64_t(DoubleAsInt64(val)))); + result = + emitOpConstant(inst, type, SpvLiteralBits::from64(uint64_t(DoubleAsInt64(val)))); } - else if(type->getOp() == kIROp_FloatType) + else if (type->getOp() == kIROp_FloatType) { result = emitOpConstant( inst, type, SpvLiteralBits::from32(uint32_t(FloatAsInt(float(val))))); } - else if(type->getOp() == kIROp_HalfType) + else if (type->getOp() == kIROp_HalfType) { result = emitOpConstant( inst, @@ -1045,24 +1043,24 @@ struct SPIRVEmitContext return result; } - /// Emit operand words for all the operands of a given IR instruction + /// Emit operand words for all the operands of a given IR instruction void emitOperand(OperandsOf const& other) { auto irInst = other.irInst; auto operandCount = irInst->getOperandCount(); - for( UInt ii = 0; ii < operandCount; ++ii ) + for (UInt ii = 0; ii < operandCount; ++ii) { emitOperand(irInst->getOperand(ii)); } } - /// Do nothing - void emitOperand(SkipThisOptionalOperand) { } + /// Do nothing + void emitOperand(SkipThisOptionalOperand) {} template<typename T> void emitOperand(OptionalOperand<T> o) { - if(o.present) + if (o.present) emitOperand(o.value); } @@ -1082,18 +1080,21 @@ struct SPIRVEmitContext // encouraged to use these instead. // template<typename... Operands> - SpvInst* emitInst(SpvInstParent* parent, IRInst* irInst, SpvOp opcode, const Operands& ...ops) + SpvInst* emitInst(SpvInstParent* parent, IRInst* irInst, SpvOp opcode, const Operands&... ops) { return emitInstCustomOperandFunc( parent, irInst, opcode, - [&](){(emitOperand(ops), ...);} - ); + [&]() { (emitOperand(ops), ...); }); } template<typename OperandEmitFunc> - SpvInst* emitInstCustomOperandFunc(SpvInstParent* parent, IRInst* irInst, SpvOp opcode, const OperandEmitFunc& f) + SpvInst* emitInstCustomOperandFunc( + SpvInstParent* parent, + IRInst* irInst, + SpvOp opcode, + const OperandEmitFunc& f) { InstConstructScope scopeInst(this, opcode, irInst); SpvInst* spvInst = scopeInst; @@ -1113,16 +1114,14 @@ struct SPIRVEmitContext // We take the resultId here explicitly here to make sure we don't try // and memoize its value. ResultIDToken resultId, - const Operands& ...ops - ) + const Operands&... ops) { return emitInstMemoizedCustomOperandFunc( parent, irInst, opcode, resultId, - [&](){(emitOperand(ops), ...);} - ); + [&]() { (emitOperand(ops), ...); }); } template<typename OperandEmitFunc> @@ -1133,8 +1132,7 @@ struct SPIRVEmitContext // We take the resultId here explicitly here to make sure we don't try // and memoize its value. ResultIDToken resultId, - const OperandEmitFunc& f - ) + const OperandEmitFunc& f) { List<SpvWord> ourOperands; { @@ -1182,8 +1180,7 @@ struct SPIRVEmitContext SpvInstParent* parent, IRInst* irInst, SpvOp opcode, - const OperandEmitFunc& f - ) + const OperandEmitFunc& f) { List<SpvWord> ourOperands; { @@ -1217,13 +1214,13 @@ struct SPIRVEmitContext // Specific emit funcs // -# define SLANG_IN_SPIRV_EMIT_CONTEXT -# include "slang-emit-spirv-ops.h" - #include "slang-emit-spirv-ops-debug-info-ext.h" -# undef SLANG_IN_SPIRV_EMIT_CONTEXT +#define SLANG_IN_SPIRV_EMIT_CONTEXT +#include "slang-emit-spirv-ops-debug-info-ext.h" +#include "slang-emit-spirv-ops.h" +#undef SLANG_IN_SPIRV_EMIT_CONTEXT - /// The SPIRV OpExtInstImport inst that represents the GLSL450 - /// extended instruction set. + /// The SPIRV OpExtInstImport inst that represents the GLSL450 + /// extended instruction set. SpvInst* m_glsl450ExtInst = nullptr; SpvInst* getGLSL450ExtInst() @@ -1272,50 +1269,30 @@ struct SPIRVEmitContext SLANG_EXHAUSTIVE_SWITCH_BEGIN switch (addrSpace) { - case AddressSpace::Generic: - return SpvStorageClassMax; - case AddressSpace::ThreadLocal: - return SpvStorageClassPrivate; - case AddressSpace::GroupShared: - return SpvStorageClassWorkgroup; - case AddressSpace::Uniform: - return SpvStorageClassUniform; - case AddressSpace::Input: - return SpvStorageClassInput; - case AddressSpace::Output: - return SpvStorageClassOutput; - case AddressSpace::TaskPayloadWorkgroup: - return SpvStorageClassTaskPayloadWorkgroupEXT; - case AddressSpace::Function: - return SpvStorageClassFunction; - case AddressSpace::StorageBuffer: - return SpvStorageClassStorageBuffer; - case AddressSpace::PushConstant: - return SpvStorageClassPushConstant; - case AddressSpace::RayPayloadKHR: - return SpvStorageClassRayPayloadKHR; - case AddressSpace::IncomingRayPayload: - return SpvStorageClassIncomingRayPayloadKHR; - case AddressSpace::CallableDataKHR: - return SpvStorageClassCallableDataKHR; - case AddressSpace::IncomingCallableData: - return SpvStorageClassIncomingCallableDataKHR; - case AddressSpace::HitObjectAttribute: - return SpvStorageClassHitObjectAttributeNV; - case AddressSpace::HitAttribute: - return SpvStorageClassHitAttributeKHR; - case AddressSpace::ShaderRecordBuffer: - return SpvStorageClassShaderRecordBufferKHR; - case AddressSpace::UniformConstant: - return SpvStorageClassUniformConstant; - case AddressSpace::Image: - return SpvStorageClassImage; - case AddressSpace::UserPointer: - return SpvStorageClassPhysicalStorageBuffer; + case AddressSpace::Generic: return SpvStorageClassMax; + case AddressSpace::ThreadLocal: return SpvStorageClassPrivate; + case AddressSpace::GroupShared: return SpvStorageClassWorkgroup; + case AddressSpace::Uniform: return SpvStorageClassUniform; + case AddressSpace::Input: return SpvStorageClassInput; + case AddressSpace::Output: return SpvStorageClassOutput; + case AddressSpace::TaskPayloadWorkgroup: return SpvStorageClassTaskPayloadWorkgroupEXT; + case AddressSpace::Function: return SpvStorageClassFunction; + case AddressSpace::StorageBuffer: return SpvStorageClassStorageBuffer; + case AddressSpace::PushConstant: return SpvStorageClassPushConstant; + case AddressSpace::RayPayloadKHR: return SpvStorageClassRayPayloadKHR; + case AddressSpace::IncomingRayPayload: return SpvStorageClassIncomingRayPayloadKHR; + case AddressSpace::CallableDataKHR: return SpvStorageClassCallableDataKHR; + case AddressSpace::IncomingCallableData: return SpvStorageClassIncomingCallableDataKHR; + case AddressSpace::HitObjectAttribute: return SpvStorageClassHitObjectAttributeNV; + case AddressSpace::HitAttribute: return SpvStorageClassHitAttributeKHR; + case AddressSpace::ShaderRecordBuffer: return SpvStorageClassShaderRecordBufferKHR; + case AddressSpace::UniformConstant: return SpvStorageClassUniformConstant; + case AddressSpace::Image: return SpvStorageClassImage; + case AddressSpace::UserPointer: return SpvStorageClassPhysicalStorageBuffer; case AddressSpace::Global: case AddressSpace::MetalObjectData: case AddressSpace::SpecializationConstant: - // msvc is limiting us from putting the UNEXPECTED macro here, so + // msvc is limiting us from putting the UNEXPECTED macro here, so // just fall out ; } @@ -1332,8 +1309,8 @@ struct SPIRVEmitContext // which do not directly relate to any instruction in the // Slang IR. - /// Emit the mandatory "front-matter" instructions that - /// the SPIR-V module must include to make it usable. + /// Emit the mandatory "front-matter" instructions that + /// the SPIR-V module must include to make it usable. void emitFrontMatter() { // TODO: We should ideally add SPIR-V capabilities to @@ -1344,8 +1321,7 @@ struct SPIRVEmitContext emitOpCapability( getSection(SpvLogicalSectionID::Capabilities), nullptr, - SpvCapabilityShader - ); + SpvCapabilityShader); // [2.4: Logical Layout of a Module] // @@ -1365,8 +1341,7 @@ struct SPIRVEmitContext getSection(SpvLogicalSectionID::MemoryModel), nullptr, m_addressingMode, - SpvMemoryModelGLSL450 - ); + SpvMemoryModelGLSL450); } IRInst* m_defaultDebugSource = nullptr; @@ -1377,11 +1352,7 @@ struct SPIRVEmitContext SpvInst* result = nullptr; if (m_extensionInsts.tryGetValue(name, result)) return result; - result = emitOpExtension( - getSection(SpvLogicalSectionID::Extensions), - nullptr, - name - ); + result = emitOpExtension(getSection(SpvLogicalSectionID::Extensions), nullptr, name); m_extensionInsts[name] = result; return result; } @@ -1429,7 +1400,8 @@ struct SPIRVEmitContext bool shouldEmitSPIRVReflectionInfo() { - return m_targetProgram->getOptionSet().getBoolOption(CompilerOptionName::VulkanEmitReflection); + return m_targetProgram->getOptionSet().getBoolOption( + CompilerOptionName::VulkanEmitReflection); } void requirePhysicalStorageAddressing() @@ -1444,21 +1416,22 @@ struct SPIRVEmitContext // Next, let's look at emitting some of the instructions // that can occur at global scope. - /// Emit an instruction that is expected to appear at the global scope of the SPIR-V module. - /// - /// Returns the corresponding SPIR-V instruction. - /// + /// Emit an instruction that is expected to appear at the global scope of the SPIR-V module. + /// + /// Returns the corresponding SPIR-V instruction. + /// SpvInst* emitGlobalInst(IRInst* inst) { - switch( inst->getOp() & kIROpMask_OpMask ) + switch (inst->getOp() & kIROpMask_OpMask) { - // [3.32.6: Type-Declaration Instructions] - // + // [3.32.6: Type-Declaration Instructions] + // case kIROp_VoidType: return emitOpTypeVoid(inst); - case kIROp_BoolType: return emitOpTypeBool(inst); + case kIROp_BoolType: + return emitOpTypeBool(inst); - // > OpTypeInt + // > OpTypeInt case kIROp_UInt16Type: case kIROp_Int16Type: @@ -1479,11 +1452,10 @@ struct SPIRVEmitContext return emitOpTypeInt( inst, SpvLiteralInteger::from32(int32_t(i.width)), - SpvLiteralInteger::from32(i.isSigned) - ); + SpvLiteralInteger::from32(i.isSigned)); } - // > OpTypeFloat + // > OpTypeFloat case kIROp_HalfType: case kIROp_FloatType: @@ -1508,16 +1480,17 @@ struct SPIRVEmitContext if (ptrType->hasAddressSpace()) storageClass = addressSpaceToStorageClass(ptrType->getAddressSpace()); if (storageClass == SpvStorageClassStorageBuffer) - ensureExtensionDeclaration(UnownedStringSlice("SPV_KHR_storage_buffer_storage_class")); + ensureExtensionDeclaration( + UnownedStringSlice("SPV_KHR_storage_buffer_storage_class")); if (storageClass == SpvStorageClassPhysicalStorageBuffer) { requirePhysicalStorageAddressing(); } auto valueType = ptrType->getValueType(); // If we haven't emitted the inner type yet, we need to emit a forward declaration. - bool useForwardDeclaration = (!m_mapIRInstToSpvInst.containsKey(valueType) - && as<IRStructType>(valueType) - && storageClass == SpvStorageClassPhysicalStorageBuffer); + bool useForwardDeclaration = + (!m_mapIRInstToSpvInst.containsKey(valueType) && as<IRStructType>(valueType) && + storageClass == SpvStorageClassPhysicalStorageBuffer); SpvId valueTypeId; if (as<IRVoidType>(valueType)) { @@ -1539,14 +1512,11 @@ struct SPIRVEmitContext } } - auto resultSpvType = emitOpTypePointer( - inst, - storageClass, - valueTypeId); + auto resultSpvType = emitOpTypePointer(inst, storageClass, valueTypeId); if (useForwardDeclaration) { - // After everything has been emitted, we will move the pointer definition to the end - // of the Types & Constants section. + // After everything has been emitted, we will move the pointer definition to the + // end of the Types & Constants section. if (m_forwardDeclaredPointers.add(ptrType)) emitOpTypeForwardPointer(resultSpvType, storageClass); } @@ -1557,14 +1527,18 @@ struct SPIRVEmitContext IRSizeAndAlignment sizeAndAlignment; uint32_t stride; - getNaturalSizeAndAlignment(m_targetProgram->getOptionSet(), valueType, &sizeAndAlignment); + getNaturalSizeAndAlignment( + m_targetProgram->getOptionSet(), + valueType, + &sizeAndAlignment); uint64_t valueSize = sizeAndAlignment.size; - // Any unsized data type (e.g. struct or array) will have size of kIndeterminateSize, - // in such case the stride is invalid, so we have to provide a non-zero value to pass the - // spirv validator. - stride = (valueSize >= (uint64_t)sizeAndAlignment.kIndeterminateSize) ? - 0xFFFF : (uint32_t)sizeAndAlignment.getStride(); + // Any unsized data type (e.g. struct or array) will have size of + // kIndeterminateSize, in such case the stride is invalid, so we have to + // provide a non-zero value to pass the spirv validator. + stride = (valueSize >= (uint64_t)sizeAndAlignment.kIndeterminateSize) + ? 0xFFFF + : (uint32_t)sizeAndAlignment.getStride(); emitOpDecorateArrayStride( getSection(SpvLogicalSectionID::Annotations), nullptr, @@ -1583,10 +1557,7 @@ struct SPIRVEmitContext { types.add(field->getFieldType()); } - auto spvStructType = emitOpTypeStruct( - inst, - types - ); + auto spvStructType = emitOpTypeStruct(inst, types); emitDecorations(inst, getID(spvStructType)); auto structType = as<IRStructType>(inst); @@ -1599,8 +1570,9 @@ struct SPIRVEmitContext if (structSize >= (uint64_t)IRSizeAndAlignment::kIndeterminateSize) { IRBuilder builder(inst); - if ((isSpirv14OrLater() || !inst->findDecorationImpl(kIROp_SPIRVBufferBlockDecoration)) - && !inst->findDecorationImpl(kIROp_SPIRVBlockDecoration)) + if ((isSpirv14OrLater() || + !inst->findDecorationImpl(kIROp_SPIRVBufferBlockDecoration)) && + !inst->findDecorationImpl(kIROp_SPIRVBlockDecoration)) { auto decoration = builder.addDecoration(inst, kIROp_SPIRVBlockDecoration); emitDecoration(getID(spvStructType), decoration); @@ -1624,21 +1596,25 @@ struct SPIRVEmitContext static_cast<IRBasicType*>(matrixType->getElementType())->getBaseType(), static_cast<IRIntLit*>(matrixType->getColumnCount())->getValue(), nullptr); - const auto columnCount = static_cast<IRIntLit*>(matrixType->getRowCount())->getValue(); + const auto columnCount = + static_cast<IRIntLit*>(matrixType->getRowCount())->getValue(); auto matrixSPVType = emitOpTypeMatrix( inst, vectorSpvType, - SpvLiteralInteger::from32(int32_t(columnCount)) - ); + SpvLiteralInteger::from32(int32_t(columnCount))); return matrixSPVType; } case kIROp_ArrayType: case kIROp_UnsizedArrayType: { const auto elementType = static_cast<IRArrayTypeBase*>(inst)->getElementType(); - const auto arrayType = inst->getOp() == kIROp_ArrayType - ? emitOpTypeArray(inst, elementType, static_cast<IRArrayTypeBase*>(inst)->getElementCount()) - : emitOpTypeRuntimeArray(inst, elementType); + const auto arrayType = + inst->getOp() == kIROp_ArrayType + ? emitOpTypeArray( + inst, + elementType, + static_cast<IRArrayTypeBase*>(inst)->getElementCount()) + : emitOpTypeRuntimeArray(inst, elementType); auto strideInst = as<IRArrayTypeBase>(inst)->getArrayStride(); int stride = 0; if (strideInst) @@ -1648,7 +1624,10 @@ struct SPIRVEmitContext else { IRSizeAndAlignment sizeAndAlignment; - getNaturalSizeAndAlignment(m_targetProgram->getOptionSet(), elementType, &sizeAndAlignment); + getNaturalSizeAndAlignment( + m_targetProgram->getOptionSet(), + elementType, + &sizeAndAlignment); stride = (int)sizeAndAlignment.getStride(); } emitOpDecorateArrayStride( @@ -1666,11 +1645,9 @@ struct SPIRVEmitContext } case kIROp_SubpassInputType: return ensureSubpassInputType(inst, cast<IRSubpassInputType>(inst)); - case kIROp_TextureType: - return ensureTextureType(inst, cast<IRTextureType>(inst)); + case kIROp_TextureType: return ensureTextureType(inst, cast<IRTextureType>(inst)); case kIROp_SamplerStateType: - case kIROp_SamplerComparisonStateType: - return emitOpTypeSampler(inst); + case kIROp_SamplerComparisonStateType: return emitOpTypeSampler(inst); case kIROp_RaytracingAccelerationStructureType: requireSPIRVCapability(SpvCapabilityRayTracingKHR); @@ -1689,7 +1666,10 @@ struct SPIRVEmitContext case kIROp_HLSLConstBufferPointerType: requirePhysicalStorageAddressing(); - return emitOpTypePointer(inst, SpvStorageClassPhysicalStorageBuffer, inst->getOperand(0)); + return emitOpTypePointer( + inst, + SpvStorageClassPhysicalStorageBuffer, + inst->getOperand(0)); case kIROp_FuncType: // > OpTypeFunction @@ -1701,8 +1681,7 @@ struct SPIRVEmitContext return emitOpTypeFunction( inst, static_cast<IRFuncType*>(inst)->getResultType(), - static_cast<IRFuncType*>(inst)->getParamTypes() - ); + static_cast<IRFuncType*>(inst)->getParamTypes()); case kIROp_RateQualifiedType: { @@ -1710,7 +1689,7 @@ struct SPIRVEmitContext registerInst(inst, result); return result; } - // > OpTypeForwardPointer + // > OpTypeForwardPointer case kIROp_Func: // [3.32.6: Function Instructions] @@ -1727,49 +1706,50 @@ struct SPIRVEmitContext case kIROp_FloatLit: case kIROp_StringLit: case kIROp_PtrLit: - { - return emitLit(inst); - } + { + return emitLit(inst); + } case kIROp_MakeVectorFromScalar: - { - const auto scalar = inst->getOperand(0); - const auto vecTy = as<IRVectorType>(inst->getDataType()); - SLANG_ASSERT(vecTy); - const auto numElems = as<IRIntLit>(vecTy->getElementCount()); - SLANG_ASSERT(numElems); - return emitSplat( - getSection(SpvLogicalSectionID::ConstantsAndTypes), - inst, - scalar, - numElems->getValue()); - } + { + const auto scalar = inst->getOperand(0); + const auto vecTy = as<IRVectorType>(inst->getDataType()); + SLANG_ASSERT(vecTy); + const auto numElems = as<IRIntLit>(vecTy->getElementCount()); + SLANG_ASSERT(numElems); + return emitSplat( + getSection(SpvLogicalSectionID::ConstantsAndTypes), + inst, + scalar, + numElems->getValue()); + } case kIROp_MakeVector: case kIROp_MakeArray: case kIROp_MakeStruct: return emitCompositeConstruct(getSection(SpvLogicalSectionID::ConstantsAndTypes), inst); case kIROp_MakeArrayFromElement: - return emitMakeArrayFromElement(getSection(SpvLogicalSectionID::ConstantsAndTypes), inst); + return emitMakeArrayFromElement( + getSection(SpvLogicalSectionID::ConstantsAndTypes), + inst); case kIROp_MakeMatrix: return emitMakeMatrix(getSection(SpvLogicalSectionID::ConstantsAndTypes), inst); case kIROp_MakeMatrixFromScalar: - return emitMakeMatrixFromScalar(getSection(SpvLogicalSectionID::ConstantsAndTypes), inst); - case kIROp_GlobalParam: - return emitGlobalParam(as<IRGlobalParam>(inst)); - case kIROp_GlobalVar: - return emitGlobalVar(as<IRGlobalVar>(inst)); - case kIROp_SPIRVAsmOperandBuiltinVar: - return emitBuiltinVar(inst); + return emitMakeMatrixFromScalar( + getSection(SpvLogicalSectionID::ConstantsAndTypes), + inst); + case kIROp_GlobalParam: return emitGlobalParam(as<IRGlobalParam>(inst)); + case kIROp_GlobalVar: return emitGlobalVar(as<IRGlobalVar>(inst)); + case kIROp_SPIRVAsmOperandBuiltinVar: return emitBuiltinVar(inst); case kIROp_Var: return emitVar(getSection(SpvLogicalSectionID::GlobalVariables), inst); - // ... + // ... case kIROp_Specialize: { const auto s = as<IRSpecialize>(inst); const auto g = s->getBase(); - const auto e = - "Specialize instruction remains in IR for SPIR-V emit, is something undefined?\n" + - dumpIRToString(g); + const auto e = "Specialize instruction remains in IR for SPIR-V emit, is something " + "undefined?\n" + + dumpIRToString(g); SLANG_UNEXPECTED(e.getBuffer()); } @@ -1788,9 +1768,10 @@ struct SPIRVEmitContext getNonSemanticDebugInfoExtInst(), debugSource->getFileName()); } - // SPIRV does not allow string lits longer than 65535, so we need to split the source string - // in OpDebugSourceContinued instructions. - auto sourceStrHead = sourceStr.getLength() > 65535 ? sourceStr.head(65535) : sourceStr; + // SPIRV does not allow string lits longer than 65535, so we need to split the + // source string in OpDebugSourceContinued instructions. + auto sourceStrHead = + sourceStr.getLength() > 65535 ? sourceStr.head(65535) : sourceStr; auto spvStrHead = emitInst( getSection(SpvLogicalSectionID::DebugStringsAndSource), nullptr, @@ -1816,8 +1797,12 @@ struct SPIRVEmitContext SpvOpString, kResultID, SpvLiteralBits::fromUnownedStringSlice(slice)); - emitOpDebugSourceContinued(getSection(SpvLogicalSectionID::ConstantsAndTypes), - nullptr, m_voidType, getNonSemanticDebugInfoExtInst(), sliceSpvStr); + emitOpDebugSourceContinued( + getSection(SpvLogicalSectionID::ConstantsAndTypes), + nullptr, + m_voidType, + getNonSemanticDebugInfoExtInst(), + sliceSpvStr); } auto moduleInst = inst->getModule()->getModuleInst(); @@ -1832,33 +1817,31 @@ struct SPIRVEmitContext moduleInst, inst->getFullType(), getNonSemanticDebugInfoExtInst(), - emitIntConstant(100, builder.getUIntType()), // ExtDebugInfo version. - emitIntConstant(5, builder.getUIntType()), // DWARF version. + emitIntConstant(100, builder.getUIntType()), // ExtDebugInfo version. + emitIntConstant(5, builder.getUIntType()), // DWARF version. result, - emitIntConstant(SpvSourceLanguageSlang, builder.getUIntType())); // Language. + emitIntConstant( + SpvSourceLanguageSlang, + builder.getUIntType())); // Language. registerDebugInst(moduleInst, translationUnit); } return result; } - case kIROp_GetStringHash: - return emitGetStringHash(inst); - case kIROp_AttributedType: - return ensureInst(as<IRAttributedType>(inst)->getBaseType()); - case kIROp_AllocateOpaqueHandle: - return nullptr; + case kIROp_GetStringHash: return emitGetStringHash(inst); + case kIROp_AttributedType: return ensureInst(as<IRAttributedType>(inst)->getBaseType()); + case kIROp_AllocateOpaqueHandle: return nullptr; case kIROp_HLSLTriangleStreamType: case kIROp_HLSLLineStreamType: case kIROp_HLSLPointStreamType: case kIROp_VerticesType: case kIROp_IndicesType: - case kIROp_PrimitivesType: - return nullptr; + case kIROp_PrimitivesType: return nullptr; default: { if (as<IRSPIRVAsmOperand>(inst)) return nullptr; - String e = "Unhandled global inst in spirv-emit:\n" - + dumpIRToString(inst, {IRDumpOptions::Mode::Detailed, 0}); + String e = "Unhandled global inst in spirv-emit:\n" + + dumpIRToString(inst, {IRDumpOptions::Mode::Detailed, 0}); SLANG_UNIMPLEMENTED_X(e.begin()); } } @@ -1866,52 +1849,53 @@ struct SPIRVEmitContext static SpvImageFormat getSpvImageFormat(IRTextureTypeBase* type) { - ImageFormat imageFormat = type->hasFormat() ? (ImageFormat)type->getFormat() : ImageFormat::unknown; + ImageFormat imageFormat = + type->hasFormat() ? (ImageFormat)type->getFormat() : ImageFormat::unknown; switch (imageFormat) { - case ImageFormat::unknown: return SpvImageFormatUnknown; - case ImageFormat::rgba32f: return SpvImageFormatRgba32f; - case ImageFormat::rgba16f: return SpvImageFormatRgba16f; - case ImageFormat::rg32f: return SpvImageFormatRg32f; - case ImageFormat::rg16f: return SpvImageFormatRg16f; - case ImageFormat::r11f_g11f_b10f: return SpvImageFormatR11fG11fB10f; - case ImageFormat::r32f: return SpvImageFormatR32f; - case ImageFormat::r16f: return SpvImageFormatR16f; - case ImageFormat::rgba16: return SpvImageFormatRgba16; - case ImageFormat::rgb10_a2: return SpvImageFormatRgb10A2; - case ImageFormat::rgba8: return SpvImageFormatRgba8; - case ImageFormat::rg16: return SpvImageFormatRg16; - case ImageFormat::rg8: return SpvImageFormatRg8; - case ImageFormat::r16: return SpvImageFormatR16; - case ImageFormat::r8: return SpvImageFormatR8; - case ImageFormat::rgba16_snorm: return SpvImageFormatRgba16Snorm; - case ImageFormat::rgba8_snorm: return SpvImageFormatRgba8Snorm; - case ImageFormat::rg16_snorm: return SpvImageFormatRg16Snorm; - case ImageFormat::rg8_snorm: return SpvImageFormatRg8Snorm; - case ImageFormat::r16_snorm: return SpvImageFormatR16Snorm; - case ImageFormat::r8_snorm: return SpvImageFormatR8Snorm; - case ImageFormat::rgba32i: return SpvImageFormatRgba32i; - case ImageFormat::rgba16i: return SpvImageFormatRgba16i; - case ImageFormat::rgba8i: return SpvImageFormatRgba8i; - case ImageFormat::rg32i: return SpvImageFormatRg32i; - case ImageFormat::rg16i: return SpvImageFormatRg16i; - case ImageFormat::rg8i: return SpvImageFormatRg8i; - case ImageFormat::r32i: return SpvImageFormatR32i; - case ImageFormat::r16i: return SpvImageFormatR16i; - case ImageFormat::r8i: return SpvImageFormatR8i; - case ImageFormat::rgba32ui: return SpvImageFormatRgba32ui; - case ImageFormat::rgba16ui: return SpvImageFormatRgba16ui; - case ImageFormat::rgb10_a2ui: return SpvImageFormatRgb10a2ui; - case ImageFormat::rgba8ui: return SpvImageFormatRgba8ui; - case ImageFormat::rg32ui: return SpvImageFormatRg32ui; - case ImageFormat::rg16ui: return SpvImageFormatRg16ui; - case ImageFormat::rg8ui: return SpvImageFormatRg8ui; - case ImageFormat::r32ui: return SpvImageFormatR32ui; - case ImageFormat::r16ui: return SpvImageFormatR16ui; - case ImageFormat::r8ui: return SpvImageFormatR8ui; - case ImageFormat::r64ui: return SpvImageFormatR64ui; - case ImageFormat::r64i: return SpvImageFormatR64i; - default: SLANG_UNIMPLEMENTED_X("unknown image format for spirv emit"); + case ImageFormat::unknown: return SpvImageFormatUnknown; + case ImageFormat::rgba32f: return SpvImageFormatRgba32f; + case ImageFormat::rgba16f: return SpvImageFormatRgba16f; + case ImageFormat::rg32f: return SpvImageFormatRg32f; + case ImageFormat::rg16f: return SpvImageFormatRg16f; + case ImageFormat::r11f_g11f_b10f: return SpvImageFormatR11fG11fB10f; + case ImageFormat::r32f: return SpvImageFormatR32f; + case ImageFormat::r16f: return SpvImageFormatR16f; + case ImageFormat::rgba16: return SpvImageFormatRgba16; + case ImageFormat::rgb10_a2: return SpvImageFormatRgb10A2; + case ImageFormat::rgba8: return SpvImageFormatRgba8; + case ImageFormat::rg16: return SpvImageFormatRg16; + case ImageFormat::rg8: return SpvImageFormatRg8; + case ImageFormat::r16: return SpvImageFormatR16; + case ImageFormat::r8: return SpvImageFormatR8; + case ImageFormat::rgba16_snorm: return SpvImageFormatRgba16Snorm; + case ImageFormat::rgba8_snorm: return SpvImageFormatRgba8Snorm; + case ImageFormat::rg16_snorm: return SpvImageFormatRg16Snorm; + case ImageFormat::rg8_snorm: return SpvImageFormatRg8Snorm; + case ImageFormat::r16_snorm: return SpvImageFormatR16Snorm; + case ImageFormat::r8_snorm: return SpvImageFormatR8Snorm; + case ImageFormat::rgba32i: return SpvImageFormatRgba32i; + case ImageFormat::rgba16i: return SpvImageFormatRgba16i; + case ImageFormat::rgba8i: return SpvImageFormatRgba8i; + case ImageFormat::rg32i: return SpvImageFormatRg32i; + case ImageFormat::rg16i: return SpvImageFormatRg16i; + case ImageFormat::rg8i: return SpvImageFormatRg8i; + case ImageFormat::r32i: return SpvImageFormatR32i; + case ImageFormat::r16i: return SpvImageFormatR16i; + case ImageFormat::r8i: return SpvImageFormatR8i; + case ImageFormat::rgba32ui: return SpvImageFormatRgba32ui; + case ImageFormat::rgba16ui: return SpvImageFormatRgba16ui; + case ImageFormat::rgb10_a2ui: return SpvImageFormatRgb10a2ui; + case ImageFormat::rgba8ui: return SpvImageFormatRgba8ui; + case ImageFormat::rg32ui: return SpvImageFormatRg32ui; + case ImageFormat::rg16ui: return SpvImageFormatRg16ui; + case ImageFormat::rg8ui: return SpvImageFormatRg8ui; + case ImageFormat::r32ui: return SpvImageFormatR32ui; + case ImageFormat::r16ui: return SpvImageFormatR16ui; + case ImageFormat::r8ui: return SpvImageFormatR8ui; + case ImageFormat::r64ui: return SpvImageFormatR64ui; + case ImageFormat::r64i: return SpvImageFormatR64i; + default: SLANG_UNIMPLEMENTED_X("unknown image format for spirv emit"); } } @@ -1926,18 +1910,16 @@ struct SPIRVEmitContext } // https://registry.khronos.org/vulkan/specs/1.3/html/chap37.html#VUID-StandaloneSpirv-DescriptorSet-06491 - // Only UniformConstant, Uniform or StorageBuffer storage class are allowed to be decorated with descriptor - // set or binding. + // Only UniformConstant, Uniform or StorageBuffer storage class are allowed to be decorated with + // descriptor set or binding. static inline bool isBindingAllowed(SpvStorageClass storageClass) { - switch(storageClass) + switch (storageClass) { case SpvStorageClassUniformConstant: case SpvStorageClassUniform: - case SpvStorageClassStorageBuffer: - return true; - default: - return false; + case SpvStorageClassStorageBuffer: return true; + default: return false; } } @@ -1958,17 +1940,16 @@ struct SPIRVEmitContext case SpvImageFormatRgba32ui: case SpvImageFormatRgba16ui: case SpvImageFormatRgba8ui: - case SpvImageFormatR32ui: - return SpvCapabilityShader; + case SpvImageFormatR32ui: return SpvCapabilityShader; case SpvImageFormatR64ui: - case SpvImageFormatR64i: - return SpvCapabilityInt64ImageEXT; - default: - return SpvCapabilityStorageImageExtendedFormats; + case SpvImageFormatR64i: return SpvCapabilityInt64ImageEXT; + default: return SpvCapabilityStorageImageExtendedFormats; } } - void setImageFormatCapabilityAndExtension(SpvImageFormat format, SpvCapability_ setCapabilityMask) + void setImageFormatCapabilityAndExtension( + SpvImageFormat format, + SpvCapability_ setCapabilityMask) { switch (format) { @@ -1986,17 +1967,20 @@ struct SPIRVEmitContext case SpvImageFormatRgba16ui: case SpvImageFormatRgba8ui: case SpvImageFormatR32ui: - if(setCapabilityMask == SpvCapabilityShader) return; + if (setCapabilityMask == SpvCapabilityShader) + return; requireSPIRVCapability(SpvCapabilityShader); return; case SpvImageFormatR64ui: case SpvImageFormatR64i: - if(setCapabilityMask == SpvCapabilityInt64ImageEXT) return; + if (setCapabilityMask == SpvCapabilityInt64ImageEXT) + return; ensureExtensionDeclaration(UnownedStringSlice("SPV_EXT_shader_image_int64")); requireSPIRVCapability(SpvCapabilityInt64ImageEXT); return; default: - if(setCapabilityMask == SpvCapabilityStorageImageExtendedFormats) return; + if (setCapabilityMask == SpvCapabilityStorageImageExtendedFormats) + return; requireSPIRVCapability(SpvCapabilityStorageImageExtendedFormats); return; } @@ -2025,7 +2009,8 @@ struct SPIRVEmitContext sampledUnknown = 0, // indicates an image compatible with sampling operations sampledImage = 1, - // indicates an image compatible with read/write operations (a storage or subpass data image). + // indicates an image compatible with read/write operations (a storage or subpass data + // image). readWriteImage = 2, // indicates single-sampled content @@ -2039,8 +2024,9 @@ struct SPIRVEmitContext { IRInst* sampledType = inst->getElementType(); SpvDim dim = SpvDimSubpassData; - SpvWord ms = inst->isMultisample() ? ImageOpConstants::isMultisampled : ImageOpConstants::notMultisampled; - SpvWord sampled = 2; + SpvWord ms = inst->isMultisample() ? ImageOpConstants::isMultisampled + : ImageOpConstants::notMultisampled; + SpvWord sampled = 2; requireSPIRVCapability(SpvCapabilityInputAttachment); requireSPIRVCapability(SpvCapabilityStorageImageReadWithoutFormat); setImageFormatCapabilityAndExtension(SpvImageFormatUnknown, SpvCapabilityShader); @@ -2052,49 +2038,41 @@ struct SPIRVEmitContext SpvLiteralInteger::from32(0), SpvLiteralInteger::from32(ms), SpvLiteralInteger::from32(sampled), - SpvImageFormatUnknown - ); + SpvImageFormatUnknown); } SpvInst* ensureTextureType(IRInst* assignee, IRTextureTypeBase* inst) { IRInst* sampledType = inst->getElementType(); SpvDim dim = SpvDim1D; // Silence uninitialized warnings from msvc... - switch(inst->GetBaseShape()) + switch (inst->GetBaseShape()) { - case SLANG_TEXTURE_1D: - dim = SpvDim1D; - break; - case SLANG_TEXTURE_2D: - dim = SpvDim2D; - break; - case SLANG_TEXTURE_3D: - dim = SpvDim3D; - break; - case SLANG_TEXTURE_CUBE: - dim = SpvDimCube; - break; - case SLANG_TEXTURE_BUFFER: - dim = SpvDimBuffer; - break; + case SLANG_TEXTURE_1D: dim = SpvDim1D; break; + case SLANG_TEXTURE_2D: dim = SpvDim2D; break; + case SLANG_TEXTURE_3D: dim = SpvDim3D; break; + case SLANG_TEXTURE_CUBE: dim = SpvDimCube; break; + case SLANG_TEXTURE_BUFFER: dim = SpvDimBuffer; break; } - SpvWord arrayed = inst->isArray() ? ImageOpConstants::isArrayed : ImageOpConstants::notArrayed; + SpvWord arrayed = + inst->isArray() ? ImageOpConstants::isArrayed : ImageOpConstants::notArrayed; // Vulkan spec 16.1: "The “Depth” operand of OpTypeImage is ignored." - SpvWord depth = ImageOpConstants::unknownDepthImage; // No knowledge of if this is a depth image - SpvWord ms = inst->isMultisample() ? ImageOpConstants::isMultisampled : ImageOpConstants::notMultisampled; + SpvWord depth = + ImageOpConstants::unknownDepthImage; // No knowledge of if this is a depth image + SpvWord ms = inst->isMultisample() ? ImageOpConstants::isMultisampled + : ImageOpConstants::notMultisampled; SpvWord sampled = ImageOpConstants::sampledUnknown; - switch(inst->getAccess()) + switch (inst->getAccess()) { - case SlangResourceAccess::SLANG_RESOURCE_ACCESS_READ_WRITE: - case SlangResourceAccess::SLANG_RESOURCE_ACCESS_RASTER_ORDERED: - sampled = ImageOpConstants::readWriteImage; - break; - case SlangResourceAccess::SLANG_RESOURCE_ACCESS_NONE: - case SlangResourceAccess::SLANG_RESOURCE_ACCESS_READ: - sampled = ImageOpConstants::sampledImage; - break; + case SlangResourceAccess::SLANG_RESOURCE_ACCESS_READ_WRITE: + case SlangResourceAccess::SLANG_RESOURCE_ACCESS_RASTER_ORDERED: + sampled = ImageOpConstants::readWriteImage; + break; + case SlangResourceAccess::SLANG_RESOURCE_ACCESS_NONE: + case SlangResourceAccess::SLANG_RESOURCE_ACCESS_READ: + sampled = ImageOpConstants::sampledImage; + break; } SpvImageFormat format = getSpvImageFormat(inst); @@ -2116,35 +2094,19 @@ struct SPIRVEmitContext case kIROp_UNormAttr: switch (vectorSize) { - case 1: - format = SpvImageFormatR8; - break; - case 2: - format = SpvImageFormatRg8; - break; - case 3: - format = SpvImageFormatRgba8; - break; - case 4: - format = SpvImageFormatRgba8; - break; + case 1: format = SpvImageFormatR8; break; + case 2: format = SpvImageFormatRg8; break; + case 3: format = SpvImageFormatRgba8; break; + case 4: format = SpvImageFormatRgba8; break; } break; case kIROp_SNormAttr: switch (vectorSize) { - case 1: - format = SpvImageFormatR8Snorm; - break; - case 2: - format = SpvImageFormatRg8Snorm; - break; - case 3: - format = SpvImageFormatRgba8Snorm; - break; - case 4: - format = SpvImageFormatRgba8Snorm; - break; + case 1: format = SpvImageFormatR8Snorm; break; + case 2: format = SpvImageFormatRg8Snorm; break; + case 3: format = SpvImageFormatRgba8Snorm; break; + case 4: format = SpvImageFormatRgba8Snorm; break; } break; } @@ -2156,44 +2118,53 @@ struct SPIRVEmitContext // Capabilities, according to section 3.8 // // SPIR-V requires that the sampled/rw info on the image isn't unknown - SLANG_ASSERT(sampled == ImageOpConstants::sampledImage || sampled == ImageOpConstants::readWriteImage); - if(ms == ImageOpConstants::isMultisampled) + SLANG_ASSERT( + sampled == ImageOpConstants::sampledImage || + sampled == ImageOpConstants::readWriteImage); + if (ms == ImageOpConstants::isMultisampled) requireSPIRVCapability(SpvCapabilityStorageImageMultisample); - switch(dim) + switch (dim) { case SpvDim1D: - requireSPIRVCapability(sampled == ImageOpConstants::sampledImage ? SpvCapabilitySampled1D : SpvCapabilityImage1D); + requireSPIRVCapability( + sampled == ImageOpConstants::sampledImage ? SpvCapabilitySampled1D + : SpvCapabilityImage1D); break; case SpvDim2D: // Also requires Shader or Kernel, but these are a given (?) - if(sampled == ImageOpConstants::readWriteImage && ms == ImageOpConstants::isMultisampled && arrayed == ImageOpConstants::isArrayed) + if (sampled == ImageOpConstants::readWriteImage && + ms == ImageOpConstants::isMultisampled && arrayed == ImageOpConstants::isArrayed) requireSPIRVCapability(SpvCapabilityImageMSArray); break; - case SpvDim3D: - break; + case SpvDim3D: break; case SpvDimCube: // Requires shader also - if(sampled == ImageOpConstants::readWriteImage && arrayed == ImageOpConstants::isArrayed) + if (sampled == ImageOpConstants::readWriteImage && + arrayed == ImageOpConstants::isArrayed) requireSPIRVCapability(SpvCapabilityImageCubeArray); break; case SpvDimRect: - requireSPIRVCapability(sampled == ImageOpConstants::sampledImage ? SpvCapabilitySampledRect : SpvCapabilityImageRect); + requireSPIRVCapability( + sampled == ImageOpConstants::sampledImage ? SpvCapabilitySampledRect + : SpvCapabilityImageRect); break; case SpvDimBuffer: - requireSPIRVCapability(sampled == ImageOpConstants::sampledImage ? SpvCapabilitySampledBuffer : SpvCapabilityImageBuffer); + requireSPIRVCapability( + sampled == ImageOpConstants::sampledImage ? SpvCapabilitySampledBuffer + : SpvCapabilityImageBuffer); break; case SpvDimTileImageDataEXT: SLANG_UNIMPLEMENTED_X("OpTypeImage Capabilities for SpvDimTileImageDataEXT"); break; } - if(format == SpvImageFormatUnknown && sampled == ImageOpConstants::readWriteImage) + if (format == SpvImageFormatUnknown && sampled == ImageOpConstants::readWriteImage) { // TODO: It may not be necessary to have both of these // depending on if we read or write requireSPIRVCapability(SpvCapabilityStorageImageReadWithoutFormat); requireSPIRVCapability(SpvCapabilityStorageImageWriteWithoutFormat); } - + setImageFormatCapabilityAndExtension(format, SpvCapabilityShader); // @@ -2210,11 +2181,8 @@ struct SPIRVEmitContext SpvLiteralInteger::from32(arrayed), SpvLiteralInteger::from32(ms), SpvLiteralInteger::from32(sampled), - format - ); - return emitOpTypeSampledImage( - assignee, - imageType); + format); + return emitOpTypeSampledImage(assignee, imageType); } return emitOpTypeImage( @@ -2225,8 +2193,7 @@ struct SPIRVEmitContext SpvLiteralInteger::from32(arrayed), SpvLiteralInteger::from32(ms), SpvLiteralInteger::from32(sampled), - format - ); + format); } // Ensures an SpvInst for the specified vector type is emitted. @@ -2245,8 +2212,7 @@ struct SPIRVEmitContext auto result = emitOpTypeVector( inst, inst->getElementType(), - SpvLiteralInteger::from32(int32_t(elementCount)) - ); + SpvLiteralInteger::from32(int32_t(elementCount))); return result; } @@ -2255,21 +2221,35 @@ struct SPIRVEmitContext switch (mode) { case IRInterpolationMode::NoInterpolation: - emitOpDecorate(getSection(SpvLogicalSectionID::Annotations), nullptr, varInst, SpvDecorationFlat); + emitOpDecorate( + getSection(SpvLogicalSectionID::Annotations), + nullptr, + varInst, + SpvDecorationFlat); return true; case IRInterpolationMode::NoPerspective: - emitOpDecorate(getSection(SpvLogicalSectionID::Annotations), nullptr, varInst, SpvDecorationNoPerspective); - return true; - case IRInterpolationMode::Linear: + emitOpDecorate( + getSection(SpvLogicalSectionID::Annotations), + nullptr, + varInst, + SpvDecorationNoPerspective); return true; + case IRInterpolationMode::Linear: return true; case IRInterpolationMode::Sample: - emitOpDecorate(getSection(SpvLogicalSectionID::Annotations), nullptr, varInst, SpvDecorationSample); + emitOpDecorate( + getSection(SpvLogicalSectionID::Annotations), + nullptr, + varInst, + SpvDecorationSample); return true; case IRInterpolationMode::Centroid: - emitOpDecorate(getSection(SpvLogicalSectionID::Annotations), nullptr, varInst, SpvDecorationCentroid); + emitOpDecorate( + getSection(SpvLogicalSectionID::Annotations), + nullptr, + varInst, + SpvDecorationCentroid); return true; - default: - return false; + default: return false; } } void emitSystemVarDecoration(IRInst* var, SpvInst* varInst) @@ -2279,7 +2259,11 @@ struct SPIRVEmitContext switch (decor->getOp()) { case kIROp_GLSLPrimitivesRateDecoration: - emitOpDecorate(getSection(SpvLogicalSectionID::Annotations), decor, varInst, SpvDecorationPerPrimitiveEXT); + emitOpDecorate( + getSection(SpvLogicalSectionID::Annotations), + decor, + varInst, + SpvDecorationPerPrimitiveEXT); break; } } @@ -2300,16 +2284,14 @@ struct SPIRVEmitContext UInt space = rr->getSpace(); switch (rr->getResourceKind()) { - case LayoutResourceKind::Uniform: - break; + case LayoutResourceKind::Uniform: break; case LayoutResourceKind::VaryingInput: emitOpDecorateLocation( getSection(SpvLogicalSectionID::Annotations), nullptr, varInst, - SpvLiteralInteger::from32(int32_t(index)) - ); + SpvLiteralInteger::from32(int32_t(index))); if (space != 0) { emitOpDecorateIndex( @@ -2324,8 +2306,7 @@ struct SPIRVEmitContext getSection(SpvLogicalSectionID::Annotations), nullptr, varInst, - SpvLiteralInteger::from32(int32_t(index)) - ); + SpvLiteralInteger::from32(int32_t(index))); if (space != 0) { emitOpDecorateIndex( @@ -2341,8 +2322,7 @@ struct SPIRVEmitContext getSection(SpvLogicalSectionID::Annotations), nullptr, varInst, - SpvLiteralInteger::from32(int32_t(index)) - ); + SpvLiteralInteger::from32(int32_t(index))); break; case LayoutResourceKind::ConstantBuffer: @@ -2394,12 +2374,10 @@ struct SPIRVEmitContext getSection(SpvLogicalSectionID::Annotations), nullptr, varInst, - SpvLiteralInteger::from32((int32_t)index) - ); + SpvLiteralInteger::from32((int32_t)index)); } break; - default: - break; + default: break; } } if (needDefaultSetBindingDecoration && !hasExplicitSetBinding && !isDescirptorSetDecorated) @@ -2420,13 +2398,16 @@ struct SPIRVEmitContext { // Only emit a default `flat` for fragment // stage varying inputs. - if (layout - && layout->getStage() == Stage::Fragment - && layout->usesResourceKind(LayoutResourceKind::VaryingInput)) + if (layout && layout->getStage() == Stage::Fragment && + layout->usesResourceKind(LayoutResourceKind::VaryingInput)) { const auto ptrType = as<IRPtrTypeBase>(var->getDataType()); if (ptrType && isIntegralScalarOrCompositeType(ptrType->getValueType())) - emitOpDecorate(getSection(SpvLogicalSectionID::Annotations), nullptr, varInst, SpvDecorationFlat); + emitOpDecorate( + getSection(SpvLogicalSectionID::Annotations), + nullptr, + varInst, + SpvDecorationFlat); } } @@ -2435,10 +2416,15 @@ struct SPIRVEmitContext switch (decor->getOp()) { case kIROp_GLSLPrimitivesRateDecoration: - emitOpDecorate(getSection(SpvLogicalSectionID::Annotations), decor, varInst, SpvDecorationPerPrimitiveEXT); + emitOpDecorate( + getSection(SpvLogicalSectionID::Annotations), + decor, + varInst, + SpvDecorationPerPrimitiveEXT); break; case kIROp_RequireSPIRVDescriptorIndexingExtensionDecoration: - ensureExtensionDeclarationBeforeSpv15(UnownedStringSlice("SPV_EXT_descriptor_indexing")); + ensureExtensionDeclarationBeforeSpv15( + UnownedStringSlice("SPV_EXT_descriptor_indexing")); requireSPIRVCapability(SpvCapabilityRuntimeDescriptorArray); break; } @@ -2449,11 +2435,15 @@ struct SPIRVEmitContext { if (auto nameDecor = irInst->findDecoration<IRNameHintDecoration>()) { - emitOpName(getSection(SpvLogicalSectionID::DebugNames), nullptr, spvInst, nameDecor->getName()); + emitOpName( + getSection(SpvLogicalSectionID::DebugNames), + nullptr, + spvInst, + nameDecor->getName()); } } - /// Emit a specialization constant. + /// Emit a specialization constant. SpvInst* emitSpecializationConstant(IRGlobalParam* param, IRVarOffsetAttr* offset) { IRInst* defaultVal = nullptr; @@ -2524,7 +2514,7 @@ struct SPIRVEmitContext return result; } - /// Emit a global parameter definition. + /// Emit a global parameter definition. SpvInst* emitGlobalParam(IRGlobalParam* param) { auto layout = getVarLayout(param); @@ -2551,8 +2541,7 @@ struct SPIRVEmitContext getSection(SpvLogicalSectionID::GlobalVariables), param, param->getDataType(), - storageClass - ); + storageClass); maybeEmitPointerDecoration(varInst, param); if (layout) emitVarLayout(param, varInst, layout); @@ -2560,7 +2549,7 @@ struct SPIRVEmitContext return varInst; } - /// Emit a global variable definition. + /// Emit a global variable definition. SpvInst* emitGlobalVar(IRGlobalVar* globalVar) { auto layout = getVarLayout(globalVar); @@ -2574,10 +2563,9 @@ struct SPIRVEmitContext getSection(SpvLogicalSectionID::GlobalVariables), globalVar, globalVar->getDataType(), - storageClass - ); + storageClass); maybeEmitPointerDecoration(varInst, globalVar); - if(layout) + if (layout) emitVarLayout(globalVar, varInst, layout); emitDecorations(globalVar, getID(varInst)); return varInst; @@ -2588,7 +2576,10 @@ struct SPIRVEmitContext const auto kind = (SpvBuiltIn)(getIntVal(spvAsmBuiltinVar->getOperand(0))); IRBuilder builder(spvAsmBuiltinVar); builder.setInsertBefore(spvAsmBuiltinVar); - auto varInst = getBuiltinGlobalVar(builder.getPtrType(kIROp_PtrType, spvAsmBuiltinVar->getDataType(), AddressSpace::Input), kind, spvAsmBuiltinVar); + auto varInst = getBuiltinGlobalVar( + builder.getPtrType(kIROp_PtrType, spvAsmBuiltinVar->getDataType(), AddressSpace::Input), + kind, + spvAsmBuiltinVar); registerInst(spvAsmBuiltinVar, varInst); return varInst; } @@ -2597,7 +2588,9 @@ struct SPIRVEmitContext { StringBuilder sb; sb << "-target spirv "; - m_targetProgram->getOptionSet().writeCommandLineArgs(m_targetProgram->getTargetReq()->getSession(), sb); + m_targetProgram->getOptionSet().writeCommandLineArgs( + m_targetProgram->getTargetReq()->getSession(), + sb); sb << " -stage " << getStageName(entryPointDecor->getProfile().getStage()); if (auto entryPointName = as<IRStringLit>(getName(entryPointDecor->getParent()))) { @@ -2607,7 +2600,7 @@ struct SPIRVEmitContext return sb.produceString(); } - /// Emit the given `irFunc` to SPIR-V + /// Emit the given `irFunc` to SPIR-V SpvInst* emitFunc(IRFunc* irFunc) { // [2.4: Logical Layout of a Module] @@ -2622,7 +2615,7 @@ struct SPIRVEmitContext // on whether they have a body or not, since these // are encoded differently (and to different sections). // - if( isDefinition(irFunc) ) + if (isDefinition(irFunc)) { return emitFuncDefinition(irFunc); } @@ -2632,7 +2625,7 @@ struct SPIRVEmitContext } } - /// Emit a declaration for the given `irFunc` + /// Emit a declaration for the given `irFunc` SpvInst* emitFuncDeclaration(IRFunc* irFunc) { if (irFunc->findDecorationImpl(kIROp_SPIRVOpDecoration)) @@ -2645,10 +2638,10 @@ struct SPIRVEmitContext UNREACHABLE_RETURN(nullptr); } - /// Emit a SPIR-V function definition for the Slang IR function `irFunc`. + /// Emit a SPIR-V function definition for the Slang IR function `irFunc`. SpvInst* emitFuncDefinition(IRFunc* irFunc) { - if(!irFunc->getFirstBlock()) + if (!irFunc->getFirstBlock()) m_sink->diagnose(irFunc, Diagnostics::noBlocksOrIntrinsic, "spirv"); // [2.4: Logical Layout of a Module] @@ -2688,8 +2681,7 @@ struct SPIRVEmitContext irFunc, irFunc->getDataType()->getResultType(), spvFunctionControl, - irFunc->getDataType() - ); + irFunc->getDataType()); // > OpFunctionParameter // @@ -2697,7 +2689,7 @@ struct SPIRVEmitContext // the parameters of a SPIR-V function must appear as direct // children of the function instruction, and before any basic blocks. // - for( auto irParam : irFunc->getParams() ) + for (auto irParam : irFunc->getParams()) { emitParam(spvFunc, irParam); } @@ -2719,7 +2711,7 @@ struct SPIRVEmitContext // the blocks in the Slang IR) // SpvInst* funcDebugScope = nullptr; - for( auto irBlock : irFunc->getBlocks() ) + for (auto irBlock : irFunc->getBlocks()) { auto spvBlock = emitOpLabel(spvFunc, irBlock); if (irBlock == irFunc->getFirstBlock()) @@ -2732,12 +2724,11 @@ struct SPIRVEmitContext { switch (inst->getOp()) { - case kIROp_Var: - emitLocalInst(spvBlock, inst); - break; + case kIROp_Var: emitLocalInst(spvBlock, inst); break; case kIROp_DebugVar: - // Declare an ordinary local variable for debugDeclare association of a debug variable. - // This variable is what we will actually write values to upon a `kIROp_DebugValue` inst. + // Declare an ordinary local variable for debugDeclare association + // of a debug variable. This variable is what we will actually write + // values to upon a `kIROp_DebugValue` inst. emitDebugVarBackingLocalVarDeclaration(spvBlock, as<IRDebugVar>(inst)); break; } @@ -2748,7 +2739,12 @@ struct SPIRVEmitContext } if (funcDebugScope) { - emitOpDebugScope(spvBlock, nullptr, m_voidType, getNonSemanticDebugInfoExtInst(), funcDebugScope); + emitOpDebugScope( + spvBlock, + nullptr, + m_voidType, + getNonSemanticDebugInfoExtInst(), + funcDebugScope); } // In addition to normal basic blocks, // all loops gets a header block. @@ -2788,7 +2784,7 @@ struct SPIRVEmitContext // We will defer the emit of the contents in loop header block // until all Phi insts are emitted. List<IRLoop*> pendingLoopInsts; - for( auto irBlock : irFunc->getBlocks() ) + for (auto irBlock : irFunc->getBlocks()) { // Note: because we already created the block above, // we can be sure that it will have been registred. @@ -2807,7 +2803,7 @@ struct SPIRVEmitContext emitPhi(spvBlock, irParam); } } - for( auto irInst : irBlock->getOrdinaryInsts() ) + for (auto irInst : irBlock->getOrdinaryInsts()) { // Any instructions local to the block will be emitted as children // of the block. @@ -2855,7 +2851,7 @@ struct SPIRVEmitContext return spvFunc; } - /// Check if a block is a loop's target block. + /// Check if a block is a loop's target block. bool isLoopTargetBlock(IRInst* block, IRInst*& loopInst) { for (auto use = block->firstUse; use; use = use->nextUse) @@ -2882,35 +2878,43 @@ struct SPIRVEmitContext switch (memoryOrder) { case kIRMemoryOrder_Relaxed: - return emitIntConstant(IRIntegerValue{ SpvMemorySemanticsMaskNone }, builder.getUIntType()); + return emitIntConstant( + IRIntegerValue{SpvMemorySemanticsMaskNone}, + builder.getUIntType()); case kIRMemoryOrder_Acquire: - return emitIntConstant(IRIntegerValue{ SpvMemorySemanticsAcquireMask }, builder.getUIntType()); + return emitIntConstant( + IRIntegerValue{SpvMemorySemanticsAcquireMask}, + builder.getUIntType()); case kIRMemoryOrder_Release: - return emitIntConstant(IRIntegerValue{ SpvMemorySemanticsReleaseMask }, builder.getUIntType()); + return emitIntConstant( + IRIntegerValue{SpvMemorySemanticsReleaseMask}, + builder.getUIntType()); case kIRMemoryOrder_AcquireRelease: - return emitIntConstant(IRIntegerValue{ SpvMemorySemanticsAcquireReleaseMask }, builder.getUIntType()); + return emitIntConstant( + IRIntegerValue{SpvMemorySemanticsAcquireReleaseMask}, + builder.getUIntType()); case kIRMemoryOrder_SeqCst: - return emitIntConstant(IRIntegerValue{ SpvMemorySemanticsSequentiallyConsistentMask }, builder.getUIntType()); - default: - SLANG_UNEXPECTED("unhandled memory order"); - UNREACHABLE_RETURN(nullptr); + return emitIntConstant( + IRIntegerValue{SpvMemorySemanticsSequentiallyConsistentMask}, + builder.getUIntType()); + default: SLANG_UNEXPECTED("unhandled memory order"); UNREACHABLE_RETURN(nullptr); } } SpvOp getSpvAtomicOp(IRInst* atomicInst, bool& outNegateOperand) { auto typeSelect = [&](SpvOp sop, SpvOp uop, SpvOp fop) + { + auto scalarType = getVectorElementType(atomicInst->getDataType()); + if (isIntegralType(scalarType)) { - auto scalarType = getVectorElementType(atomicInst->getDataType()); - if (isIntegralType(scalarType)) - { - auto intInfo = getIntTypeInfo(scalarType); - if (intInfo.isSigned) - return sop; - return uop; - } - return fop; - }; + auto intInfo = getIntTypeInfo(scalarType); + if (intInfo.isSigned) + return sop; + return uop; + } + return fop; + }; outNegateOperand = false; switch (atomicInst->getOp()) { @@ -2924,15 +2928,10 @@ struct SPIRVEmitContext return typeSelect(SpvOpAtomicSMin, SpvOpAtomicUMin, SpvOpAtomicFMinEXT); case kIROp_AtomicMax: return typeSelect(SpvOpAtomicSMax, SpvOpAtomicUMax, SpvOpAtomicFMaxEXT); - case kIROp_AtomicAnd: - return SpvOpAtomicAnd; - case kIROp_AtomicOr: - return SpvOpAtomicOr; - case kIROp_AtomicXor: - return SpvOpAtomicXor; - default: - SLANG_UNEXPECTED("unhandled atomic op"); - UNREACHABLE_RETURN(SpvOpNop); + case kIROp_AtomicAnd: return SpvOpAtomicAnd; + case kIROp_AtomicOr: return SpvOpAtomicOr; + case kIROp_AtomicXor: return SpvOpAtomicXor; + default: SLANG_UNEXPECTED("unhandled atomic op"); UNREACHABLE_RETURN(SpvOpNop); } } @@ -2942,65 +2941,65 @@ struct SPIRVEmitContext switch (op) { case SpvOpAtomicFAddEXT: - { - switch (typeOp) { - case kIROp_FloatType: - ensureExtensionDeclaration(toSlice("SPV_EXT_shader_atomic_float_add")); - requireSPIRVCapability(SpvCapabilityAtomicFloat32AddEXT); - break; - case kIROp_DoubleType: - ensureExtensionDeclaration(toSlice("SPV_EXT_shader_atomic_float_add")); - requireSPIRVCapability(SpvCapabilityAtomicFloat64AddEXT); - break; - case kIROp_HalfType: - ensureExtensionDeclaration(toSlice("SPV_EXT_shader_atomic_float16_add")); - requireSPIRVCapability(SpvCapabilityAtomicFloat16AddEXT); - break; - case kIROp_VectorType: - if (as<IRVectorType>(atomicInst->getDataType())->getElementType()->getOp() == kIROp_HalfType) + switch (typeOp) { - ensureExtensionDeclaration(toSlice("VK_NV_shader_atomic_float16_vector")); - requireSPIRVCapability(SpvCapabilityAtomicFloat16VectorNV); + case kIROp_FloatType: + ensureExtensionDeclaration(toSlice("SPV_EXT_shader_atomic_float_add")); + requireSPIRVCapability(SpvCapabilityAtomicFloat32AddEXT); + break; + case kIROp_DoubleType: + ensureExtensionDeclaration(toSlice("SPV_EXT_shader_atomic_float_add")); + requireSPIRVCapability(SpvCapabilityAtomicFloat64AddEXT); + break; + case kIROp_HalfType: + ensureExtensionDeclaration(toSlice("SPV_EXT_shader_atomic_float16_add")); + requireSPIRVCapability(SpvCapabilityAtomicFloat16AddEXT); + break; + case kIROp_VectorType: + if (as<IRVectorType>(atomicInst->getDataType())->getElementType()->getOp() == + kIROp_HalfType) + { + ensureExtensionDeclaration(toSlice("VK_NV_shader_atomic_float16_vector")); + requireSPIRVCapability(SpvCapabilityAtomicFloat16VectorNV); + } + break; } - break; } - } - break; + break; case SpvOpAtomicFMinEXT: case SpvOpAtomicFMaxEXT: - { - switch (typeOp) { - case kIROp_FloatType: - ensureExtensionDeclaration(toSlice("SPV_EXT_shader_atomic_float_min_max")); - requireSPIRVCapability(SpvCapabilityAtomicFloat32MinMaxEXT); - break; - case kIROp_DoubleType: - ensureExtensionDeclaration(toSlice("SPV_EXT_shader_atomic_float_min_max")); - requireSPIRVCapability(SpvCapabilityAtomicFloat64MinMaxEXT); - break; - case kIROp_HalfType: - ensureExtensionDeclaration(toSlice("SPV_EXT_shader_atomic_float_min_max")); - requireSPIRVCapability(SpvCapabilityAtomicFloat16MinMaxEXT); - break; - case kIROp_VectorType: - if (as<IRVectorType>(atomicInst->getDataType())->getElementType()->getOp() == kIROp_HalfType) + switch (typeOp) { - ensureExtensionDeclaration(toSlice("VK_NV_shader_atomic_float16_vector")); - requireSPIRVCapability(SpvCapabilityAtomicFloat16VectorNV); + case kIROp_FloatType: + ensureExtensionDeclaration(toSlice("SPV_EXT_shader_atomic_float_min_max")); + requireSPIRVCapability(SpvCapabilityAtomicFloat32MinMaxEXT); + break; + case kIROp_DoubleType: + ensureExtensionDeclaration(toSlice("SPV_EXT_shader_atomic_float_min_max")); + requireSPIRVCapability(SpvCapabilityAtomicFloat64MinMaxEXT); + break; + case kIROp_HalfType: + ensureExtensionDeclaration(toSlice("SPV_EXT_shader_atomic_float_min_max")); + requireSPIRVCapability(SpvCapabilityAtomicFloat16MinMaxEXT); + break; + case kIROp_VectorType: + if (as<IRVectorType>(atomicInst->getDataType())->getElementType()->getOp() == + kIROp_HalfType) + { + ensureExtensionDeclaration(toSlice("VK_NV_shader_atomic_float16_vector")); + requireSPIRVCapability(SpvCapabilityAtomicFloat16VectorNV); + } + break; } - break; } - } - break; + break; } switch (typeOp) { case kIROp_UInt64Type: - case kIROp_Int64Type: - requireSPIRVCapability(SpvCapabilityInt64Atomics); - break; + case kIROp_Int64Type: requireSPIRVCapability(SpvCapabilityInt64Atomics); break; } } @@ -3042,8 +3041,15 @@ struct SPIRVEmitContext if (hasBackingVar) { - emitOpDebugDeclare(parent, nullptr, m_voidType, getNonSemanticDebugInfoExtInst(), - spvDebugLocalVar, debugVar, getDwarfExpr(), List<SpvInst*>()); + emitOpDebugDeclare( + parent, + nullptr, + m_voidType, + getNonSemanticDebugInfoExtInst(), + spvDebugLocalVar, + debugVar, + getDwarfExpr(), + List<SpvInst*>()); } return spvDebugLocalVar; @@ -3053,14 +3059,11 @@ struct SPIRVEmitContext { switch (type->getOp()) { - case kIROp_UnsizedArrayType: - return false; - case kIROp_ArrayType: - return isLegalType(as<IRArrayType>(type)->getElementType()); + case kIROp_UnsizedArrayType: return false; + case kIROp_ArrayType: return isLegalType(as<IRArrayType>(type)->getElementType()); case kIROp_VectorType: case kIROp_StructType: - case kIROp_MatrixType: - return true; + case kIROp_MatrixType: return true; case kIROp_PtrType: return as<IRPtrTypeBase>(type)->getAddressSpace() == AddressSpace::UserPointer; default: @@ -3088,7 +3091,8 @@ struct SPIRVEmitContext if (sizeAlignment.size != IRSizeAndAlignment::kIndeterminateSize) { auto debugVarPtrType = builder.getPtrType(varType, AddressSpace::Function); - auto actualHelperVar = emitOpVariable(parent, debugVar, debugVarPtrType, SpvStorageClassFunction); + auto actualHelperVar = + emitOpVariable(parent, debugVar, debugVarPtrType, SpvStorageClassFunction); maybeEmitPointerDecoration(actualHelperVar, debugVar); return actualHelperVar; } @@ -3103,108 +3107,64 @@ struct SPIRVEmitContext // for local instructions they will usually emit into // a known parent (the basic block that contains them). - /// Emit an instruction that is local to the body of the given `parent`. + /// Emit an instruction that is local to the body of the given `parent`. SpvInst* emitLocalInst(SpvInstParent* parent, IRInst* inst) { SpvInst* result = nullptr; - switch( inst->getOp() ) + switch (inst->getOp()) { default: { if (as<IRSPIRVAsmOperand>(inst)) return nullptr; - String e = "Unhandled local inst in spirv-emit:\n" - + dumpIRToString(inst, {IRDumpOptions::Mode::Detailed, 0}); + String e = "Unhandled local inst in spirv-emit:\n" + + dumpIRToString(inst, {IRDumpOptions::Mode::Detailed, 0}); SLANG_UNIMPLEMENTED_X(e.getBuffer()); } case kIROp_Specialize: case kIROp_MissingReturn: case kIROp_StaticAssert: - case kIROp_Unmodified: - break; - case kIROp_Var: - result = emitVar(parent, inst); - break; - case kIROp_Call: - result = emitCall(parent, static_cast<IRCall*>(inst)); - break; - case kIROp_FieldAddress: - result = emitFieldAddress(parent, as<IRFieldAddress>(inst)); - break; - case kIROp_FieldExtract: - result = emitFieldExtract(parent, as<IRFieldExtract>(inst)); - break; + case kIROp_Unmodified: break; + case kIROp_Var: result = emitVar(parent, inst); break; + case kIROp_Call: result = emitCall(parent, static_cast<IRCall*>(inst)); break; + case kIROp_FieldAddress: result = emitFieldAddress(parent, as<IRFieldAddress>(inst)); break; + case kIROp_FieldExtract: result = emitFieldExtract(parent, as<IRFieldExtract>(inst)); break; case kIROp_GetElementPtr: result = emitGetElementPtr(parent, as<IRGetElementPtr>(inst)); break; - case kIROp_GetOffsetPtr: - result = emitGetOffsetPtr(parent, inst); - break; - case kIROp_GetElement: - result = emitGetElement(parent, as<IRGetElement>(inst)); - break; - case kIROp_MakeStruct: - result = emitCompositeConstruct(parent, inst); - break; - case kIROp_MakeArrayFromElement: - result = emitMakeArrayFromElement(parent, inst); - break; - case kIROp_MakeMatrixFromScalar: - result = emitMakeMatrixFromScalar(parent, inst); - break; - case kIROp_MakeMatrix: - result = emitMakeMatrix(parent, inst); - break; - case kIROp_Load: - result = emitLoad(parent, as<IRLoad>(inst)); - break; - case kIROp_Store: - result = emitStore(parent, as<IRStore>(inst)); - break; + case kIROp_GetOffsetPtr: result = emitGetOffsetPtr(parent, inst); break; + case kIROp_GetElement: result = emitGetElement(parent, as<IRGetElement>(inst)); break; + case kIROp_MakeStruct: result = emitCompositeConstruct(parent, inst); break; + case kIROp_MakeArrayFromElement: result = emitMakeArrayFromElement(parent, inst); break; + case kIROp_MakeMatrixFromScalar: result = emitMakeMatrixFromScalar(parent, inst); break; + case kIROp_MakeMatrix: result = emitMakeMatrix(parent, inst); break; + case kIROp_Load: result = emitLoad(parent, as<IRLoad>(inst)); break; + case kIROp_Store: result = emitStore(parent, as<IRStore>(inst)); break; case kIROp_SwizzledStore: result = emitSwizzledStore(parent, as<IRSwizzledStore>(inst)); break; - case kIROp_swizzleSet: - result = emitSwizzleSet(parent, as<IRSwizzleSet>(inst)); - break; + case kIROp_swizzleSet: result = emitSwizzleSet(parent, as<IRSwizzleSet>(inst)); break; case kIROp_RWStructuredBufferGetElementPtr: result = emitStructuredBufferGetElementPtr(parent, inst); break; case kIROp_StructuredBufferGetDimensions: result = emitStructuredBufferGetDimensions(parent, inst); break; - case kIROp_swizzle: - result = emitSwizzle(parent, as<IRSwizzle>(inst)); - break; - case kIROp_IntCast: - result = emitIntCast(parent, as<IRIntCast>(inst)); - break; - case kIROp_FloatCast: - result = emitFloatCast(parent, as<IRFloatCast>(inst)); - break; + case kIROp_swizzle: result = emitSwizzle(parent, as<IRSwizzle>(inst)); break; + case kIROp_IntCast: result = emitIntCast(parent, as<IRIntCast>(inst)); break; + case kIROp_FloatCast: result = emitFloatCast(parent, as<IRFloatCast>(inst)); break; case kIROp_CastIntToFloat: result = emitIntToFloatCast(parent, as<IRCastIntToFloat>(inst)); break; case kIROp_CastFloatToInt: result = emitFloatToIntCast(parent, as<IRCastFloatToInt>(inst)); break; - case kIROp_CastPtrToInt: - result = emitCastPtrToInt(parent, inst); - break; - case kIROp_CastPtrToBool: - result = emitCastPtrToBool(parent, inst); - break; - case kIROp_CastIntToPtr: - result = emitCastIntToPtr(parent, inst); - break; + case kIROp_CastPtrToInt: result = emitCastPtrToInt(parent, inst); break; + case kIROp_CastPtrToBool: result = emitCastPtrToBool(parent, inst); break; + case kIROp_CastIntToPtr: result = emitCastIntToPtr(parent, inst); break; case kIROp_PtrCast: case kIROp_BitCast: - result = emitOpBitcast( - parent, - inst, - inst->getDataType(), - inst->getOperand(0) - ); + result = emitOpBitcast(parent, inst, inst->getDataType(), inst->getOperand(0)); break; case kIROp_Add: case kIROp_Sub: @@ -3227,9 +3187,7 @@ struct SPIRVEmitContext case kIROp_Greater: case kIROp_Geq: case kIROp_Rsh: - case kIROp_Lsh: - result = emitArithmetic(parent, inst); - break; + case kIROp_Lsh: result = emitArithmetic(parent, inst); break; case kIROp_GlobalValueRef: { auto inner = ensureInst(inst->getOperand(0)); @@ -3256,33 +3214,53 @@ struct SPIRVEmitContext { auto parentFunc = getParentFunc(inst); - HashSet<IRFunc*>* entryPointsUsingInst = getReferencingEntryPoints(m_referencingEntryPoints, parentFunc); + HashSet<IRFunc*>* entryPointsUsingInst = + getReferencingEntryPoints(m_referencingEntryPoints, parentFunc); for (IRFunc* entryPoint : *entryPointsUsingInst) { bool isQuad = true; IREntryPointDecoration* entryPointDecor = nullptr; - for(auto dec : entryPoint->getDecorations()) + for (auto dec : entryPoint->getDecorations()) { - if(auto maybeEntryPointDecor = as<IREntryPointDecoration>(dec)) + if (auto maybeEntryPointDecor = as<IREntryPointDecoration>(dec)) entryPointDecor = maybeEntryPointDecor; - if(as<IRDerivativeGroupLinearDecoration>(dec)) + if (as<IRDerivativeGroupLinearDecoration>(dec)) isQuad = false; } - if (!entryPointDecor || entryPointDecor->getProfile().getStage() != Stage::Compute) + if (!entryPointDecor || + entryPointDecor->getProfile().getStage() != Stage::Compute) continue; - ensureExtensionDeclaration(UnownedStringSlice("SPV_NV_compute_shader_derivatives")); - auto numThreadsDecor = entryPointDecor->findDecoration<IRNumThreadsDecoration>(); + ensureExtensionDeclaration( + UnownedStringSlice("SPV_NV_compute_shader_derivatives")); + auto numThreadsDecor = + entryPointDecor->findDecoration<IRNumThreadsDecoration>(); if (isQuad) { - verifyComputeDerivativeGroupModifiers(this->m_sink, inst->sourceLoc, true, false, numThreadsDecor); - requireSPIRVExecutionMode(nullptr, getIRInstSpvID(entryPoint), SpvExecutionModeDerivativeGroupQuadsNV); + verifyComputeDerivativeGroupModifiers( + this->m_sink, + inst->sourceLoc, + true, + false, + numThreadsDecor); + requireSPIRVExecutionMode( + nullptr, + getIRInstSpvID(entryPoint), + SpvExecutionModeDerivativeGroupQuadsNV); requireSPIRVCapability(SpvCapabilityComputeDerivativeGroupQuadsNV); } else { - verifyComputeDerivativeGroupModifiers(this->m_sink, inst->sourceLoc, false, true, numThreadsDecor); - requireSPIRVExecutionMode(nullptr, getIRInstSpvID(entryPoint), SpvExecutionModeDerivativeGroupLinearNV); + verifyComputeDerivativeGroupModifiers( + this->m_sink, + inst->sourceLoc, + false, + true, + numThreadsDecor); + requireSPIRVExecutionMode( + nullptr, + getIRInstSpvID(entryPoint), + SpvExecutionModeDerivativeGroupLinearNV); requireSPIRVCapability(SpvCapabilityComputeDerivativeGroupLinearNV); } } @@ -3298,7 +3276,8 @@ struct SPIRVEmitContext case kIROp_discard: if (shouldEmitDiscardAsDemote()) { - ensureExtensionDeclarationBeforeSpv16(toSlice("SPV_EXT_demote_to_helper_invocation")); + ensureExtensionDeclarationBeforeSpv16( + toSlice("SPV_EXT_demote_to_helper_invocation")); requireSPIRVCapability(SpvCapabilityDemoteToHelperInvocation); result = emitOpDemoteToHelperInvocation(parent, inst); } @@ -3310,7 +3289,10 @@ struct SPIRVEmitContext case kIROp_BeginFragmentShaderInterlock: ensureExtensionDeclaration(UnownedStringSlice("SPV_EXT_fragment_shader_interlock")); requireSPIRVCapability(SpvCapabilityFragmentShaderPixelInterlockEXT); - requireSPIRVExecutionMode(nullptr, getIRInstSpvID(getParentFunc(inst)), SpvExecutionModePixelInterlockOrderedEXT); + requireSPIRVExecutionMode( + nullptr, + getIRInstSpvID(getParentFunc(inst)), + SpvExecutionModePixelInterlockOrderedEXT); result = emitOpBeginInvocationInterlockEXT(parent, inst); break; case kIROp_EndFragmentShaderInterlock: @@ -3342,7 +3324,7 @@ struct SPIRVEmitContext // after everything else to ensure Phi instructions (which come // from the actual loop target block) are emitted first. emitOpBranch(parent, nullptr, blockId); - + result = block; break; } @@ -3358,8 +3340,7 @@ struct SPIRVEmitContext ifelseInst->getCondition(), ifelseInst->getTrueBlock(), falseLabel ? getID(ensureInst(falseLabel)) : afterBlockID, - makeArray<SpvLiteralInteger>() - ); + makeArray<SpvLiteralInteger>()); break; } case kIROp_Switch: @@ -3367,31 +3348,32 @@ struct SPIRVEmitContext auto switchInst = as<IRSwitch>(inst); auto mergeBlockID = getIRInstSpvID(switchInst->getBreakLabel()); emitOpSelectionMerge(parent, nullptr, mergeBlockID, SpvSelectionControlMaskNone); - result = emitInstCustomOperandFunc(parent, inst, SpvOpSwitch, [&]() { - emitOperand(switchInst->getCondition()); - auto defaultLabel = switchInst->getDefaultLabel(); - emitOperand(defaultLabel ? getID(ensureInst(defaultLabel)) : mergeBlockID); - for (UInt c = 0; c < switchInst->getCaseCount(); c++) + result = emitInstCustomOperandFunc( + parent, + inst, + SpvOpSwitch, + [&]() { - auto value = switchInst->getCaseValue(c); - auto intLit = as<IRIntLit>(value); - SLANG_ASSERT(intLit); - emitOperand((SpvWord)intLit->getValue()); - auto caseLabel = switchInst->getCaseLabel(c); - emitOperand(caseLabel ? getID(ensureInst(caseLabel)) : mergeBlockID); - } - }); + emitOperand(switchInst->getCondition()); + auto defaultLabel = switchInst->getDefaultLabel(); + emitOperand(defaultLabel ? getID(ensureInst(defaultLabel)) : mergeBlockID); + for (UInt c = 0; c < switchInst->getCaseCount(); c++) + { + auto value = switchInst->getCaseValue(c); + auto intLit = as<IRIntLit>(value); + SLANG_ASSERT(intLit); + emitOperand((SpvWord)intLit->getValue()); + auto caseLabel = switchInst->getCaseLabel(c); + emitOperand(caseLabel ? getID(ensureInst(caseLabel)) : mergeBlockID); + } + }); break; } - case kIROp_Unreachable: - result = emitOpUnreachable(parent, inst); - break; + case kIROp_Unreachable: result = emitOpUnreachable(parent, inst); break; case kIROp_conditionalBranch: SLANG_UNEXPECTED("Unstructured branching is not supported by SPIRV."); break; - case kIROp_MakeVector: - result = emitConstruct(parent, inst); - break; + case kIROp_MakeVector: result = emitConstruct(parent, inst); break; case kIROp_MakeVectorFromScalar: { const auto scalar = inst->getOperand(0); @@ -3402,94 +3384,125 @@ struct SPIRVEmitContext result = emitSplat(parent, inst, scalar, numElems->getValue()); } break; - case kIROp_MakeArray: - result = emitConstruct(parent, inst); - break; + case kIROp_MakeArray: result = emitConstruct(parent, inst); break; case kIROp_Select: - result = emitInst(parent, inst, SpvOpSelect, inst->getFullType(), kResultID, OperandsOf(inst)); - break; - case kIROp_DebugLine: - result = emitDebugLine(parent, as<IRDebugLine>(inst)); - break; - case kIROp_DebugVar: - result = emitDebugVarDeclaration(parent, as<IRDebugVar>(inst)); - break; - case kIROp_DebugValue: - result = emitDebugValue(parent, as<IRDebugValue>(inst)); - break; - case kIROp_GetStringHash: - result = emitGetStringHash(inst); - break; - case kIROp_undefined: - result = emitOpUndef(parent, inst, inst->getDataType()); - break; - case kIROp_SPIRVAsm: - result = emitSPIRVAsm(parent, as<IRSPIRVAsm>(inst)); - break; - case kIROp_ImageLoad: - result = emitImageLoad(parent, as<IRImageLoad>(inst)); - break; - case kIROp_ImageStore: - result = emitImageStore(parent, as<IRImageStore>(inst)); - break; + result = emitInst( + parent, + inst, + SpvOpSelect, + inst->getFullType(), + kResultID, + OperandsOf(inst)); + break; + case kIROp_DebugLine: result = emitDebugLine(parent, as<IRDebugLine>(inst)); break; + case kIROp_DebugVar: result = emitDebugVarDeclaration(parent, as<IRDebugVar>(inst)); break; + case kIROp_DebugValue: result = emitDebugValue(parent, as<IRDebugValue>(inst)); break; + case kIROp_GetStringHash: result = emitGetStringHash(inst); break; + case kIROp_undefined: result = emitOpUndef(parent, inst, inst->getDataType()); break; + case kIROp_SPIRVAsm: result = emitSPIRVAsm(parent, as<IRSPIRVAsm>(inst)); break; + case kIROp_ImageLoad: result = emitImageLoad(parent, as<IRImageLoad>(inst)); break; + case kIROp_ImageStore: result = emitImageStore(parent, as<IRImageStore>(inst)); break; case kIROp_ImageSubscript: result = emitImageSubscript(parent, as<IRImageSubscript>(inst)); break; case kIROp_AtomicInc: { IRBuilder builder{inst}; - const auto memoryScope = emitIntConstant(IRIntegerValue{SpvScopeDevice}, builder.getUIntType()); + const auto memoryScope = + emitIntConstant(IRIntegerValue{SpvScopeDevice}, builder.getUIntType()); const auto memorySemantics = emitMemorySemanticMask(inst->getOperand(1)); - result = emitOpAtomicIIncrement(parent, inst, inst->getFullType(), inst->getOperand(0), memoryScope, memorySemantics); + result = emitOpAtomicIIncrement( + parent, + inst, + inst->getFullType(), + inst->getOperand(0), + memoryScope, + memorySemantics); ensureAtomicCapability(inst, SpvOpAtomicIIncrement); } break; case kIROp_AtomicDec: { - IRBuilder builder{ inst }; - const auto memoryScope = emitIntConstant(IRIntegerValue{ SpvScopeDevice }, builder.getUIntType()); + IRBuilder builder{inst}; + const auto memoryScope = + emitIntConstant(IRIntegerValue{SpvScopeDevice}, builder.getUIntType()); const auto memorySemantics = emitMemorySemanticMask(inst->getOperand(1)); - result = emitOpAtomicIDecrement(parent, inst, inst->getFullType(), inst->getOperand(0), memoryScope, memorySemantics); + result = emitOpAtomicIDecrement( + parent, + inst, + inst->getFullType(), + inst->getOperand(0), + memoryScope, + memorySemantics); ensureAtomicCapability(inst, SpvOpAtomicIDecrement); } break; case kIROp_AtomicLoad: { - IRBuilder builder{ inst }; - const auto memoryScope = emitIntConstant(IRIntegerValue{ SpvScopeDevice }, builder.getUIntType()); + IRBuilder builder{inst}; + const auto memoryScope = + emitIntConstant(IRIntegerValue{SpvScopeDevice}, builder.getUIntType()); const auto memorySemantics = emitMemorySemanticMask(inst->getOperand(1)); - result = emitOpAtomicLoad(parent, inst, inst->getFullType(), inst->getOperand(0), memoryScope, memorySemantics); + result = emitOpAtomicLoad( + parent, + inst, + inst->getFullType(), + inst->getOperand(0), + memoryScope, + memorySemantics); ensureAtomicCapability(inst, SpvOpAtomicLoad); } break; case kIROp_AtomicStore: { - IRBuilder builder{ inst }; - const auto memoryScope = emitIntConstant(IRIntegerValue{ SpvScopeDevice }, builder.getUIntType()); + IRBuilder builder{inst}; + const auto memoryScope = + emitIntConstant(IRIntegerValue{SpvScopeDevice}, builder.getUIntType()); const auto memorySemantics = emitMemorySemanticMask(inst->getOperand(2)); - result = emitOpAtomicStore(parent, inst, inst->getOperand(0), memoryScope, memorySemantics, inst->getOperand(1)); + result = emitOpAtomicStore( + parent, + inst, + inst->getOperand(0), + memoryScope, + memorySemantics, + inst->getOperand(1)); ensureAtomicCapability(inst, SpvOpAtomicStore); } break; case kIROp_AtomicExchange: { - IRBuilder builder{ inst }; - const auto memoryScope = emitIntConstant(IRIntegerValue{ SpvScopeDevice }, builder.getUIntType()); + IRBuilder builder{inst}; + const auto memoryScope = + emitIntConstant(IRIntegerValue{SpvScopeDevice}, builder.getUIntType()); const auto memorySemantics = emitMemorySemanticMask(inst->getOperand(2)); - result = emitOpAtomicExchange(parent, inst, inst->getFullType(), inst->getOperand(0), memoryScope, memorySemantics, inst->getOperand(1)); + result = emitOpAtomicExchange( + parent, + inst, + inst->getFullType(), + inst->getOperand(0), + memoryScope, + memorySemantics, + inst->getOperand(1)); ensureAtomicCapability(inst, SpvOpAtomicExchange); } break; case kIROp_AtomicCompareExchange: { - IRBuilder builder{ inst }; - const auto memoryScope = emitIntConstant(IRIntegerValue{ SpvScopeDevice }, builder.getUIntType()); + IRBuilder builder{inst}; + const auto memoryScope = + emitIntConstant(IRIntegerValue{SpvScopeDevice}, builder.getUIntType()); const auto memorySemanticsEqual = emitMemorySemanticMask(inst->getOperand(3)); const auto memorySemanticsUnequal = emitMemorySemanticMask(inst->getOperand(4)); result = emitOpAtomicCompareExchange( - parent, inst, inst->getFullType(), inst->getOperand(0), - memoryScope, memorySemanticsEqual, memorySemanticsUnequal, - inst->getOperand(2), inst->getOperand(1)); + parent, + inst, + inst->getFullType(), + inst->getOperand(0), + memoryScope, + memorySemanticsEqual, + memorySemanticsUnequal, + inst->getOperand(2), + inst->getOperand(1)); ensureAtomicCapability(inst, SpvOpAtomicCompareExchange); } break; @@ -3501,8 +3514,9 @@ struct SPIRVEmitContext case kIROp_AtomicOr: case kIROp_AtomicXor: { - IRBuilder builder{ inst }; - const auto memoryScope = emitIntConstant(IRIntegerValue{ SpvScopeDevice }, builder.getUIntType()); + IRBuilder builder{inst}; + const auto memoryScope = + emitIntConstant(IRIntegerValue{SpvScopeDevice}, builder.getUIntType()); const auto memorySemantics = emitMemorySemanticMask(inst->getOperand(2)); bool negateOperand = false; auto spvOp = getSpvAtomicOp(inst, negateOperand); @@ -3513,17 +3527,35 @@ struct SPIRVEmitContext auto negatedOperand = builder.emitNeg(inst->getDataType(), operand); operand = negatedOperand; } - result = emitOpAtomicOp(parent, inst, spvOp, inst->getFullType(), inst->getOperand(0), memoryScope, memorySemantics, operand); + result = emitOpAtomicOp( + parent, + inst, + spvOp, + inst->getFullType(), + inst->getOperand(0), + memoryScope, + memorySemantics, + operand); ensureAtomicCapability(inst, spvOp); } break; case kIROp_ControlBarrier: { - IRBuilder builder{ inst }; - const auto executionScope = emitIntConstant(IRIntegerValue{ SpvScopeWorkgroup }, builder.getUIntType()); - const auto memoryScope = emitIntConstant(IRIntegerValue{ SpvScopeInvocation }, builder.getUIntType()); - const auto memorySemantics = emitIntConstant(IRIntegerValue{ SpvMemorySemanticsMaskNone }, builder.getUIntType()); - emitInst(parent, inst, SpvOpControlBarrier, executionScope, memoryScope, memorySemantics); + IRBuilder builder{inst}; + const auto executionScope = + emitIntConstant(IRIntegerValue{SpvScopeWorkgroup}, builder.getUIntType()); + const auto memoryScope = + emitIntConstant(IRIntegerValue{SpvScopeInvocation}, builder.getUIntType()); + const auto memorySemantics = emitIntConstant( + IRIntegerValue{SpvMemorySemanticsMaskNone}, + builder.getUIntType()); + emitInst( + parent, + inst, + SpvOpControlBarrier, + executionScope, + memoryScope, + memorySemantics); } break; case kIROp_Printf: @@ -3543,8 +3575,15 @@ struct SPIRVEmitContext } } ensureExtensionDeclaration(toSlice("SPV_KHR_non_semantic_info")); - result = emitInst(parent, inst, SpvOpExtInst, inst->getFullType(), kResultID, - getNonSemanticDebugPrintfExtInst(), SpvLiteralInteger::from32(1), operands.getArrayView()); + result = emitInst( + parent, + inst, + SpvOpExtInst, + inst->getFullType(), + kResultID, + getNonSemanticDebugPrintfExtInst(), + SpvLiteralInteger::from32(1), + operands.getArrayView()); } break; } @@ -3557,11 +3596,27 @@ struct SPIRVEmitContext { if (load->hasAuxCoord1()) { - return emitInst(parent, load, SpvOpImageRead, load->getDataType(), kResultID, load->getImage(), load->getCoord(), SpvImageOperandsSampleMask, load->getAuxCoord1()); + return emitInst( + parent, + load, + SpvOpImageRead, + load->getDataType(), + kResultID, + load->getImage(), + load->getCoord(), + SpvImageOperandsSampleMask, + load->getAuxCoord1()); } else { - return emitInst(parent, load, SpvOpImageRead, load->getDataType(), kResultID, load->getImage(), load->getCoord()); + return emitInst( + parent, + load, + SpvOpImageRead, + load->getDataType(), + kResultID, + load->getImage(), + load->getCoord()); } } @@ -3569,11 +3624,25 @@ struct SPIRVEmitContext { if (store->hasAuxCoord1()) { - return emitInst(parent, store, SpvOpImageWrite, store->getImage(), store->getCoord(), store->getValue(), SpvImageOperandsSampleMask, store->getAuxCoord1()); + return emitInst( + parent, + store, + SpvOpImageWrite, + store->getImage(), + store->getCoord(), + store->getValue(), + SpvImageOperandsSampleMask, + store->getAuxCoord1()); } else { - return emitInst(parent, store, SpvOpImageWrite, store->getImage(), store->getCoord(), store->getValue()); + return emitInst( + parent, + store, + SpvOpImageWrite, + store->getImage(), + store->getCoord(), + store->getValue()); } } @@ -3581,7 +3650,15 @@ struct SPIRVEmitContext { IRBuilder builder(subscript); builder.setInsertBefore(subscript); - return emitInst(parent, subscript, SpvOpImageTexelPointer, subscript->getDataType(), kResultID, subscript->getImage(), subscript->getCoord(), builder.getIntValue(builder.getIntType(), 0)); + return emitInst( + parent, + subscript, + SpvOpImageTexelPointer, + subscript->getDataType(), + kResultID, + subscript->getImage(), + subscript->getCoord(), + builder.getIntValue(builder.getIntType(), 0)); } SpvInst* emitGetStringHash(IRInst* inst) @@ -3592,13 +3669,15 @@ struct SPIRVEmitContext if (stringLit) { auto slice = stringLit->getStringSlice(); - return emitIntConstant(getStableHashCode32(slice.begin(), slice.getLength()).hash, inst->getDataType()); + return emitIntConstant( + getStableHashCode32(slice.begin(), slice.getLength()).hash, + inst->getDataType()); } else { - // Couldn't handle - String e = "Unhandled local inst in spirv-emit:\n" - + dumpIRToString(inst, { IRDumpOptions::Mode::Detailed, 0 }); + // Couldn't handle + String e = "Unhandled local inst in spirv-emit:\n" + + dumpIRToString(inst, {IRDumpOptions::Mode::Detailed, 0}); SLANG_UNIMPLEMENTED_X(e.getBuffer()); } } @@ -3623,28 +3702,26 @@ struct SPIRVEmitContext SpvInst* spvInst = nullptr; if (cast<IRBoolLit>(inst)->getValue()) { - spvInst = emitOpConstantTrue( - inst, - inst->getDataType() - ); + spvInst = emitOpConstantTrue(inst, inst->getDataType()); } else { - spvInst = emitOpConstantFalse( - inst, - inst->getDataType() - ); + spvInst = emitOpConstantFalse(inst, inst->getDataType()); } m_mapIRInstToSpvInst[inst] = spvInst; return spvInst; } case kIROp_StringLit: - { - auto value = as<IRStringLit>(inst)->getStringSlice(); - return emitInst(getSection(SpvLogicalSectionID::DebugStringsAndSource), inst, SpvOpString, kResultID, SpvLiteralBits::fromUnownedStringSlice(value)); - } - default: - return nullptr; + { + auto value = as<IRStringLit>(inst)->getStringSlice(); + return emitInst( + getSection(SpvLogicalSectionID::DebugStringsAndSource), + inst, + SpvOpString, + kResultID, + SpvLiteralBits::fromUnownedStringSlice(value)); + } + default: return nullptr; } } @@ -3653,14 +3730,14 @@ struct SPIRVEmitContext // to emit any decoratons that were attached to it that have // a SPIR-V equivalent. - /// Emit appropriate SPIR-V decorations for the given IR `irInst`. - /// - /// The given `dstID` should be the `<id>` of the SPIR-V instruction being decorated, - /// and should correspond to `irInst`. - /// + /// Emit appropriate SPIR-V decorations for the given IR `irInst`. + /// + /// The given `dstID` should be the `<id>` of the SPIR-V instruction being decorated, + /// and should correspond to `irInst`. + /// void emitDecorations(IRInst* irInst, SpvWord dstID) { - for( auto decoration : irInst->getDecorations() ) + for (auto decoration : irInst->getDecorations()) { emitDecoration(dstID, decoration); } @@ -3731,8 +3808,7 @@ struct SPIRVEmitContext { case kIROp_SwizzledStore: case kIROp_Store: - case kIROp_Call: - return result; + case kIROp_Call: return result; } } return SpvExecutionModeMax; @@ -3781,11 +3857,12 @@ struct SPIRVEmitContext return sb.produceString(); } - /// Emit an appropriate SPIR-V decoration for the given IR `decoration`, if necessary and possible. - /// - /// The given `dstID` should be the `<id>` of the SPIR-V instruction being decorated, - /// and should correspond to the parent of `decoration` in the Slang IR. - /// + /// Emit an appropriate SPIR-V decoration for the given IR `decoration`, if necessary and + /// possible. + /// + /// The given `dstID` should be the `<id>` of the SPIR-V instruction being decorated, + /// and should correspond to the parent of `decoration` in the Slang IR. + /// void emitDecoration(SpvWord dstID, IRDecoration* decoration) { // Unlike in the Slang IR, decorations in SPIR-V are not children @@ -3802,10 +3879,9 @@ struct SPIRVEmitContext // be emitted if the owning instruction gets emitted. bool isRayTracingObject = false; - switch( decoration->getOp() ) + switch (decoration->getOp()) { - default: - break; + default: break; // [3.32.2. Debug Instructions] // @@ -3838,7 +3914,8 @@ struct SPIRVEmitContext List<SpvInst*> params; HashSet<SpvInst*> paramsSet; List<IRInst*> referencedBuiltinIRVars; - // `interface` part: reference all global variables that are used by this entrypoint. + // `interface` part: reference all global variables that are used by this + // entrypoint. for (auto globalInst : m_irModule->getModuleInst()->getChildren()) { switch (globalInst->getOp()) @@ -3846,79 +3923,76 @@ struct SPIRVEmitContext case kIROp_GlobalVar: case kIROp_GlobalParam: case kIROp_SPIRVAsmOperandBuiltinVar: - { - SpvInst* spvGlobalInst; - if (m_mapIRInstToSpvInst.tryGetValue(globalInst, spvGlobalInst)) { - // Is this globalInst referenced by this entry point? - auto refSet = m_referencingEntryPoints.tryGetValue(globalInst); - if (refSet && refSet->contains(entryPoint)) + SpvInst* spvGlobalInst; + if (m_mapIRInstToSpvInst.tryGetValue(globalInst, spvGlobalInst)) { - if (!isSpirv14OrLater()) + // Is this globalInst referenced by this entry point? + auto refSet = m_referencingEntryPoints.tryGetValue(globalInst); + if (refSet && refSet->contains(entryPoint)) { - // Prior to SPIRV 1.4, we can only reference In and Out variables - // in the interface part. - if (auto ptrType = as<IRPtrTypeBase>(globalInst->getDataType())) + if (!isSpirv14OrLater()) { - auto addrSpace = ptrType->getAddressSpace(); - if (addrSpace != AddressSpace::Input && addrSpace != AddressSpace::Output) - continue; + // Prior to SPIRV 1.4, we can only reference In and Out + // variables in the interface part. + if (auto ptrType = + as<IRPtrTypeBase>(globalInst->getDataType())) + { + auto addrSpace = ptrType->getAddressSpace(); + if (addrSpace != AddressSpace::Input && + addrSpace != AddressSpace::Output) + continue; + } } - } - paramsSet.add(spvGlobalInst); - referencedBuiltinIRVars.add(globalInst); + paramsSet.add(spvGlobalInst); + referencedBuiltinIRVars.add(globalInst); - // Don't add a global param to the interface if it is a specialization constant. - switch (spvGlobalInst->opcode) - { - case SpvOpSpecConstant: - case SpvOpSpecConstantFalse: - case SpvOpSpecConstantTrue: - case SpvOpSpecConstantComposite: - break; - default: - params.add(spvGlobalInst); - break; + // Don't add a global param to the interface if it is a + // specialization constant. + switch (spvGlobalInst->opcode) + { + case SpvOpSpecConstant: + case SpvOpSpecConstantFalse: + case SpvOpSpecConstantTrue: + case SpvOpSpecConstantComposite: break; + default: params.add(spvGlobalInst); break; + } } } + break; } - break; - } - default: - break; + default: break; } } - emitOpEntryPoint( - section, - decoration, - spvStage, - dstID, - name, - params - ); + emitOpEntryPoint(section, decoration, spvStage, dstID, name, params); // Stage specific execution mode and capability declarations. switch (entryPointDecor->getProfile().getStage()) { case Stage::Fragment: - //OpExecutionMode %main OriginUpperLeft - requireSPIRVExecutionMode(nullptr, getIRInstSpvID(entryPoint), SpvExecutionModeOriginUpperLeft); - maybeEmitEntryPointDepthReplacingExecutionMode(entryPoint, referencedBuiltinIRVars); + // OpExecutionMode %main OriginUpperLeft + requireSPIRVExecutionMode( + nullptr, + getIRInstSpvID(entryPoint), + SpvExecutionModeOriginUpperLeft); + maybeEmitEntryPointDepthReplacingExecutionMode( + entryPoint, + referencedBuiltinIRVars); for (auto decor : entryPoint->getDecorations()) { switch (decor->getOp()) { case kIROp_EarlyDepthStencilDecoration: - requireSPIRVExecutionMode(nullptr, getIRInstSpvID(entryPoint), SpvExecutionModeEarlyFragmentTests); - break; - default: + requireSPIRVExecutionMode( + nullptr, + getIRInstSpvID(entryPoint), + SpvExecutionModeEarlyFragmentTests); break; + default: break; } } break; - case Stage::Geometry: - requireSPIRVCapability(SpvCapabilityGeometry); - break; + case Stage::Geometry: requireSPIRVCapability(SpvCapabilityGeometry); break; case Stage::Miss: case Stage::AnyHit: case Stage::ClosestHit: @@ -3934,30 +4008,31 @@ struct SPIRVEmitContext ensureExtensionDeclaration(UnownedStringSlice("SPV_EXT_mesh_shader")); break; case Stage::Hull: - { - requireSPIRVCapability(SpvCapabilityTessellation); - - SpvExecutionMode mode = SpvExecutionModeSpacingEqual; - if (auto partitioningDecor = entryPoint->findDecoration<IRPartitioningDecoration>()) { - auto arg = partitioningDecor->getPartitioning()->getStringSlice(); - if (arg.caseInsensitiveEquals(toSlice("integer"))) - mode = SpvExecutionModeSpacingEqual; - else if (arg.caseInsensitiveEquals(toSlice("fractional_even"))) - mode = SpvExecutionModeSpacingFractionalEven; - else if (arg.caseInsensitiveEquals(toSlice("fractional_odd"))) - mode = SpvExecutionModeSpacingFractionalOdd; - else - m_sink->diagnose(partitioningDecor, Diagnostics::unknownTessPartitioning, arg); + requireSPIRVCapability(SpvCapabilityTessellation); + + SpvExecutionMode mode = SpvExecutionModeSpacingEqual; + if (auto partitioningDecor = + entryPoint->findDecoration<IRPartitioningDecoration>()) + { + auto arg = partitioningDecor->getPartitioning()->getStringSlice(); + if (arg.caseInsensitiveEquals(toSlice("integer"))) + mode = SpvExecutionModeSpacingEqual; + else if (arg.caseInsensitiveEquals(toSlice("fractional_even"))) + mode = SpvExecutionModeSpacingFractionalEven; + else if (arg.caseInsensitiveEquals(toSlice("fractional_odd"))) + mode = SpvExecutionModeSpacingFractionalOdd; + else + m_sink->diagnose( + partitioningDecor, + Diagnostics::unknownTessPartitioning, + arg); + } + requireSPIRVExecutionMode(nullptr, getIRInstSpvID(entryPoint), mode); + break; } - requireSPIRVExecutionMode(nullptr, getIRInstSpvID(entryPoint), mode); - break; - } - case Stage::Domain: - requireSPIRVCapability(SpvCapabilityTessellation); - break; - default: - break; + case Stage::Domain: requireSPIRVCapability(SpvCapabilityTessellation); break; + default: break; } } break; @@ -3982,20 +4057,23 @@ struct SPIRVEmitContext SpvExecutionModeLocalSize, SpvLiteralInteger::from32(int32_t(numThreads->getX()->getValue())), SpvLiteralInteger::from32(int32_t(numThreads->getY()->getValue())), - SpvLiteralInteger::from32(int32_t(numThreads->getZ()->getValue())) - ); + SpvLiteralInteger::from32(int32_t(numThreads->getZ()->getValue()))); } break; case kIROp_MaxVertexCountDecoration: // Don't do anything here, instead wait until we see OutputTopologyDecoration - // and emit them together to ensure MaxVertexCount always appears before OutputTopology, - // which seemed to be required by SPIRV. + // and emit them together to ensure MaxVertexCount always appears before + // OutputTopology, which seemed to be required by SPIRV. break; case kIROp_InstanceDecoration: { auto decor = as<IRInstanceDecoration>(decoration); auto count = int32_t(getIntVal(decor->getCount())); - requireSPIRVExecutionMode(decoration, dstID, SpvExecutionModeInvocations, SpvLiteralInteger::from32(count)); + requireSPIRVExecutionMode( + decoration, + dstID, + SpvExecutionModeInvocations, + SpvLiteralInteger::from32(count)); } break; case kIROp_TriangleInputPrimitiveTypeDecoration: @@ -4003,8 +4081,8 @@ struct SPIRVEmitContext case kIROp_LineAdjInputPrimitiveTypeDecoration: case kIROp_PointInputPrimitiveTypeDecoration: case kIROp_TriangleAdjInputPrimitiveTypeDecoration: - // Defer this until we see kIROp_StreamOutputTypeDecoration because the driver wants to see - // them before the output. + // Defer this until we see kIROp_StreamOutputTypeDecoration because the driver wants + // to see them before the output. break; case kIROp_StreamOutputTypeDecoration: { @@ -4019,26 +4097,32 @@ struct SPIRVEmitContext requireSPIRVExecutionMode(inputDecor, dstID, SpvExecutionModeInputLines); break; case kIROp_LineAdjInputPrimitiveTypeDecoration: - requireSPIRVExecutionMode(inputDecor, dstID, SpvExecutionModeInputLinesAdjacency); + requireSPIRVExecutionMode( + inputDecor, + dstID, + SpvExecutionModeInputLinesAdjacency); break; case kIROp_PointInputPrimitiveTypeDecoration: requireSPIRVExecutionMode(inputDecor, dstID, SpvExecutionModeInputPoints); break; case kIROp_TriangleAdjInputPrimitiveTypeDecoration: - requireSPIRVExecutionMode(inputDecor, dstID, SpvExecutionModeInputTrianglesAdjacency); + requireSPIRVExecutionMode( + inputDecor, + dstID, + SpvExecutionModeInputTrianglesAdjacency); break; } } - // SPIRV requires MaxVertexCount decoration to appear before OutputTopologyDecoration, - // so we emit them here. - if (auto maxVertexCount = decoration->getParent()->findDecoration<IRMaxVertexCountDecoration>()) + // SPIRV requires MaxVertexCount decoration to appear before + // OutputTopologyDecoration, so we emit them here. + if (auto maxVertexCount = + decoration->getParent()->findDecoration<IRMaxVertexCountDecoration>()) { requireSPIRVExecutionMode( maxVertexCount, dstID, SpvExecutionModeOutputVertices, - SpvLiteralInteger::from32(int32_t(getIntVal(maxVertexCount->getCount()))) - ); + SpvLiteralInteger::from32(int32_t(getIntVal(maxVertexCount->getCount())))); } auto decor = as<IRStreamOutputTypeDecoration>(decoration); @@ -4053,7 +4137,10 @@ struct SPIRVEmitContext requireSPIRVExecutionMode(decoration, dstID, SpvExecutionModeOutputLineStrip); break; case kIROp_HLSLTriangleStreamType: - requireSPIRVExecutionMode(decoration, dstID, SpvExecutionModeOutputTriangleStrip); + requireSPIRVExecutionMode( + decoration, + dstID, + SpvExecutionModeOutputTriangleStrip); break; default: SLANG_ASSERT(!"Unknown stream out type"); } @@ -4065,8 +4152,7 @@ struct SPIRVEmitContext getSection(SpvLogicalSectionID::Annotations), decoration, dstID, - SpvDecorationBufferBlock - ); + SpvDecorationBufferBlock); } break; case kIROp_SPIRVBlockDecoration: @@ -4075,8 +4161,7 @@ struct SPIRVEmitContext getSection(SpvLogicalSectionID::Annotations), decoration, dstID, - SpvDecorationBlock - ); + SpvDecorationBlock); } break; @@ -4089,15 +4174,15 @@ struct SPIRVEmitContext getSection(SpvLogicalSectionID::Annotations), decoration, dstID, - SpvDecorationNonUniform - ); + SpvDecorationNonUniform); } break; case kIROp_OutputTopologyDecoration: { auto entryPoint = decoration->getParent(); - IREntryPointDecoration* entryPointDecor = entryPoint ? entryPoint->findDecoration<IREntryPointDecoration>() : nullptr; + IREntryPointDecoration* entryPointDecor = + entryPoint ? entryPoint->findDecoration<IREntryPointDecoration>() : nullptr; const auto o = cast<IROutputTopologyDecoration>(decoration); const auto t = o->getTopology()->getStringSlice(); @@ -4125,7 +4210,7 @@ struct SPIRVEmitContext else if (t == "point") m = SpvExecutionModeOutputPoints; } - + SLANG_ASSERT(m != SpvExecutionModeMax); requireSPIRVExecutionMode(decoration, dstID, m); } @@ -4138,8 +4223,7 @@ struct SPIRVEmitContext decoration, dstID, SpvExecutionModeOutputVertices, - SpvLiteralInteger::from32(int32_t(c->getMaxSize()->getValue())) - ); + SpvLiteralInteger::from32(int32_t(c->getMaxSize()->getValue()))); } break; @@ -4150,8 +4234,7 @@ struct SPIRVEmitContext decoration, dstID, SpvExecutionModeOutputPrimitivesEXT, - SpvLiteralInteger::from32(int32_t(c->getMaxSize()->getValue())) - ); + SpvLiteralInteger::from32(int32_t(c->getMaxSize()->getValue()))); } break; @@ -4163,14 +4246,14 @@ struct SPIRVEmitContext isRayTracingObject = true; break; case kIROp_VulkanHitObjectAttributesDecoration: - // needed since GLSL will not set optypes accordingly, but will keep the decoration + // needed since GLSL will not set optypes accordingly, but will keep the decoration ensureExtensionDeclaration(UnownedStringSlice("SPV_NV_shader_invocation_reorder")); requireSPIRVCapability(SpvCapabilityShaderInvocationReorderNV); isRayTracingObject = true; break; case kIROp_VulkanRayPayloadDecoration: case kIROp_VulkanRayPayloadInDecoration: - // needed since GLSL will not set optypes accordingly, but will keep the decoration + // needed since GLSL will not set optypes accordingly, but will keep the decoration ensureExtensionDeclaration(UnownedStringSlice("SPV_KHR_ray_tracing")); requireSPIRVCapability(SpvCapabilityRayTracingKHR); isRayTracingObject = true; @@ -4215,65 +4298,76 @@ struct SPIRVEmitContext } break; case kIROp_MemoryQualifierSetDecoration: - { - auto collection = as<IRMemoryQualifierSetDecoration>(decoration); - IRIntegerValue flags = collection->getMemoryQualifierBit(); - if (flags & MemoryQualifierSetModifier::Flags::kCoherent) - { - emitOpDecorate(getSection(SpvLogicalSectionID::Annotations), - nullptr, - dstID, - SpvDecorationCoherent); - } - if (flags & MemoryQualifierSetModifier::Flags::kVolatile) - { - emitOpDecorate(getSection(SpvLogicalSectionID::Annotations), - nullptr, - dstID, - SpvDecorationVolatile); - } - if (flags & MemoryQualifierSetModifier::Flags::kRestrict) { - emitOpDecorate(getSection(SpvLogicalSectionID::Annotations), - nullptr, - dstID, - SpvDecorationRestrict); - } - if (flags & MemoryQualifierSetModifier::Flags::kReadOnly) - { - emitOpDecorate(getSection(SpvLogicalSectionID::Annotations), - nullptr, - dstID, - SpvDecorationNonWritable); + auto collection = as<IRMemoryQualifierSetDecoration>(decoration); + IRIntegerValue flags = collection->getMemoryQualifierBit(); + if (flags & MemoryQualifierSetModifier::Flags::kCoherent) + { + emitOpDecorate( + getSection(SpvLogicalSectionID::Annotations), + nullptr, + dstID, + SpvDecorationCoherent); + } + if (flags & MemoryQualifierSetModifier::Flags::kVolatile) + { + emitOpDecorate( + getSection(SpvLogicalSectionID::Annotations), + nullptr, + dstID, + SpvDecorationVolatile); + } + if (flags & MemoryQualifierSetModifier::Flags::kRestrict) + { + emitOpDecorate( + getSection(SpvLogicalSectionID::Annotations), + nullptr, + dstID, + SpvDecorationRestrict); + } + if (flags & MemoryQualifierSetModifier::Flags::kReadOnly) + { + emitOpDecorate( + getSection(SpvLogicalSectionID::Annotations), + nullptr, + dstID, + SpvDecorationNonWritable); + } + if (flags & MemoryQualifierSetModifier::Flags::kWriteOnly) + { + emitOpDecorate( + getSection(SpvLogicalSectionID::Annotations), + nullptr, + dstID, + SpvDecorationNonReadable); + } + break; } - if (flags & MemoryQualifierSetModifier::Flags::kWriteOnly) + case kIROp_DownstreamModuleExportDecoration: { - emitOpDecorate(getSection(SpvLogicalSectionID::Annotations), - nullptr, + requireSPIRVCapability(SpvCapabilityLinkage); + auto name = + decoration->getParent()->findDecoration<IRExportDecoration>()->getMangledName(); + emitInst( + getSection(SpvLogicalSectionID::Annotations), + decoration, + SpvOpDecorate, dstID, - SpvDecorationNonReadable); + SpvDecorationLinkageAttributes, + name, + SpvLinkageTypeExport); + break; } - break; - } - case kIROp_DownstreamModuleExportDecoration: - { - requireSPIRVCapability(SpvCapabilityLinkage); - auto name = decoration->getParent()->findDecoration<IRExportDecoration>()->getMangledName(); - emitInst(getSection(SpvLogicalSectionID::Annotations), - decoration, - SpvOpDecorate, - dstID, - SpvDecorationLinkageAttributes, name, SpvLinkageTypeExport); - break; - } - // ... + // ... } - if(isRayTracingObject) + if (isRayTracingObject) { - if (decoration->getOperandCount() > 0) { - //if not greater than 0, this is not a layout decoration (no val) - emitOpDecorateLocation(getSection(SpvLogicalSectionID::Annotations), + if (decoration->getOperandCount() > 0) + { + // if not greater than 0, this is not a layout decoration (no val) + emitOpDecorateLocation( + getSection(SpvLogicalSectionID::Annotations), decoration, dstID, SpvLiteralInteger::from32(int32_t(getIntVal(decoration->getOperand(0))))); @@ -4284,35 +4378,42 @@ struct SPIRVEmitContext { switch (decoration->getOp()) { - default: - break; + default: break; case kIROp_SemanticDecoration: { - ensureExtensionDeclarationBeforeSpv14(toSlice("SPV_GOOGLE_hlsl_functionality1")); - emitOpDecorateString(getSection(SpvLogicalSectionID::Annotations), - decoration, - dstID, - SpvDecorationUserSemantic, - cast<IRSemanticDecoration>(decoration)->getSemanticName()); + ensureExtensionDeclarationBeforeSpv14( + toSlice("SPV_GOOGLE_hlsl_functionality1")); + emitOpDecorateString( + getSection(SpvLogicalSectionID::Annotations), + decoration, + dstID, + SpvDecorationUserSemantic, + cast<IRSemanticDecoration>(decoration)->getSemanticName()); } break; case kIROp_UserTypeNameDecoration: { ensureExtensionDeclaration(toSlice("SPV_GOOGLE_user_type")); - ensureExtensionDeclarationBeforeSpv14(toSlice("SPV_GOOGLE_hlsl_functionality1")); - emitOpDecorateString(getSection(SpvLogicalSectionID::Annotations), + ensureExtensionDeclarationBeforeSpv14( + toSlice("SPV_GOOGLE_hlsl_functionality1")); + emitOpDecorateString( + getSection(SpvLogicalSectionID::Annotations), decoration, dstID, SpvDecorationUserTypeGOOGLE, - legalizeUserTypeName(cast<IRUserTypeNameDecoration>(decoration)->getUserTypeName()->getStringSlice()).getUnownedSlice()); + legalizeUserTypeName(cast<IRUserTypeNameDecoration>(decoration) + ->getUserTypeName() + ->getStringSlice()) + .getUnownedSlice()); } break; case kIROp_CounterBufferDecoration: { - emitOpDecorateCounterBuffer(getSection(SpvLogicalSectionID::Annotations), - decoration, - dstID, - as<IRCounterBufferDecoration>(decoration)->getCounterBuffer()); + emitOpDecorateCounterBuffer( + getSection(SpvLogicalSectionID::Annotations), + decoration, + dstID, + as<IRCounterBufferDecoration>(decoration)->getCounterBuffer()); } break; } @@ -4322,24 +4423,24 @@ struct SPIRVEmitContext void emitLayoutDecorations(IRStructType* structType, SpvWord spvStructID) { /***** - * SPIRV Spec: - * Each structure-type member must have an Offset decoration. - * - * Each array type must have an ArrayStride decoration, unless it is an - * array that contains a structure decorated with Block or BufferBlock, in - * which case it must not have an ArrayStride decoration. - * - * Each structure-type member that is a matrix or array-of-matrices must be - * decorated with a MatrixStride Decoration, and one of the RowMajor or - * ColMajor decorations. - * - * The ArrayStride, MatrixStride, and Offset decorations must be large - * enough to hold the size of the objects they affect (that is, specifying - * overlap is invalid). Each ArrayStride and MatrixStride must be greater - * than zero, and it is invalid for two members of a given structure to be - * assigned the same Offset. - * - *****/ + * SPIRV Spec: + * Each structure-type member must have an Offset decoration. + * + * Each array type must have an ArrayStride decoration, unless it is an + * array that contains a structure decorated with Block or BufferBlock, in + * which case it must not have an ArrayStride decoration. + * + * Each structure-type member that is a matrix or array-of-matrices must be + * decorated with a MatrixStride Decoration, and one of the RowMajor or + * ColMajor decorations. + * + * The ArrayStride, MatrixStride, and Offset decorations must be large + * enough to hold the size of the objects they affect (that is, specifying + * overlap is invalid). Each ArrayStride and MatrixStride must be greater + * than zero, and it is invalid for two members of a given structure to be + * assigned the same Offset. + * + *****/ auto layout = structType->findDecoration<IRSizeAndAlignmentDecoration>(); IRTypeLayoutRuleName layoutRuleName = IRTypeLayoutRuleName::Natural; if (layout) @@ -4370,8 +4471,7 @@ struct SPIRVEmitContext nullptr, spvStructID, SpvLiteralInteger::from32(id), - SpvDecorationCoherent - ); + SpvDecorationCoherent); } if (flags & MemoryQualifierSetModifier::Flags::kVolatile) { @@ -4380,8 +4480,7 @@ struct SPIRVEmitContext nullptr, spvStructID, SpvLiteralInteger::from32(id), - SpvDecorationVolatile - ); + SpvDecorationVolatile); } if (flags & MemoryQualifierSetModifier::Flags::kRestrict) { @@ -4390,8 +4489,7 @@ struct SPIRVEmitContext nullptr, spvStructID, SpvLiteralInteger::from32(id), - SpvDecorationRestrict - ); + SpvDecorationRestrict); } if (flags & MemoryQualifierSetModifier::Flags::kReadOnly) { @@ -4400,8 +4498,7 @@ struct SPIRVEmitContext nullptr, spvStructID, SpvLiteralInteger::from32(id), - SpvDecorationNonWritable - ); + SpvDecorationNonWritable); } if (flags & MemoryQualifierSetModifier::Flags::kWriteOnly) { @@ -4410,15 +4507,16 @@ struct SPIRVEmitContext nullptr, spvStructID, SpvLiteralInteger::from32(id), - SpvDecorationNonReadable - ); + SpvDecorationNonReadable); } } - else if (auto semanticDecor = field->getKey()->findDecoration<IRSemanticDecoration>()) + else if ( + auto semanticDecor = field->getKey()->findDecoration<IRSemanticDecoration>()) { if (shouldEmitSPIRVReflectionInfo()) { - ensureExtensionDeclarationBeforeSpv14(toSlice("SPV_GOOGLE_hlsl_functionality1")); + ensureExtensionDeclarationBeforeSpv14( + toSlice("SPV_GOOGLE_hlsl_functionality1")); emitOpMemberDecorateString( getSection(SpvLogicalSectionID::Annotations), nullptr, @@ -4433,11 +4531,17 @@ struct SPIRVEmitContext IRIntegerValue offset = 0; if (auto offsetDecor = field->getKey()->findDecoration<IRPackOffsetDecoration>()) { - offset = (getIntVal(offsetDecor->getRegisterOffset()) * 4 + getIntVal(offsetDecor->getComponentOffset())) * 4; + offset = (getIntVal(offsetDecor->getRegisterOffset()) * 4 + + getIntVal(offsetDecor->getComponentOffset())) * + 4; } else { - getOffset(m_targetProgram->getOptionSet(), IRTypeLayoutRules::get(layoutRuleName), field, &offset); + getOffset( + m_targetProgram->getOptionSet(), + IRTypeLayoutRules::get(layoutRuleName), + field, + &offset); } emitOpMemberDecorateOffset( getSection(SpvLogicalSectionID::Annotations), @@ -4462,7 +4566,11 @@ struct SPIRVEmitContext IRIntegerValue matrixStride = 0; auto rule = IRTypeLayoutRules::get(layoutRuleName); IRSizeAndAlignment elementSizeAlignment; - getSizeAndAlignment(m_targetProgram->getOptionSet(), rule, matrixType->getElementType(), &elementSizeAlignment); + getSizeAndAlignment( + m_targetProgram->getOptionSet(), + rule, + matrixType->getElementType(), + &elementSizeAlignment); IRIntegerValue matrixMinorVectorCount = 0; // Reminder: the meaning of row/column major layout // in our semantics is the *opposite* of what GLSL/SPIRV @@ -4493,7 +4601,8 @@ struct SPIRVEmitContext // We need the size of our vector. To get the stride we need to know how 'big' // each vector element is inside an array, due to this we align our vector // as if a composite. - auto vectorSize = rule->getVectorSizeAndAlignment(elementSizeAlignment, matrixMinorVectorCount); + auto vectorSize = + rule->getVectorSizeAndAlignment(elementSizeAlignment, matrixMinorVectorCount); vectorSize = rule->alignCompositeElement(vectorSize); matrixStride = vectorSize.getStride(); emitOpMemberDecorateMatrixStride( @@ -4507,33 +4616,31 @@ struct SPIRVEmitContext } } - /// Map a Slang `Stage` to a corresponding SPIR-V execution model + /// Map a Slang `Stage` to a corresponding SPIR-V execution model SpvExecutionModel mapStageToExecutionModel(Stage stage) { - switch( stage ) + switch (stage) { - default: - SLANG_UNEXPECTED("unhandled stage"); - UNREACHABLE_RETURN((SpvExecutionModel)0); + default: SLANG_UNEXPECTED("unhandled stage"); UNREACHABLE_RETURN((SpvExecutionModel)0); #define CASE(STAGE, MODEL) \ - case Stage::STAGE: return SpvExecutionModel##MODEL - - CASE(Vertex, Vertex); - CASE(Hull, TessellationControl); - CASE(Domain, TessellationEvaluation); - CASE(Geometry, Geometry); - CASE(Fragment, Fragment); - CASE(Compute, GLCompute); - CASE(Mesh, MeshEXT); - CASE(Amplification, TaskEXT); - CASE(ClosestHit, ClosestHitKHR); - CASE(AnyHit, AnyHitKHR); - CASE(Callable, CallableKHR); - CASE(Miss, MissKHR); - CASE(Intersection, IntersectionKHR); - CASE(RayGeneration, RayGenerationKHR); - // TODO: Extended execution models for ray tracing, etc. + case Stage::STAGE: return SpvExecutionModel##MODEL + + CASE(Vertex, Vertex); + CASE(Hull, TessellationControl); + CASE(Domain, TessellationEvaluation); + CASE(Geometry, Geometry); + CASE(Fragment, Fragment); + CASE(Compute, GLCompute); + CASE(Mesh, MeshEXT); + CASE(Amplification, TaskEXT); + CASE(ClosestHit, ClosestHitKHR); + CASE(AnyHit, AnyHitKHR); + CASE(Callable, CallableKHR); + CASE(Miss, MissKHR); + CASE(Intersection, IntersectionKHR); + CASE(RayGeneration, RayGenerationKHR); + // TODO: Extended execution models for ray tracing, etc. #undef CASE } @@ -4580,8 +4687,7 @@ struct SPIRVEmitContext { if (!irInst) return; - if (irInst->getOp() != kIROp_GlobalVar && - irInst->getOp() != kIROp_GlobalParam) + if (irInst->getOp() != kIROp_GlobalVar && irInst->getOp() != kIROp_GlobalParam) return; auto ptrType = as<IRPtrType>(irInst->getDataType()); if (!ptrType) @@ -4592,7 +4698,9 @@ struct SPIRVEmitContext if (isIntegralScalarOrCompositeType(ptrType->getValueType())) { if (isInstUsedInStage(irInst, Stage::Fragment)) - _maybeEmitInterpolationModifierDecoration(IRInterpolationMode::NoInterpolation, getID(spvInst)); + _maybeEmitInterpolationModifierDecoration( + IRInterpolationMode::NoInterpolation, + getID(spvInst)); } } } @@ -4614,14 +4722,12 @@ struct SPIRVEmitContext getSection(SpvLogicalSectionID::GlobalVariables), nullptr, type, - addressSpaceToStorageClass(ptrType->getAddressSpace()) - ); + addressSpaceToStorageClass(ptrType->getAddressSpace())); emitOpDecorateBuiltIn( getSection(SpvLogicalSectionID::Annotations), nullptr, varInst, - builtinVal - ); + builtinVal); switch (builtinVal) { case SpvBuiltInTessLevelInner: @@ -4630,8 +4736,7 @@ struct SPIRVEmitContext getSection(SpvLogicalSectionID::Annotations), nullptr, varInst, - SpvDecorationPatch - ); + SpvDecorationPatch); break; } m_builtinGlobalVars[key] = varInst; @@ -4683,8 +4788,12 @@ struct SPIRVEmitContext else if (semanticName == "sv_innercoverage") { requireSPIRVCapability(SpvCapabilityFragmentFullyCoveredEXT); - ensureExtensionDeclaration(UnownedStringSlice("SPV_EXT_fragment_fully_covered")); - return getBuiltinGlobalVar(inst->getFullType(), SpvBuiltInFullyCoveredEXT, inst); + ensureExtensionDeclaration( + UnownedStringSlice("SPV_EXT_fragment_fully_covered")); + return getBuiltinGlobalVar( + inst->getFullType(), + SpvBuiltInFullyCoveredEXT, + inst); } else if (semanticName == "sv_depth") { @@ -4700,7 +4809,10 @@ struct SPIRVEmitContext } else if (semanticName == "sv_dispatchthreadid") { - return getBuiltinGlobalVar(inst->getFullType(), SpvBuiltInGlobalInvocationId, inst); + return getBuiltinGlobalVar( + inst->getFullType(), + SpvBuiltInGlobalInvocationId, + inst); } else if (semanticName == "sv_domainlocation") { @@ -4712,11 +4824,17 @@ struct SPIRVEmitContext } else if (semanticName == "sv_groupindex") { - return getBuiltinGlobalVar(inst->getFullType(), SpvBuiltInLocalInvocationIndex, inst); + return getBuiltinGlobalVar( + inst->getFullType(), + SpvBuiltInLocalInvocationIndex, + inst); } else if (semanticName == "sv_groupthreadid") { - return getBuiltinGlobalVar(inst->getFullType(), SpvBuiltInLocalInvocationId, inst); + return getBuiltinGlobalVar( + inst->getFullType(), + SpvBuiltInLocalInvocationId, + inst); } else if (semanticName == "sv_gsinstanceid") { @@ -4752,7 +4870,8 @@ struct SPIRVEmitContext { for (auto entryPoint : *entryPoints) { - if (auto entryPointDecor = entryPoint->findDecoration<IREntryPointDecoration>()) + if (auto entryPointDecor = + entryPoint->findDecoration<IREntryPointDecoration>()) { switch (entryPointDecor->getProfile().getStage()) { @@ -4763,9 +4882,7 @@ struct SPIRVEmitContext case Stage::AnyHit: case Stage::ClosestHit: case Stage::Hull: - case Stage::Domain: - needGeometryCapability = false; - break; + case Stage::Domain: needGeometryCapability = false; break; } } } @@ -4791,7 +4908,10 @@ struct SPIRVEmitContext { requireSPIRVCapability(SpvCapabilityStencilExportEXT); ensureExtensionDeclaration(UnownedStringSlice("SPV_EXT_shader_stencil_export")); - return getBuiltinGlobalVar(inst->getFullType(), SpvBuiltInFragStencilRefEXT, inst); + return getBuiltinGlobalVar( + inst->getFullType(), + SpvBuiltInFragStencilRefEXT, + inst); } else if (semanticName == "sv_tessfactor") { @@ -4825,12 +4945,16 @@ struct SPIRVEmitContext { requireSPIRVCapability(SpvCapabilityPerViewAttributesNV); ensureExtensionDeclaration(UnownedStringSlice("SPV_NV_mesh_shader")); - return getBuiltinGlobalVar(inst->getFullType(), SpvBuiltInViewportMaskPerViewNV, inst); + return getBuiltinGlobalVar( + inst->getFullType(), + SpvBuiltInViewportMaskPerViewNV, + inst); } else if (semanticName == "sv_barycentrics") { requireSPIRVCapability(SpvCapabilityFragmentBarycentricKHR); - ensureExtensionDeclaration(UnownedStringSlice("SPV_KHR_fragment_shader_barycentric")); + ensureExtensionDeclaration( + UnownedStringSlice("SPV_KHR_fragment_shader_barycentric")); return getBuiltinGlobalVar(inst->getFullType(), SpvBuiltInBaryCoordKHR, inst); // TODO: There is also the `gl_BaryCoordNoPerspNV` builtin, which @@ -4841,17 +4965,27 @@ struct SPIRVEmitContext { requireSPIRVCapability(SpvCapabilityMeshShadingEXT); ensureExtensionDeclaration(UnownedStringSlice("SPV_EXT_mesh_shader")); - return getBuiltinGlobalVar(inst->getFullType(), SpvBuiltInCullPrimitiveEXT, inst); + return getBuiltinGlobalVar( + inst->getFullType(), + SpvBuiltInCullPrimitiveEXT, + inst); } else if (semanticName == "sv_shadingrate") { requireSPIRVCapability(SpvCapabilityFragmentShadingRateKHR); ensureExtensionDeclaration(UnownedStringSlice("SPV_KHR_fragment_shading_rate")); auto importDecor = inst->findDecoration<IRImportDecoration>(); - if (importDecor && importDecor->getMangledName() == "gl_PrimitiveShadingRateEXT") - return getBuiltinGlobalVar(inst->getFullType(), SpvBuiltInPrimitiveShadingRateKHR, inst); + if (importDecor && + importDecor->getMangledName() == "gl_PrimitiveShadingRateEXT") + return getBuiltinGlobalVar( + inst->getFullType(), + SpvBuiltInPrimitiveShadingRateKHR, + inst); else - return getBuiltinGlobalVar(inst->getFullType(), SpvBuiltInShadingRateKHR, inst); + return getBuiltinGlobalVar( + inst->getFullType(), + SpvBuiltInShadingRateKHR, + inst); } SLANG_UNREACHABLE("Unimplemented system value in spirv emit."); } @@ -4862,15 +4996,24 @@ struct SPIRVEmitContext // GLSL, SPIR-V makes no such distinction so we can use similar logic // to above. // - if(const auto linkageDecoration = inst->findDecoration<IRLinkageDecoration>()) + if (const auto linkageDecoration = inst->findDecoration<IRLinkageDecoration>()) { const auto name = linkageDecoration->getMangledName(); - if(name == "gl_PrimitiveTriangleIndicesEXT") - return getBuiltinGlobalVar(inst->getFullType(), SpvBuiltInPrimitiveTriangleIndicesEXT, inst); - if(name == "gl_PrimitiveLineIndicesEXT") - return getBuiltinGlobalVar(inst->getFullType(), SpvBuiltInPrimitiveLineIndicesEXT, inst); - if(name == "gl_PrimitivePointIndicesEXT") - return getBuiltinGlobalVar(inst->getFullType(), SpvBuiltInPrimitivePointIndicesEXT, inst); + if (name == "gl_PrimitiveTriangleIndicesEXT") + return getBuiltinGlobalVar( + inst->getFullType(), + SpvBuiltInPrimitiveTriangleIndicesEXT, + inst); + if (name == "gl_PrimitiveLineIndicesEXT") + return getBuiltinGlobalVar( + inst->getFullType(), + SpvBuiltInPrimitiveLineIndicesEXT, + inst); + if (name == "gl_PrimitivePointIndicesEXT") + return getBuiltinGlobalVar( + inst->getFullType(), + SpvBuiltInPrimitivePointIndicesEXT, + inst); } return nullptr; @@ -4881,7 +5024,8 @@ struct SPIRVEmitContext auto ptrType = as<IRPtrType>(unwrapArray(inst->getDataType())); if (!ptrType) return; - if (addressSpaceToStorageClass(ptrType->getAddressSpace()) == SpvStorageClassPhysicalStorageBuffer) + if (addressSpaceToStorageClass(ptrType->getAddressSpace()) == + SpvStorageClassPhysicalStorageBuffer) { // If inst has a pointer type with PhysicalStorageBuffer address space, // emit AliasedPointer decoration. @@ -4889,8 +5033,7 @@ struct SPIRVEmitContext getSection(SpvLogicalSectionID::Annotations), nullptr, varInst, - (as<IRVar>(inst) ? SpvDecorationAliasedPointer : SpvDecorationAliased) - ); + (as<IRVar>(inst) ? SpvDecorationAliasedPointer : SpvDecorationAliased)); } else { @@ -4899,15 +5042,17 @@ struct SPIRVEmitContext ptrType = as<IRPtrType>(unwrapArray(ptrType->getValueType())); if (!ptrType) return; - if (addressSpaceToStorageClass(ptrType->getAddressSpace()) == SpvStorageClassPhysicalStorageBuffer) + if (addressSpaceToStorageClass(ptrType->getAddressSpace()) == + SpvStorageClassPhysicalStorageBuffer) { emitOpDecorate( getSection(SpvLogicalSectionID::Annotations), nullptr, varInst, - (inst->getOp() == kIROp_GlobalVar || inst->getOp() == kIROp_Var || inst->getOp() == kIROp_DebugVar - ? SpvDecorationAliasedPointer : SpvDecorationAliased) - ); + (inst->getOp() == kIROp_GlobalVar || inst->getOp() == kIROp_Var || + inst->getOp() == kIROp_DebugVar + ? SpvDecorationAliasedPointer + : SpvDecorationAliased)); } } } @@ -4932,15 +5077,15 @@ struct SPIRVEmitContext return varSpvInst; } - /// Cached `IRParam` indices in an `IRBlock`. For use in `getParamIndexInBlock`. + /// Cached `IRParam` indices in an `IRBlock`. For use in `getParamIndexInBlock`. struct BlockParamIndexInfo : public RefObject { Dictionary<IRParam*, int> mapParamToIndex; }; Dictionary<IRBlock*, RefPtr<BlockParamIndexInfo>> m_mapIRBlockToParamIndexInfo; - /// Returns the index of an `IRParam` inside a `IRBlock`. - /// The results are cached in `m_mapIRBlockToParamIndexInfo` to avoid linear search. + /// Returns the index of an `IRParam` inside a `IRBlock`. + /// The results are cached in `m_mapIRBlockToParamIndexInfo` to avoid linear search. int getParamIndexInBlock(IRBlock* block, IRParam* paramInst) { RefPtr<BlockParamIndexInfo> info; @@ -4973,10 +5118,8 @@ struct SPIRVEmitContext { case kIROp_Func: case kIROp_GlobalParam: - case kIROp_GlobalVar: - return true; - default: - return false; + case kIROp_GlobalVar: return true; + default: return false; } } @@ -5001,9 +5144,11 @@ struct SPIRVEmitContext loopHeaderBlock, nullptr, getIRInstSpvID(loopInst->getBreakBlock()), - SpvSelectionControlMaskNone - ); - emitInst(loopHeaderBlock, nullptr, SpvOpSwitch, + SpvSelectionControlMaskNone); + emitInst( + loopHeaderBlock, + nullptr, + SpvOpSwitch, emitIntConstant(0, builder.getIntType()), getIRInstSpvID(loopInst->getTargetBlock())); return; @@ -5020,8 +5165,7 @@ struct SPIRVEmitContext case IRLoopControl::kIRLoopControl_Loop: loopControl = SpvLoopControlDontUnrollMask; break; - default: - break; + default: break; } } emitOpLoopMerge( @@ -5029,8 +5173,7 @@ struct SPIRVEmitContext nullptr, getIRInstSpvID(loopInst->getBreakBlock()), getIRInstSpvID(loopInst->getContinueBlock()), - loopControl - ); + loopControl); emitOpBranch(loopHeaderBlock, nullptr, loopInst->getTargetBlock()); } @@ -5058,42 +5201,43 @@ struct SPIRVEmitContext int paramIndex = getParamIndexInBlock(block, inst); // Emit a Phi instruction. - auto phiSpvInst = emitInstCustomOperandFunc(parent, inst, SpvOpPhi, [&]() { - emitOperand(inst->getFullType()); - emitOperand(kResultID); - // Find phi arguments from incoming branch instructions that target `block`. - for (auto use = block->firstUse; use; use = use->nextUse) - { - auto branchInst = as<IRUnconditionalBranch>(use->getUser()); - if (!branchInst) - continue; - if (branchInst->getTargetBlock() != inst->getParent()) - continue; - - UInt argStartIndex = 0; - switch (branchInst->getOp()) + auto phiSpvInst = emitInstCustomOperandFunc( + parent, + inst, + SpvOpPhi, + [&]() + { + emitOperand(inst->getFullType()); + emitOperand(kResultID); + // Find phi arguments from incoming branch instructions that target `block`. + for (auto use = block->firstUse; use; use = use->nextUse) { - case kIROp_unconditionalBranch: - argStartIndex = 1; - break; - case kIROp_loop: - argStartIndex = 3; - break; - default: - // A phi argument can only come from an unconditional branch inst. - // Other uses are not relavent so we should skip. - continue; + auto branchInst = as<IRUnconditionalBranch>(use->getUser()); + if (!branchInst) + continue; + if (branchInst->getTargetBlock() != inst->getParent()) + continue; + + UInt argStartIndex = 0; + switch (branchInst->getOp()) + { + case kIROp_unconditionalBranch: argStartIndex = 1; break; + case kIROp_loop: argStartIndex = 3; break; + default: + // A phi argument can only come from an unconditional branch inst. + // Other uses are not relavent so we should skip. + continue; + } + SLANG_ASSERT(argStartIndex + paramIndex < branchInst->getOperandCount()); + auto valueInst = branchInst->getOperand(argStartIndex + paramIndex); + if (isGlobalValueInst(valueInst)) + ensureInst(valueInst); + emitOperand(getIRInstSpvID(valueInst)); + auto sourceBlock = as<IRBlock>(branchInst->getParent()); + SLANG_ASSERT(sourceBlock); + emitOperand(getIRInstSpvID(sourceBlock)); } - SLANG_ASSERT(argStartIndex + paramIndex < branchInst->getOperandCount()); - auto valueInst = branchInst->getOperand(argStartIndex + paramIndex); - if (isGlobalValueInst(valueInst)) - ensureInst(valueInst); - emitOperand(getIRInstSpvID(valueInst)); - auto sourceBlock = as<IRBlock>(branchInst->getParent()); - SLANG_ASSERT(sourceBlock); - emitOperand(getIRInstSpvID(sourceBlock)); - } - }); + }); maybeEmitName(phiSpvInst, inst); return phiSpvInst; @@ -5109,7 +5253,8 @@ struct SPIRVEmitContext // We want to detect any call to an intrinsic operation, and inline // the SPIRV snippet directly at the call site. if (auto targetIntrinsic = Slang::findBestTargetIntrinsicDecoration( - funcValue, m_targetRequest->getTargetCaps())) + funcValue, + m_targetRequest->getTargetCaps())) { return emitIntrinsicCallExpr(parent, static_cast<IRCall*>(inst), targetIntrinsic); } @@ -5128,8 +5273,7 @@ struct SPIRVEmitContext inst, inst->getFullType(), funcValue, - inst->getArgsList() - ); + inst->getArgsList()); } } @@ -5164,7 +5308,7 @@ struct SPIRVEmitContext { IRBuilder builder(m_irModule); builder.setInsertBefore(inst); - if(snippet->usedPtrResultTypeStorageClasses.getCount()) + if (snippet->usedPtrResultTypeStorageClasses.getCount()) SLANG_UNIMPLEMENTED_X("specifying storage classes in __target_intrinsic modifiers"); } return emitSpvSnippet(parent, inst, context, snippet); @@ -5194,15 +5338,16 @@ struct SPIRVEmitContext result = emitOpConstantComposite( nullptr, builder.getVectorType(floatType, builder.getIntValue(builder.getIntType(), 2)), - makeArray(element1, element2) - ); + makeArray(element1, element2)); } break; case SpvSnippet::ASMType::Int: result = emitIntConstant((IRIntegerValue)constant.intValues[0], builder.getIntType()); break; case SpvSnippet::ASMType::UInt16: - result = emitIntConstant((IRIntegerValue)constant.intValues[0], builder.getType(kIROp_UInt16Type)); + result = emitIntConstant( + (IRIntegerValue)constant.intValues[0], + builder.getType(kIROp_UInt16Type)); break; case SpvSnippet::ASMType::UInt2: { @@ -5212,8 +5357,7 @@ struct SPIRVEmitContext result = emitOpConstantComposite( nullptr, builder.getVectorType(uintType, builder.getIntValue(builder.getIntType(), 2)), - makeArray(element1, element2) - ); + makeArray(element1, element2)); } break; } @@ -5229,31 +5373,22 @@ struct SPIRVEmitContext IRType* irType = nullptr; switch (type) { - case SpvSnippet::ASMType::Float: - irType = builder.getType(kIROp_FloatType); - break; - case SpvSnippet::ASMType::Half: - irType = builder.getType(kIROp_HalfType); - break; - case SpvSnippet::ASMType::Int: - irType = builder.getIntType(); - break; - case SpvSnippet::ASMType::UInt: - irType = builder.getUIntType(); - break; - case SpvSnippet::ASMType::UInt16: - irType = builder.getType(kIROp_UInt16Type); - break; + case SpvSnippet::ASMType::Float: irType = builder.getType(kIROp_FloatType); break; + case SpvSnippet::ASMType::Half: irType = builder.getType(kIROp_HalfType); break; + case SpvSnippet::ASMType::Int: irType = builder.getIntType(); break; + case SpvSnippet::ASMType::UInt: irType = builder.getUIntType(); break; + case SpvSnippet::ASMType::UInt16: irType = builder.getType(kIROp_UInt16Type); break; case SpvSnippet::ASMType::Float2: irType = builder.getVectorType( - builder.getType(kIROp_FloatType), builder.getIntValue(builder.getIntType(), 2)); + builder.getType(kIROp_FloatType), + builder.getIntValue(builder.getIntType(), 2)); break; case SpvSnippet::ASMType::UInt2: irType = builder.getVectorType( - builder.getType(kIROp_UIntType), builder.getIntValue(builder.getIntType(), 2)); + builder.getType(kIROp_UIntType), + builder.getIntValue(builder.getIntType(), 2)); break; - default: - SLANG_UNEXPECTED("unhandled case in emitSpvSnippetASMTypeOperand"); + default: SLANG_UNEXPECTED("unhandled case in emitSpvSnippetASMTypeOperand"); } emitOperand(irType); } @@ -5274,16 +5409,12 @@ struct SPIRVEmitContext { switch (operand.type) { - case SpvSnippet::ASMOperandType::SpvWord: - emitOperand(operand.content); - break; + case SpvSnippet::ASMOperandType::SpvWord: emitOperand(operand.content); break; case SpvSnippet::ASMOperandType::ObjectReference: SLANG_ASSERT(operand.content < (SpvWord)context.argumentIds.getCount()); emitOperand(context.argumentIds[operand.content]); break; - case SpvSnippet::ASMOperandType::ResultId: - emitOperand(kResultID); - break; + case SpvSnippet::ASMOperandType::ResultId: emitOperand(kResultID); break; case SpvSnippet::ASMOperandType::ResultTypeId: { emitOperand(context.resultType); @@ -5335,14 +5466,11 @@ struct SPIRVEmitContext { switch (extractBaseType(context.irResultType)) { - case BaseType::Float: - constant.type = SpvSnippet::ASMType::Float; - break; + case BaseType::Float: constant.type = SpvSnippet::ASMType::Float; break; case BaseType::Double: constant.type = SpvSnippet::ASMType::Double; break; - default: - break; + default: break; } } SpvInst* spvConstant = maybeEmitSpvConstant(constant); @@ -5413,14 +5541,9 @@ struct SPIRVEmitContext else { baseStructType = as<IRStructType>(base->getDataType()); - + auto structPtrType = builder.getPtrType(baseStructType); - auto varInst = emitOpVariable( - parent, - nullptr, - structPtrType, - SpvStorageClassFunction - ); + auto varInst = emitOpVariable(parent, nullptr, structPtrType, SpvStorageClassFunction); emitOpStore(parent, nullptr, varInst, base); baseId = getID(varInst); } @@ -5434,8 +5557,7 @@ struct SPIRVEmitContext fieldAddress, fieldAddress->getFullType(), baseId, - makeArray(fieldId) - ); + makeArray(fieldId)); } SpvInst* emitFieldExtract(SpvInstParent* parent, IRFieldExtract* inst) @@ -5445,22 +5567,25 @@ struct SPIRVEmitContext IRStructType* baseStructType = as<IRStructType>(inst->getBase()->getDataType()); SLANG_ASSERT(baseStructType && "field_extract requires base to be a struct."); - auto fieldId = static_cast<SpvWord>(getStructFieldId( - baseStructType, - as<IRStructKey>(inst->getField()))); - + auto fieldId = static_cast<SpvWord>( + getStructFieldId(baseStructType, as<IRStructKey>(inst->getField()))); + return emitOpCompositeExtract( parent, inst, inst->getDataType(), inst->getBase(), - makeArray(SpvLiteralInteger::from32(fieldId)) - ); + makeArray(SpvLiteralInteger::from32(fieldId))); } SpvInst* emitGetOffsetPtr(SpvInstParent* parent, IRInst* inst) { - return emitOpPtrAccessChain(parent, inst, inst->getDataType(), inst->getOperand(0), inst->getOperand(1)); + return emitOpPtrAccessChain( + parent, + inst, + inst->getDataType(), + inst->getOperand(0), + inst->getOperand(1)); } SpvInst* emitGetElementPtr(SpvInstParent* parent, IRGetElementPtr* inst) @@ -5473,24 +5598,27 @@ struct SPIRVEmitContext auto resultType = as<IRPtrTypeBase>(inst->getDataType()); SLANG_ASSERT(resultType); - if(const auto basePtrType = as<IRPtrTypeBase>(base->getDataType())) + if (const auto basePtrType = as<IRPtrTypeBase>(base->getDataType())) { // If the base pointer has a specific address space and the // expected result type doesn't, then make sure they match. // It's invalid spir-v if they don't match - resultType = getPtrTypeWithAddressSpace(cast<IRPtrTypeBase>(inst->getDataType()), basePtrType->getAddressSpace()); + resultType = getPtrTypeWithAddressSpace( + cast<IRPtrTypeBase>(inst->getDataType()), + basePtrType->getAddressSpace()); } else { - SLANG_ASSERT(as<IRPointerLikeType>(base->getDataType()) || !"invalid IR: base of getElementPtr must be a pointer."); + SLANG_ASSERT( + as<IRPointerLikeType>(base->getDataType()) || + !"invalid IR: base of getElementPtr must be a pointer."); } return emitOpAccessChain( parent, inst, inst->getFullType(), baseId, - makeArray(inst->getIndex()) - ); + makeArray(inst->getIndex())); } SpvInst* emitGetElement(SpvInstParent* parent, IRGetElement* inst) @@ -5499,9 +5627,7 @@ struct SPIRVEmitContext auto base = inst->getBase(); const auto baseTy = base->getDataType(); SLANG_ASSERT( - as<IRPointerLikeType>(baseTy) || - as<IRArrayType>(baseTy) || - as<IRVectorType>(baseTy) || + as<IRPointerLikeType>(baseTy) || as<IRArrayType>(baseTy) || as<IRVectorType>(baseTy) || as<IRMatrixType>(baseTy)); IRBuilder builder(m_irModule); @@ -5516,25 +5642,38 @@ struct SPIRVEmitContext inst, inst->getFullType(), inst->getBase(), - makeArray(SpvLiteralInteger::from32((int32_t)index->getValue())) - ); + makeArray(SpvLiteralInteger::from32((int32_t)index->getValue()))); } else { SLANG_ASSERT(as<IRVectorType>(baseTy)); // SPIRV Only allows dynamic element extract on vector types. - return emitOpVectorExtractDynamic(parent, inst, inst->getFullType(), inst->getBase(), inst->getIndex()); + return emitOpVectorExtractDynamic( + parent, + inst, + inst->getFullType(), + inst->getBase(), + inst->getIndex()); } } SpvInst* emitLoad(SpvInstParent* parent, IRLoad* inst) { auto ptrType = as<IRPtrTypeBase>(inst->getPtr()->getDataType()); - if (ptrType && addressSpaceToStorageClass(ptrType->getAddressSpace()) == SpvStorageClassPhysicalStorageBuffer) + if (ptrType && addressSpaceToStorageClass(ptrType->getAddressSpace()) == + SpvStorageClassPhysicalStorageBuffer) { IRSizeAndAlignment sizeAndAlignment; - getNaturalSizeAndAlignment(m_targetProgram->getOptionSet(), ptrType->getValueType(), &sizeAndAlignment); - return emitOpLoadAligned(parent, inst, inst->getDataType(), inst->getPtr(), SpvLiteralInteger::from32(sizeAndAlignment.alignment)); + getNaturalSizeAndAlignment( + m_targetProgram->getOptionSet(), + ptrType->getValueType(), + &sizeAndAlignment); + return emitOpLoadAligned( + parent, + inst, + inst->getDataType(), + inst->getPtr(), + SpvLiteralInteger::from32(sizeAndAlignment.alignment)); } else { @@ -5545,11 +5684,20 @@ struct SPIRVEmitContext SpvInst* emitStore(SpvInstParent* parent, IRStore* inst) { auto ptrType = as<IRPtrTypeBase>(inst->getPtr()->getDataType()); - if (ptrType && addressSpaceToStorageClass(ptrType->getAddressSpace()) == SpvStorageClassPhysicalStorageBuffer) + if (ptrType && addressSpaceToStorageClass(ptrType->getAddressSpace()) == + SpvStorageClassPhysicalStorageBuffer) { IRSizeAndAlignment sizeAndAlignment; - getNaturalSizeAndAlignment(m_targetProgram->getOptionSet(), ptrType->getValueType(), &sizeAndAlignment); - return emitOpStoreAligned(parent, inst, inst->getPtr(), inst->getVal(), SpvLiteralInteger::from32(sizeAndAlignment.alignment)); + getNaturalSizeAndAlignment( + m_targetProgram->getOptionSet(), + ptrType->getValueType(), + &sizeAndAlignment); + return emitOpStoreAligned( + parent, + inst, + inst->getPtr(), + inst->getVal(), + SpvLiteralInteger::from32(sizeAndAlignment.alignment)); } else { @@ -5562,7 +5710,9 @@ struct SPIRVEmitContext auto sourceVectorType = as<IRVectorType>(inst->getSource()->getDataType()); SLANG_ASSERT(sourceVectorType); auto sourceElementType = sourceVectorType->getElementType(); - SLANG_ASSERT(getIntVal(sourceVectorType->getElementCount()) == (IRIntegerValue)inst->getElementCount()); + SLANG_ASSERT( + getIntVal(sourceVectorType->getElementCount()) == + (IRIntegerValue)inst->getElementCount()); SpvInst* result = nullptr; IRBuilder builder(inst); builder.setInsertBefore(inst); @@ -5574,9 +5724,20 @@ struct SPIRVEmitContext for (UInt i = 0; i < inst->getElementCount(); i++) { auto index = inst->getElementIndex(i); - auto addr = emitOpAccessChain(parent, nullptr, ptrElementType, inst->getDest(), makeArray(index)); - auto val = emitOpCompositeExtract(parent, nullptr, sourceElementType, inst->getSource(), makeArray(SpvLiteralInteger::from32((int32_t)i))); - result = emitOpStore(parent, (i == inst->getElementCount() - 1 ? inst : nullptr), addr, val); + auto addr = emitOpAccessChain( + parent, + nullptr, + ptrElementType, + inst->getDest(), + makeArray(index)); + auto val = emitOpCompositeExtract( + parent, + nullptr, + sourceElementType, + inst->getSource(), + makeArray(SpvLiteralInteger::from32((int32_t)i))); + result = + emitOpStore(parent, (i == inst->getElementCount() - 1 ? inst : nullptr), addr, val); } return result; } @@ -5587,7 +5748,13 @@ struct SPIRVEmitContext { auto index = inst->getElementIndex(0); if (auto intLit = as<IRIntLit>(index)) - return emitOpCompositeInsert(parent, inst, inst->getFullType(), inst->getSource(), inst->getBase(), makeArray(SpvLiteralInteger::from32((uint32_t)intLit->value.intVal))); + return emitOpCompositeInsert( + parent, + inst, + inst->getFullType(), + inst->getSource(), + inst->getBase(), + makeArray(SpvLiteralInteger::from32((uint32_t)intLit->value.intVal))); } auto resultVectorType = as<IRVectorType>(inst->getDataType()); List<SpvLiteralInteger> shuffleIndices; @@ -5599,7 +5766,8 @@ struct SPIRVEmitContext { auto destIndex = (int32_t)getIntVal(inst->getElementIndex(i)); SLANG_ASSERT(destIndex < shuffleIndices.getCount()); - shuffleIndices[destIndex] = SpvLiteralInteger::from32((int32_t)(i + shuffleIndices.getCount())); + shuffleIndices[destIndex] = + SpvLiteralInteger::from32((int32_t)(i + shuffleIndices.getCount())); } auto source = inst->getSource(); if (!as<IRVectorType>(source->getDataType())) @@ -5608,13 +5776,21 @@ struct SPIRVEmitContext builder.setInsertBefore(inst); source = builder.emitMakeVectorFromScalar(resultVectorType, source); } - return emitOpVectorShuffle(parent, inst, inst->getFullType(), inst->getBase(), inst->getSource(), shuffleIndices.getArrayView()); + return emitOpVectorShuffle( + parent, + inst, + inst->getFullType(), + inst->getBase(), + inst->getSource(), + shuffleIndices.getArrayView()); } - IRPtrTypeBase* getPtrTypeWithAddressSpace(IRPtrTypeBase* ptrTypeWithNoAddressSpace, AddressSpace addressSpace) + IRPtrTypeBase* getPtrTypeWithAddressSpace( + IRPtrTypeBase* ptrTypeWithNoAddressSpace, + AddressSpace addressSpace) { // If it's already ok, return as is - if(ptrTypeWithNoAddressSpace->getAddressSpace() == addressSpace) + if (ptrTypeWithNoAddressSpace->getAddressSpace() == addressSpace) return ptrTypeWithNoAddressSpace; // It has an address space, but it doesn't match then fail, this @@ -5625,29 +5801,35 @@ struct SPIRVEmitContext return builder.getPtrType( ptrTypeWithNoAddressSpace->getOp(), ptrTypeWithNoAddressSpace->getValueType(), - addressSpace - ); + addressSpace); } SpvInst* emitStructuredBufferGetElementPtr(SpvInstParent* parent, IRInst* inst) { //"%addr = OpAccessChain resultType*StorageBuffer resultId _0 const(int, 0) _1;" IRBuilder builder(inst); - auto addressSpace = isSpirv14OrLater() ? AddressSpace::StorageBuffer : AddressSpace::Uniform; + auto addressSpace = + isSpirv14OrLater() ? AddressSpace::StorageBuffer : AddressSpace::Uniform; return emitOpAccessChain( parent, inst, // Make sure the resulting pointer has the correct storage class getPtrTypeWithAddressSpace(cast<IRPtrTypeBase>(inst->getDataType()), addressSpace), inst->getOperand(0), - makeArray(emitIntConstant(0, builder.getIntType()), ensureInst(inst->getOperand(1))) - ); + makeArray(emitIntConstant(0, builder.getIntType()), ensureInst(inst->getOperand(1)))); } SpvInst* emitStructuredBufferGetDimensions(SpvInstParent* parent, IRInst* inst) { IRBuilder builder(inst); - auto arrayLength = emitInst(parent, nullptr, SpvOpArrayLength, builder.getUIntType(), kResultID, inst->getOperand(0), SpvLiteralInteger::from32(0)); + auto arrayLength = emitInst( + parent, + nullptr, + SpvOpArrayLength, + builder.getUIntType(), + kResultID, + inst->getOperand(0), + SpvLiteralInteger::from32(0)); auto elementType = as<IRPtrType>(inst->getOperand(0)->getDataType())->getValueType(); IRIntegerValue stride = 0; if (auto sizeDecor = elementType->findDecoration<IRSizeAndAlignmentDecoration>()) @@ -5655,7 +5837,8 @@ struct SPIRVEmitContext stride = align(sizeDecor->getSize(), (int)sizeDecor->getAlignment()); } auto strideOperand = emitIntConstant(stride, builder.getUIntType()); - auto result = emitOpCompositeConstruct(parent, inst, inst->getDataType(), arrayLength, strideOperand); + auto result = + emitOpCompositeConstruct(parent, inst, inst->getDataType(), arrayLength, strideOperand); return result; } @@ -5669,22 +5852,26 @@ struct SPIRVEmitContext inst, inst->getDataType(), inst->getBase(), - makeArray(SpvLiteralInteger::from32(int32_t(index))) - ); + makeArray(SpvLiteralInteger::from32(int32_t(index)))); } else { - return emitInstCustomOperandFunc(parent, inst, SpvOpVectorShuffle, [&]() { - emitOperand(inst->getDataType()); - emitOperand(kResultID); - emitOperand(inst->getBase()); - emitOperand(inst->getBase()); - for (UInt i = 0; i < inst->getElementCount(); i++) + return emitInstCustomOperandFunc( + parent, + inst, + SpvOpVectorShuffle, + [&]() { - auto index = as<IRIntLit>(inst->getElementIndex(i)); - emitOperand((SpvWord)index->getValue()); - } - }); + emitOperand(inst->getDataType()); + emitOperand(kResultID); + emitOperand(inst->getBase()); + emitOperand(inst->getBase()); + for (UInt i = 0; i < inst->getElementCount(); i++) + { + auto index = as<IRIntLit>(inst->getElementIndex(i)); + emitOperand((SpvWord)index->getValue()); + } + }); } } @@ -5705,12 +5892,28 @@ struct SPIRVEmitContext auto one = builder.getIntValue(toType, 1); if (auto vecType = as<IRVectorType>(toTypeV)) { - auto zeroV = emitSplat(parent, nullptr, zero, getIntVal(vecType->getElementCount())); + auto zeroV = + emitSplat(parent, nullptr, zero, getIntVal(vecType->getElementCount())); auto oneV = emitSplat(parent, nullptr, one, getIntVal(vecType->getElementCount())); - return emitInst(parent, inst, SpvOpSelect, inst->getFullType(), kResultID, inst->getOperand(0), - oneV, zeroV); + return emitInst( + parent, + inst, + SpvOpSelect, + inst->getFullType(), + kResultID, + inst->getOperand(0), + oneV, + zeroV); } - return emitInst(parent, inst, SpvOpSelect, inst->getFullType(), kResultID, inst->getOperand(0), one, zero); + return emitInst( + parent, + inst, + SpvOpSelect, + inst->getFullType(), + kResultID, + inst->getOperand(0), + one, + zero); } else if (as<IRBoolType>(toType)) { @@ -5720,12 +5923,23 @@ struct SPIRVEmitContext auto zero = builder.getIntValue(fromType, 0); if (auto vecType = as<IRVectorType>(toTypeV)) { - auto zeroV = emitSplat(parent, nullptr, zero, getIntVal(vecType->getElementCount())); - return emitOpINotEqual(parent, inst, inst->getFullType(), inst->getOperand(0), zeroV); + auto zeroV = + emitSplat(parent, nullptr, zero, getIntVal(vecType->getElementCount())); + return emitOpINotEqual( + parent, + inst, + inst->getFullType(), + inst->getOperand(0), + zeroV); } else { - return emitOpINotEqual(parent, inst, inst->getFullType(), inst->getOperand(0), zero); + return emitOpINotEqual( + parent, + inst, + inst->getFullType(), + inst->getOperand(0), + zero); } } @@ -5735,29 +5949,34 @@ struct SPIRVEmitContext const auto fromInfo = getIntTypeInfo(fromType); const auto toInfo = getIntTypeInfo(toType); - if(fromInfo == toInfo) + if (fromInfo == toInfo) return emitOpCopyObject(parent, inst, toTypeV, inst->getOperand(0)); - else if(fromInfo.width == toInfo.width) + else if (fromInfo.width == toInfo.width) return emitOpBitcast(parent, inst, toTypeV, inst->getOperand(0)); - else if(!fromInfo.isSigned && !toInfo.isSigned) + else if (!fromInfo.isSigned && !toInfo.isSigned) // unsigned to unsigned, don't sign extend return emitOpUConvert(parent, inst, toTypeV, inst->getOperand(0)); - else if(toInfo.isSigned) + else if (toInfo.isSigned) // unsigned to signed, sign extend return emitOpSConvert(parent, inst, toTypeV, inst->getOperand(0)); - else if(fromInfo.isSigned) + else if (fromInfo.isSigned) // signed to unsigned, sign extend return emitOpSConvert(parent, inst, toTypeV, inst->getOperand(0)); - else if(fromInfo.isSigned && toInfo.isSigned) + else if (fromInfo.isSigned && toInfo.isSigned) // signed to signed, sign extend return emitOpSConvert(parent, inst, toTypeV, inst->getOperand(0)); SLANG_UNREACHABLE(__func__); } - SpvInst* emitFloatCastForMatrix(SpvInstParent* parent, IRFloatCast* inst, IRMatrixType* fromTypeM, IRMatrixType* toTypeM) + SpvInst* emitFloatCastForMatrix( + SpvInstParent* parent, + IRFloatCast* inst, + IRMatrixType* fromTypeM, + IRMatrixType* toTypeM) { - // Because there is no spirv instruction to convert matrix to matrix, we need to convert it row by row. + // Because there is no spirv instruction to convert matrix to matrix, we need to convert it + // row by row. auto rowCount = getIntVal(fromTypeM->getRowCount()); auto colCount = getIntVal(fromTypeM->getColumnCount()); @@ -5770,8 +5989,12 @@ struct SPIRVEmitContext // convert each row vector to toType. for (uint32_t i = 0; i < rowCount; i++) { - auto rowVector = emitOpCompositeExtract(parent, nullptr, fromTypeV, - inst->getOperand(0), makeArray(SpvLiteralInteger::from32(i))); + auto rowVector = emitOpCompositeExtract( + parent, + nullptr, + fromTypeV, + inst->getOperand(0), + makeArray(SpvLiteralInteger::from32(i))); auto rowVectorConverted = emitOpFConvert(parent, nullptr, toVectorV, rowVector); rowVectorsConverted.add(rowVectorConverted); @@ -5807,13 +6030,15 @@ struct SPIRVEmitContext toType = toTypeV; } - // We'd better give some diagnostics to at least point out which line in the shader is wrong, so - // it can help the user or developers to locate the issue easier. - if (!isFloatingType(fromType)) { + // We'd better give some diagnostics to at least point out which line in the shader is + // wrong, so it can help the user or developers to locate the issue easier. + if (!isFloatingType(fromType)) + { m_sink->diagnose(inst, Diagnostics::internalCompilerError); } - if (!isFloatingType(toType)) { + if (!isFloatingType(toType)) + { m_sink->diagnose(inst, Diagnostics::internalCompilerError); } @@ -5823,7 +6048,11 @@ struct SPIRVEmitContext if (isMatrixCast) { - return emitFloatCastForMatrix(parent, inst, as<IRMatrixType>(fromTypeV), as<IRMatrixType>(toTypeV)); + return emitFloatCastForMatrix( + parent, + inst, + as<IRMatrixType>(fromTypeV), + as<IRMatrixType>(toTypeV)); } return emitOpFConvert(parent, inst, toTypeV, inst->getOperand(0)); @@ -5843,8 +6072,8 @@ struct SPIRVEmitContext const auto fromInfo = getIntTypeInfo(fromType); return fromInfo.isSigned - ? emitOpConvertSToF(parent, inst, toTypeV, inst->getOperand(0)) - : emitOpConvertUToF(parent, inst, toTypeV, inst->getOperand(0)); + ? emitOpConvertSToF(parent, inst, toTypeV, inst->getOperand(0)) + : emitOpConvertUToF(parent, inst, toTypeV, inst->getOperand(0)); } else if (as<IRBoolType>(fromType)) { @@ -5857,7 +6086,15 @@ struct SPIRVEmitContext one = builder.emitMakeVectorFromScalar(toTypeV, one); zero = builder.emitMakeVectorFromScalar(toTypeV, zero); } - return emitInst(parent, inst, SpvOpSelect, inst->getFullType(), kResultID, inst->getOperand(0), one, zero); + return emitInst( + parent, + inst, + SpvOpSelect, + inst->getFullType(), + kResultID, + inst->getOperand(0), + one, + zero); } else { @@ -5882,12 +6119,27 @@ struct SPIRVEmitContext auto zero = builder.getIntValue(fromType, 0); if (auto vecType = as<IRVectorType>(toTypeV)) { - auto zeroV = emitSplat(parent, nullptr, zero, getIntVal(vecType->getElementCount())); - return emitInst(parent, inst, SpvOpFUnordNotEqual, inst->getFullType(), kResultID, inst->getOperand(0), zeroV); + auto zeroV = + emitSplat(parent, nullptr, zero, getIntVal(vecType->getElementCount())); + return emitInst( + parent, + inst, + SpvOpFUnordNotEqual, + inst->getFullType(), + kResultID, + inst->getOperand(0), + zeroV); } else { - return emitInst(parent, inst, SpvOpFUnordNotEqual, inst->getFullType(), kResultID, inst->getOperand(0), zero); + return emitInst( + parent, + inst, + SpvOpFUnordNotEqual, + inst->getFullType(), + kResultID, + inst->getOperand(0), + zero); } } @@ -5895,26 +6147,48 @@ struct SPIRVEmitContext const auto toInfo = getIntTypeInfo(toType); - return toInfo.isSigned - ? emitOpConvertFToS(parent, inst, toTypeV, inst->getOperand(0)) - : emitOpConvertFToU(parent, inst, toTypeV, inst->getOperand(0)); + return toInfo.isSigned ? emitOpConvertFToS(parent, inst, toTypeV, inst->getOperand(0)) + : emitOpConvertFToU(parent, inst, toTypeV, inst->getOperand(0)); } SpvInst* emitCastPtrToInt(SpvInstParent* parent, IRInst* inst) { - return emitInst(parent, inst, SpvOpConvertPtrToU, inst->getFullType(), kResultID, inst->getOperand(0)); + return emitInst( + parent, + inst, + SpvOpConvertPtrToU, + inst->getFullType(), + kResultID, + inst->getOperand(0)); } SpvInst* emitCastPtrToBool(SpvInstParent* parent, IRInst* inst) { IRBuilder builder(inst); - auto uintVal = emitInst(parent, nullptr, SpvOpConvertPtrToU, builder.getUInt64Type(), kResultID, inst->getOperand(0)); - return emitOpINotEqual(parent, inst, kResultID, uintVal, builder.getIntValue(builder.getUInt64Type(), 0)); + auto uintVal = emitInst( + parent, + nullptr, + SpvOpConvertPtrToU, + builder.getUInt64Type(), + kResultID, + inst->getOperand(0)); + return emitOpINotEqual( + parent, + inst, + kResultID, + uintVal, + builder.getIntValue(builder.getUInt64Type(), 0)); } SpvInst* emitCastIntToPtr(SpvInstParent* parent, IRInst* inst) { - return emitInst(parent, inst, SpvOpConvertUToPtr, inst->getFullType(), kResultID, inst->getOperand(0)); + return emitInst( + parent, + inst, + SpvOpConvertUToPtr, + inst->getFullType(), + kResultID, + inst->getOperand(0)); } template<typename T, typename Ts> @@ -6009,17 +6283,9 @@ struct SPIRVEmitContext if (inst->getOperandCount() == 1) { if (inst->getDataType() == inst->getOperand(0)->getDataType()) - return emitOpCopyObject( - parent, - inst, - inst->getFullType(), - inst->getOperand(0)); + return emitOpCopyObject(parent, inst, inst->getFullType(), inst->getOperand(0)); else - return emitOpBitcast( - parent, - inst, - inst->getFullType(), - inst->getOperand(0)); + return emitOpBitcast(parent, inst, inst->getFullType(), inst->getOperand(0)); } else { @@ -6037,16 +6303,12 @@ struct SPIRVEmitContext { const auto scalarTy = as<IRBasicType>(scalar->getDataType()); SLANG_ASSERT(scalarTy); - const auto spvVecTy = ensureVectorType( - scalarTy->getBaseType(), - numElems, - nullptr); + const auto spvVecTy = ensureVectorType(scalarTy->getBaseType(), numElems, nullptr); return emitCompositeConstruct( parent, inst, spvVecTy, - List<IRInst*>::makeRepeated(scalar, Index(numElems)) - ); + List<IRInst*>::makeRepeated(scalar, Index(numElems))); } bool isSignedType(IRType* type) @@ -6054,19 +6316,14 @@ struct SPIRVEmitContext switch (type->getOp()) { case kIROp_FloatType: - case kIROp_DoubleType: - return true; + case kIROp_DoubleType: return true; case kIROp_IntType: case kIROp_Int16Type: case kIROp_Int64Type: - case kIROp_Int8Type: - return true; - case kIROp_VectorType: - return isSignedType(as<IRVectorType>(type)->getElementType()); - case kIROp_MatrixType: - return isSignedType(as<IRMatrixType>(type)->getElementType()); - default: - return false; + case kIROp_Int8Type: return true; + case kIROp_VectorType: return isSignedType(as<IRVectorType>(type)->getElementType()); + case kIROp_MatrixType: return isSignedType(as<IRMatrixType>(type)->getElementType()); + default: return false; } } @@ -6076,18 +6333,20 @@ struct SPIRVEmitContext { case kIROp_FloatType: case kIROp_DoubleType: - case kIROp_HalfType: - return true; - case kIROp_VectorType: - return isFloatType(as<IRVectorType>(type)->getElementType()); - case kIROp_MatrixType: - return isFloatType(as<IRMatrixType>(type)->getElementType()); - default: - return false; + case kIROp_HalfType: return true; + case kIROp_VectorType: return isFloatType(as<IRVectorType>(type)->getElementType()); + case kIROp_MatrixType: return isFloatType(as<IRMatrixType>(type)->getElementType()); + default: return false; } } - SpvInst* emitVectorOrScalarArithmetic(SpvInstParent* parent, IRInst* instToRegister, IRInst* type, IROp op, UInt operandCount, ArrayView<IRInst*> operands) + SpvInst* emitVectorOrScalarArithmetic( + SpvInstParent* parent, + IRInst* instToRegister, + IRInst* type, + IROp op, + UInt operandCount, + ArrayView<IRInst*> operands) { IRType* elementType = getVectorElementType(operands[0]->getDataType()); IRBasicType* basicType = as<IRBasicType>(elementType); @@ -6097,72 +6356,54 @@ struct SPIRVEmitContext { case BaseType::Float: case BaseType::Double: - case BaseType::Half: - isFloatingPoint = true; - break; - case BaseType::Bool: - isBool = true; - break; - default: - break; + case BaseType::Half: isFloatingPoint = true; break; + case BaseType::Bool: isBool = true; break; + default: break; } SpvOp opCode = SpvOpUndef; bool isSigned = isSignedType(basicType); switch (op) { - case kIROp_Add: - opCode = isFloatingPoint ? SpvOpFAdd : SpvOpIAdd; - break; - case kIROp_Sub: - opCode = isFloatingPoint ? SpvOpFSub : SpvOpISub; - break; - case kIROp_Mul: - opCode = isFloatingPoint ? SpvOpFMul : SpvOpIMul; - break; + case kIROp_Add: opCode = isFloatingPoint ? SpvOpFAdd : SpvOpIAdd; break; + case kIROp_Sub: opCode = isFloatingPoint ? SpvOpFSub : SpvOpISub; break; + case kIROp_Mul: opCode = isFloatingPoint ? SpvOpFMul : SpvOpIMul; break; case kIROp_Div: opCode = isFloatingPoint ? SpvOpFDiv : isSigned ? SpvOpSDiv : SpvOpUDiv; break; - case kIROp_IRem: - opCode = isSigned ? SpvOpSRem : SpvOpUMod; - break; - case kIROp_FRem: - opCode = SpvOpFRem; - break; + case kIROp_IRem: opCode = isSigned ? SpvOpSRem : SpvOpUMod; break; + case kIROp_FRem: opCode = SpvOpFRem; break; case kIROp_Less: opCode = isFloatingPoint ? SpvOpFOrdLessThan - : isSigned ? SpvOpSLessThan : SpvOpULessThan; + : isSigned ? SpvOpSLessThan + : SpvOpULessThan; break; case kIROp_Leq: opCode = isFloatingPoint ? SpvOpFOrdLessThanEqual - : isSigned ? SpvOpSLessThanEqual : SpvOpULessThanEqual; + : isSigned ? SpvOpSLessThanEqual + : SpvOpULessThanEqual; break; case kIROp_Eql: opCode = isFloatingPoint ? SpvOpFOrdEqual : isBool ? SpvOpLogicalEqual : SpvOpIEqual; break; case kIROp_Neq: opCode = isFloatingPoint ? SpvOpFUnordNotEqual - : isBool ? SpvOpLogicalNotEqual : SpvOpINotEqual; + : isBool ? SpvOpLogicalNotEqual + : SpvOpINotEqual; break; case kIROp_Geq: opCode = isFloatingPoint ? SpvOpFOrdGreaterThanEqual - : isSigned ? SpvOpSGreaterThanEqual : SpvOpUGreaterThanEqual; + : isSigned ? SpvOpSGreaterThanEqual + : SpvOpUGreaterThanEqual; break; case kIROp_Greater: opCode = isFloatingPoint ? SpvOpFOrdGreaterThan - : isSigned ? SpvOpSGreaterThan : SpvOpUGreaterThan; - break; - case kIROp_Neg: - opCode = isFloatingPoint ? SpvOpFNegate : SpvOpSNegate; - break; - case kIROp_And: - opCode = SpvOpLogicalAnd; - break; - case kIROp_Or: - opCode = SpvOpLogicalOr; - break; - case kIROp_Not: - opCode = SpvOpLogicalNot; + : isSigned ? SpvOpSGreaterThan + : SpvOpUGreaterThan; break; + case kIROp_Neg: opCode = isFloatingPoint ? SpvOpFNegate : SpvOpSNegate; break; + case kIROp_And: opCode = SpvOpLogicalAnd; break; + case kIROp_Or: opCode = SpvOpLogicalOr; break; + case kIROp_Not: opCode = SpvOpLogicalNot; break; case kIROp_BitAnd: if (isBool) opCode = SpvOpLogicalAnd; @@ -6190,12 +6431,8 @@ struct SPIRVEmitContext case kIROp_Rsh: opCode = isSigned ? SpvOpShiftRightArithmetic : SpvOpShiftRightLogical; break; - case kIROp_Lsh: - opCode = SpvOpShiftLeftLogical; - break; - default: - SLANG_ASSERT(!"unknown arithmetic opcode"); - break; + case kIROp_Lsh: opCode = SpvOpShiftLeftLogical; break; + default: SLANG_ASSERT(!"unknown arithmetic opcode"); break; } if (operandCount == 1) { @@ -6211,17 +6448,28 @@ struct SPIRVEmitContext { if (lVec && !rVec) { - return emitInst(parent, instToRegister, SpvOpVectorTimesScalar, type, kResultID, operands); + return emitInst( + parent, + instToRegister, + SpvOpVectorTimesScalar, + type, + kResultID, + operands); } else if (!lVec && rVec) { - IRInst* newOperands[2] = { operands[1], operands[0] }; - return emitInst(parent, instToRegister, SpvOpVectorTimesScalar, type, kResultID, ArrayView<IRInst*>(newOperands, 2)); + IRInst* newOperands[2] = {operands[1], operands[0]}; + return emitInst( + parent, + instToRegister, + SpvOpVectorTimesScalar, + type, + kResultID, + ArrayView<IRInst*>(newOperands, 2)); } } - const auto go = [&](const auto l, const auto r) { - return emitInst(parent, instToRegister, opCode, type, kResultID, l, r); - }; + const auto go = [&](const auto l, const auto r) + { return emitInst(parent, instToRegister, opCode, type, kResultID, l, r); }; if (lVec && !rVec) { const auto len = as<IRIntLit>(lVec->getElementCount()); @@ -6267,7 +6515,13 @@ struct SPIRVEmitContext operands.add(originalOperand); } } - rows.add(emitVectorOrScalarArithmetic(parent, nullptr, rowVectorType, inst->getOp(), inst->getOperandCount(), operands.getArrayView())); + rows.add(emitVectorOrScalarArithmetic( + parent, + nullptr, + rowVectorType, + inst->getOp(), + inst->getOperandCount(), + operands.getArrayView())); } return emitCompositeConstruct(parent, inst, inst->getDataType(), rows); } @@ -6275,7 +6529,13 @@ struct SPIRVEmitContext Array<IRInst*, 4> operands; for (UInt i = 0; i < inst->getOperandCount(); i++) operands.add(inst->getOperand(i)); - return emitVectorOrScalarArithmetic(parent, inst, inst->getDataType(), inst->getOp(), inst->getOperandCount(), operands.getView()); + return emitVectorOrScalarArithmetic( + parent, + inst, + inst->getDataType(), + inst->getOp(), + inst->getOperandCount(), + operands.getView()); } SpvInst* emitDebugLine(SpvInstParent* parent, IRDebugLine* debugLine) @@ -6283,7 +6543,11 @@ struct SPIRVEmitContext auto scope = findDebugScope(debugLine); if (!scope) return nullptr; - return emitOpDebugLine(parent, debugLine, debugLine->getFullType(), getNonSemanticDebugInfoExtInst(), + return emitOpDebugLine( + parent, + debugLine, + debugLine->getFullType(), + getNonSemanticDebugInfoExtInst(), debugLine->getSource(), debugLine->getLineStart(), debugLine->getLineEnd(), @@ -6304,7 +6568,11 @@ struct SPIRVEmitContext return m_nullDwarfExpr; } - bool translateIRAccessChain(IRBuilder& builder, IRInst* baseType, const List<IRInst*>& irAccessChain, List<SpvInst*>& spvAccessChain) + bool translateIRAccessChain( + IRBuilder& builder, + IRInst* baseType, + const List<IRInst*>& irAccessChain, + List<SpvInst*>& spvAccessChain) { auto type = baseType; for (Index i = 0; i < irAccessChain.getCount(); i++) @@ -6335,7 +6603,9 @@ struct SPIRVEmitContext else if (auto vectorType = as<IRVectorType>(type)) type = vectorType->getElementType(); else if (auto matrixType = as<IRMatrixType>(type)) - type = builder.getVectorType(matrixType->getElementType(), matrixType->getColumnCount()); + type = builder.getVectorType( + matrixType->getElementType(), + matrixType->getColumnCount()); else return false; spvAccessChain.add(ensureInst(element)); @@ -6347,7 +6617,7 @@ struct SPIRVEmitContext SpvInst* emitDebugValue(SpvInstParent* parent, IRDebugValue* debugValue) { // We are asked to update the value for a debug variable. - // A debug variable is already emited as a OpDebugVariable + + // A debug variable is already emited as a OpDebugVariable + // OpVariable + OpDebugDeclare. We only need to store the new value // into the associated OpVariable. The `debugValue->getDebugVar()` inst // already maps to the `OpVariable` SpvInst, so we just need to emit @@ -6372,26 +6642,33 @@ struct SPIRVEmitContext // If the root variable can't be represented by a normal variable, // try to emit a DebugValue if possible. Usually this means that the variable // represents a shader resource. - // + // // SPIR-V requires the access chain specified in a DebugValue operation to // be fully static. We will skip emitting the debug inst if the access chain // isn't static. // auto type = unwrapAttributedType(debugValue->getDebugVar()->getDataType()); List<SpvInst*> accessChain; - bool isConstAccessChain = translateIRAccessChain(builder, type, irAccessChain, accessChain); - + bool isConstAccessChain = + translateIRAccessChain(builder, type, irAccessChain, accessChain); + if (isConstAccessChain) { return emitOpDebugValue( - parent, debugValue, m_voidType, getNonSemanticDebugInfoExtInst(), - rootVar, debugValue->getValue(), getDwarfExpr(), accessChain); + parent, + debugValue, + m_voidType, + getNonSemanticDebugInfoExtInst(), + rootVar, + debugValue->getValue(), + getDwarfExpr(), + accessChain); } // Fallback to not emit anything for now. return nullptr; } - + // The ordinary case is the debug variable has a backing ordinary variable. // We can simply emit a store into the backing variable for the DebugValue operation. // @@ -6453,7 +6730,8 @@ struct SPIRVEmitContext { static uint32_t uid = 0; uid++; - name = builder.getStringValue((String("unnamed_type_") + String(uid)).getUnownedSlice()); + name = builder.getStringValue( + (String("unnamed_type_") + String(uid)).getUnownedSlice()); } IRSizeAndAlignment structSizeAlignment; getNaturalSizeAndAlignment(m_targetProgram->getOptionSet(), type, &structSizeAlignment); @@ -6466,21 +6744,25 @@ struct SPIRVEmitContext getNaturalOffset(m_targetProgram->getOptionSet(), field, &offset); auto fieldType = field->getFieldType(); - getNaturalSizeAndAlignment(m_targetProgram->getOptionSet(), fieldType, &sizeAlignment); + getNaturalSizeAndAlignment( + m_targetProgram->getOptionSet(), + fieldType, + &sizeAlignment); SpvInst* forwardRef = nullptr; SpvInst* spvFieldType = nullptr; if (auto fieldPtrType = as<IRPtrTypeBase>(fieldType)) { auto fieldPtrBaseType = fieldPtrType->getValueType(); - if (as<IRStructType>(fieldPtrBaseType) - && m_emittingTypes.contains(fieldPtrBaseType)) + if (as<IRStructType>(fieldPtrBaseType) && + m_emittingTypes.contains(fieldPtrBaseType)) { forwardRef = emitDebugForwardRefs(fieldPtrBaseType); SpvStorageClass storageClass = SpvStorageClassFunction; if (fieldPtrType->hasAddressSpace()) - storageClass = addressSpaceToStorageClass(fieldPtrType->getAddressSpace()); + storageClass = + addressSpaceToStorageClass(fieldPtrType->getAddressSpace()); spvFieldType = emitOpDebugTypePointer( getSection(SpvLogicalSectionID::ConstantsAndTypes), @@ -6519,8 +6801,12 @@ struct SPIRVEmitContext if (m_mapForwardRefsToDebugType.tryGetValue(type, forwardRef)) { // "OpExtInstWithForwardRefsKHR" requires "forward declared ID" at the end. - auto tmp = m_memoryArena.allocateArray<SpvWord>(forwardRef->operandWordsCount + members.getCount()); - memcpy(tmp, forwardRef->operandWords, forwardRef->operandWordsCount * sizeof(SpvWord)); + auto tmp = m_memoryArena.allocateArray<SpvWord>( + forwardRef->operandWordsCount + members.getCount()); + memcpy( + tmp, + forwardRef->operandWords, + forwardRef->operandWordsCount * sizeof(SpvWord)); for (Index i = 0; i < members.getCount(); i++) tmp[forwardRef->operandWordsCount + i] = getID(members[i]); forwardRef->operandWords = tmp; @@ -6547,14 +6833,16 @@ struct SPIRVEmitContext if (auto arrayType = as<IRArrayTypeBase>(type)) { auto sizedArrayType = as<IRArrayType>(arrayType); - return emitOpDebugTypeArray(getSection(SpvLogicalSectionID::ConstantsAndTypes), + return emitOpDebugTypeArray( + getSection(SpvLogicalSectionID::ConstantsAndTypes), nullptr, m_voidType, getNonSemanticDebugInfoExtInst(), emitDebugType(arrayType->getElementType()), - sizedArrayType - ? builder.getIntValue(builder.getUIntType(), getIntVal(sizedArrayType->getElementCount())) - : builder.getIntValue(builder.getUIntType(), 0)); + sizedArrayType ? builder.getIntValue( + builder.getUIntType(), + getIntVal(sizedArrayType->getElementCount())) + : builder.getIntValue(builder.getUIntType(), 0)); } else if (auto vectorType = as<IRVectorType>(type)) { @@ -6565,7 +6853,9 @@ struct SPIRVEmitContext m_voidType, getNonSemanticDebugInfoExtInst(), elementType, - builder.getIntValue(builder.getUIntType(), getIntVal(vectorType->getElementCount()))); + builder.getIntValue( + builder.getUIntType(), + getIntVal(vectorType->getElementCount()))); } else if (auto matrixType = as<IRMatrixType>(type)) { @@ -6574,13 +6864,16 @@ struct SPIRVEmitContext IRType* innerVectorType = nullptr; if (getIntVal(matrixType->getLayout()) == kMatrixLayoutMode_ColumnMajor) { - innerVectorType = builder.getVectorType(matrixType->getElementType(), matrixType->getRowCount()); + innerVectorType = + builder.getVectorType(matrixType->getElementType(), matrixType->getRowCount()); isColumnMajor = true; count = matrixType->getColumnCount(); } else { - innerVectorType = builder.getVectorType(matrixType->getElementType(), matrixType->getColumnCount()); + innerVectorType = builder.getVectorType( + matrixType->getElementType(), + matrixType->getColumnCount()); count = matrixType->getRowCount(); } auto elementType = emitDebugType(innerVectorType); @@ -6692,7 +6985,8 @@ struct SPIRVEmitContext { static uint32_t uid = 0; uid++; - name = builder.getStringValue((String("unnamed_forward_type_") + String(uid)).getUnownedSlice()); + name = builder.getStringValue( + (String("unnamed_forward_type_") + String(uid)).getUnownedSlice()); } IRSizeAndAlignment structSizeAlignment; getNaturalSizeAndAlignment(m_targetProgram->getOptionSet(), type, &structSizeAlignment); @@ -6740,12 +7034,27 @@ struct SPIRVEmitContext IRBuilder builder(function); auto debugFunc = emitOpDebugFunction( getSection(SpvLogicalSectionID::ConstantsAndTypes), - nullptr, m_voidType, getNonSemanticDebugInfoExtInst(), - name, debugType, debugLoc->getSource(), debugLoc->getLine(), debugLoc->getCol(), scope, name, - builder.getIntValue(builder.getUIntType(), 0), debugLoc->getLine()); + nullptr, + m_voidType, + getNonSemanticDebugInfoExtInst(), + name, + debugType, + debugLoc->getSource(), + debugLoc->getLine(), + debugLoc->getCol(), + scope, + name, + builder.getIntValue(builder.getUIntType(), 0), + debugLoc->getLine()); registerDebugInst(function, debugFunc); - emitOpDebugFunctionDefinition(firstBlock, nullptr, m_voidType, getNonSemanticDebugInfoExtInst(), debugFunc, spvFunc); + emitOpDebugFunctionDefinition( + firstBlock, + nullptr, + m_voidType, + getNonSemanticDebugInfoExtInst(), + debugFunc, + spvFunc); return debugFunc; } @@ -6757,175 +7066,178 @@ struct SPIRVEmitContext // This keeps track of the named IDs used in the asm block Dictionary<UnownedStringSlice, SpvWord> idMap; - for(const auto spvInst : inst->getInsts()) + for (const auto spvInst : inst->getInsts()) { const bool isLast = spvInst == inst->getLastChild(); - const auto parentForOpCode = [this](SpvOp opcode, SpvInstParent* defaultParent) -> SpvInstParent*{ + const auto parentForOpCode = + [this](SpvOp opcode, SpvInstParent* defaultParent) -> SpvInstParent* + { const auto info = m_grammarInfo->opInfos.lookup(opcode); SLANG_ASSERT(info.has_value()); - switch(info->class_) + switch (info->class_) { - case SPIRVCoreGrammarInfo::OpInfo::TypeDeclaration: - case SPIRVCoreGrammarInfo::OpInfo::ConstantCreation: - return getSection(SpvLogicalSectionID::ConstantsAndTypes); - // Don't add this case, it's not correct as not all "Debug" - // instructions belong in this block - // case SPIRVCoreGrammarInfo::OpInfo::Debug: - // return getSection(SpvLogicalSectionID::DebugNames); - default: - switch(opcode) - { - case SpvOpName: - return getSection(SpvLogicalSectionID::DebugNames); - case SpvOpCapability: - return getSection(SpvLogicalSectionID::Capabilities); - case SpvOpExtension: - return getSection(SpvLogicalSectionID::Extensions); - case SpvOpExecutionMode: - case SpvOpExecutionModeId: - return getSection(SpvLogicalSectionID::ExecutionModes); - case SpvOpDecorate: - case SpvOpDecorateId: - case SpvOpDecorateString: - case SpvOpMemberDecorate: - case SpvOpMemberDecorateString: - return getSection(SpvLogicalSectionID::Annotations); - default: - return defaultParent; - - } + case SPIRVCoreGrammarInfo::OpInfo::TypeDeclaration: + case SPIRVCoreGrammarInfo::OpInfo::ConstantCreation: + return getSection(SpvLogicalSectionID::ConstantsAndTypes); + // Don't add this case, it's not correct as not all "Debug" + // instructions belong in this block + // case SPIRVCoreGrammarInfo::OpInfo::Debug: + // return getSection(SpvLogicalSectionID::DebugNames); + default: + switch (opcode) + { + case SpvOpName: return getSection(SpvLogicalSectionID::DebugNames); + case SpvOpCapability: return getSection(SpvLogicalSectionID::Capabilities); + case SpvOpExtension: return getSection(SpvLogicalSectionID::Extensions); + case SpvOpExecutionMode: + case SpvOpExecutionModeId: + return getSection(SpvLogicalSectionID::ExecutionModes); + case SpvOpDecorate: + case SpvOpDecorateId: + case SpvOpDecorateString: + case SpvOpMemberDecorate: + case SpvOpMemberDecorateString: + return getSection(SpvLogicalSectionID::Annotations); + default: return defaultParent; + } } }; - const auto emitSpvAsmOperand = [&](IRSPIRVAsmOperand* operand){ - switch(operand->getOp()) + const auto emitSpvAsmOperand = [&](IRSPIRVAsmOperand* operand) + { + switch (operand->getOp()) { case kIROp_SPIRVAsmOperandEnum: case kIROp_SPIRVAsmOperandLiteral: - { - const auto v = as<IRConstant>(operand->getValue()); - SLANG_ASSERT(v); - if(operand->getOperandCount() >= 2) - { - const auto constantType = cast<IRType>(operand->getOperand(1)); - SpvInst* constant; - switch(v->getOp()) - { - case kIROp_IntLit: + const auto v = as<IRConstant>(operand->getValue()); + SLANG_ASSERT(v); + if (operand->getOperandCount() >= 2) + { - // TODO: range checking - const auto i = cast<IRIntLit>(v)->getValue(); - constant = emitIntConstant(i, constantType); - break; - } - case kIROp_StringLit: - SLANG_UNIMPLEMENTED_X("String constants in SPIR-V emit"); - default: - SLANG_UNREACHABLE("Unhandled case in emitSPIRVAsm"); + const auto constantType = cast<IRType>(operand->getOperand(1)); + SpvInst* constant; + switch (v->getOp()) + { + case kIROp_IntLit: + { + // TODO: range checking + const auto i = cast<IRIntLit>(v)->getValue(); + constant = emitIntConstant(i, constantType); + break; + } + case kIROp_StringLit: + SLANG_UNIMPLEMENTED_X("String constants in SPIR-V emit"); + default: SLANG_UNREACHABLE("Unhandled case in emitSPIRVAsm"); + } + emitOperand(constant); } - emitOperand(constant); - } - else - { - switch(v->getOp()) - { - case kIROp_StringLit: - emitOperand(SpvLiteralBits::fromUnownedStringSlice(v->getStringSlice())); - break; - case kIROp_IntLit: + else { - // TODO: range checking - const auto i = cast<IRIntLit>(v)->getValue(); - emitOperand(SpvLiteralInteger::from32(uint32_t(i))); - break; - } - default: - SLANG_UNREACHABLE("Unhandled case in emitSPIRVAsm"); + switch (v->getOp()) + { + case kIROp_StringLit: + emitOperand( + SpvLiteralBits::fromUnownedStringSlice(v->getStringSlice())); + break; + case kIROp_IntLit: + { + // TODO: range checking + const auto i = cast<IRIntLit>(v)->getValue(); + emitOperand(SpvLiteralInteger::from32(uint32_t(i))); + break; + } + default: SLANG_UNREACHABLE("Unhandled case in emitSPIRVAsm"); + } } + break; } - break; - } case kIROp_SPIRVAsmOperandInst: - { - const auto i = operand->getValue(); - emitOperand(ensureInst(i)); + { + const auto i = operand->getValue(); + emitOperand(ensureInst(i)); - break; - } + break; + } case kIROp_SPIRVAsmOperandResult: - { - SLANG_ASSERT(isLast); - emitOperand(kResultID); - break; - } + { + SLANG_ASSERT(isLast); + emitOperand(kResultID); + break; + } case kIROp_SPIRVAsmOperandId: - { - const auto idName = cast<IRStringLit>(operand->getValue())->getStringSlice(); - SpvWord id; - if(!idMap.tryGetValue(idName, id)) { - id = freshID(); - idMap.set(idName, id); + const auto idName = + cast<IRStringLit>(operand->getValue())->getStringSlice(); + SpvWord id; + if (!idMap.tryGetValue(idName, id)) + { + id = freshID(); + idMap.set(idName, id); + } + emitOperand(id); + break; } - emitOperand(id); - break; - } case kIROp_SPIRVAsmOperandSampledType: - { - // Make a 4 vector of the component type - IRBuilder builder(m_irModule); - const auto elementType = cast<IRType>(operand->getValue()); - const auto sampledType = builder.getVectorType(getSPIRVSampledElementType(getVectorElementType(elementType)), 4); - emitOperand(ensureInst(sampledType)); - break; - } + { + // Make a 4 vector of the component type + IRBuilder builder(m_irModule); + const auto elementType = cast<IRType>(operand->getValue()); + const auto sampledType = builder.getVectorType( + getSPIRVSampledElementType(getVectorElementType(elementType)), + 4); + emitOperand(ensureInst(sampledType)); + break; + } case kIROp_SPIRVAsmOperandImageType: case kIROp_SPIRVAsmOperandSampledImageType: - { - IRBuilder builder(m_irModule); - auto textureInst = as<IRTextureTypeBase>(operand->getValue()->getDataType()); - auto imageType = builder.getTextureType( - textureInst->getElementType(), - textureInst->getShapeInst(), - textureInst->getIsArrayInst(), - textureInst->getIsMultisampleInst(), - textureInst->getSampleCountInst(), - textureInst->getAccessInst(), - textureInst->getIsShadowInst(), - builder.getIntValue(builder.getIntType(), (operand->getOp() == kIROp_SPIRVAsmOperandSampledImageType ? 1 : 0)), - textureInst->getFormatInst()); - emitOperand(ensureInst(imageType)); - break; - } + { + IRBuilder builder(m_irModule); + auto textureInst = + as<IRTextureTypeBase>(operand->getValue()->getDataType()); + auto imageType = builder.getTextureType( + textureInst->getElementType(), + textureInst->getShapeInst(), + textureInst->getIsArrayInst(), + textureInst->getIsMultisampleInst(), + textureInst->getSampleCountInst(), + textureInst->getAccessInst(), + textureInst->getIsShadowInst(), + builder.getIntValue( + builder.getIntType(), + (operand->getOp() == kIROp_SPIRVAsmOperandSampledImageType ? 1 + : 0)), + textureInst->getFormatInst()); + emitOperand(ensureInst(imageType)); + break; + } case kIROp_SPIRVAsmOperandBuiltinVar: - { - emitOperand(ensureInst(operand)); - break; - } + { + emitOperand(ensureInst(operand)); + break; + } case kIROp_SPIRVAsmOperandGLSL450Set: - { - emitOperand(getGLSL450ExtInst()); - break; - } + { + emitOperand(getGLSL450ExtInst()); + break; + } case kIROp_SPIRVAsmOperandDebugPrintfSet: - { - emitOperand(getNonSemanticDebugPrintfExtInst()); - break; - } - default: - SLANG_UNREACHABLE("Unhandled case in emitSPIRVAsm"); + { + emitOperand(getNonSemanticDebugPrintfExtInst()); + break; + } + default: SLANG_UNREACHABLE("Unhandled case in emitSPIRVAsm"); } }; - if(spvInst->getOpcodeOperand()->getOp() == kIROp_SPIRVAsmOperandTruncate) + if (spvInst->getOpcodeOperand()->getOp() == kIROp_SPIRVAsmOperandTruncate) { - const auto getSlangType = [&](IRSPIRVAsmOperand* operand) -> IRType*{ - switch(operand->getOp()) + const auto getSlangType = [&](IRSPIRVAsmOperand* operand) -> IRType* + { + switch (operand->getOp()) { - case kIROp_SPIRVAsmOperandInst: - return cast<IRType>(operand->getValue()); + case kIROp_SPIRVAsmOperandInst: return cast<IRType>(operand->getValue()); case kIROp_SPIRVAsmOperandSampledType: { // Make a 4 vector of the component type @@ -6938,8 +7250,7 @@ struct SPIRVEmitContext case kIROp_SPIRVAsmOperandResult: case kIROp_SPIRVAsmOperandId: SLANG_UNEXPECTED("truncate should have been given slang types"); - default: - SLANG_UNREACHABLE("Unhandled case in emitSPIRVAsm"); + default: SLANG_UNREACHABLE("Unhandled case in emitSPIRVAsm"); } }; @@ -6953,22 +7264,26 @@ struct SPIRVEmitContext // If the component types are not the same, convert them to be so. if (!isTypeEqual(getVectorElementType(toType), fromElementType)) { - SpvOp convertOp = isIntegralType(fromElementType) ? (isSignedType(fromElementType) ? SpvOpSConvert : SpvOpUConvert) : SpvOpFConvert; - auto newFromType = replaceVectorElementType(fromType, getVectorElementType(toType)); + SpvOp convertOp = + isIntegralType(fromElementType) + ? (isSignedType(fromElementType) ? SpvOpSConvert : SpvOpUConvert) + : SpvOpFConvert; + auto newFromType = + replaceVectorElementType(fromType, getVectorElementType(toType)); fromSpvInst = emitInstCustomOperandFunc( parent, nullptr, convertOp, - [&]() { + [&]() + { emitOperand(newFromType); - emitOperand(kResultID), - emitSpvAsmOperand(fromIdOperand); + emitOperand(kResultID), emitSpvAsmOperand(fromIdOperand); }); } // If we don't need truncation, but a different result ID is // expected, then just unify them in the idMap - if(isTypeEqual(toType, fromType)) + if (isTypeEqual(toType, fromType)) { // TODO: if this is the last inst, we should just remove it // and rewrite the penultimate one @@ -6976,41 +7291,44 @@ struct SPIRVEmitContext parent, isLast ? as<IRInst>(inst) : spvInst, SpvOpCopyObject, - [&](){ + [&]() + { emitOperand(toType); emitSpvAsmOperand(toIdOperand); - fromSpvInst ? emitOperand(fromSpvInst) : emitSpvAsmOperand(fromIdOperand); - } - ); + fromSpvInst ? emitOperand(fromSpvInst) + : emitSpvAsmOperand(fromIdOperand); + }); } // Otherwise, if we are truncating to a scalar, extract the first element - else if(!as<IRVectorType>(toType)) + else if (!as<IRVectorType>(toType)) { last = emitInstCustomOperandFunc( parent, isLast ? as<IRInst>(inst) : spvInst, SpvOpCompositeExtract, - [&](){ + [&]() + { emitOperand(toType); emitSpvAsmOperand(toIdOperand); - fromSpvInst ? emitOperand(fromSpvInst) : emitSpvAsmOperand(fromIdOperand); + fromSpvInst ? emitOperand(fromSpvInst) + : emitSpvAsmOperand(fromIdOperand); emitOperand(SpvLiteralInteger::from32(0)); - } - ); + }); } // Otherwise, if we are truncating to a 1-vector from a scalar - else if(as<IRVectorType>(toType) && !as<IRVectorType>(fromType)) + else if (as<IRVectorType>(toType) && !as<IRVectorType>(fromType)) { last = emitInstCustomOperandFunc( parent, isLast ? as<IRInst>(inst) : spvInst, SpvOpCompositeConstruct, - [&](){ + [&]() + { emitOperand(toType); emitSpvAsmOperand(toIdOperand); - fromSpvInst ? emitOperand(fromSpvInst) : emitSpvAsmOperand(fromIdOperand); - } - ); + fromSpvInst ? emitOperand(fromSpvInst) + : emitSpvAsmOperand(fromIdOperand); + }); } // Otherwise, we are truncating a vector to a smaller vector else @@ -7019,21 +7337,22 @@ struct SPIRVEmitContext const auto toVectorSize = getIntVal(toVector->getElementCount()); const auto fromVector = cast<IRVectorType>(unwrapAttributedType(fromType)); const auto fromVectorSize = getIntVal(fromVector->getElementCount()); - if(toVectorSize > fromVectorSize) + if (toVectorSize > fromVectorSize) m_sink->diagnose(inst, Diagnostics::spirvInvalidTruncate); last = emitInstCustomOperandFunc( parent, isLast ? as<IRInst>(inst) : spvInst, SpvOpVectorShuffle, - [&](){ + [&]() + { emitOperand(toType); emitSpvAsmOperand(toIdOperand); - fromSpvInst ? emitOperand(fromSpvInst) : emitSpvAsmOperand(fromIdOperand); + fromSpvInst ? emitOperand(fromSpvInst) + : emitSpvAsmOperand(fromIdOperand); emitOperand(emitOpUndef(parent, nullptr, fromVector)); - for(Int32 i = 0; i < toVectorSize; ++i) + for (Int32 i = 0; i < toVectorSize; ++i) emitOperand(SpvLiteralInteger::from32(i)); - } - ); + }); } } else @@ -7043,36 +7362,44 @@ struct SPIRVEmitContext switch (opcode) { case SpvOpCapability: - requireSPIRVCapability((SpvCapability)getIntVal(spvInst->getOperand(1)->getOperand(0))); + requireSPIRVCapability( + (SpvCapability)getIntVal(spvInst->getOperand(1)->getOperand(0))); continue; case SpvOpExtension: - ensureExtensionDeclaration(as<IRStringLit>(spvInst->getOperand(1)->getOperand(0))->getStringSlice()); + ensureExtensionDeclaration( + as<IRStringLit>(spvInst->getOperand(1)->getOperand(0))->getStringSlice()); continue; case SpvOpExecutionMode: - { - if (auto refEntryPointSet = m_referencingEntryPoints.tryGetValue(getParentFunc(inst))) { - for (auto entryPoint : *refEntryPointSet) + if (auto refEntryPointSet = + m_referencingEntryPoints.tryGetValue(getParentFunc(inst))) { - emitInstMemoizedNoResultIDCustomOperandFunc(getSection(SpvLogicalSectionID::ExecutionModes), nullptr, SpvOpExecutionMode, - [&]() { - emitOperand(entryPoint); - for (UInt s = 2; s < spvInst->getOperandCount(); s++) - emitSpvAsmOperand(as<IRSPIRVAsmOperand>(spvInst->getOperand(s))); - }); + for (auto entryPoint : *refEntryPointSet) + { + emitInstMemoizedNoResultIDCustomOperandFunc( + getSection(SpvLogicalSectionID::ExecutionModes), + nullptr, + SpvOpExecutionMode, + [&]() + { + emitOperand(entryPoint); + for (UInt s = 2; s < spvInst->getOperandCount(); s++) + emitSpvAsmOperand( + as<IRSPIRVAsmOperand>(spvInst->getOperand(s))); + }); + } } + continue; } - continue; - } - default: - break; + default: break; } const auto opParent = parentForOpCode(opcode, parent); const auto opInfo = m_grammarInfo->opInfos.lookup(opcode); // TODO: handle resultIdIndex == 1, for constants - const bool memoize = opParent == getSection(SpvLogicalSectionID::ConstantsAndTypes) - && opInfo && opInfo->resultIdIndex == 0; + const bool memoize = + opParent == getSection(SpvLogicalSectionID::ConstantsAndTypes) && opInfo && + opInfo->resultIdIndex == 0; // We want the "result instruction" to refer to the top level // block which assumes its value, the others are free to refer @@ -7081,21 +7408,22 @@ struct SPIRVEmitContext // assigned to result is not necessarily the last instruction const auto assignedInst = isLast ? as<IRInst>(inst) : spvInst; - if(memoize) + if (memoize) { last = emitInstMemoizedCustomOperandFunc( opParent, assignedInst, opcode, kResultID, - [&](){ + [&]() + { Index i = 0; - for(const auto operand : spvInst->getSPIRVOperands()) { - if(i++ != 0) + for (const auto operand : spvInst->getSPIRVOperands()) + { + if (i++ != 0) emitSpvAsmOperand(operand); }; - } - ); + }); // The result operand is the one at index 1, after the // opcode itself. @@ -7105,7 +7433,7 @@ struct SPIRVEmitContext // memoized instructions is that they come before their // uses. const auto resOperand = cast<IRSPIRVAsmOperand>(spvInst->getOperand(1)); - if(resOperand->getOp() == kIROp_SPIRVAsmOperandId) + if (resOperand->getOp() == kIROp_SPIRVAsmOperandId) { const auto idName = cast<IRStringLit>(resOperand->getValue())->getStringSlice(); @@ -7118,16 +7446,16 @@ struct SPIRVEmitContext opParent, assignedInst, opcode, - [&](){ - for(const auto operand : spvInst->getSPIRVOperands()) + [&]() + { + for (const auto operand : spvInst->getSPIRVOperands()) emitSpvAsmOperand(operand); - } - ); + }); } } } - for(const auto& [name, id] : idMap) + for (const auto& [name, id] : idMap) emitOpName(getSection(SpvLogicalSectionID::DebugNames), nullptr, id, name); return last; @@ -7138,18 +7466,18 @@ struct SPIRVEmitContext { if (m_capabilities.add(capability)) { - emitOpCapability( - getSection(SpvLogicalSectionID::Capabilities), - nullptr, - capability - ); + emitOpCapability(getSection(SpvLogicalSectionID::Capabilities), nullptr, capability); } } // https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpExecutionMode Dictionary<SpvWord, OrderedHashSet<SpvExecutionMode>> m_executionModes; template<typename... Operands> - void requireSPIRVExecutionMode(IRInst* parentInst, SpvWord entryPoint, SpvExecutionMode executionMode, const Operands& ...ops) + void requireSPIRVExecutionMode( + IRInst* parentInst, + SpvWord entryPoint, + SpvExecutionMode executionMode, + const Operands&... ops) { if (m_executionModes[entryPoint].add(executionMode)) { @@ -7159,24 +7487,21 @@ struct SPIRVEmitContext SpvOpExecutionMode, entryPoint, executionMode, - ops... - ); + ops...); } - } + } SPIRVEmitContext(IRModule* module, TargetProgram* program, DiagnosticSink* sink) - : SPIRVEmitSharedContext(module, program, sink) - , m_irModule(module) - , m_memoryArena(2048) + : SPIRVEmitSharedContext(module, program, sink), m_irModule(module), m_memoryArena(2048) { } }; SlangResult emitSPIRVFromIR( - CodeGenContext* codeGenContext, - IRModule* irModule, - const List<IRFunc*>& irEntryPoints, - List<uint8_t>& spirvOut) + CodeGenContext* codeGenContext, + IRModule* irModule, + const List<IRFunc*>& irEntryPoints, + List<uint8_t>& spirvOut) { spirvOut.clear(); @@ -7196,7 +7521,7 @@ SlangResult emitSPIRVFromIR( SPIRVEmitContext context(irModule, codeGenContext->getTargetProgram(), sink); legalizeIRForSPIRV(&context, irModule, irEntryPoints, codeGenContext); - + #if 0 { DiagnosticSinkWriter writer(codeGenContext->getSink()); @@ -7209,8 +7534,10 @@ SlangResult emitSPIRVFromIR( } #endif - auto shouldPreserveParams = codeGenContext->getTargetProgram()->getOptionSet().getBoolOption(CompilerOptionName::PreserveParameters); - auto generateWholeProgram = codeGenContext->getTargetProgram()->getOptionSet().getBoolOption(CompilerOptionName::GenerateWholeProgram); + auto shouldPreserveParams = codeGenContext->getTargetProgram()->getOptionSet().getBoolOption( + CompilerOptionName::PreserveParameters); + auto generateWholeProgram = codeGenContext->getTargetProgram()->getOptionSet().getBoolOption( + CompilerOptionName::GenerateWholeProgram); for (auto inst : irModule->getGlobalInsts()) { if (as<IRDebugSource>(inst)) @@ -7240,13 +7567,19 @@ SlangResult emitSPIRVFromIR( // environment variable that will be set in the software testing environment. auto sourceLanguage = SpvSourceLanguageSlang; StringBuilder noSlangEnv; - PlatformUtil::getEnvironmentVariable(toSlice("SLANG_USE_SPV_SOURCE_LANGUAGE_UNKNOWN"), noSlangEnv); + PlatformUtil::getEnvironmentVariable( + toSlice("SLANG_USE_SPV_SOURCE_LANGUAGE_UNKNOWN"), + noSlangEnv); if (noSlangEnv.produceString() == "1") { sourceLanguage = SpvSourceLanguageUnknown; } - context.emitInst(context.getSection(SpvLogicalSectionID::DebugStringsAndSource), nullptr, SpvOpSource, - SpvLiteralInteger::from32(sourceLanguage), // language identifier, should be SpvSourceLanguageSlang. + context.emitInst( + context.getSection(SpvLogicalSectionID::DebugStringsAndSource), + nullptr, + SpvOpSource, + SpvLiteralInteger::from32( + sourceLanguage), // language identifier, should be SpvSourceLanguageSlang. SpvLiteralInteger::from32(1)); // language version. for (auto irEntryPoint : irEntryPoints) @@ -7279,7 +7612,7 @@ SlangResult emitSPIRVFromIR( context.emitPhysicalLayout(); spirvOut.addRange( - (uint8_t const*) context.m_words.getBuffer(), + (uint8_t const*)context.m_words.getBuffer(), context.m_words.getCount() * Index(sizeof(context.m_words[0]))); return SLANG_OK; |
