spirv-val: Validate PhysicalStorageBuffer Align are large enough (#6266)
* spirv-val: Validate PhysicalStorageBuffer Align are large enough
* spirv-val: Move pointer to GetBitWidth
* spirv-val: Add UntypedPointer test
* spirv-val: Add Untyped PSB test
diff --git a/source/val/validate_memory.cpp b/source/val/validate_memory.cpp
index 37673df..7dbd9f9 100644
--- a/source/val/validate_memory.cpp
+++ b/source/val/validate_memory.cpp
@@ -196,10 +196,10 @@
return false;
}
-std::pair<spv::StorageClass, spv::StorageClass> GetStorageClass(
- ValidationState_t& _, const Instruction* inst) {
- spv::StorageClass dst_sc = spv::StorageClass::Max;
- spv::StorageClass src_sc = spv::StorageClass::Max;
+std::pair<Instruction*, Instruction*> GetPointerTypes(ValidationState_t& _,
+ const Instruction* inst) {
+ Instruction* dst_pointer_type = nullptr;
+ Instruction* src_pointer_type = nullptr;
switch (inst->opcode()) {
case spv::Op::OpCooperativeMatrixLoadNV:
case spv::Op::OpCooperativeMatrixLoadTensorNV:
@@ -207,8 +207,7 @@
case spv::Op::OpCooperativeVectorLoadNV:
case spv::Op::OpLoad: {
auto load_pointer = _.FindDef(inst->GetOperandAs<uint32_t>(2));
- auto load_pointer_type = _.FindDef(load_pointer->type_id());
- dst_sc = load_pointer_type->GetOperandAs<spv::StorageClass>(1);
+ dst_pointer_type = _.FindDef(load_pointer->type_id());
break;
}
case spv::Op::OpCooperativeMatrixStoreNV:
@@ -217,25 +216,23 @@
case spv::Op::OpCooperativeVectorStoreNV:
case spv::Op::OpStore: {
auto store_pointer = _.FindDef(inst->GetOperandAs<uint32_t>(0));
- auto store_pointer_type = _.FindDef(store_pointer->type_id());
- dst_sc = store_pointer_type->GetOperandAs<spv::StorageClass>(1);
+ dst_pointer_type = _.FindDef(store_pointer->type_id());
break;
}
+ // Spec: "Matching Storage Class is not required"
case spv::Op::OpCopyMemory:
case spv::Op::OpCopyMemorySized: {
- auto dst = _.FindDef(inst->GetOperandAs<uint32_t>(0));
- auto dst_type = _.FindDef(dst->type_id());
- dst_sc = dst_type->GetOperandAs<spv::StorageClass>(1);
- auto src = _.FindDef(inst->GetOperandAs<uint32_t>(1));
- auto src_type = _.FindDef(src->type_id());
- src_sc = src_type->GetOperandAs<spv::StorageClass>(1);
+ auto dst_pointer = _.FindDef(inst->GetOperandAs<uint32_t>(0));
+ dst_pointer_type = _.FindDef(dst_pointer->type_id());
+ auto src_pointer = _.FindDef(inst->GetOperandAs<uint32_t>(1));
+ src_pointer_type = _.FindDef(src_pointer->type_id());
break;
}
default:
break;
}
- return std::make_pair(dst_sc, src_sc);
+ return std::make_pair(dst_pointer_type, src_pointer_type);
}
// Returns the number of instruction words taken up by a memory access
@@ -288,8 +285,17 @@
spv_result_t CheckMemoryAccess(ValidationState_t& _, const Instruction* inst,
uint32_t index) {
- spv::StorageClass dst_sc, src_sc;
- std::tie(dst_sc, src_sc) = GetStorageClass(_, inst);
+ Instruction* dst_pointer_type = nullptr;
+ Instruction* src_pointer_type = nullptr; // only used for OpCopyMemory
+ std::tie(dst_pointer_type, src_pointer_type) = GetPointerTypes(_, inst);
+
+ const spv::StorageClass dst_sc =
+ dst_pointer_type ? dst_pointer_type->GetOperandAs<spv::StorageClass>(1)
+ : spv::StorageClass::Max;
+ const spv::StorageClass src_sc =
+ src_pointer_type ? src_pointer_type->GetOperandAs<spv::StorageClass>(1)
+ : spv::StorageClass::Max;
+
if (inst->operands().size() <= index) {
// Cases where lack of some operand is invalid
if (src_sc == spv::StorageClass::PhysicalStorageBuffer ||
@@ -390,6 +396,23 @@
<< "Memory accesses Aligned operand value " << aligned_value
<< " is not a power of two.";
}
+
+ uint32_t largest_scalar = 0;
+ if (dst_sc == spv::StorageClass::PhysicalStorageBuffer) {
+ largest_scalar =
+ _.GetLargestScalarType(dst_pointer_type->GetOperandAs<uint32_t>(2));
+ }
+ if (src_sc == spv::StorageClass::PhysicalStorageBuffer) {
+ largest_scalar = std::max(
+ largest_scalar,
+ _.GetLargestScalarType(src_pointer_type->GetOperandAs<uint32_t>(2)));
+ }
+ if (aligned_value < largest_scalar) {
+ return _.diag(SPV_ERROR_INVALID_ID, inst)
+ << _.VkErrorID(6314) << "Memory accesses Aligned operand value "
+ << aligned_value << " is too small, the largest scalar type is "
+ << largest_scalar << " bytes.";
+ }
}
return SPV_SUCCESS;
diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp
index 132e4c5..37e7c16 100644
--- a/source/val/validation_state.cpp
+++ b/source/val/validation_state.cpp
@@ -903,6 +903,8 @@
case spv::Op::OpTypeFloat:
case spv::Op::OpTypeInt:
case spv::Op::OpTypeBool:
+ case spv::Op::OpTypePointer:
+ case spv::Op::OpTypeUntypedPointerKHR:
return id;
case spv::Op::OpTypeArray:
@@ -968,11 +970,20 @@
const Instruction* inst = FindDef(component_type_id);
assert(inst);
- if (inst->opcode() == spv::Op::OpTypeFloat ||
- inst->opcode() == spv::Op::OpTypeInt)
- return inst->word(2);
-
- if (inst->opcode() == spv::Op::OpTypeBool) return 1;
+ switch (inst->opcode()) {
+ case spv::Op::OpTypeFloat:
+ case spv::Op::OpTypeInt:
+ return inst->word(2);
+ case spv::Op::OpTypeBool:
+ return 1;
+ case spv::Op::OpTypePointer:
+ case spv::Op::OpTypeUntypedPointerKHR:
+ assert(inst->GetOperandAs<spv::StorageClass>(1) ==
+ spv::StorageClass::PhysicalStorageBuffer);
+ return 64; // all pointers to another PSB is 64-bit
+ default:
+ break;
+ }
assert(0);
return 0;
@@ -1370,6 +1381,27 @@
return true;
}
+uint32_t ValidationState_t::GetLargestScalarType(uint32_t id) const {
+ const Instruction* inst = FindDef(id);
+ uint32_t size = 0;
+
+ switch (inst->opcode()) {
+ case spv::Op::OpTypeStruct:
+ for (uint32_t i = 1; i < inst->operands().size(); ++i) {
+ const uint32_t member_size =
+ GetLargestScalarType(inst->GetOperandAs<uint32_t>(i));
+ size = std::max(size, member_size);
+ }
+ break;
+ default:
+ const uint32_t bytes = GetBitWidth(id) / 8;
+ size = std::max(size, bytes);
+ break;
+ }
+
+ return size;
+}
+
bool ValidationState_t::IsAccelerationStructureType(uint32_t id) const {
const Instruction* inst = FindDef(id);
return inst && inst->opcode() == spv::Op::OpTypeAccelerationStructureKHR;
@@ -2569,6 +2601,8 @@
return VUID_WRAP(VUID-StandaloneSpirv-Flat-06202);
case 6214:
return VUID_WRAP(VUID-StandaloneSpirv-OpTypeImage-06214);
+ case 6314:
+ return VUID_WRAP(VUID-StandaloneSpirv-PhysicalStorageBuffer64-06314);
case 6491:
return VUID_WRAP(VUID-StandaloneSpirv-DescriptorSet-06491);
case 6671:
diff --git a/source/val/validation_state.h b/source/val/validation_state.h
index 6047fbb..7305f26 100644
--- a/source/val/validation_state.h
+++ b/source/val/validation_state.h
@@ -731,6 +731,12 @@
/* traverse_all_types = */ false);
}
+ // Will walk the type to find the largest scalar value size.
+ // Returns value is in bytes.
+ // This is designed to pass in the %type from a PSB pointer
+ // %ptr = OpTypePointer PhysicalStorageBuffer %type
+ uint32_t GetLargestScalarType(uint32_t id) const;
+
// Returns true if |id| is a type id that contains |type| (or integer or
// floating point type) of |width| bits.
bool ContainsSizedIntOrFloatType(uint32_t id, spv::Op type,
diff --git a/test/val/val_memory_test.cpp b/test/val/val_memory_test.cpp
index d278776..0f5210e 100644
--- a/test/val/val_memory_test.cpp
+++ b/test/val/val_memory_test.cpp
@@ -1890,7 +1890,6 @@
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpDecorate %val1 AliasedPointer
-%int = OpTypeInt 32 0
%uint64 = OpTypeInt 64 0
%u64_1 = OpConstant %uint64 1
%ptr = OpTypePointer PhysicalStorageBuffer %uint64
@@ -1902,8 +1901,8 @@
%val1 = OpVariable %pptr_f Function
%val2 = OpLoad %ptr %val1
%val3 = OpLoad %ptr %val1
-OpCopyMemory %val2 %val3 Aligned 4
-OpCopyMemory %val3 %val2 Aligned 4 Aligned 4
+OpCopyMemory %val2 %val3 Aligned 8
+OpCopyMemory %val3 %val2 Aligned 8 Aligned 8
OpReturn
OpFunctionEnd
)";
@@ -1922,7 +1921,6 @@
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpDecorate %val1 AliasedPointer
-%int = OpTypeInt 32 0
%uint64 = OpTypeInt 64 0
%u64_1 = OpConstant %uint64 1
%ptr = OpTypePointer PhysicalStorageBuffer %uint64
@@ -1934,7 +1932,7 @@
%val1 = OpVariable %pptr_f Function
%val2 = OpLoad %ptr %val1
%val3 = OpLoad %ptr %val1
-OpCopyMemory %val2 %val3 Volatile Aligned 4
+OpCopyMemory %val2 %val3 Volatile Aligned 8
OpReturn
OpFunctionEnd
)";
@@ -1958,7 +1956,6 @@
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpDecorate %val1 AliasedPointer
-%int = OpTypeInt 32 0
%uint64 = OpTypeInt 64 0
%u64_1 = OpConstant %uint64 1
%ptr = OpTypePointer PhysicalStorageBuffer %uint64
@@ -1970,7 +1967,7 @@
%val1 = OpVariable %pptr_f Function
%val2 = OpLoad %ptr %val1
%val3 = OpLoad %ptr %val1
-OpCopyMemory %val2 %val3 Aligned 4 Volatile
+OpCopyMemory %val2 %val3 Aligned 8 Volatile
OpReturn
OpFunctionEnd
)";
@@ -1994,7 +1991,6 @@
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpDecorate %val1 AliasedPointer
-%int = OpTypeInt 32 0
%uint64 = OpTypeInt 64 0
%u64_1 = OpConstant %uint64 1
%ptr = OpTypePointer PhysicalStorageBuffer %uint64
@@ -2048,6 +2044,427 @@
HasSubstr("PhysicalStorageBuffer must not be used with OpVariable"));
}
+TEST_F(ValidateMemory, PSBStoreAlignedOneWithUvec4) {
+ const std::string body = R"(
+ OpCapability Shader
+ OpCapability PhysicalStorageBufferAddresses
+ OpMemoryModel PhysicalStorageBuffer64 GLSL450
+ OpEntryPoint GLCompute %main "main" %_
+ OpExecutionMode %main LocalSize 1 1 1
+ OpDecorate %SSBO Block
+ OpMemberDecorate %SSBO 0 Offset 0
+ OpDecorate %Ptr Block
+ OpMemberDecorate %Ptr 0 Offset 0
+ OpDecorate %_ Binding 0
+ OpDecorate %_ DescriptorSet 0
+ %void = OpTypeVoid
+ %4 = OpTypeFunction %void
+ OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_Ptr PhysicalStorageBuffer
+ %SSBO = OpTypeStruct %_ptr_PhysicalStorageBuffer_Ptr
+ %uint = OpTypeInt 32 0
+ %v4uint = OpTypeVector %uint 4
+ %Ptr = OpTypeStruct %v4uint
+%_ptr_PhysicalStorageBuffer_Ptr = OpTypePointer PhysicalStorageBuffer %Ptr
+%_ptr_StorageBuffer_SSBO = OpTypePointer StorageBuffer %SSBO
+ %_ = OpVariable %_ptr_StorageBuffer_SSBO StorageBuffer
+ %int = OpTypeInt 32 1
+ %int_0 = OpConstant %int 0
+%_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_Ptr = OpTypePointer StorageBuffer %_ptr_PhysicalStorageBuffer_Ptr
+ %uint_0 = OpConstant %uint 0
+ %20 = OpConstantComposite %v4uint %uint_0 %uint_0 %uint_0 %uint_0
+%_ptr_PhysicalStorageBuffer_v4uint = OpTypePointer PhysicalStorageBuffer %v4uint
+ %main = OpFunction %void None %4
+ %6 = OpLabel
+ %17 = OpAccessChain %_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_Ptr %_ %int_0
+ %18 = OpLoad %_ptr_PhysicalStorageBuffer_Ptr %17
+ %22 = OpAccessChain %_ptr_PhysicalStorageBuffer_v4uint %18 %int_0
+ OpStore %22 %20 Aligned 1
+ OpReturn
+ OpFunctionEnd
+)";
+
+ CompileSuccessfully(body.c_str(), SPV_ENV_VULKAN_1_2);
+ ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-PhysicalStorageBuffer64-06314"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Memory accesses Aligned operand value 1 is too small, "
+ "the largest scalar type is 4 bytes"));
+}
+
+TEST_F(ValidateMemory, PSBStoreAlignedOneWithUint32) {
+ const std::string body = R"(
+ OpCapability Shader
+ OpCapability PhysicalStorageBufferAddresses
+ OpMemoryModel PhysicalStorageBuffer64 GLSL450
+ OpEntryPoint GLCompute %main "main" %_
+ OpExecutionMode %main LocalSize 1 1 1
+ OpDecorate %SSBO Block
+ OpMemberDecorate %SSBO 0 Offset 0
+ OpDecorate %B Block
+ OpMemberDecorate %B 0 Offset 0
+ OpDecorate %_ Binding 0
+ OpDecorate %_ DescriptorSet 0
+ %void = OpTypeVoid
+ %4 = OpTypeFunction %void
+ OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_B PhysicalStorageBuffer
+ %SSBO = OpTypeStruct %_ptr_PhysicalStorageBuffer_B
+ %uint = OpTypeInt 32 0
+ %B = OpTypeStruct %uint
+%_ptr_PhysicalStorageBuffer_B = OpTypePointer PhysicalStorageBuffer %B
+%_ptr_StorageBuffer_SSBO = OpTypePointer StorageBuffer %SSBO
+ %_ = OpVariable %_ptr_StorageBuffer_SSBO StorageBuffer
+ %int = OpTypeInt 32 1
+ %int_0 = OpConstant %int 0
+%_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_B = OpTypePointer StorageBuffer %_ptr_PhysicalStorageBuffer_B
+ %uint_0 = OpConstant %uint 0
+%_ptr_PhysicalStorageBuffer_uint = OpTypePointer PhysicalStorageBuffer %uint
+ %main = OpFunction %void None %4
+ %6 = OpLabel
+ %16 = OpAccessChain %_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_B %_ %int_0
+ %17 = OpLoad %_ptr_PhysicalStorageBuffer_B %16
+ %20 = OpAccessChain %_ptr_PhysicalStorageBuffer_uint %17 %int_0
+ OpStore %20 %uint_0 Aligned 2
+ OpReturn
+ OpFunctionEnd
+)";
+
+ CompileSuccessfully(body.c_str(), SPV_ENV_VULKAN_1_2);
+ ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-PhysicalStorageBuffer64-06314"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Memory accesses Aligned operand value 2 is too small, "
+ "the largest scalar type is 4 bytes"));
+}
+
+// https://github.com/KhronosGroup/glslang/issues/4024
+TEST_F(ValidateMemory, PSBStoreAlignedPointerNot8) {
+ const std::string body = R"(
+ OpCapability Shader
+ OpCapability PhysicalStorageBufferAddresses
+ OpMemoryModel PhysicalStorageBuffer64 GLSL450
+ OpEntryPoint GLCompute %main "main" %_
+ OpExecutionMode %main LocalSize 1 1 1
+ OpDecorate %SSBO Block
+ OpMemberDecorate %SSBO 0 Offset 0
+ OpDecorate %B Block
+ OpMemberDecorate %B 0 Offset 0
+ OpDecorate %A Block
+ OpMemberDecorate %A 0 Offset 0
+ OpDecorate %_ Binding 0
+ OpDecorate %_ DescriptorSet 0
+ %void = OpTypeVoid
+ %4 = OpTypeFunction %void
+ OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_B PhysicalStorageBuffer
+ %SSBO = OpTypeStruct %_ptr_PhysicalStorageBuffer_B
+ OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_A PhysicalStorageBuffer
+ %B = OpTypeStruct %_ptr_PhysicalStorageBuffer_A
+ %uint = OpTypeInt 32 0
+ %A = OpTypeStruct %uint
+%_ptr_PhysicalStorageBuffer_A = OpTypePointer PhysicalStorageBuffer %A
+%_ptr_PhysicalStorageBuffer_B = OpTypePointer PhysicalStorageBuffer %B
+%_ptr_StorageBuffer_SSBO = OpTypePointer StorageBuffer %SSBO
+ %_ = OpVariable %_ptr_StorageBuffer_SSBO StorageBuffer
+ %int = OpTypeInt 32 1
+ %int_0 = OpConstant %int 0
+%_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_B = OpTypePointer StorageBuffer %_ptr_PhysicalStorageBuffer_B
+%_ptr_PhysicalStorageBuffer__ptr_PhysicalStorageBuffer_A = OpTypePointer PhysicalStorageBuffer %_ptr_PhysicalStorageBuffer_A
+ %uint_0 = OpConstant %uint 0
+%_ptr_PhysicalStorageBuffer_uint = OpTypePointer PhysicalStorageBuffer %uint
+ %main = OpFunction %void None %4
+ %6 = OpLabel
+ %18 = OpAccessChain %_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_B %_ %int_0
+ %19 = OpLoad %_ptr_PhysicalStorageBuffer_B %18
+ %21 = OpAccessChain %_ptr_PhysicalStorageBuffer__ptr_PhysicalStorageBuffer_A %19 %int_0
+ %22 = OpLoad %_ptr_PhysicalStorageBuffer_A %21 Aligned 4
+ %25 = OpAccessChain %_ptr_PhysicalStorageBuffer_uint %22 %int_0
+ OpStore %25 %uint_0 Aligned 4
+ OpReturn
+ OpFunctionEnd
+)";
+
+ CompileSuccessfully(body.c_str(), SPV_ENV_VULKAN_1_2);
+ ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-PhysicalStorageBuffer64-06314"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Memory accesses Aligned operand value 4 is too small, "
+ "the largest scalar type is 8 bytes"));
+}
+
+// https://godbolt.org/z/sbGv6a7os
+TEST_F(ValidateMemory, PSBStoreAlignedStructCopyWithDeepDouble) {
+ const std::string body = R"(
+ OpCapability Shader
+ OpCapability Float64
+ OpCapability PhysicalStorageBufferAddresses
+ OpMemoryModel PhysicalStorageBuffer64 GLSL450
+ OpEntryPoint GLCompute %main "main" %_
+ OpExecutionMode %main LocalSize 1 1 1
+ OpDecorate %SSBO Block
+ OpMemberDecorate %SSBO 0 Offset 0
+ OpMemberDecorate %A 0 Offset 0
+ OpMemberDecorate %A 1 Offset 8
+ OpMemberDecorate %B 0 Offset 0
+ OpMemberDecorate %B 1 Offset 16
+ OpMemberDecorate %C 0 Offset 0
+ OpMemberDecorate %C 1 Offset 32
+ OpDecorate %Ptr Block
+ OpMemberDecorate %Ptr 0 Offset 0
+ OpDecorate %_ Binding 0
+ OpDecorate %_ DescriptorSet 0
+ %void = OpTypeVoid
+ %4 = OpTypeFunction %void
+ OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_Ptr PhysicalStorageBuffer
+ %SSBO = OpTypeStruct %_ptr_PhysicalStorageBuffer_Ptr
+ %float = OpTypeFloat 32
+ %v3float = OpTypeVector %float 3
+ %uint = OpTypeInt 32 0
+ %double = OpTypeFloat 64
+ %A = OpTypeStruct %uint %double
+ %B = OpTypeStruct %v3float %A
+ %C = OpTypeStruct %B %uint
+ %Ptr = OpTypeStruct %C
+%_ptr_PhysicalStorageBuffer_Ptr = OpTypePointer PhysicalStorageBuffer %Ptr
+%_ptr_StorageBuffer_SSBO = OpTypePointer StorageBuffer %SSBO
+ %_ = OpVariable %_ptr_StorageBuffer_SSBO StorageBuffer
+ %int = OpTypeInt 32 1
+ %int_0 = OpConstant %int 0
+%_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_Ptr = OpTypePointer StorageBuffer %_ptr_PhysicalStorageBuffer_Ptr
+ %A_0 = OpTypeStruct %uint %double
+ %B_0 = OpTypeStruct %v3float %A_0
+ %C_0 = OpTypeStruct %B_0 %uint
+%_ptr_Function_C_0 = OpTypePointer Function %C_0
+%_ptr_PhysicalStorageBuffer_C = OpTypePointer PhysicalStorageBuffer %C
+ %main = OpFunction %void None %4
+ %6 = OpLabel
+ %newC = OpVariable %_ptr_Function_C_0 Function
+ %22 = OpAccessChain %_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_Ptr %_ %int_0
+ %23 = OpLoad %_ptr_PhysicalStorageBuffer_Ptr %22
+ %29 = OpLoad %C_0 %newC
+ %31 = OpAccessChain %_ptr_PhysicalStorageBuffer_C %23 %int_0
+ %32 = OpCopyLogical %C %29
+ OpStore %31 %32 Aligned 4
+ OpReturn
+ OpFunctionEnd
+)";
+
+ CompileSuccessfully(body.c_str(), SPV_ENV_VULKAN_1_2);
+ ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-PhysicalStorageBuffer64-06314"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Memory accesses Aligned operand value 4 is too small, "
+ "the largest scalar type is 8 bytes"));
+}
+
+TEST_F(ValidateMemory, PSBStoreAlignedPtrAccessChain) {
+ const std::string body = R"(
+ OpCapability PhysicalStorageBufferAddresses
+ OpCapability Int64
+ OpCapability Shader
+ OpExtension "SPV_KHR_non_semantic_info"
+ OpExtension "SPV_KHR_physical_storage_buffer"
+ %2 = OpExtInstImport "NonSemantic.Shader.DebugInfo.100"
+ OpMemoryModel PhysicalStorageBuffer64 GLSL450
+ OpEntryPoint GLCompute %computeMain "main" %globalParams
+ OpExecutionMode %computeMain LocalSize 1 1 1
+ OpDecorate %_ptr_PhysicalStorageBuffer_ulong ArrayStride 8
+ OpDecorate %GlobalParams_std140 Block
+ OpMemberDecorate %GlobalParams_std140 0 Offset 0
+ OpDecorate %globalParams Binding 0
+ OpDecorate %globalParams DescriptorSet 0
+ %void = OpTypeVoid
+ %uint = OpTypeInt 32 0
+ %12 = OpTypeFunction %void
+ %ulong = OpTypeInt 64 0
+%_ptr_PhysicalStorageBuffer_ulong = OpTypePointer PhysicalStorageBuffer %ulong
+%GlobalParams_std140 = OpTypeStruct %_ptr_PhysicalStorageBuffer_ulong
+%_ptr_Uniform_GlobalParams_std140 = OpTypePointer Uniform %GlobalParams_std140
+ %int = OpTypeInt 32 1
+ %int_0 = OpConstant %int 0
+%_ptr_Uniform__ptr_PhysicalStorageBuffer_ulong = OpTypePointer Uniform %_ptr_PhysicalStorageBuffer_ulong
+ %ulong_1 = OpConstant %ulong 1
+%globalParams = OpVariable %_ptr_Uniform_GlobalParams_std140 Uniform
+%computeMain = OpFunction %void None %12
+ %13 = OpLabel
+ %36 = OpInBoundsAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_ulong %globalParams %int_0
+ %37 = OpLoad %_ptr_PhysicalStorageBuffer_ulong %36
+ %38 = OpPtrAccessChain %_ptr_PhysicalStorageBuffer_ulong %37 %int_0
+ OpStore %38 %ulong_1 Aligned 4
+ OpReturn
+ OpFunctionEnd
+)";
+
+ CompileSuccessfully(body.c_str(), SPV_ENV_VULKAN_1_2);
+ ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-PhysicalStorageBuffer64-06314"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Memory accesses Aligned operand value 4 is too small, "
+ "the largest scalar type is 8 bytes"));
+}
+
+TEST_F(ValidateMemory, PSBStoreAlignedUntypedStorageBuffer) {
+ const std::string body = R"(
+ OpCapability Shader
+ OpCapability UntypedPointersKHR
+ OpCapability PhysicalStorageBufferAddresses
+ OpExtension "SPV_KHR_untyped_pointers"
+ OpMemoryModel PhysicalStorageBuffer64 GLSL450
+ OpEntryPoint GLCompute %main "main" %_
+ OpExecutionMode %main LocalSize 1 1 1
+ OpDecorate %SSBO Block
+ OpMemberDecorate %SSBO 0 Offset 0
+ OpDecorate %B Block
+ OpMemberDecorate %B 0 Offset 0
+ OpDecorate %_ Binding 0
+ OpDecorate %_ DescriptorSet 0
+ %void = OpTypeVoid
+ %4 = OpTypeFunction %void
+ OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_B PhysicalStorageBuffer
+ %SSBO = OpTypeStruct %_ptr_PhysicalStorageBuffer_B
+ %uint = OpTypeInt 32 0
+ %int = OpTypeInt 32 1
+ %int_0 = OpConstant %int 0
+ %uint_0 = OpConstant %uint 0
+ %B = OpTypeStruct %uint
+%_ptr_PhysicalStorageBuffer_B = OpTypePointer PhysicalStorageBuffer %B
+%_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_B = OpTypePointer StorageBuffer %_ptr_PhysicalStorageBuffer_B
+%untyped_ptr = OpTypeUntypedPointerKHR StorageBuffer
+ %_ = OpUntypedVariableKHR %untyped_ptr StorageBuffer %SSBO
+%_ptr_PhysicalStorageBuffer_uint = OpTypePointer PhysicalStorageBuffer %uint
+ %main = OpFunction %void None %4
+ %6 = OpLabel
+ %16 = OpUntypedAccessChainKHR %untyped_ptr %SSBO %_ %int_0
+ %17 = OpLoad %_ptr_PhysicalStorageBuffer_B %16
+ %20 = OpAccessChain %_ptr_PhysicalStorageBuffer_uint %17 %int_0
+ OpStore %20 %uint_0 Aligned 2
+ OpReturn
+ OpFunctionEnd
+)";
+
+ CompileSuccessfully(body.c_str(), SPV_ENV_VULKAN_1_2);
+ ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-PhysicalStorageBuffer64-06314"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Memory accesses Aligned operand value 2 is too small, "
+ "the largest scalar type is 4 bytes"));
+}
+
+TEST_F(ValidateMemory, PSBStoreAlignedUntypedPhysicalStorageBuffer) {
+ const std::string body = R"(
+ OpCapability Shader
+ OpCapability UntypedPointersKHR
+ OpCapability PhysicalStorageBufferAddresses
+ OpExtension "SPV_KHR_untyped_pointers"
+ OpMemoryModel PhysicalStorageBuffer64 GLSL450
+ OpEntryPoint GLCompute %main "main" %_
+ OpExecutionMode %main LocalSize 1 1 1
+ OpDecorate %SSBO Block
+ OpMemberDecorate %SSBO 0 Offset 0
+ OpDecorate %B Block
+ OpMemberDecorate %B 0 Offset 0
+ OpDecorate %_ Binding 0
+ OpDecorate %_ DescriptorSet 0
+ %void = OpTypeVoid
+ %4 = OpTypeFunction %void
+ OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_B PhysicalStorageBuffer
+ %SSBO = OpTypeStruct %_ptr_PhysicalStorageBuffer_B
+ %uint = OpTypeInt 32 0
+ %int = OpTypeInt 32 1
+ %int_0 = OpConstant %int 0
+ %uint_0 = OpConstant %uint 0
+ %B = OpTypeStruct %uint
+%_ptr_PhysicalStorageBuffer_B = OpTypePointer PhysicalStorageBuffer %B
+%_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_B = OpTypePointer StorageBuffer %_ptr_PhysicalStorageBuffer_B
+%untyped_ptr = OpTypeUntypedPointerKHR StorageBuffer
+ %_ = OpUntypedVariableKHR %untyped_ptr StorageBuffer %SSBO
+%_ptr_PhysicalStorageBuffer_uint = OpTypePointer PhysicalStorageBuffer %uint
+ %main = OpFunction %void None %4
+ %6 = OpLabel
+ %16 = OpUntypedAccessChainKHR %untyped_ptr %SSBO %_ %int_0
+ %17 = OpLoad %_ptr_PhysicalStorageBuffer_B %16
+ %20 = OpAccessChain %_ptr_PhysicalStorageBuffer_uint %17 %int_0
+ OpStore %20 %uint_0 Aligned 2
+ OpReturn
+ OpFunctionEnd
+)";
+
+ CompileSuccessfully(body.c_str(), SPV_ENV_VULKAN_1_2);
+ ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-PhysicalStorageBuffer64-06314"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Memory accesses Aligned operand value 2 is too small, "
+ "the largest scalar type is 4 bytes"));
+}
+
+TEST_F(ValidateMemory, PSBStoreAlignedVariousTypeSuccess) {
+ const std::string body = R"(
+ OpCapability Shader
+ OpCapability Float64
+ OpCapability Int8
+ OpCapability StorageBuffer8BitAccess
+ OpCapability PhysicalStorageBufferAddresses
+ %2 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel PhysicalStorageBuffer64 GLSL450
+ OpEntryPoint GLCompute %main "main" %_
+ OpExecutionMode %main LocalSize 1 1 1
+ OpDecorate %SSBO Block
+ OpMemberDecorate %SSBO 0 Offset 0
+ OpDecorate %Ptr Block
+ OpMemberDecorate %Ptr 0 Offset 0
+ OpMemberDecorate %Ptr 1 Offset 4
+ OpMemberDecorate %Ptr 2 Offset 8
+ OpDecorate %_ Binding 0
+ OpDecorate %_ DescriptorSet 0
+ %void = OpTypeVoid
+ %4 = OpTypeFunction %void
+ OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_Ptr PhysicalStorageBuffer
+ %SSBO = OpTypeStruct %_ptr_PhysicalStorageBuffer_Ptr
+ %uchar = OpTypeInt 8 0
+ %uint = OpTypeInt 32 0
+ %double = OpTypeFloat 64
+ %Ptr = OpTypeStruct %uchar %uint %double
+%_ptr_PhysicalStorageBuffer_Ptr = OpTypePointer PhysicalStorageBuffer %Ptr
+%_ptr_StorageBuffer_SSBO = OpTypePointer StorageBuffer %SSBO
+ %_ = OpVariable %_ptr_StorageBuffer_SSBO StorageBuffer
+ %int = OpTypeInt 32 1
+ %int_0 = OpConstant %int 0
+%_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_Ptr = OpTypePointer StorageBuffer %_ptr_PhysicalStorageBuffer_Ptr
+ %uchar_0 = OpConstant %uchar 0
+%_ptr_PhysicalStorageBuffer_uchar = OpTypePointer PhysicalStorageBuffer %uchar
+ %int_1 = OpConstant %int 1
+ %uint_0 = OpConstant %uint 0
+%_ptr_PhysicalStorageBuffer_uint = OpTypePointer PhysicalStorageBuffer %uint
+ %int_2 = OpConstant %int 2
+ %double_0 = OpConstant %double 0
+%_ptr_PhysicalStorageBuffer_double = OpTypePointer PhysicalStorageBuffer %double
+ %main = OpFunction %void None %4
+ %6 = OpLabel
+ %18 = OpAccessChain %_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_Ptr %_ %int_0
+ %19 = OpLoad %_ptr_PhysicalStorageBuffer_Ptr %18
+ %22 = OpAccessChain %_ptr_PhysicalStorageBuffer_uchar %19 %int_0
+ OpStore %22 %uchar_0 Aligned 1
+ %23 = OpAccessChain %_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_Ptr %_ %int_0
+ %24 = OpLoad %_ptr_PhysicalStorageBuffer_Ptr %23
+ %28 = OpAccessChain %_ptr_PhysicalStorageBuffer_uint %24 %int_1
+ OpStore %28 %uint_0 Aligned 4
+ %29 = OpAccessChain %_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_Ptr %_ %int_0
+ %30 = OpLoad %_ptr_PhysicalStorageBuffer_Ptr %29
+ %34 = OpAccessChain %_ptr_PhysicalStorageBuffer_double %30 %int_2
+ OpStore %34 %double_0 Aligned 8
+ OpReturn
+ OpFunctionEnd
+)";
+
+ CompileSuccessfully(body.c_str(), SPV_ENV_VULKAN_1_2);
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
+}
+
std::string GenCoopMatLoadStoreShader(const std::string& storeMemoryAccess,
const std::string& loadMemoryAccess) {
std::string s = R"(