Check for spv language version

When checking for capabilities in SPIR-V,
`capabilities_available == None` indicates that all capabilities are
available. However, some capabilities are not even defined for all
language versions, so we still need to check if the requested
capabilities even exist in the language version we're using.
This commit is contained in:
Robert Bamler
2025-04-19 00:43:12 +02:00
committed by Teodor Tanasoaia
parent 2271480f17
commit 065d6546c4
6 changed files with 117 additions and 36 deletions

View File

@@ -1143,13 +1143,14 @@ impl BlockContext<'_> {
),
},
fun @ (Mf::Dot4I8Packed | Mf::Dot4U8Packed) => {
if self
.writer
.require_all(&[
spirv::Capability::DotProduct,
spirv::Capability::DotProductInput4x8BitPacked,
])
.is_ok()
if self.writer.lang_version() >= (1, 6)
&& self
.writer
.require_all(&[
spirv::Capability::DotProduct,
spirv::Capability::DotProductInput4x8BitPacked,
])
.is_ok()
{
// Write optimized code using `PackedVectorFormat4x8Bit`.
self.writer.use_extension("SPV_KHR_integer_dot_product");

View File

@@ -12,7 +12,8 @@ use alloc::format;
const GENERATOR: Word = 28;
impl PhysicalLayout {
pub(super) const fn new(version: Word) -> Self {
pub(super) const fn new(major_version: u8, minor_version: u8) -> Self {
let version = ((major_version as u32) << 16) | ((minor_version as u32) << 8);
PhysicalLayout {
magic_number: MAGIC_NUMBER,
version,
@@ -29,6 +30,13 @@ impl PhysicalLayout {
sink.extend(iter::once(self.bound));
sink.extend(iter::once(self.instruction_schema));
}
/// Returns `(major, minor)`.
pub(super) const fn lang_version(&self) -> (u8, u8) {
let major = (self.version >> 16) as u8;
let minor = (self.version >> 8) as u8;
(major, minor)
}
}
impl super::recyclable::Recyclable for PhysicalLayout {
@@ -150,10 +158,13 @@ impl Instruction {
#[test]
fn test_physical_layout_in_words() {
let bound = 5;
let version = 0x10203;
// The least and most significant bytes of `version` must both be zero
// according to the SPIR-V spec.
let version = 0x0001_0200;
let mut output = vec![];
let mut layout = PhysicalLayout::new(version);
let mut layout = PhysicalLayout::new(1, 2);
layout.bound = bound;
layout.in_words(&mut output);

View File

@@ -60,7 +60,6 @@ impl Writer {
if major != 1 {
return Err(Error::UnsupportedVersion(major, minor));
}
let raw_version = ((major as u32) << 16) | ((minor as u32) << 8);
let mut capabilities_used = crate::FastIndexSet::default();
capabilities_used.insert(spirv::Capability::Shader);
@@ -70,7 +69,7 @@ impl Writer {
let void_type = id_gen.next();
Ok(Writer {
physical_layout: PhysicalLayout::new(raw_version),
physical_layout: PhysicalLayout::new(major, minor),
logical_layout: LogicalLayout::default(),
id_gen,
capabilities_available: options.capabilities.clone(),
@@ -99,6 +98,11 @@ impl Writer {
})
}
/// Returns `(major, minor)` of the SPIR-V language version.
pub const fn lang_version(&self) -> (u8, u8) {
self.physical_layout.lang_version()
}
/// Reset `Writer` to its initial state, retaining any allocations.
///
/// Why not just implement `Recyclable` for `Writer`? By design,

View File

@@ -5,6 +5,7 @@ targets = "SPIRV | HLSL"
[spv]
capabilities = ["DotProduct", "DotProductInput4x8BitPacked"]
version = [1, 6]
[hlsl]
shader_model = "V6_4"

View File

@@ -1,5 +1,5 @@
; SPIR-V
; Version: 1.1
; Version: 1.6
; Generator: rspirv
; Bound: 30
OpCapability Shader

View File

@@ -1,15 +1,12 @@
; SPIR-V
; Version: 1.1
; Generator: rspirv
; Bound: 95
; Bound: 162
OpCapability Shader
OpCapability DotProductKHR
OpCapability DotProductInput4x8BitPackedKHR
OpExtension "SPV_KHR_integer_dot_product"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %89 "main"
OpExecutionMode %89 LocalSize 1 1 1
OpEntryPoint GLCompute %156 "main"
OpExecutionMode %156 LocalSize 1 1 1
%2 = OpTypeVoid
%4 = OpTypeFloat 32
%3 = OpTypeVector %4 2
@@ -42,7 +39,10 @@ OpExecutionMode %89 LocalSize 1 1 1
%76 = OpConstant %6 6
%77 = OpConstant %6 7
%78 = OpConstant %6 8
%90 = OpTypeFunction %2
%83 = OpConstant %6 0
%84 = OpConstant %6 16
%85 = OpConstant %6 24
%157 = OpTypeFunction %2
%8 = OpFunction %3 None %9
%7 = OpLabel
OpBranch %14
@@ -96,22 +96,86 @@ OpFunctionEnd
%69 = OpLabel
OpBranch %79
%79 = OpLabel
%80 = OpSDotKHR %5 %22 %72 PackedVectorFormat4x8BitKHR
%81 = OpUDotKHR %6 %73 %74 PackedVectorFormat4x8BitKHR
%82 = OpIAdd %6 %75 %81
%83 = OpIAdd %6 %76 %81
%84 = OpSDotKHR %5 %82 %83 PackedVectorFormat4x8BitKHR
%85 = OpIAdd %6 %77 %81
%86 = OpIAdd %6 %78 %81
%87 = OpUDotKHR %6 %85 %86 PackedVectorFormat4x8BitKHR
OpReturnValue %87
%81 = OpBitcast %5 %22
%82 = OpBitcast %5 %72
%86 = OpBitFieldSExtract %5 %81 %83 %78
%87 = OpBitFieldSExtract %5 %82 %83 %78
%88 = OpIMul %5 %86 %87
%89 = OpIAdd %5 %32 %88
%90 = OpBitFieldSExtract %5 %81 %78 %78
%91 = OpBitFieldSExtract %5 %82 %78 %78
%92 = OpIMul %5 %90 %91
%93 = OpIAdd %5 %89 %92
%94 = OpBitFieldSExtract %5 %81 %84 %78
%95 = OpBitFieldSExtract %5 %82 %84 %78
%96 = OpIMul %5 %94 %95
%97 = OpIAdd %5 %93 %96
%98 = OpBitFieldSExtract %5 %81 %85 %78
%99 = OpBitFieldSExtract %5 %82 %85 %78
%100 = OpIMul %5 %98 %99
%80 = OpIAdd %5 %97 %100
%102 = OpBitFieldUExtract %6 %73 %83 %78
%103 = OpBitFieldUExtract %6 %74 %83 %78
%104 = OpIMul %6 %102 %103
%105 = OpIAdd %6 %41 %104
%106 = OpBitFieldUExtract %6 %73 %78 %78
%107 = OpBitFieldUExtract %6 %74 %78 %78
%108 = OpIMul %6 %106 %107
%109 = OpIAdd %6 %105 %108
%110 = OpBitFieldUExtract %6 %73 %84 %78
%111 = OpBitFieldUExtract %6 %74 %84 %78
%112 = OpIMul %6 %110 %111
%113 = OpIAdd %6 %109 %112
%114 = OpBitFieldUExtract %6 %73 %85 %78
%115 = OpBitFieldUExtract %6 %74 %85 %78
%116 = OpIMul %6 %114 %115
%101 = OpIAdd %6 %113 %116
%117 = OpIAdd %6 %75 %101
%118 = OpIAdd %6 %76 %101
%120 = OpBitcast %5 %117
%121 = OpBitcast %5 %118
%122 = OpBitFieldSExtract %5 %120 %83 %78
%123 = OpBitFieldSExtract %5 %121 %83 %78
%124 = OpIMul %5 %122 %123
%125 = OpIAdd %5 %32 %124
%126 = OpBitFieldSExtract %5 %120 %78 %78
%127 = OpBitFieldSExtract %5 %121 %78 %78
%128 = OpIMul %5 %126 %127
%129 = OpIAdd %5 %125 %128
%130 = OpBitFieldSExtract %5 %120 %84 %78
%131 = OpBitFieldSExtract %5 %121 %84 %78
%132 = OpIMul %5 %130 %131
%133 = OpIAdd %5 %129 %132
%134 = OpBitFieldSExtract %5 %120 %85 %78
%135 = OpBitFieldSExtract %5 %121 %85 %78
%136 = OpIMul %5 %134 %135
%119 = OpIAdd %5 %133 %136
%137 = OpIAdd %6 %77 %101
%138 = OpIAdd %6 %78 %101
%140 = OpBitFieldUExtract %6 %137 %83 %78
%141 = OpBitFieldUExtract %6 %138 %83 %78
%142 = OpIMul %6 %140 %141
%143 = OpIAdd %6 %41 %142
%144 = OpBitFieldUExtract %6 %137 %78 %78
%145 = OpBitFieldUExtract %6 %138 %78 %78
%146 = OpIMul %6 %144 %145
%147 = OpIAdd %6 %143 %146
%148 = OpBitFieldUExtract %6 %137 %84 %78
%149 = OpBitFieldUExtract %6 %138 %84 %78
%150 = OpIMul %6 %148 %149
%151 = OpIAdd %6 %147 %150
%152 = OpBitFieldUExtract %6 %137 %85 %78
%153 = OpBitFieldUExtract %6 %138 %85 %78
%154 = OpIMul %6 %152 %153
%139 = OpIAdd %6 %151 %154
OpReturnValue %139
OpFunctionEnd
%89 = OpFunction %2 None %90
%88 = OpLabel
OpBranch %91
%91 = OpLabel
%92 = OpFunctionCall %3 %8
%93 = OpFunctionCall %5 %17
%94 = OpFunctionCall %6 %70
%156 = OpFunction %2 None %157
%155 = OpLabel
OpBranch %158
%158 = OpLabel
%159 = OpFunctionCall %3 %8
%160 = OpFunctionCall %5 %17
%161 = OpFunctionCall %6 %70
OpReturn
OpFunctionEnd