mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-11-25 13:00:04 +00:00
spirv-val: Add OpPtrAccessChain Base checks (#4965)
This commit is contained in:
parent
eb113f0fdf
commit
0ebf830572
@ -1410,7 +1410,51 @@ spv_result_t ValidatePtrAccessChain(ValidationState_t& _,
|
|||||||
<< "VariablePointers or VariablePointersStorageBuffer";
|
<< "VariablePointers or VariablePointersStorageBuffer";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ValidateAccessChain(_, inst);
|
|
||||||
|
// Need to call first, will make sure Base is a valid ID
|
||||||
|
if (auto error = ValidateAccessChain(_, inst)) return error;
|
||||||
|
|
||||||
|
const auto base_id = inst->GetOperandAs<uint32_t>(2);
|
||||||
|
const auto base = _.FindDef(base_id);
|
||||||
|
const auto base_type = _.FindDef(base->type_id());
|
||||||
|
const auto base_type_storage_class = base_type->word(2);
|
||||||
|
|
||||||
|
if (_.HasCapability(SpvCapabilityShader) &&
|
||||||
|
(base_type_storage_class == SpvStorageClassUniform ||
|
||||||
|
base_type_storage_class == SpvStorageClassStorageBuffer ||
|
||||||
|
base_type_storage_class == SpvStorageClassPhysicalStorageBuffer ||
|
||||||
|
base_type_storage_class == SpvStorageClassPushConstant ||
|
||||||
|
(_.HasCapability(SpvCapabilityWorkgroupMemoryExplicitLayoutKHR) &&
|
||||||
|
base_type_storage_class == SpvStorageClassWorkgroup)) &&
|
||||||
|
!_.HasDecoration(base_type->id(), SpvDecorationArrayStride)) {
|
||||||
|
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||||
|
<< "OpPtrAccessChain must have a Base whose type is decorated "
|
||||||
|
"with ArrayStride";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spvIsVulkanEnv(_.context()->target_env)) {
|
||||||
|
if (base_type_storage_class == SpvStorageClassWorkgroup) {
|
||||||
|
if (!_.HasCapability(SpvCapabilityVariablePointers)) {
|
||||||
|
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||||
|
<< "OpPtrAccessChain Base operand pointing to Workgroup "
|
||||||
|
"storage class must use VariablePointers capability";
|
||||||
|
}
|
||||||
|
} else if (base_type_storage_class == SpvStorageClassStorageBuffer) {
|
||||||
|
if (!_.features().variable_pointers) {
|
||||||
|
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||||
|
<< "OpPtrAccessChain Base operand pointing to StorageBuffer "
|
||||||
|
"storage class must use VariablePointers or "
|
||||||
|
"VariablePointersStorageBuffer capability";
|
||||||
|
}
|
||||||
|
} else if (base_type_storage_class !=
|
||||||
|
SpvStorageClassPhysicalStorageBuffer) {
|
||||||
|
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||||
|
<< "OpPtrAccessChain Base operand must point to Workgroup, "
|
||||||
|
"StorageBuffer, or PhysicalStorageBuffer storage class";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SPV_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
spv_result_t ValidateArrayLength(ValidationState_t& state,
|
spv_result_t ValidateArrayLength(ValidationState_t& state,
|
||||||
|
@ -978,6 +978,7 @@ TEST_F(EliminateDeadMemberTest, RemoveMemberPtrAccessChain) {
|
|||||||
OpMemberDecorate %type__Globals 1 Offset 4
|
OpMemberDecorate %type__Globals 1 Offset 4
|
||||||
OpMemberDecorate %type__Globals 2 Offset 16
|
OpMemberDecorate %type__Globals 2 Offset 16
|
||||||
OpDecorate %type__Globals Block
|
OpDecorate %type__Globals Block
|
||||||
|
OpDecorate %_ptr_Uniform_type__Globals ArrayStride 8
|
||||||
%uint = OpTypeInt 32 0
|
%uint = OpTypeInt 32 0
|
||||||
%uint_0 = OpConstant %uint 0
|
%uint_0 = OpConstant %uint 0
|
||||||
%uint_1 = OpConstant %uint 1
|
%uint_1 = OpConstant %uint 1
|
||||||
|
@ -3981,8 +3981,11 @@ OpFunctionEnd
|
|||||||
TEST_P(AccessChainInstructionTest, AccessChainTooManyIndexesGood) {
|
TEST_P(AccessChainInstructionTest, AccessChainTooManyIndexesGood) {
|
||||||
const std::string instr = GetParam();
|
const std::string instr = GetParam();
|
||||||
const std::string elem = AccessChainRequiresElemId(instr) ? " %int_0 " : "";
|
const std::string elem = AccessChainRequiresElemId(instr) ? " %int_0 " : "";
|
||||||
|
const std::string arrayStride =
|
||||||
|
" OpDecorate %_ptr_Uniform_deep_struct ArrayStride 8 ";
|
||||||
int depth = 255;
|
int depth = 255;
|
||||||
std::string header = kGLSL450MemoryModel + kDeeplyNestedStructureSetup;
|
std::string header =
|
||||||
|
kGLSL450MemoryModel + arrayStride + kDeeplyNestedStructureSetup;
|
||||||
header.erase(header.find("%func"));
|
header.erase(header.find("%func"));
|
||||||
std::ostringstream spirv;
|
std::ostringstream spirv;
|
||||||
spirv << header << "\n";
|
spirv << header << "\n";
|
||||||
@ -4044,8 +4047,11 @@ TEST_P(AccessChainInstructionTest, AccessChainTooManyIndexesBad) {
|
|||||||
TEST_P(AccessChainInstructionTest, CustomizedAccessChainTooManyIndexesGood) {
|
TEST_P(AccessChainInstructionTest, CustomizedAccessChainTooManyIndexesGood) {
|
||||||
const std::string instr = GetParam();
|
const std::string instr = GetParam();
|
||||||
const std::string elem = AccessChainRequiresElemId(instr) ? " %int_0 " : "";
|
const std::string elem = AccessChainRequiresElemId(instr) ? " %int_0 " : "";
|
||||||
|
const std::string arrayStride =
|
||||||
|
" OpDecorate %_ptr_Uniform_deep_struct ArrayStride 8 ";
|
||||||
int depth = 10;
|
int depth = 10;
|
||||||
std::string header = kGLSL450MemoryModel + kDeeplyNestedStructureSetup;
|
std::string header =
|
||||||
|
kGLSL450MemoryModel + arrayStride + kDeeplyNestedStructureSetup;
|
||||||
header.erase(header.find("%func"));
|
header.erase(header.find("%func"));
|
||||||
std::ostringstream spirv;
|
std::ostringstream spirv;
|
||||||
spirv << header << "\n";
|
spirv << header << "\n";
|
||||||
@ -4217,8 +4223,11 @@ TEST_P(AccessChainInstructionTest, AccessChainIndexIntoAllTypesGood) {
|
|||||||
// 0 will select the element at the index 0 of the vector. (which is a float).
|
// 0 will select the element at the index 0 of the vector. (which is a float).
|
||||||
const std::string instr = GetParam();
|
const std::string instr = GetParam();
|
||||||
const std::string elem = AccessChainRequiresElemId(instr) ? "%int_0 " : "";
|
const std::string elem = AccessChainRequiresElemId(instr) ? "%int_0 " : "";
|
||||||
|
const std::string arrayStride =
|
||||||
|
" OpDecorate %_ptr_Uniform_blockName ArrayStride 8 ";
|
||||||
std::ostringstream spirv;
|
std::ostringstream spirv;
|
||||||
spirv << kGLSL450MemoryModel << kDeeplyNestedStructureSetup << std::endl;
|
spirv << kGLSL450MemoryModel << arrayStride << kDeeplyNestedStructureSetup
|
||||||
|
<< std::endl;
|
||||||
spirv << "%ss = " << instr << " %_ptr_Uniform_struct_s %blockName_var "
|
spirv << "%ss = " << instr << " %_ptr_Uniform_struct_s %blockName_var "
|
||||||
<< elem << "%int_0" << std::endl;
|
<< elem << "%int_0" << std::endl;
|
||||||
spirv << "%sa = " << instr << " %_ptr_Uniform_array5_mat4x3 %blockName_var "
|
spirv << "%sa = " << instr << " %_ptr_Uniform_array5_mat4x3 %blockName_var "
|
||||||
@ -4241,9 +4250,12 @@ OpFunctionEnd
|
|||||||
TEST_P(AccessChainInstructionTest, AccessChainIndexIntoRuntimeArrayGood) {
|
TEST_P(AccessChainInstructionTest, AccessChainIndexIntoRuntimeArrayGood) {
|
||||||
const std::string instr = GetParam();
|
const std::string instr = GetParam();
|
||||||
const std::string elem = AccessChainRequiresElemId(instr) ? "%int_0 " : "";
|
const std::string elem = AccessChainRequiresElemId(instr) ? "%int_0 " : "";
|
||||||
std::string spirv = kGLSL450MemoryModel + kDeeplyNestedStructureSetup + R"(
|
const std::string arrayStride =
|
||||||
%runtime_arr_entry = )" +
|
" OpDecorate %_ptr_Uniform_blockName ArrayStride 8 ";
|
||||||
instr + R"( %_ptr_Uniform_float %blockName_var )" + elem +
|
std::string spirv = kGLSL450MemoryModel + arrayStride +
|
||||||
|
kDeeplyNestedStructureSetup + R"(
|
||||||
|
%runtime_arr_entry = )" + instr +
|
||||||
|
R"( %_ptr_Uniform_float %blockName_var )" + elem +
|
||||||
R"(%int_2 %int_0
|
R"(%int_2 %int_0
|
||||||
OpReturn
|
OpReturn
|
||||||
OpFunctionEnd
|
OpFunctionEnd
|
||||||
@ -5631,6 +5643,7 @@ TEST_P(ValidateIdWithMessage, StgBufOpPtrAccessChainGood) {
|
|||||||
OpExtension "SPV_KHR_variable_pointers"
|
OpExtension "SPV_KHR_variable_pointers"
|
||||||
OpMemoryModel Logical GLSL450
|
OpMemoryModel Logical GLSL450
|
||||||
OpEntryPoint GLCompute %3 ""
|
OpEntryPoint GLCompute %3 ""
|
||||||
|
OpDecorate %ptr ArrayStride 8
|
||||||
%int = OpTypeInt 32 0
|
%int = OpTypeInt 32 0
|
||||||
%int_2 = OpConstant %int 2
|
%int_2 = OpConstant %int 2
|
||||||
%int_4 = OpConstant %int 4
|
%int_4 = OpConstant %int 4
|
||||||
|
@ -4712,6 +4712,220 @@ OpFunctionEnd
|
|||||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidateMemory, PtrAccessChainArrayStrideBad) {
|
||||||
|
const std::string spirv = R"(
|
||||||
|
OpCapability Shader
|
||||||
|
OpCapability VariablePointersStorageBuffer
|
||||||
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
||||||
|
OpExtension "SPV_KHR_variable_pointers"
|
||||||
|
OpMemoryModel Logical GLSL450
|
||||||
|
OpEntryPoint GLCompute %main "foo" %var
|
||||||
|
OpExecutionMode %main LocalSize 1 1 1
|
||||||
|
OpDecorate %var DescriptorSet 0
|
||||||
|
OpDecorate %var Binding 0
|
||||||
|
%uint = OpTypeInt 32 0
|
||||||
|
%uint_0 = OpConstant %uint 0
|
||||||
|
%uint_1 = OpConstant %uint 1
|
||||||
|
%ptr = OpTypePointer StorageBuffer %uint
|
||||||
|
%void = OpTypeVoid
|
||||||
|
%func = OpTypeFunction %void
|
||||||
|
%var = OpVariable %ptr StorageBuffer
|
||||||
|
%main = OpFunction %void None %func
|
||||||
|
%label = OpLabel
|
||||||
|
%access = OpAccessChain %ptr %var
|
||||||
|
%ptr_access = OpPtrAccessChain %ptr %access %uint_1
|
||||||
|
OpReturn
|
||||||
|
OpFunctionEnd
|
||||||
|
)";
|
||||||
|
|
||||||
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_5);
|
||||||
|
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
|
||||||
|
ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
|
||||||
|
EXPECT_THAT(getDiagnosticString(),
|
||||||
|
HasSubstr("OpPtrAccessChain must have a Base whose type is "
|
||||||
|
"decorated with ArrayStride"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidateMemory, PtrAccessChainArrayStrideSuccess) {
|
||||||
|
const std::string spirv = R"(
|
||||||
|
OpCapability Shader
|
||||||
|
OpCapability VariablePointersStorageBuffer
|
||||||
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
||||||
|
OpExtension "SPV_KHR_variable_pointers"
|
||||||
|
OpMemoryModel Logical GLSL450
|
||||||
|
OpEntryPoint GLCompute %main "foo" %var
|
||||||
|
OpExecutionMode %main LocalSize 1 1 1
|
||||||
|
OpDecorate %var DescriptorSet 0
|
||||||
|
OpDecorate %var Binding 00
|
||||||
|
OpDecorate %ptr ArrayStride 4
|
||||||
|
%uint = OpTypeInt 32 0
|
||||||
|
%uint_0 = OpConstant %uint 0
|
||||||
|
%uint_1 = OpConstant %uint 1
|
||||||
|
%ptr = OpTypePointer StorageBuffer %uint
|
||||||
|
%void = OpTypeVoid
|
||||||
|
%func = OpTypeFunction %void
|
||||||
|
%var = OpVariable %ptr StorageBuffer
|
||||||
|
%main = OpFunction %void None %func
|
||||||
|
%label = OpLabel
|
||||||
|
%access = OpAccessChain %ptr %var
|
||||||
|
%ptr_access = OpPtrAccessChain %ptr %access %uint_1
|
||||||
|
OpReturn
|
||||||
|
OpFunctionEnd
|
||||||
|
)";
|
||||||
|
|
||||||
|
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_5);
|
||||||
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidateMemory, VulkanPtrAccessChainStorageBufferSuccess) {
|
||||||
|
const std::string spirv = R"(
|
||||||
|
OpCapability Shader
|
||||||
|
OpCapability VariablePointersStorageBuffer
|
||||||
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
||||||
|
OpExtension "SPV_KHR_variable_pointers"
|
||||||
|
OpMemoryModel Logical GLSL450
|
||||||
|
OpEntryPoint GLCompute %main "foo" %var
|
||||||
|
OpExecutionMode %main LocalSize 1 1 1
|
||||||
|
OpDecorate %_runtimearr_uint ArrayStride 4
|
||||||
|
OpMemberDecorate %_struct_10 0 Offset 0
|
||||||
|
OpDecorate %_struct_10 Block
|
||||||
|
OpDecorate %var DescriptorSet 0
|
||||||
|
OpDecorate %var Binding 0
|
||||||
|
OpDecorate %_ptr_StorageBuffer_uint ArrayStride 4
|
||||||
|
%uint = OpTypeInt 32 0
|
||||||
|
%uint_0 = OpConstant %uint 0
|
||||||
|
%uint_1 = OpConstant %uint 1
|
||||||
|
%_runtimearr_uint = OpTypeRuntimeArray %uint
|
||||||
|
%_struct_10 = OpTypeStruct %_runtimearr_uint
|
||||||
|
%_ptr_StorageBuffer__struct_10 = OpTypePointer StorageBuffer %_struct_10
|
||||||
|
%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
|
||||||
|
%void = OpTypeVoid
|
||||||
|
%func2 = OpTypeFunction %void %_ptr_StorageBuffer_uint
|
||||||
|
%func1 = OpTypeFunction %void
|
||||||
|
%var = OpVariable %_ptr_StorageBuffer__struct_10 StorageBuffer
|
||||||
|
%called = OpFunction %void None %func2
|
||||||
|
%param = OpFunctionParameter %_ptr_StorageBuffer_uint
|
||||||
|
%label2 = OpLabel
|
||||||
|
%ptr_access = OpPtrAccessChain %_ptr_StorageBuffer_uint %param %uint_1
|
||||||
|
OpReturn
|
||||||
|
OpFunctionEnd
|
||||||
|
%main = OpFunction %void None %func1
|
||||||
|
%label1 = OpLabel
|
||||||
|
%access = OpAccessChain %_ptr_StorageBuffer_uint %var %uint_0 %uint_0
|
||||||
|
%call = OpFunctionCall %void %called %access
|
||||||
|
OpReturn
|
||||||
|
OpFunctionEnd
|
||||||
|
)";
|
||||||
|
|
||||||
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_2);
|
||||||
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidateMemory, VulkanPtrAccessChainStorageBufferCapability) {
|
||||||
|
const std::string spirv = R"(
|
||||||
|
OpCapability Shader
|
||||||
|
OpCapability PhysicalStorageBufferAddresses
|
||||||
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
||||||
|
OpExtension "SPV_KHR_variable_pointers"
|
||||||
|
OpMemoryModel PhysicalStorageBuffer64 GLSL450
|
||||||
|
OpEntryPoint GLCompute %main "foo" %var
|
||||||
|
OpExecutionMode %main LocalSize 1 1 1
|
||||||
|
OpDecorate %_runtimearr_uint ArrayStride 4
|
||||||
|
OpMemberDecorate %_struct_10 0 Offset 0
|
||||||
|
OpDecorate %_struct_10 Block
|
||||||
|
OpDecorate %var DescriptorSet 0
|
||||||
|
OpDecorate %var Binding 0
|
||||||
|
OpDecorate %_ptr_StorageBuffer_uint ArrayStride 4
|
||||||
|
%uint = OpTypeInt 32 0
|
||||||
|
%uint_0 = OpConstant %uint 0
|
||||||
|
%uint_1 = OpConstant %uint 1
|
||||||
|
%_runtimearr_uint = OpTypeRuntimeArray %uint
|
||||||
|
%_struct_10 = OpTypeStruct %_runtimearr_uint
|
||||||
|
%_ptr_StorageBuffer__struct_10 = OpTypePointer StorageBuffer %_struct_10
|
||||||
|
%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
|
||||||
|
%void = OpTypeVoid
|
||||||
|
%func = OpTypeFunction %void
|
||||||
|
%var = OpVariable %_ptr_StorageBuffer__struct_10 StorageBuffer
|
||||||
|
%main = OpFunction %void None %func
|
||||||
|
%label = OpLabel
|
||||||
|
%access = OpAccessChain %_ptr_StorageBuffer_uint %var %uint_0 %uint_0
|
||||||
|
%ptr_access = OpPtrAccessChain %_ptr_StorageBuffer_uint %access %uint_1
|
||||||
|
OpReturn
|
||||||
|
OpFunctionEnd
|
||||||
|
)";
|
||||||
|
|
||||||
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_2);
|
||||||
|
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2));
|
||||||
|
EXPECT_THAT(getDiagnosticString(),
|
||||||
|
HasSubstr("OpPtrAccessChain Base operand pointing to "
|
||||||
|
"StorageBuffer storage class must use VariablePointers "
|
||||||
|
"or VariablePointersStorageBuffer capability"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidateMemory, VulkanPtrAccessChainWorkgroupCapability) {
|
||||||
|
const std::string spirv = R"(
|
||||||
|
OpCapability Shader
|
||||||
|
OpCapability VariablePointersStorageBuffer
|
||||||
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
||||||
|
OpExtension "SPV_KHR_variable_pointers"
|
||||||
|
OpMemoryModel Logical GLSL450
|
||||||
|
OpEntryPoint GLCompute %main "foo" %var
|
||||||
|
OpExecutionMode %main LocalSize 1 1 1
|
||||||
|
OpDecorate %_ptr_Workgroup_uint ArrayStride 4
|
||||||
|
%uint = OpTypeInt 32 0
|
||||||
|
%uint_0 = OpConstant %uint 0
|
||||||
|
%uint_1 = OpConstant %uint 1
|
||||||
|
%_arr_uint = OpTypeArray %uint %uint_1
|
||||||
|
%_ptr_Workgroup__arr_uint = OpTypePointer Workgroup %_arr_uint
|
||||||
|
%_ptr_Workgroup_uint = OpTypePointer Workgroup %uint
|
||||||
|
%void = OpTypeVoid
|
||||||
|
%func = OpTypeFunction %void
|
||||||
|
%var = OpVariable %_ptr_Workgroup__arr_uint Workgroup
|
||||||
|
%main = OpFunction %void None %func
|
||||||
|
%label = OpLabel
|
||||||
|
%access = OpAccessChain %_ptr_Workgroup_uint %var %uint_0
|
||||||
|
%ptr_access = OpPtrAccessChain %_ptr_Workgroup_uint %access %uint_1
|
||||||
|
OpReturn
|
||||||
|
OpFunctionEnd
|
||||||
|
)";
|
||||||
|
|
||||||
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_2);
|
||||||
|
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2));
|
||||||
|
EXPECT_THAT(getDiagnosticString(),
|
||||||
|
HasSubstr("OpPtrAccessChain Base operand pointing to Workgroup "
|
||||||
|
"storage class must use VariablePointers capability"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidateMemory, VulkanPtrAccessChainWorkgroupNoArrayStrideSuccess) {
|
||||||
|
const std::string spirv = R"(
|
||||||
|
OpCapability Shader
|
||||||
|
OpCapability VariablePointers
|
||||||
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
||||||
|
OpExtension "SPV_KHR_variable_pointers"
|
||||||
|
OpMemoryModel Logical GLSL450
|
||||||
|
OpEntryPoint GLCompute %main "foo" %var
|
||||||
|
OpExecutionMode %main LocalSize 1 1 1
|
||||||
|
%uint = OpTypeInt 32 0
|
||||||
|
%uint_0 = OpConstant %uint 0
|
||||||
|
%uint_1 = OpConstant %uint 1
|
||||||
|
%_arr_uint = OpTypeArray %uint %uint_1
|
||||||
|
%_ptr_Workgroup__arr_uint = OpTypePointer Workgroup %_arr_uint
|
||||||
|
%_ptr_Workgroup_uint = OpTypePointer Workgroup %uint
|
||||||
|
%void = OpTypeVoid
|
||||||
|
%func = OpTypeFunction %void
|
||||||
|
%var = OpVariable %_ptr_Workgroup__arr_uint Workgroup
|
||||||
|
%main = OpFunction %void None %func
|
||||||
|
%label = OpLabel
|
||||||
|
%access = OpAccessChain %_ptr_Workgroup_uint %var %uint_0
|
||||||
|
%ptr_access = OpPtrAccessChain %_ptr_Workgroup_uint %access %uint_1
|
||||||
|
OpReturn
|
||||||
|
OpFunctionEnd
|
||||||
|
)";
|
||||||
|
|
||||||
|
CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_2);
|
||||||
|
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace val
|
} // namespace val
|
||||||
} // namespace spvtools
|
} // namespace spvtools
|
||||||
|
Loading…
Reference in New Issue
Block a user