diff options
| -rw-r--r-- | docs/language-reference/08-attributes.md | 26 | ||||
| -rw-r--r-- | source/slang/core.meta.slang | 3 | ||||
| -rw-r--r-- | source/slang/slang-ast-modifier.h | 5 | ||||
| -rw-r--r-- | source/slang/slang-check-modifier.cpp | 3 | ||||
| -rw-r--r-- | source/slang/slang-emit-glsl.cpp | 2 | ||||
| -rw-r--r-- | source/slang/slang-ir-glsl-liveness.cpp | 10 | ||||
| -rw-r--r-- | source/slang/slang-lower-to-ir.cpp | 6 | ||||
| -rw-r--r-- | tests/spirv/spirv-instruction.slang | 17 | ||||
| -rw-r--r-- | tests/spirv/spirv-instruction.slang.expected.txt | 4 |
9 files changed, 70 insertions, 6 deletions
diff --git a/docs/language-reference/08-attributes.md b/docs/language-reference/08-attributes.md index 4098303cf..76a739315 100644 --- a/docs/language-reference/08-attributes.md +++ b/docs/language-reference/08-attributes.md @@ -2,3 +2,29 @@ Attributes ========== > Note: This section is not yet complete. + +## [[vk::spirv_instruction]] + +** SPIR-V only ** + +This attribute is only available for Vulkan SPIR-V output via GLSLANG. In the future it could be supported via the `direct-spirv` option. The attribute will be ignored for any other target. This attribute requires the `GL_EXT_spirv_intrinsics` GLSL extension. + +The attibute allows access to SPIR-V intrinsics, by supplying a function declaration with the appropriate signature for the SPIR-V op and no body. The intrinsic takes a single parameter which is the integer value for the SPIR-V op. + +In the example below the add function, uses the mechanism to directly use the SPIR-V integer add 'op' which is 128 in this case. + +```HLSL +// 128 is OpIAdd in SPIR-V +[[vk::spirv_instruction(128)]] +uint add(uint a, uint b); + +RWStructuredBuffer<uint> resultBuffer; + +[numthreads(4,1,1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + uint threadId = dispatchThreadID.x; + resultBuffer[threadId] = add(threadId, threadId); +} +``` + diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang index 9a09196c5..476e88e3f 100644 --- a/source/slang/core.meta.slang +++ b/source/slang/core.meta.slang @@ -2059,6 +2059,9 @@ attribute_syntax [vk_location(locaiton : int)] : GLSLLocationAttribute; __attributeTarget(VarDeclBase) attribute_syntax [vk_index(index : int)] : GLSLIndexAttribute; +__attributeTarget(FuncDecl) +attribute_syntax [vk_spirv_instruction(op : int)] : SPIRVInstructionOpAttribute; + // Statement Attributes __attributeTarget(LoopStmt) diff --git a/source/slang/slang-ast-modifier.h b/source/slang/slang-ast-modifier.h index a8185e06e..4522b7148 100644 --- a/source/slang/slang-ast-modifier.h +++ b/source/slang/slang-ast-modifier.h @@ -671,6 +671,11 @@ class GLSLIndexAttribute : public GLSLSimpleIntegerLayoutAttribute SLANG_AST_CLASS(GLSLIndexAttribute) }; +// [[vk_spirv_instruction]] +class SPIRVInstructionOpAttribute : public Attribute +{ + SLANG_AST_CLASS(SPIRVInstructionOpAttribute) +}; // TODO: for attributes that take arguments, the syntax node // classes should provide accessors for the values of those arguments. diff --git a/source/slang/slang-check-modifier.cpp b/source/slang/slang-check-modifier.cpp index 320b980e9..1d9e30c95 100644 --- a/source/slang/slang-check-modifier.cpp +++ b/source/slang/slang-check-modifier.cpp @@ -398,7 +398,8 @@ namespace Slang getSink()->diagnose(attr, Diagnostics::expectedSingleStringArg, attr->keywordName); } } - else if (as<OutputControlPointsAttribute>(attr)) + else if (as<OutputControlPointsAttribute>(attr) || + as<SPIRVInstructionOpAttribute>(attr)) { // Let it go thru iff single integral attribute if (!hasIntArgs(attr, 1)) diff --git a/source/slang/slang-emit-glsl.cpp b/source/slang/slang-emit-glsl.cpp index d9c81f14b..c1bbf813b 100644 --- a/source/slang/slang-emit-glsl.cpp +++ b/source/slang/slang-emit-glsl.cpp @@ -1881,6 +1881,8 @@ void GLSLSourceEmitter::emitFuncDecorationImpl(IRDecoration* decoration) { if (decoration->getOp() == kIROp_SPIRVOpDecoration) { + m_glslExtensionTracker->requireExtension(UnownedStringSlice::fromLiteral("GL_EXT_spirv_intrinsics")); + m_writer->emit("spirv_instruction(id = "); emitSimpleValue(decoration->getOperand(0)); m_writer->emit(")\n"); diff --git a/source/slang/slang-ir-glsl-liveness.cpp b/source/slang/slang-ir-glsl-liveness.cpp index 3cfde0246..d5448a788 100644 --- a/source/slang/slang-ir-glsl-liveness.cpp +++ b/source/slang/slang-ir-glsl-liveness.cpp @@ -60,7 +60,6 @@ struct GLSLLivenessContext Entry m_entries[Index(Kind::CountOf)]; /// Entry for each kind of function - IRStringLit* m_extensionStringLiteral = nullptr; ///< The string literal holding the SPIR-V extension needed IRInst* m_zeroIntLiteral = nullptr; ///< Zero value literal IRType* m_spirvIntLiteralType = nullptr; ///< Int type that emits as `spirv_literal` @@ -92,9 +91,8 @@ void GLSLLivenessContext::_addDecorations(Kind kind, IRFunc* func) // // m_builder.addTargetDecoration(); - // We need the spirv extension - m_builder.addDecoration(func, kIROp_RequireGLSLExtensionDecoration, m_extensionStringLiteral); - + // We don't need to explictly add the "GL_EXT_spirv_intrinsics" + // as it will be added on the GLSL emit, with the SPIRVOpDecoration is hit const auto& entry = m_entries[Index(kind)]; if (entry.m_nameHintLiteral) { @@ -207,8 +205,10 @@ void GLSLLivenessContext::processModule() // Zero value literal m_zeroIntLiteral = m_builder.getIntValue(m_builder.getIntType(), 0); + // We don't need to explicitly add this decoration because it will be added as needed on GLSL emit + // m_extensionStringLiteral = m_builder.getStringValue(UnownedStringSlice::fromLiteral("GL_EXT_spirv_intrinsics")); + // Set up some values that will be needed on instructions - m_extensionStringLiteral = m_builder.getStringValue(UnownedStringSlice::fromLiteral("GL_EXT_spirv_intrinsics")); // The op values are from the SPIR-V spec // https://www.khronos.org/registry/SPIR-V/specs/unified1/SPIRV.html#OpLifetimeStart diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp index 585b02a02..4ff43b697 100644 --- a/source/slang/slang-lower-to-ir.cpp +++ b/source/slang/slang-lower-to-ir.cpp @@ -7517,6 +7517,12 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> getBuilder()->addDecoration(irFunc, kIROp_OutputControlPointsDecoration, intLit); } + if (auto attr = decl->findModifier<SPIRVInstructionOpAttribute>()) + { + IRIntLit* intLit = _getIntLitFromAttribute(getBuilder(), attr); + getBuilder()->addDecoration(irFunc, kIROp_SPIRVOpDecoration, intLit); + } + if(decl->findModifier<UnsafeForceInlineEarlyAttribute>()) { getBuilder()->addDecoration(irFunc, kIROp_UnsafeForceInlineEarlyDecoration); diff --git a/tests/spirv/spirv-instruction.slang b/tests/spirv/spirv-instruction.slang new file mode 100644 index 000000000..1f85479f9 --- /dev/null +++ b/tests/spirv/spirv-instruction.slang @@ -0,0 +1,17 @@ +// spirv-instruction.slang +//TEST(compute, vulkan):COMPARE_COMPUTE_EX:-vk -compute + +// Test using a spirv op. 128 is SpvOpIAdd + +[[vk::spirv_instruction(128)]] +uint add(uint a, uint b); + +//TEST_INPUT:set resultBuffer = out ubuffer(data=[0 0 0 0], stride=4) +RWStructuredBuffer<uint> resultBuffer; + +[numthreads(4,1,1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + uint threadId = dispatchThreadID.x; + resultBuffer[threadId] = add(threadId, threadId); +} diff --git a/tests/spirv/spirv-instruction.slang.expected.txt b/tests/spirv/spirv-instruction.slang.expected.txt new file mode 100644 index 000000000..e1e8ccec4 --- /dev/null +++ b/tests/spirv/spirv-instruction.slang.expected.txt @@ -0,0 +1,4 @@ +0 +2 +4 +6 |
