From 4c2f34a504817cc96d3e8b0435265a743cb2038a Mon Sep 17 00:00:00 2001 From: Diego Novillo Date: Thu, 3 Dec 2020 09:50:38 -0500 Subject: Finalize SPIRV-Tools v2020.6 --- CHANGES | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 7ad7b661..aadfada2 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,6 @@ Revision history for SPIRV-Tools -v2020.6-dev 2020-12-02 +v2020.6 2020-12-02 - General CMake: Add SPIRV_TOOLS_BUILD_STATIC flag (#3910) - Disassembler -- cgit v1.2.3 From 21f7c5675da3a45c13024dc1169438eb4e8f7e0c Mon Sep 17 00:00:00 2001 From: Diego Novillo Date: Thu, 3 Dec 2020 09:52:56 -0500 Subject: Start SPIRV-Tools v2020.7 --- CHANGES | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES b/CHANGES index aadfada2..94d6e2d2 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,8 @@ Revision history for SPIRV-Tools +v2020.7-dev 2020-12-03 + - Start v2020.7-dev + v2020.6 2020-12-02 - General CMake: Add SPIRV_TOOLS_BUILD_STATIC flag (#3910) -- cgit v1.2.3 From cd05078662182f1739585faee27f5e9ad46f7dec Mon Sep 17 00:00:00 2001 From: Ehsan Date: Mon, 7 Dec 2020 09:26:05 -0600 Subject: Take new (raytracing) termination instructions into account. (#4050) * Take new (raytracing) termination instructions into account. * Remove duplicate function and add unit test. * Use KHR for symbols in the test. --- source/opcode.cpp | 21 +++++++++++++++-- source/opcode.h | 8 +++++++ source/opt/basic_block.cpp | 2 +- source/opt/inline_pass.cpp | 7 ++---- source/opt/ir_loader.cpp | 2 +- source/opt/module.cpp | 2 +- source/opt/reflect.h | 4 ---- test/opt/inline_test.cpp | 57 ++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 89 insertions(+), 14 deletions(-) diff --git a/source/opcode.cpp b/source/opcode.cpp index c80e3a00..d87e8287 100644 --- a/source/opcode.cpp +++ b/source/opcode.cpp @@ -444,15 +444,32 @@ bool spvOpcodeIsReturn(SpvOp opcode) { } } +bool spvOpcodeIsAbort(SpvOp opcode) { + switch (opcode) { + case SpvOpKill: + case SpvOpUnreachable: + case SpvOpTerminateInvocation: + case SpvOpTerminateRayKHR: + case SpvOpIgnoreIntersectionKHR: + return true; + default: + return false; + } +} + bool spvOpcodeIsReturnOrAbort(SpvOp opcode) { - return spvOpcodeIsReturn(opcode) || opcode == SpvOpKill || - opcode == SpvOpUnreachable || opcode == SpvOpTerminateInvocation; + return spvOpcodeIsReturn(opcode) || spvOpcodeIsAbort(opcode); } bool spvOpcodeIsBlockTerminator(SpvOp opcode) { return spvOpcodeIsBranch(opcode) || spvOpcodeIsReturnOrAbort(opcode); } +bool spvOpcodeTerminatesExecution(SpvOp opcode) { + return opcode == SpvOpKill || opcode == SpvOpTerminateInvocation || + opcode == SpvOpTerminateRayKHR || opcode == SpvOpIgnoreIntersectionKHR; +} + bool spvOpcodeIsBaseOpaqueType(SpvOp opcode) { switch (opcode) { case SpvOpTypeImage: diff --git a/source/opcode.h b/source/opcode.h index 3702cb35..c8525a25 100644 --- a/source/opcode.h +++ b/source/opcode.h @@ -110,10 +110,18 @@ bool spvOpcodeIsBranch(SpvOp opcode); // Returns true if the given opcode is a return instruction. bool spvOpcodeIsReturn(SpvOp opcode); +// Returns true if the given opcode aborts execution. +bool spvOpcodeIsAbort(SpvOp opcode); + // Returns true if the given opcode is a return instruction or it aborts // execution. bool spvOpcodeIsReturnOrAbort(SpvOp opcode); +// Returns true if the given opcode is a kill instruction or it terminates +// execution. Note that branches, returns, and unreachables do not terminate +// execution. +bool spvOpcodeTerminatesExecution(SpvOp opcode); + // Returns true if the given opcode is a basic block terminator. bool spvOpcodeIsBlockTerminator(SpvOp opcode); diff --git a/source/opt/basic_block.cpp b/source/opt/basic_block.cpp index b7e122c4..e82a744a 100644 --- a/source/opt/basic_block.cpp +++ b/source/opt/basic_block.cpp @@ -230,7 +230,7 @@ std::string BasicBlock::PrettyPrint(uint32_t options) const { std::ostringstream str; ForEachInst([&str, options](const Instruction* inst) { str << inst->PrettyPrint(options); - if (!IsTerminatorInst(inst->opcode())) { + if (!spvOpcodeIsBlockTerminator(inst->opcode())) { str << std::endl; } }); diff --git a/source/opt/inline_pass.cpp b/source/opt/inline_pass.cpp index 88f395f0..8159ebf7 100644 --- a/source/opt/inline_pass.cpp +++ b/source/opt/inline_pass.cpp @@ -383,9 +383,7 @@ std::unique_ptr InlinePass::InlineReturn( uint32_t returnLabelId = 0; for (auto callee_block_itr = calleeFn->begin(); callee_block_itr != calleeFn->end(); ++callee_block_itr) { - if (callee_block_itr->tail()->opcode() == SpvOpUnreachable || - callee_block_itr->tail()->opcode() == SpvOpKill || - callee_block_itr->tail()->opcode() == SpvOpTerminateInvocation) { + if (spvOpcodeIsAbort(callee_block_itr->tail()->opcode())) { returnLabelId = context()->TakeNextId(); break; } @@ -759,8 +757,7 @@ bool InlinePass::IsInlinableFunction(Function* func) { bool InlinePass::ContainsKillOrTerminateInvocation(Function* func) const { return !func->WhileEachInst([](Instruction* inst) { - const auto opcode = inst->opcode(); - return (opcode != SpvOpKill) && (opcode != SpvOpTerminateInvocation); + return !spvOpcodeTerminatesExecution(inst->opcode()); }); } diff --git a/source/opt/ir_loader.cpp b/source/opt/ir_loader.cpp index 06099ce0..70e5144a 100644 --- a/source/opt/ir_loader.cpp +++ b/source/opt/ir_loader.cpp @@ -137,7 +137,7 @@ bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) { return false; } block_ = MakeUnique(std::move(spv_inst)); - } else if (IsTerminatorInst(opcode)) { + } else if (spvOpcodeIsBlockTerminator(opcode)) { if (function_ == nullptr) { Error(consumer_, src, loc, "terminator instruction outside function"); return false; diff --git a/source/opt/module.cpp b/source/opt/module.cpp index 9d3b0edc..0c886010 100644 --- a/source/opt/module.cpp +++ b/source/opt/module.cpp @@ -188,7 +188,7 @@ void Module::ToBinary(std::vector* binary, bool skip_nop) const { i->ToBinaryWithoutAttachedDebugInsts(binary); } // Update the last line instruction. - if (IsTerminatorInst(opcode) || opcode == SpvOpNoLine) { + if (spvOpcodeIsBlockTerminator(opcode) || opcode == SpvOpNoLine) { last_line_inst = nullptr; } else if (opcode == SpvOpLoopMerge || opcode == SpvOpSelectionMerge) { between_merge_and_branch = true; diff --git a/source/opt/reflect.h b/source/opt/reflect.h index d374e682..c7d46df5 100644 --- a/source/opt/reflect.h +++ b/source/opt/reflect.h @@ -59,10 +59,6 @@ inline bool IsCompileTimeConstantInst(SpvOp opcode) { inline bool IsSpecConstantInst(SpvOp opcode) { return opcode >= SpvOpSpecConstantTrue && opcode <= SpvOpSpecConstantOp; } -inline bool IsTerminatorInst(SpvOp opcode) { - return (opcode >= SpvOpBranch && opcode <= SpvOpUnreachable) || - (opcode == SpvOpTerminateInvocation); -} } // namespace opt } // namespace spvtools diff --git a/test/opt/inline_test.cpp b/test/opt/inline_test.cpp index d3ef09c3..29399013 100644 --- a/test/opt/inline_test.cpp +++ b/test/opt/inline_test.cpp @@ -2581,6 +2581,63 @@ OpFunctionEnd SinglePassRunAndCheck(before, after, false, true); } +TEST_F(InlineTest, InlineFuncWithOpTerminateRayNotInContinue) { + const std::string text = + R"( + OpCapability RayTracingKHR + OpExtension "SPV_KHR_ray_tracing" + OpMemoryModel Logical GLSL450 + OpEntryPoint AnyHitKHR %MyAHitMain2 "MyAHitMain2" %a + OpSource HLSL 630 + OpName %a "a" + OpName %MyAHitMain2 "MyAHitMain2" + OpName %param_var_a "param.var.a" + OpName %src_MyAHitMain2 "src.MyAHitMain2" + OpName %a_0 "a" + OpName %bb_entry "bb.entry" + %int = OpTypeInt 32 1 +%_ptr_IncomingRayPayloadKHR_int = OpTypePointer IncomingRayPayloadKHR %int + %void = OpTypeVoid + %6 = OpTypeFunction %void +%_ptr_Function_int = OpTypePointer Function %int + %14 = OpTypeFunction %void %_ptr_Function_int + %a = OpVariable %_ptr_IncomingRayPayloadKHR_int IncomingRayPayloadKHR +%MyAHitMain2 = OpFunction %void None %6 + %7 = OpLabel +%param_var_a = OpVariable %_ptr_Function_int Function + %10 = OpLoad %int %a + OpStore %param_var_a %10 + %11 = OpFunctionCall %void %src_MyAHitMain2 %param_var_a + %13 = OpLoad %int %param_var_a + OpStore %a %13 + OpReturn + OpFunctionEnd +%src_MyAHitMain2 = OpFunction %void None %14 + %a_0 = OpFunctionParameter %_ptr_Function_int + %bb_entry = OpLabel + %17 = OpLoad %int %a_0 + OpStore %a %17 + OpTerminateRayKHR + OpFunctionEnd + +; CHECK: %MyAHitMain2 = OpFunction %void None +; CHECK-NEXT: OpLabel +; CHECK-NEXT: %param_var_a = OpVariable %_ptr_Function_int Function +; CHECK-NEXT: OpLoad %int %a +; CHECK-NEXT: OpStore %param_var_a {{%\d+}} +; CHECK-NEXT: OpLoad %int %param_var_a +; CHECK-NEXT: OpStore %a {{%\d+}} +; CHECK-NEXT: OpTerminateRayKHR +; CHECK-NEXT: OpLabel +; CHECK-NEXT: OpLoad %int %param_var_a +; CHECK-NEXT: OpStore %a %16 +; CHECK-NEXT: OpReturn +; CHECK-NEXT: OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, false); +} + TEST_F(InlineTest, EarlyReturnFunctionInlined) { // #version 140 // -- cgit v1.2.3 From b27b1afd12d05bf238ac7368bb49de73cd620a8e Mon Sep 17 00:00:00 2001 From: Diego Novillo Date: Mon, 7 Dec 2020 11:14:01 -0500 Subject: Update CHANGES to include latest ray tacing fixes. --- CHANGES | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 94d6e2d2..d7a49f72 100644 --- a/CHANGES +++ b/CHANGES @@ -1,14 +1,15 @@ Revision history for SPIRV-Tools -v2020.7-dev 2020-12-03 +v2020.7-dev 2020-12-07 - Start v2020.7-dev -v2020.6 2020-12-02 +v2020.6 2020-12-07 - General CMake: Add SPIRV_TOOLS_BUILD_STATIC flag (#3910) - Disassembler Add some context comments to disassembly. (#3847) - Optimizer + - Take new (raytracing) termination instructions into account. (#4050) - Do run DCE if SPV_KHR_ray_query is used. (#4047) - Handle 8-bit index in elim dead member (#4043) - Add texel buffer out-of-bounds checking instrumentation (#4038) -- cgit v1.2.3 From bda102d7a76e31702a887737f9b46d27478382c0 Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Mon, 7 Dec 2020 20:42:25 +0100 Subject: opt: Run DCE when SPV_KHR_shader_clock is used (#4049) Similar to [1] DCE should be ran when this extension is enabled to prevent unused bindings from showing up (in particular atomic counters attached to buffers). [1]: https://github.com/KhronosGroup/SPIRV-Tools/pull/4047 --- source/opt/aggressive_dead_code_elim_pass.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/source/opt/aggressive_dead_code_elim_pass.cpp b/source/opt/aggressive_dead_code_elim_pass.cpp index 94451a29..81b2232f 100644 --- a/source/opt/aggressive_dead_code_elim_pass.cpp +++ b/source/opt/aggressive_dead_code_elim_pass.cpp @@ -995,6 +995,7 @@ void AggressiveDCEPass::InitExtensions() { "SPV_EXT_fragment_invocation_density", "SPV_EXT_physical_storage_buffer", "SPV_KHR_terminate_invocation", + "SPV_KHR_shader_clock", }); } -- cgit v1.2.3 From 862d44a86ede5b18da5bd1315c725fc1b4027d63 Mon Sep 17 00:00:00 2001 From: alan-baker Date: Tue, 8 Dec 2020 08:46:47 -0500 Subject: Allow forward pointer to be used in types generally (#4044) Fixes #4042 * Allow types to have forward declarations as long as that declaration is an OpTypeForwardPointer --- source/operand.cpp | 7 ++++++- source/val/validate_id.cpp | 2 +- test/val/val_data_test.cpp | 36 +++++++++++++++++++++++++++++++++++- 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/source/operand.cpp b/source/operand.cpp index d4b64a8b..6755eaba 100644 --- a/source/operand.cpp +++ b/source/operand.cpp @@ -24,6 +24,7 @@ #include "DebugInfo.h" #include "OpenCLDebugInfo100.h" #include "source/macro.h" +#include "source/opcode.h" #include "source/spirv_constant.h" #include "source/spirv_target_env.h" @@ -491,6 +492,11 @@ bool spvIsInIdType(spv_operand_type_t type) { std::function spvOperandCanBeForwardDeclaredFunction( SpvOp opcode) { std::function out; + if (spvOpcodeGeneratesType(opcode)) { + // All types can use forward pointers. + out = [](unsigned) { return true; }; + return out; + } switch (opcode) { case SpvOpExecutionMode: case SpvOpExecutionModeId: @@ -503,7 +509,6 @@ std::function spvOperandCanBeForwardDeclaredFunction( case SpvOpDecorateId: case SpvOpDecorateStringGOOGLE: case SpvOpMemberDecorateStringGOOGLE: - case SpvOpTypeStruct: case SpvOpBranch: case SpvOpLoopMerge: out = [](unsigned) { return true; }; diff --git a/source/val/validate_id.cpp b/source/val/validate_id.cpp index e1a775a8..2bab2034 100644 --- a/source/val/validate_id.cpp +++ b/source/val/validate_id.cpp @@ -201,7 +201,7 @@ spv_result_t IdPass(ValidationState_t& _, Instruction* inst) { ret = SPV_SUCCESS; } } else if (can_have_forward_declared_ids(i)) { - if (inst->opcode() == SpvOpTypeStruct && + if (spvOpcodeGeneratesType(inst->opcode()) && !_.IsForwardPointer(operand_word)) { ret = _.diag(SPV_ERROR_INVALID_ID, inst) << "Operand " << _.getIdName(operand_word) diff --git a/test/val/val_data_test.cpp b/test/val/val_data_test.cpp index 30afd03c..1080a59f 100644 --- a/test/val/val_data_test.cpp +++ b/test/val/val_data_test.cpp @@ -497,7 +497,7 @@ TEST_F(ValidateData, ids_should_be_validated_before_data) { CompileSuccessfully(str.c_str()); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("ID 3[%3] has not been defined")); + HasSubstr("Operand 3[%3] requires a previous definition")); } TEST_F(ValidateData, matrix_bad_column_type) { @@ -944,6 +944,40 @@ TEST_F(ValidateData, webgpu_RTA_not_at_end_of_struct) { "OpTypeStruct %_runtimearr_uint %uint\n")); } +TEST_F(ValidateData, TypeForwardReference) { + std::string test = R"( +OpCapability Shader +OpCapability PhysicalStorageBufferAddresses +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpTypeForwardPointer %1 PhysicalStorageBuffer +%2 = OpTypeStruct +%3 = OpTypeRuntimeArray %1 +%1 = OpTypePointer PhysicalStorageBuffer %2 +)"; + + CompileSuccessfully(test, SPV_ENV_UNIVERSAL_1_5); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5)); +} + +TEST_F(ValidateData, TypeForwardReferenceMustBeForwardPointer) { + std::string test = R"( +OpCapability Shader +OpCapability PhysicalStorageBufferAddresses +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%1 = OpTypeStruct +%2 = OpTypeRuntimeArray %3 +%3 = OpTypePointer PhysicalStorageBuffer %1 +)"; + + CompileSuccessfully(test, SPV_ENV_UNIVERSAL_1_5); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Operand 3[%_ptr_PhysicalStorageBuffer__struct_1] " + "requires a previous definition")); +} + } // namespace } // namespace val } // namespace spvtools -- cgit v1.2.3 From 9df5225e672fe33a3a5899db69b99352c38f7879 Mon Sep 17 00:00:00 2001 From: sfricke-samsung <46493288+sfricke-samsung@users.noreply.github.com> Date: Tue, 8 Dec 2020 11:31:40 -0800 Subject: spirv-val: Add last Position VUID (#4052) --- source/val/validate_builtins.cpp | 11 +++++++++-- source/val/validation_state.cpp | 2 ++ test/val/val_builtins_test.cpp | 14 +++++++++++++- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/source/val/validate_builtins.cpp b/source/val/validate_builtins.cpp index 1d8a1406..86adac91 100644 --- a/source/val/validate_builtins.cpp +++ b/source/val/validate_builtins.cpp @@ -1869,7 +1869,7 @@ spv_result_t BuiltInsValidator::ValidatePositionAtReference( storage_class != SpvStorageClassInput && storage_class != SpvStorageClassOutput) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) - << "Vulkan spec allows BuiltIn Position to be only used for " + << _.VkErrorID(4320) << "Vulkan spec allows BuiltIn Position to be only used for " "variables with Input or Output storage class. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, referenced_from_inst) @@ -1879,12 +1879,19 @@ spv_result_t BuiltInsValidator::ValidatePositionAtReference( if (storage_class == SpvStorageClassInput) { assert(function_id_ == 0); id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind( - &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4320, + &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4319, "Vulkan spec doesn't allow BuiltIn Position to be used " "for variables " "with Input storage class if execution model is Vertex.", SpvExecutionModelVertex, decoration, built_in_inst, referenced_from_inst, std::placeholders::_1)); + id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind( + &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4319, + "Vulkan spec doesn't allow BuiltIn Position to be used " + "for variables " + "with Input storage class if execution model is MeshNV.", + SpvExecutionModelMeshNV, decoration, built_in_inst, + referenced_from_inst, std::placeholders::_1)); } for (const SpvExecutionModel execution_model : execution_models_) { diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index 06abb54f..bf756fef 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -1477,6 +1477,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-PointSize-PointSize-04317); case 4318: return VUID_WRAP(VUID-Position-Position-04318); + case 4319: + return VUID_WRAP(VUID-Position-Position-04319); case 4320: return VUID_WRAP(VUID-Position-Position-04320); case 4321: diff --git a/test/val/val_builtins_test.cpp b/test/val/val_builtins_test.cpp index 936279a2..3fc06fbb 100644 --- a/test/val/val_builtins_test.cpp +++ b/test/val/val_builtins_test.cpp @@ -1539,11 +1539,23 @@ INSTANTIATE_TEST_SUITE_P( "WebGPU spec allows BuiltIn Position to be only used " "for variables with Output storage class")))); +INSTANTIATE_TEST_SUITE_P( + PositionInvalidStorageClass, + ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, + Combine(Values("Position"), + Values("Geometry", "TessellationControl", "TessellationEvaluation"), + Values("Private"), Values("%f32vec4"), + Values("VUID-Position-Position-04320"), + Values(TestResult( + SPV_ERROR_INVALID_DATA, + "Vulkan spec allows BuiltIn Position to be only used for " + "variables with Input or Output storage class.")))); + INSTANTIATE_TEST_SUITE_P( PositionVertexInput, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("Position"), Values("Vertex"), Values("Input"), - Values("%f32vec4"), Values("VUID-Position-Position-04320"), + Values("%f32vec4"), Values("VUID-Position-Position-04319"), Values(TestResult( SPV_ERROR_INVALID_DATA, "Vulkan spec doesn't allow BuiltIn Position " -- cgit v1.2.3 From 1a6b4053fa01990b87748b9f26b297d55acf8cbc Mon Sep 17 00:00:00 2001 From: sfricke-samsung <46493288+sfricke-samsung@users.noreply.github.com> Date: Tue, 8 Dec 2020 11:34:51 -0800 Subject: spirv-val: Add last ViewportIndex and Layer VUID (#4053) --- source/val/validate_builtins.cpp | 3 ++- source/val/validation_state.cpp | 4 ++++ test/val/val_builtins_test.cpp | 5 +++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/source/val/validate_builtins.cpp b/source/val/validate_builtins.cpp index 86adac91..557e0678 100644 --- a/source/val/validate_builtins.cpp +++ b/source/val/validate_builtins.cpp @@ -2775,8 +2775,9 @@ spv_result_t BuiltInsValidator::ValidateLayerOrViewportIndexAtReference( if (operand == SpvBuiltInLayer) capability = "ShaderViewportIndexLayerEXT or ShaderLayer"; + uint32_t vuid = (operand == SpvBuiltInLayer) ? 4273 : 4405; return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) - << "Using BuiltIn " + << _.VkErrorID(vuid) << "Using BuiltIn " << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, operand) << " in Vertex or Tessellation execution model requires the " diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index bf756fef..1d6791ee 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -1419,6 +1419,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-LaunchSizeKHR-LaunchSizeKHR-04271); case 4272: return VUID_WRAP(VUID-Layer-Layer-04272); + case 4273: + return VUID_WRAP(VUID-Layer-Layer-04273); case 4274: return VUID_WRAP(VUID-Layer-Layer-04274); case 4275: @@ -1553,6 +1555,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-ViewIndex-ViewIndex-04403); case 4404: return VUID_WRAP(VUID-ViewportIndex-ViewportIndex-04404); + case 4405: + return VUID_WRAP(VUID-ViewportIndex-ViewportIndex-04405); case 4406: return VUID_WRAP(VUID-ViewportIndex-ViewportIndex-04406); case 4407: diff --git a/test/val/val_builtins_test.cpp b/test/val/val_builtins_test.cpp index 3fc06fbb..f9bab292 100644 --- a/test/val/val_builtins_test.cpp +++ b/test/val/val_builtins_test.cpp @@ -1256,7 +1256,8 @@ INSTANTIATE_TEST_SUITE_P( ViewportIndexExecutionModelEnabledByCapability, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("ViewportIndex"), Values("Vertex", "TessellationEvaluation"), - Values("Output"), Values("%u32"), Values(nullptr), + Values("Output"), Values("%u32"), + Values("VUID-ViewportIndex-ViewportIndex-04405"), Values(TestResult( SPV_ERROR_INVALID_DATA, "ShaderViewportIndexLayerEXT or ShaderViewportIndex")))); @@ -1265,7 +1266,7 @@ INSTANTIATE_TEST_SUITE_P( LayerExecutionModelEnabledByCapability, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("Layer"), Values("Vertex", "TessellationEvaluation"), - Values("Output"), Values("%u32"), Values(nullptr), + Values("Output"), Values("%u32"), Values("VUID-Layer-Layer-04273"), Values(TestResult(SPV_ERROR_INVALID_DATA, "ShaderViewportIndexLayerEXT or ShaderLayer")))); -- cgit v1.2.3 From 171290703a64a4e9bbf79fa3fdb18be49939d332 Mon Sep 17 00:00:00 2001 From: sfricke-samsung <46493288+sfricke-samsung@users.noreply.github.com> Date: Tue, 8 Dec 2020 11:37:24 -0800 Subject: spirv-val: Add last ClipDistance and CullDistance VUID (#4054) --- source/val/validate_builtins.cpp | 16 +++++++++++++--- source/val/validation_state.cpp | 12 ++++++++++++ test/val/val_builtins_test.cpp | 22 ++++++++++++++++++++-- 3 files changed, 45 insertions(+), 5 deletions(-) diff --git a/source/val/validate_builtins.cpp b/source/val/validate_builtins.cpp index 557e0678..9a3e481e 100644 --- a/source/val/validate_builtins.cpp +++ b/source/val/validate_builtins.cpp @@ -1098,8 +1098,9 @@ spv_result_t BuiltInsValidator::ValidateClipOrCullDistanceAtReference( if (storage_class != SpvStorageClassMax && storage_class != SpvStorageClassInput && storage_class != SpvStorageClassOutput) { + uint32_t vuid = (decoration.params()[0] == SpvBuiltInClipDistance) ? 4190 : 4199; return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) - << "Vulkan spec allows BuiltIn " + << _.VkErrorID(vuid) << "Vulkan spec allows BuiltIn " << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, operand) << " to be only used for variables with Input or Output storage " @@ -1111,19 +1112,28 @@ spv_result_t BuiltInsValidator::ValidateClipOrCullDistanceAtReference( if (storage_class == SpvStorageClassInput) { assert(function_id_ == 0); + uint32_t vuid = (decoration.params()[0] == SpvBuiltInClipDistance) ? 4188 : 4197; id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind( - &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, -1, + &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, vuid, "Vulkan spec doesn't allow BuiltIn ClipDistance/CullDistance to be " "used for variables with Input storage class if execution model is " "Vertex.", SpvExecutionModelVertex, decoration, built_in_inst, referenced_from_inst, std::placeholders::_1)); + id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind( + &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, vuid, + "Vulkan spec doesn't allow BuiltIn ClipDistance/CullDistance to be " + "used for variables with Input storage class if execution model is " + "Vertex.", + SpvExecutionModelMeshNV, decoration, built_in_inst, + referenced_from_inst, std::placeholders::_1)); } if (storage_class == SpvStorageClassOutput) { assert(function_id_ == 0); + uint32_t vuid = (decoration.params()[0] == SpvBuiltInClipDistance) ? 4189 : 4198; id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind( - &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, -1, + &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, vuid, "Vulkan spec doesn't allow BuiltIn ClipDistance/CullDistance to be " "used for variables with Output storage class if execution model is " "Fragment.", diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index 1d6791ee..50c12404 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -1315,10 +1315,22 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-BaseVertex-BaseVertex-04186); case 4187: return VUID_WRAP(VUID-ClipDistance-ClipDistance-04187); + case 4188: + return VUID_WRAP(VUID-ClipDistance-ClipDistance-04188); + case 4189: + return VUID_WRAP(VUID-ClipDistance-ClipDistance-04189); + case 4190: + return VUID_WRAP(VUID-ClipDistance-ClipDistance-04190); case 4191: return VUID_WRAP(VUID-ClipDistance-ClipDistance-04191); case 4196: return VUID_WRAP(VUID-CullDistance-CullDistance-04196); + case 4197: + return VUID_WRAP(VUID-CullDistance-CullDistance-04197); + case 4198: + return VUID_WRAP(VUID-CullDistance-CullDistance-04198); + case 4199: + return VUID_WRAP(VUID-CullDistance-CullDistance-04199); case 4200: return VUID_WRAP(VUID-CullDistance-CullDistance-04200); case 4205: diff --git a/test/val/val_builtins_test.cpp b/test/val/val_builtins_test.cpp index f9bab292..f0cd3821 100644 --- a/test/val/val_builtins_test.cpp +++ b/test/val/val_builtins_test.cpp @@ -641,11 +641,27 @@ INSTANTIATE_TEST_SUITE_P( Values("Input"), Values("%f32arr2", "%f32arr4"), Values(nullptr), Values(TestResult()))); +INSTANTIATE_TEST_SUITE_P( + ClipAndCullDistanceInvalidStorageClass, + ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, + Combine(Values("ClipDistance", "CullDistance"), + Values("Vertex", "Geometry", "TessellationControl", + "TessellationEvaluation"), + Values("Private"), Values("%f32arr2", "%f32arr4"), + Values("VUID-ClipDistance-ClipDistance-04190 " + "VUID-CullDistance-CullDistance-04199"), + Values(TestResult( + SPV_ERROR_INVALID_DATA, + "to be only used for variables with Input or Output storage " + "class.")))); + INSTANTIATE_TEST_SUITE_P( ClipAndCullDistanceFragmentOutput, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("ClipDistance", "CullDistance"), Values("Fragment"), - Values("Output"), Values("%f32arr4"), Values(nullptr), + Values("Output"), Values("%f32arr4"), + Values("VUID-ClipDistance-ClipDistance-04189 " + "VUID-CullDistance-CullDistance-04198"), Values(TestResult( SPV_ERROR_INVALID_DATA, "Vulkan spec doesn't allow BuiltIn ClipDistance/CullDistance " @@ -667,7 +683,9 @@ INSTANTIATE_TEST_SUITE_P( ClipAndCullDistanceVertexInput, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("ClipDistance", "CullDistance"), Values("Vertex"), - Values("Input"), Values("%f32arr4"), Values(nullptr), + Values("Input"), Values("%f32arr4"), + Values("VUID-ClipDistance-ClipDistance-04188 " + "VUID-CullDistance-CullDistance-04197"), Values(TestResult( SPV_ERROR_INVALID_DATA, "Vulkan spec doesn't allow BuiltIn ClipDistance/CullDistance " -- cgit v1.2.3 From 3b85234542cadf0e496788fcc2f20697152e72f8 Mon Sep 17 00:00:00 2001 From: sfricke-samsung <46493288+sfricke-samsung@users.noreply.github.com> Date: Tue, 8 Dec 2020 11:38:55 -0800 Subject: spirv-val: Add last TessLevelOuter and TessLevelInner VUID (#4055) --- source/val/validate_builtins.cpp | 6 ++++-- source/val/validation_state.cpp | 8 ++++++++ test/val/val_builtins_test.cpp | 12 ++++++++---- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/source/val/validate_builtins.cpp b/source/val/validate_builtins.cpp index 9a3e481e..d85d1f0b 100644 --- a/source/val/validate_builtins.cpp +++ b/source/val/validate_builtins.cpp @@ -2475,8 +2475,9 @@ spv_result_t BuiltInsValidator::ValidateTessLevelAtReference( if (storage_class == SpvStorageClassInput) { assert(function_id_ == 0); + uint32_t vuid = (decoration.params()[0] == SpvBuiltInTessLevelOuter) ? 4391 : 4395; id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind( - &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, -1, + &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, vuid, "Vulkan spec doesn't allow TessLevelOuter/TessLevelInner to be " "used " "for variables with Input storage class if execution model is " @@ -2487,8 +2488,9 @@ spv_result_t BuiltInsValidator::ValidateTessLevelAtReference( if (storage_class == SpvStorageClassOutput) { assert(function_id_ == 0); + uint32_t vuid = (decoration.params()[0] == SpvBuiltInTessLevelOuter) ? 4392 : 4396; id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind( - &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, -1, + &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, vuid, "Vulkan spec doesn't allow TessLevelOuter/TessLevelInner to be " "used " "for variables with Output storage class if execution model is " diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index 50c12404..1d67345b 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -1547,10 +1547,18 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-TessCoord-TessCoord-04389); case 4390: return VUID_WRAP(VUID-TessLevelOuter-TessLevelOuter-04390); + case 4391: + return VUID_WRAP(VUID-TessLevelOuter-TessLevelOuter-04391); + case 4392: + return VUID_WRAP(VUID-TessLevelOuter-TessLevelOuter-04392); case 4393: return VUID_WRAP(VUID-TessLevelOuter-TessLevelOuter-04393); case 4394: return VUID_WRAP(VUID-TessLevelInner-TessLevelInner-04394); + case 4395: + return VUID_WRAP(VUID-TessLevelInner-TessLevelInner-04395); + case 4396: + return VUID_WRAP(VUID-TessLevelInner-TessLevelInner-04396); case 4397: return VUID_WRAP(VUID-TessLevelInner-TessLevelInner-04397); case 4398: diff --git a/test/val/val_builtins_test.cpp b/test/val/val_builtins_test.cpp index f0cd3821..cce3cd54 100644 --- a/test/val/val_builtins_test.cpp +++ b/test/val/val_builtins_test.cpp @@ -1949,7 +1949,8 @@ INSTANTIATE_TEST_SUITE_P( TessLevelOuterOutputTese, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("TessLevelOuter"), Values("TessellationEvaluation"), - Values("Output"), Values("%f32arr4"), Values(nullptr), + Values("Output"), Values("%f32arr4"), + Values("VUID-TessLevelOuter-TessLevelOuter-04392"), Values(TestResult( SPV_ERROR_INVALID_DATA, "Vulkan spec doesn't allow TessLevelOuter/TessLevelInner to be " @@ -1960,7 +1961,8 @@ INSTANTIATE_TEST_SUITE_P( TessLevelOuterInputTesc, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("TessLevelOuter"), Values("TessellationControl"), - Values("Input"), Values("%f32arr4"), Values(nullptr), + Values("Input"), Values("%f32arr4"), + Values("VUID-TessLevelOuter-TessLevelOuter-04391"), Values(TestResult( SPV_ERROR_INVALID_DATA, "Vulkan spec doesn't allow TessLevelOuter/TessLevelInner to be " @@ -2036,7 +2038,8 @@ INSTANTIATE_TEST_SUITE_P( TessLevelInnerOutputTese, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("TessLevelInner"), Values("TessellationEvaluation"), - Values("Output"), Values("%f32arr2"), Values(nullptr), + Values("Output"), Values("%f32arr2"), + Values("VUID-TessLevelInner-TessLevelInner-04396"), Values(TestResult( SPV_ERROR_INVALID_DATA, "Vulkan spec doesn't allow TessLevelOuter/TessLevelInner to be " @@ -2047,7 +2050,8 @@ INSTANTIATE_TEST_SUITE_P( TessLevelInnerInputTesc, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("TessLevelInner"), Values("TessellationControl"), - Values("Input"), Values("%f32arr2"), Values(nullptr), + Values("Input"), Values("%f32arr2"), + Values("VUID-TessLevelInner-TessLevelInner-04395"), Values(TestResult( SPV_ERROR_INVALID_DATA, "Vulkan spec doesn't allow TessLevelOuter/TessLevelInner to be " -- cgit v1.2.3 From 7170218b8deb9f6a0eade971159d1b8cbb44cacf Mon Sep 17 00:00:00 2001 From: David Neto Date: Thu, 10 Dec 2020 10:40:46 -0500 Subject: validate StorageImageMultisampled capability (#4062) * validate StorageImageMultisampled capability The StorageImageMultisampled capability is required when declaring an image type with with Multisampled==1 and it's a storage image (Sampled == 2) Fixes #4061 * Allow SubpassData with Multisampled and Sampled==2 --- source/val/validate_image.cpp | 9 +++++++++ test/val/val_image_test.cpp | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/source/val/validate_image.cpp b/source/val/validate_image.cpp index 299a3efc..17ddfc05 100644 --- a/source/val/validate_image.cpp +++ b/source/val/validate_image.cpp @@ -829,6 +829,15 @@ spv_result_t ValidateTypeImage(ValidationState_t& _, const Instruction* inst) { } } + if (info.multisampled && (info.sampled == 2) && + (info.dim != SpvDimSubpassData)) { + if (!_.HasCapability(SpvCapabilityStorageImageMultisample)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Capability StorageImageMultisample is required when using " + "multisampled storage image"; + } + } + return SPV_SUCCESS; } diff --git a/test/val/val_image_test.cpp b/test/val/val_image_test.cpp index 2e84a29f..d2e1a55a 100644 --- a/test/val/val_image_test.cpp +++ b/test/val/val_image_test.cpp @@ -584,6 +584,43 @@ TEST_F(ValidateImage, TypeImageWrongFormatForSubpassData) { HasSubstr("Dim SubpassData requires format Unknown")); } +TEST_F(ValidateImage, TypeImageMultisampleStorageImage_MissingCapability) { + const std::string code = GetShaderHeader("", false) + + R"( +%img_type = OpTypeImage %f32 2D 0 0 1 2 Rgba32f +)"; + + CompileSuccessfully(code.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()) << code; + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Capability StorageImageMultisample is required when " + "using multisampled storage image")); +} + +TEST_F(ValidateImage, TypeImageMultisampleStorageImage_UsesCapability) { + const std::string code = + GetShaderHeader("OpCapability StorageImageMultisample\n", false) + + R"( +%img_type = OpTypeImage %f32 2D 0 0 1 2 Rgba32f +)"; + + CompileSuccessfully(code.c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()) << code; + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateImage, TypeImageMultisampleSubpassData_OK) { + const std::string code = + GetShaderHeader("OpCapability InputAttachment\n", false) + + R"( +%img_type = OpTypeImage %f32 SubpassData 0 0 1 2 Unknown +)"; + + CompileSuccessfully(code.c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()) << code; + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + TEST_F(ValidateImage, TypeSampledImageNotImage) { const std::string code = GetShaderHeader("", false) + R"( %simg_type = OpTypeSampledImage %f32 -- cgit v1.2.3 From 09d1fea5890cdf993a89b578b9a6ebbb97bbc3d6 Mon Sep 17 00:00:00 2001 From: Ryan Harrison Date: Thu, 10 Dec 2020 13:39:37 -0500 Subject: Force using Python 3 git-sync-deps (#4067) This scripts fails to run in Python 2. For systems that have both Python 2 and 3 installed, depending on your PATH the existing code may or may not run. Explictly using Python 3 to avoid this. --- utils/git-sync-deps | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/git-sync-deps b/utils/git-sync-deps index 05756413..eecfbe93 100755 --- a/utils/git-sync-deps +++ b/utils/git-sync-deps @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2014 Google Inc. # # Redistribution and use in source and binary forms, with or without -- cgit v1.2.3 From a0370efd589be33d5d9a85cfde2f85841b3755af Mon Sep 17 00:00:00 2001 From: David Neto Date: Thu, 10 Dec 2020 17:15:46 -0500 Subject: validate OpTypeImage Sampled values for environemnts (#4064) Fixes #4063 --- source/val/validate_image.cpp | 20 ++- test/val/val_image_test.cpp | 318 ++++++++++++++++++++++++++++++++---------- test/val/val_opencl_test.cpp | 2 +- 3 files changed, 257 insertions(+), 83 deletions(-) diff --git a/source/val/validate_image.cpp b/source/val/validate_image.cpp index 17ddfc05..0a0eeee8 100644 --- a/source/val/validate_image.cpp +++ b/source/val/validate_image.cpp @@ -736,7 +736,8 @@ spv_result_t ValidateTypeImage(ValidationState_t& _, const Instruction* inst) { << "Corrupt image type definition"; } - if (spvIsVulkanEnv(_.context()->target_env)) { + const auto target_env = _.context()->target_env; + if (spvIsVulkanEnv(target_env)) { if ((!_.IsFloatScalarType(info.sampled_type) && !_.IsIntScalarType(info.sampled_type)) || (32 != _.GetBitWidth(info.sampled_type) && @@ -746,7 +747,7 @@ spv_result_t ValidateTypeImage(ValidationState_t& _, const Instruction* inst) { << "Expected Sampled Type to be a 32-bit int or float " "scalar type for Vulkan environment"; } - } else if (spvIsOpenCLEnv(_.context()->target_env)) { + } else if (spvIsOpenCLEnv(target_env)) { if (!_.IsVoidType(info.sampled_type)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Sampled Type must be OpTypeVoid in the OpenCL environment."; @@ -774,7 +775,7 @@ spv_result_t ValidateTypeImage(ValidationState_t& _, const Instruction* inst) { << "Invalid Arrayed " << info.arrayed << " (must be 0 or 1)"; } - if (spvIsOpenCLEnv(_.context()->target_env)) { + if (spvIsOpenCLEnv(target_env)) { if ((info.arrayed == 1) && (info.dim != SpvDim1D) && (info.dim != SpvDim2D)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) @@ -788,10 +789,10 @@ spv_result_t ValidateTypeImage(ValidationState_t& _, const Instruction* inst) { << "Invalid MS " << info.multisampled << " (must be 0 or 1)"; } - if (spvIsOpenCLEnv(_.context()->target_env)) { + if (spvIsOpenCLEnv(target_env)) { if (info.multisampled != 0) { return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "MS must be 0 in the OpenCL environement."; + << "MS must be 0 in the OpenCL environment."; } } @@ -800,6 +801,15 @@ spv_result_t ValidateTypeImage(ValidationState_t& _, const Instruction* inst) { << "Invalid Sampled " << info.sampled << " (must be 0, 1 or 2)"; } + if (spvIsVulkanEnv(target_env) || spvIsWebGPUEnv(target_env)) { + if (info.sampled == 0) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Sampled must be 1 or 2 in the " + << (spvIsVulkanEnv(target_env) ? "Vulkan" : "WebGPU") + << " environment."; + } + } + if (spvIsOpenCLEnv(_.context()->target_env)) { if (info.sampled != 0) { return _.diag(SPV_ERROR_INVALID_DATA, inst) diff --git a/test/val/val_image_test.cpp b/test/val/val_image_test.cpp index d2e1a55a..31f93752 100644 --- a/test/val/val_image_test.cpp +++ b/test/val/val_image_test.cpp @@ -66,9 +66,9 @@ OpCapability ImageBuffer %uniform_image_f32_1d_0001 %uniform_image_f32_1d_0002_rgba32f %uniform_image_f32_2d_0001 -%uniform_image_f32_2d_0010 +%uniform_image_f32_2d_0011 %uniform_image_u32_2d_0001 -%uniform_image_u32_2d_0000 +%uniform_image_u32_2d_0002 %uniform_image_s32_3d_0001 %uniform_image_f32_2d_0002 %uniform_image_s32_2d_0002 @@ -99,12 +99,12 @@ OpDecorate %uniform_image_f32_1d_0002_rgba32f DescriptorSet 0 OpDecorate %uniform_image_f32_1d_0002_rgba32f Binding 1 OpDecorate %uniform_image_f32_2d_0001 DescriptorSet 0 OpDecorate %uniform_image_f32_2d_0001 Binding 2 -OpDecorate %uniform_image_f32_2d_0010 DescriptorSet 0 -OpDecorate %uniform_image_f32_2d_0010 Binding 3 +OpDecorate %uniform_image_f32_2d_0011 DescriptorSet 0 +OpDecorate %uniform_image_f32_2d_0011 Binding 3 OpDecorate %uniform_image_u32_2d_0001 DescriptorSet 1 OpDecorate %uniform_image_u32_2d_0001 Binding 0 -OpDecorate %uniform_image_u32_2d_0000 DescriptorSet 1 -OpDecorate %uniform_image_u32_2d_0000 Binding 1 +OpDecorate %uniform_image_u32_2d_0002 DescriptorSet 1 +OpDecorate %uniform_image_u32_2d_0002 Binding 1 OpDecorate %uniform_image_s32_3d_0001 DescriptorSet 1 OpDecorate %uniform_image_s32_3d_0001 Binding 2 OpDecorate %uniform_image_f32_2d_0002 DescriptorSet 1 @@ -230,20 +230,20 @@ OpDecorate %uniform_sampler Binding 0 %uniform_image_f32_2d_0001 = OpVariable %ptr_image_f32_2d_0001 UniformConstant %type_sampled_image_f32_2d_0001 = OpTypeSampledImage %type_image_f32_2d_0001 -%type_image_f32_2d_0010 = OpTypeImage %f32 2D 0 0 1 0 Unknown -%ptr_image_f32_2d_0010 = OpTypePointer UniformConstant %type_image_f32_2d_0010 -%uniform_image_f32_2d_0010 = OpVariable %ptr_image_f32_2d_0010 UniformConstant -%type_sampled_image_f32_2d_0010 = OpTypeSampledImage %type_image_f32_2d_0010 +%type_image_f32_2d_0011 = OpTypeImage %f32 2D 0 0 1 1 Unknown +%ptr_image_f32_2d_0011 = OpTypePointer UniformConstant %type_image_f32_2d_0011 +%uniform_image_f32_2d_0011 = OpVariable %ptr_image_f32_2d_0011 UniformConstant +%type_sampled_image_f32_2d_0011 = OpTypeSampledImage %type_image_f32_2d_0011 %type_image_u32_2d_0001 = OpTypeImage %u32 2D 0 0 0 1 Unknown %ptr_image_u32_2d_0001 = OpTypePointer UniformConstant %type_image_u32_2d_0001 %uniform_image_u32_2d_0001 = OpVariable %ptr_image_u32_2d_0001 UniformConstant %type_sampled_image_u32_2d_0001 = OpTypeSampledImage %type_image_u32_2d_0001 -%type_image_u32_2d_0000 = OpTypeImage %u32 2D 0 0 0 0 Unknown -%ptr_image_u32_2d_0000 = OpTypePointer UniformConstant %type_image_u32_2d_0000 -%uniform_image_u32_2d_0000 = OpVariable %ptr_image_u32_2d_0000 UniformConstant -%type_sampled_image_u32_2d_0000 = OpTypeSampledImage %type_image_u32_2d_0000 +%type_image_u32_2d_0002 = OpTypeImage %u32 2D 0 0 0 2 Unknown +%ptr_image_u32_2d_0002 = OpTypePointer UniformConstant %type_image_u32_2d_0002 +%uniform_image_u32_2d_0002 = OpVariable %ptr_image_u32_2d_0002 UniformConstant +%type_sampled_image_u32_2d_0002 = OpTypeSampledImage %type_image_u32_2d_0002 %type_image_s32_3d_0001 = OpTypeImage %s32 3D 0 0 0 1 Unknown %ptr_image_s32_3d_0001 = OpTypePointer UniformConstant %type_image_s32_3d_0001 @@ -400,15 +400,15 @@ OpMemoryModel Physical32 OpenCL %uniform_image_f32_2d_0001 = OpVariable %ptr_image_f32_2d_0001 UniformConstant %type_sampled_image_f32_2d_0001 = OpTypeSampledImage %type_image_f32_2d_0001 -%type_image_f32_2d_0010 = OpTypeImage %f32 2D 0 0 1 0 Unknown -%ptr_image_f32_2d_0010 = OpTypePointer UniformConstant %type_image_f32_2d_0010 -%uniform_image_f32_2d_0010 = OpVariable %ptr_image_f32_2d_0010 UniformConstant -%type_sampled_image_f32_2d_0010 = OpTypeSampledImage %type_image_f32_2d_0010 +%type_image_f32_2d_0011 = OpTypeImage %f32 2D 0 0 1 1 Unknown +%ptr_image_f32_2d_0011 = OpTypePointer UniformConstant %type_image_f32_2d_0011 +%uniform_image_f32_2d_0011 = OpVariable %ptr_image_f32_2d_0011 UniformConstant +%type_sampled_image_f32_2d_0011 = OpTypeSampledImage %type_image_f32_2d_0011 -%type_image_f32_3d_0010 = OpTypeImage %f32 3D 0 0 1 0 Unknown -%ptr_image_f32_3d_0010 = OpTypePointer UniformConstant %type_image_f32_3d_0010 -%uniform_image_f32_3d_0010 = OpVariable %ptr_image_f32_3d_0010 UniformConstant -%type_sampled_image_f32_3d_0010 = OpTypeSampledImage %type_image_f32_3d_0010 +%type_image_f32_3d_0011 = OpTypeImage %f32 3D 0 0 1 1 Unknown +%ptr_image_f32_3d_0011 = OpTypePointer UniformConstant %type_image_f32_3d_0011 +%uniform_image_f32_3d_0011 = OpVariable %ptr_image_f32_3d_0011 UniformConstant +%type_sampled_image_f32_3d_0011 = OpTypeSampledImage %type_image_f32_3d_0011 %type_image_f32_rect_0001 = OpTypeImage %f32 Rect 0 0 0 1 Unknown %ptr_image_f32_rect_0001 = OpTypePointer UniformConstant %type_image_f32_rect_0001 @@ -431,6 +431,41 @@ OpFunctionEnd)"; return ss.str(); } +std::string GetKernelHeader() { + return R"( + OpCapability Kernel + OpCapability Addresses + OpCapability Linkage + OpMemoryModel Physical32 OpenCL + %void = OpTypeVoid + %func = OpTypeFunction %void + %f32 = OpTypeFloat 32 + %u32 = OpTypeInt 32 0 + )"; +} + +std::string TrivialMain() { + return R"( + %main = OpFunction %void None %func + %entry = OpLabel + OpReturn + OpFunctionEnd + )"; +} + +std::string GetWebGPUShaderHeader() { + return R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + %void = OpTypeVoid + %func = OpTypeFunction %void + %f32 = OpTypeFloat 32 + %u32 = OpTypeInt 32 0 + )"; +} + std::string GetShaderHeader(const std::string& capabilities_and_extensions = "", bool include_entry_point = true) { std::ostringstream ss; @@ -571,6 +606,112 @@ TEST_F(ValidateImage, TypeImageWrongSampledForSubpassData) { HasSubstr("Dim SubpassData requires Sampled to be 2")); } +TEST_F(ValidateImage, TypeImage_OpenCL_Sampled0_OK) { + const std::string code = GetKernelHeader() + R"( +%img_type = OpTypeImage %void 2D 0 0 0 0 Unknown ReadOnly +)"; + + CompileSuccessfully(code.c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_OPENCL_2_1)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateImage, TypeImage_OpenCL_Sampled1_Invalid) { + const std::string code = GetKernelHeader() + R"( +%img_type = OpTypeImage %void 2D 0 0 0 1 Unknown ReadOnly +)"; + + CompileSuccessfully(code.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_2_1)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Sampled must be 0 in the OpenCL environment.")); +} + +TEST_F(ValidateImage, TypeImage_OpenCL_Sampled2_Invalid) { + const std::string code = GetKernelHeader() + R"( +%img_type = OpTypeImage %void 2D 0 0 0 2 Unknown ReadOnly +)"; + + CompileSuccessfully(code.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_2_1)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Sampled must be 0 in the OpenCL environment.")); +} + +TEST_F(ValidateImage, TypeImage_OpenCL_AccessQualifierMissing) { + const std::string code = GetKernelHeader() + R"( +%img_type = OpTypeImage %void 2D 0 0 0 0 Unknown +)"; + + CompileSuccessfully(code.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_2_1)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("In the OpenCL environment, the optional Access " + "Qualifier must be present")); +} + +TEST_F(ValidateImage, TypeImage_Vulkan_Sampled1_OK) { + const std::string code = GetShaderHeader() + R"( +%img_type = OpTypeImage %f32 2D 0 0 0 1 Unknown +)" + TrivialMain(); + + CompileSuccessfully(code.c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateImage, TypeImage_Vulkan_Sampled2_OK) { + const std::string code = GetShaderHeader() + R"( +%img_type = OpTypeImage %f32 2D 0 0 0 2 Rgba32f +)" + TrivialMain(); + + CompileSuccessfully(code.c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateImage, TypeImage_Vulkan_Sampled0_Invalid) { + const std::string code = GetShaderHeader() + R"( +%img_type = OpTypeImage %f32 2D 0 0 0 0 Unknown +)" + TrivialMain(); + + CompileSuccessfully(code.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Sampled must be 1 or 2 in the Vulkan environment.")); +} + +TEST_F(ValidateImage, TypeImage_WebGPU_Sampled1_OK) { + const std::string code = GetWebGPUShaderHeader() + R"( +%img_type = OpTypeImage %f32 2D 0 0 0 1 Unknown +)" + TrivialMain(); + + CompileSuccessfully(code.c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateImage, TypeImage_WebGPU_Sampled2_OK) { + const std::string code = GetWebGPUShaderHeader() + R"( +%img_type = OpTypeImage %f32 2D 0 0 0 2 Rgba32f +)" + TrivialMain(); + + CompileSuccessfully(code.c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateImage, TypeImage_WebGPU_Sampled0_Invalid) { + const std::string code = GetWebGPUShaderHeader() + R"( +%img_type = OpTypeImage %f32 2D 0 0 0 0 Unknown +)" + TrivialMain(); + + CompileSuccessfully(code.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Sampled must be 1 or 2 in the WebGPU environment.")); +} + TEST_F(ValidateImage, TypeImageWrongFormatForSubpassData) { const std::string code = GetShaderHeader("OpCapability InputAttachment\n", false) + @@ -697,9 +838,9 @@ TEST_F(ValidateImage, SampledImageImageNotForSampling) { TEST_F(ValidateImage, SampledImageVulkanUnknownSampled) { const std::string body = R"( -%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 %sampler = OpLoad %type_sampler %uniform_sampler -%simg = OpSampledImage %type_sampled_image_u32_2d_0000 %img %sampler +%simg = OpSampledImage %type_sampled_image_u32_2d_0002 %img %sampler )"; const spv_target_env env = SPV_ENV_VULKAN_1_0; @@ -838,7 +979,7 @@ TEST_F(ValidateImage, ImageTexelPointerImageCoordTypeBad) { TEST_F(ValidateImage, ImageTexelPointerImageCoordSizeBad) { const std::string body = R"( -%texel_ptr = OpImageTexelPointer %ptr_Image_u32 %uniform_image_u32_2d_0000 %u32vec3_012 %u32_0 +%texel_ptr = OpImageTexelPointer %ptr_Image_u32 %uniform_image_u32_2d_0002 %u32vec3_012 %u32_0 %sum = OpAtomicIAdd %u32 %texel_ptr %u32_1 %u32_0 %u32_1 )"; @@ -1221,9 +1362,9 @@ TEST_F(ValidateImage, LodWrongDim) { TEST_F(ValidateImage, LodMultisampled) { const std::string body = R"( -%img = OpLoad %type_image_f32_2d_0010 %uniform_image_f32_2d_0010 +%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011 %sampler = OpLoad %type_sampler %uniform_sampler -%simg = OpSampledImage %type_sampled_image_f32_2d_0010 %img %sampler +%simg = OpSampledImage %type_sampled_image_f32_2d_0011 %img %sampler %res1 = OpImageSampleExplicitLod %f32vec4 %simg %f32vec2_00 Lod %f32_0)"; CompileSuccessfully(GenerateShaderCode(body).c_str()); @@ -2386,7 +2527,7 @@ TEST_F(ValidateImage, FetchSampledImageDirectly) { TEST_F(ValidateImage, FetchNotSampled) { const std::string body = R"( -%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 %res1 = OpImageFetch %u32vec4 %img %u32vec2_01 )"; @@ -2777,7 +2918,7 @@ TEST_F(ValidateImage, DrefGatherWrongDrefType) { TEST_F(ValidateImage, ReadSuccess1) { const std::string body = R"( -%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 %res1 = OpImageRead %u32vec4 %img %u32vec2_01 )"; @@ -2820,7 +2961,7 @@ TEST_F(ValidateImage, ReadSuccess4) { TEST_F(ValidateImage, ReadNeedCapabilityStorageImageReadWithoutFormat) { const std::string body = R"( -%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 %res1 = OpImageRead %u32vec4 %img %u32vec2_01 )"; @@ -2830,7 +2971,7 @@ TEST_F(ValidateImage, ReadNeedCapabilityStorageImageReadWithoutFormat) { TEST_F(ValidateImage, ReadNeedCapabilityStorageImageReadWithoutFormatVulkan) { const std::string body = R"( -%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 %res1 = OpImageRead %u32vec4 %img %u32vec2_01 )"; @@ -2873,7 +3014,7 @@ TEST_F(ValidateImage, ReadNeedCapabilityImageCubeArray) { // TODO(atgoo@github.com) Disabled until the spec is clarified. TEST_F(ValidateImage, DISABLED_ReadWrongResultType) { const std::string body = R"( -%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 %res1 = OpImageRead %f32 %img %u32vec2_01 )"; @@ -2887,7 +3028,7 @@ TEST_F(ValidateImage, DISABLED_ReadWrongResultType) { // TODO(atgoo@github.com) Disabled until the spec is clarified. TEST_F(ValidateImage, DISABLED_ReadWrongNumComponentsResultType) { const std::string body = R"( -%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 %res1 = OpImageRead %f32vec3 %img %u32vec2_01 )"; @@ -2926,7 +3067,7 @@ TEST_F(ValidateImage, ReadImageSampled) { TEST_F(ValidateImage, ReadWrongSampledType) { const std::string body = R"( -%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 %res1 = OpImageRead %f32vec4 %img %u32vec2_01 )"; @@ -2953,7 +3094,7 @@ TEST_F(ValidateImage, ReadVoidSampledType) { TEST_F(ValidateImage, ReadWrongCoordinateType) { const std::string body = R"( -%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 %res1 = OpImageRead %u32vec4 %img %f32vec2_00 )"; @@ -2966,7 +3107,7 @@ TEST_F(ValidateImage, ReadWrongCoordinateType) { TEST_F(ValidateImage, ReadCoordinateSizeTooSmall) { const std::string body = R"( -%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 %res1 = OpImageRead %u32vec4 %img %u32_1 )"; @@ -2980,7 +3121,7 @@ TEST_F(ValidateImage, ReadCoordinateSizeTooSmall) { TEST_F(ValidateImage, WriteSuccess1) { const std::string body = R"( -%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 OpImageWrite %img %u32vec2_01 %u32vec4_0123 )"; @@ -3013,14 +3154,25 @@ OpImageWrite %img %u32vec3_012 %f32vec4_0000 TEST_F(ValidateImage, WriteSuccess4) { const std::string body = R"( -%img = OpLoad %type_image_f32_2d_0010 %uniform_image_f32_2d_0010 -;TODO(atgoo@github.com) Is it legal to write to MS image without sample index? -OpImageWrite %img %u32vec2_01 %f32vec4_0000 +%img = OpLoad %type_image_f32_2d_0012 %uniform_image_f32_2d_0012 OpImageWrite %img %u32vec2_01 %f32vec4_0000 Sample %u32_1 )"; - const std::string extra = "\nOpCapability StorageImageWriteWithoutFormat\n"; - CompileSuccessfully(GenerateShaderCode(body, extra).c_str()); + const std::string extra = R"( + OpCapability StorageImageWriteWithoutFormat + OpCapability StorageImageMultisample + )"; + + const std::string declarations = R"( +%type_image_f32_2d_0012 = OpTypeImage %f32 2D 0 0 1 2 Unknown +%ptr_image_f32_2d_0012 = OpTypePointer UniformConstant %type_image_f32_2d_0012 +%uniform_image_f32_2d_0012 = OpVariable %ptr_image_f32_2d_0012 UniformConstant +%type_sampled_image_f32_2d_0012 = OpTypeSampledImage %type_image_f32_2d_0012 + )"; + CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "", + SPV_ENV_UNIVERSAL_1_0, "GLSL450", + declarations) + .c_str()); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } @@ -3038,7 +3190,7 @@ OpImageWrite %img %u32vec2_01 %f32vec4_0000 TEST_F(ValidateImage, WriteNeedCapabilityStorageImageWriteWithoutFormat) { const std::string body = R"( -%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 OpImageWrite %img %u32vec2_01 %u32vec4_0123 )"; @@ -3048,7 +3200,7 @@ OpImageWrite %img %u32vec2_01 %u32vec4_0123 TEST_F(ValidateImage, WriteNeedCapabilityStorageImageWriteWithoutFormatVulkan) { const std::string body = R"( -%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 OpImageWrite %img %u32vec2_01 %u32vec4_0123 )"; @@ -3117,7 +3269,7 @@ OpImageWrite %img %u32vec2_01 %f32vec4_0000 TEST_F(ValidateImage, WriteWrongCoordinateType) { const std::string body = R"( -%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 OpImageWrite %img %f32vec2_00 %u32vec4_0123 )"; @@ -3130,7 +3282,7 @@ OpImageWrite %img %f32vec2_00 %u32vec4_0123 TEST_F(ValidateImage, WriteCoordinateSizeTooSmall) { const std::string body = R"( -%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 OpImageWrite %img %u32_1 %u32vec4_0123 )"; @@ -3144,7 +3296,7 @@ OpImageWrite %img %u32_1 %u32vec4_0123 TEST_F(ValidateImage, WriteTexelWrongType) { const std::string body = R"( -%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 OpImageWrite %img %u32vec2_01 %img )"; @@ -3157,7 +3309,7 @@ OpImageWrite %img %u32vec2_01 %img TEST_F(ValidateImage, DISABLED_WriteTexelNotVector4) { const std::string body = R"( -%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 OpImageWrite %img %u32vec2_01 %u32vec3_012 )"; @@ -3170,7 +3322,7 @@ OpImageWrite %img %u32vec2_01 %u32vec3_012 TEST_F(ValidateImage, WriteTexelWrongComponentType) { const std::string body = R"( -%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 OpImageWrite %img %u32vec2_01 %f32vec4_0000 )"; @@ -3185,12 +3337,24 @@ OpImageWrite %img %u32vec2_01 %f32vec4_0000 TEST_F(ValidateImage, WriteSampleNotInteger) { const std::string body = R"( -%img = OpLoad %type_image_f32_2d_0010 %uniform_image_f32_2d_0010 +%img = OpLoad %type_image_f32_2d_0012 %uniform_image_f32_2d_0012 OpImageWrite %img %u32vec2_01 %f32vec4_0000 Sample %f32_1 )"; - const std::string extra = "\nOpCapability StorageImageWriteWithoutFormat\n"; - CompileSuccessfully(GenerateShaderCode(body, extra).c_str()); + const std::string extra = R"( + OpCapability StorageImageWriteWithoutFormat + OpCapability StorageImageMultisample + )"; + const std::string declarations = R"( +%type_image_f32_2d_0012 = OpTypeImage %f32 2D 0 0 1 2 Unknown +%ptr_image_f32_2d_0012 = OpTypePointer UniformConstant %type_image_f32_2d_0012 +%uniform_image_f32_2d_0012 = OpVariable %ptr_image_f32_2d_0012 UniformConstant +%type_sampled_image_f32_2d_0012 = OpTypeSampledImage %type_image_f32_2d_0012 + )"; + CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "", + SPV_ENV_UNIVERSAL_1_0, "GLSL450", + declarations) + .c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("Expected Image Operand Sample to be int scalar")); @@ -3212,9 +3376,9 @@ OpImageWrite %img %u32vec2_01 %f32vec4_0000 Sample %u32_1 TEST_F(ValidateImage, SampleWrongOpcode) { const std::string body = R"( -%img = OpLoad %type_image_f32_2d_0010 %uniform_image_f32_2d_0010 +%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011 %sampler = OpLoad %type_sampler %uniform_sampler -%simg = OpSampledImage %type_sampled_image_f32_2d_0010 %img %sampler +%simg = OpSampledImage %type_sampled_image_f32_2d_0011 %img %sampler %res1 = OpImageSampleExplicitLod %f32vec4 %simg %f32vec2_00 Sample %u32_1 )"; @@ -3430,7 +3594,7 @@ TEST_F(ValidateImage, QuerySizeLodWrongImageDim) { TEST_F(ValidateImage, QuerySizeLodMultisampled) { const std::string body = R"( -%img = OpLoad %type_image_f32_2d_0010 %uniform_image_f32_2d_0010 +%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011 %res1 = OpImageQuerySizeLod %u32vec2 %img %u32_1 )"; @@ -3453,7 +3617,7 @@ TEST_F(ValidateImage, QuerySizeLodWrongLodType) { TEST_F(ValidateImage, QuerySizeSuccess) { const std::string body = R"( -%img = OpLoad %type_image_f32_2d_0010 %uniform_image_f32_2d_0010 +%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011 %res1 = OpImageQuerySize %u32vec2 %img )"; @@ -3463,7 +3627,7 @@ TEST_F(ValidateImage, QuerySizeSuccess) { TEST_F(ValidateImage, QuerySizeWrongResultType) { const std::string body = R"( -%img = OpLoad %type_image_f32_2d_0010 %uniform_image_f32_2d_0010 +%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011 %res1 = OpImageQuerySize %f32vec2 %img )"; @@ -3476,7 +3640,7 @@ TEST_F(ValidateImage, QuerySizeWrongResultType) { TEST_F(ValidateImage, QuerySizeNotImage) { const std::string body = R"( -%img = OpLoad %type_image_f32_2d_0010 %uniform_image_f32_2d_0010 +%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011 %sampler = OpLoad %type_sampler %uniform_sampler %simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler %res1 = OpImageQuerySize %u32vec2 %sampler @@ -3490,7 +3654,7 @@ TEST_F(ValidateImage, QuerySizeNotImage) { TEST_F(ValidateImage, QuerySizeSampledImageDirectly) { const std::string body = R"( -%img = OpLoad %type_image_f32_2d_0010 %uniform_image_f32_2d_0010 +%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011 %sampler = OpLoad %type_sampler %uniform_sampler %simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler %res1 = OpImageQuerySize %u32vec2 %simg @@ -3715,7 +3879,7 @@ TEST_F(ValidateImage, QueryLevelsWrongDim) { TEST_F(ValidateImage, QuerySamplesSuccess) { const std::string body = R"( -%img = OpLoad %type_image_f32_2d_0010 %uniform_image_f32_2d_0010 +%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011 %res1 = OpImageQuerySamples %u32 %img )"; @@ -3725,7 +3889,7 @@ TEST_F(ValidateImage, QuerySamplesSuccess) { TEST_F(ValidateImage, QuerySamplesNot2D) { const std::string body = R"( -%img = OpLoad %type_image_f32_3d_0010 %uniform_image_f32_3d_0010 +%img = OpLoad %type_image_f32_3d_0011 %uniform_image_f32_3d_0011 %res1 = OpImageQuerySamples %u32 %img )"; @@ -4490,7 +4654,7 @@ TEST_F(ValidateImage, SparseTexelsResidentResultTypeNotBool) { TEST_F(ValidateImage, MakeTexelVisibleKHRSuccessImageRead) { const std::string body = R"( -%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 %res1 = OpImageRead %u32vec4 %img %u32vec2_01 MakeTexelVisibleKHR|NonPrivateTexelKHR %u32_2 )"; @@ -4548,7 +4712,7 @@ OpExtension "SPV_KHR_vulkan_memory_model" TEST_F(ValidateImage, MakeTexelVisibleKHRFailureMissingNonPrivate) { const std::string body = R"( -%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 %res1 = OpImageRead %u32vec4 %img %u32vec2_01 MakeTexelVisibleKHR %u32_1 )"; @@ -4569,7 +4733,7 @@ OpExtension "SPV_KHR_vulkan_memory_model" TEST_F(ValidateImage, MakeTexelAvailableKHRSuccessImageWrite) { const std::string body = R"( -%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 OpImageWrite %img %u32vec2_01 %u32vec4_0123 MakeTexelAvailableKHR|NonPrivateTexelKHR %u32_2 )"; @@ -4609,7 +4773,7 @@ OpExtension "SPV_KHR_vulkan_memory_model" TEST_F(ValidateImage, MakeTexelAvailableKHRFailureMissingNonPrivate) { const std::string body = R"( -%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 OpImageWrite %img %u32vec2_01 %u32vec4_0123 MakeTexelAvailableKHR %u32_1 )"; @@ -4630,7 +4794,7 @@ OpExtension "SPV_KHR_vulkan_memory_model" TEST_F(ValidateImage, VulkanMemoryModelDeviceScopeImageWriteBad) { const std::string body = R"( -%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 OpImageWrite %img %u32vec2_01 %u32vec4_0123 MakeTexelAvailableKHR|NonPrivateTexelKHR %u32_1 )"; @@ -4652,7 +4816,7 @@ OpExtension "SPV_KHR_vulkan_memory_model" TEST_F(ValidateImage, VulkanMemoryModelDeviceScopeImageWriteGood) { const std::string body = R"( -%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 OpImageWrite %img %u32vec2_01 %u32vec4_0123 MakeTexelAvailableKHR|NonPrivateTexelKHR %u32_1 )"; @@ -4670,7 +4834,7 @@ OpExtension "SPV_KHR_vulkan_memory_model" TEST_F(ValidateImage, VulkanMemoryModelDeviceScopeImageReadBad) { const std::string body = R"( -%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 %res1 = OpImageRead %u32vec4 %img %u32vec2_01 MakeTexelVisibleKHR|NonPrivateTexelKHR %u32_1 )"; @@ -4692,7 +4856,7 @@ OpExtension "SPV_KHR_vulkan_memory_model" TEST_F(ValidateImage, VulkanMemoryModelDeviceScopeImageReadGood) { const std::string body = R"( -%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 %res1 = OpImageRead %u32vec4 %img %u32vec2_01 MakeTexelVisibleKHR|NonPrivateTexelKHR %u32_1 )"; @@ -4745,7 +4909,7 @@ TEST_F(ValidateImage, Issue2463NoSegFault) { TEST_F(ValidateImage, SignExtendV13Bad) { const std::string body = R"( -%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 %res1 = OpImageRead %u32vec4 %img %u32vec2_01 SignExtend )"; @@ -4756,7 +4920,7 @@ TEST_F(ValidateImage, SignExtendV13Bad) { TEST_F(ValidateImage, ZeroExtendV13Bad) { const std::string body = R"( -%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 %res1 = OpImageRead %u32vec4 %img %u32vec2_01 ZeroExtend )"; @@ -4768,7 +4932,7 @@ TEST_F(ValidateImage, ZeroExtendV13Bad) { TEST_F(ValidateImage, SignExtendScalarUIntTexelV14Good) { // Unsigned int sampled type const std::string body = R"( -%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 %res1 = OpImageRead %u32 %img %u32vec2_01 SignExtend )"; const std::string extra = "\nOpCapability StorageImageReadWithoutFormat\n"; @@ -4797,7 +4961,7 @@ TEST_F(ValidateImage, SignExtendScalarSIntTexelV14Good) { TEST_F(ValidateImage, SignExtendScalarVectorUIntTexelV14Good) { const std::string body = R"( -%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 %res1 = OpImageRead %u32vec4 %img %u32vec2_01 SignExtend )"; const std::string extra = "\nOpCapability StorageImageReadWithoutFormat\n"; @@ -4829,7 +4993,7 @@ TEST_F(ValidateImage, SignExtendVectorSIntTexelV14Good) { TEST_F(ValidateImage, ZeroExtendScalarUIntTexelV14Good) { // Unsigned int sampled type const std::string body = R"( -%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 %res1 = OpImageRead %u32 %img %u32vec2_01 ZeroExtend )"; const std::string extra = "\nOpCapability StorageImageReadWithoutFormat\n"; @@ -4858,7 +5022,7 @@ TEST_F(ValidateImage, ZeroExtendScalarSIntTexelV14Good) { TEST_F(ValidateImage, ZeroExtendScalarVectorUIntTexelV14Good) { const std::string body = R"( -%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 %res1 = OpImageRead %u32vec4 %img %u32vec2_01 ZeroExtend )"; const std::string extra = "\nOpCapability StorageImageReadWithoutFormat\n"; @@ -4886,7 +5050,7 @@ TEST_F(ValidateImage, ZeroExtendVectorSIntTexelV14Good) { TEST_F(ValidateImage, ReadLodAMDSuccess1) { const std::string body = R"( -%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 %res1 = OpImageRead %u32vec4 %img %u32vec2_01 Lod %u32_0 )"; @@ -4951,7 +5115,7 @@ TEST_F(ValidateImage, ReadLodAMDNeedCapability) { TEST_F(ValidateImage, WriteLodAMDSuccess1) { const std::string body = R"( -%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 OpImageWrite %img %u32vec2_01 %u32vec4_0123 Lod %u32_0 )"; diff --git a/test/val/val_opencl_test.cpp b/test/val/val_opencl_test.cpp index 10641587..e5e3b12b 100644 --- a/test/val/val_opencl_test.cpp +++ b/test/val/val_opencl_test.cpp @@ -91,7 +91,7 @@ TEST_F(ValidateOpenCL, NonZeroMSImageBad) { EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2)); EXPECT_THAT( getDiagnosticString(), - HasSubstr("MS must be 0 in the OpenCL environement." + HasSubstr("MS must be 0 in the OpenCL environment." "\n %2 = OpTypeImage %void 2D 0 0 1 0 Unknown ReadOnly\n")); } -- cgit v1.2.3 From 305caff2ebb135b688a476233ce1873efee032bb Mon Sep 17 00:00:00 2001 From: David Neto Date: Mon, 14 Dec 2020 14:45:48 -0500 Subject: validation: tighter validation of multisampled images (#4059) * validation: tighter validation of multisampled images - if MS=1, then Sample image operand is required - Sampling operations are not permitted when MS=1 Fixes #4057, #4058 * Fail early for multisampled image for sampling, dref, gather --- source/val/validate_image.cpp | 144 +++++++++++--------- test/val/val_image_test.cpp | 307 +++++++++++++++++++++++++++--------------- 2 files changed, 278 insertions(+), 173 deletions(-) diff --git a/source/val/validate_image.cpp b/source/val/validate_image.cpp index 0a0eeee8..1961a74d 100644 --- a/source/val/validate_image.cpp +++ b/source/val/validate_image.cpp @@ -16,8 +16,6 @@ // Validates correctness of image instructions. -#include "source/val/validate.h" - #include #include "source/diagnostic.h" @@ -25,6 +23,7 @@ #include "source/spirv_target_env.h" #include "source/util/bitutils.h" #include "source/val/instruction.h" +#include "source/val/validate.h" #include "source/val/validate_scopes.h" #include "source/val/validation_state.h" @@ -234,9 +233,10 @@ uint32_t GetMinCoordSize(SpvOp opcode, const ImageTypeInfo& info) { } // Checks ImageOperand bitfield and respective operands. +// word_index is the index of the first word after the image-operand mask word. spv_result_t ValidateImageOperands(ValidationState_t& _, const Instruction* inst, - const ImageTypeInfo& info, uint32_t mask, + const ImageTypeInfo& info, uint32_t word_index) { static const bool kAllImageOperandsHandled = CheckAllImageOperandsHandled(); (void)kAllImageOperandsHandled; @@ -244,24 +244,43 @@ spv_result_t ValidateImageOperands(ValidationState_t& _, const SpvOp opcode = inst->opcode(); const size_t num_words = inst->words().size(); - // NonPrivate, Volatile, SignExtend, ZeroExtend take no operand words. - const uint32_t mask_bits_having_operands = - mask & ~uint32_t(SpvImageOperandsNonPrivateTexelKHRMask | - SpvImageOperandsVolatileTexelKHRMask | - SpvImageOperandsSignExtendMask | - SpvImageOperandsZeroExtendMask); - size_t expected_num_image_operand_words = - spvtools::utils::CountSetBits(mask_bits_having_operands); - if (mask & SpvImageOperandsGradMask) { - // Grad uses two words. - ++expected_num_image_operand_words; - } + const bool have_explicit_mask = (word_index - 1 < num_words); + const uint32_t mask = have_explicit_mask ? inst->word(word_index - 1) : 0u; + + if (have_explicit_mask) { + // NonPrivate, Volatile, SignExtend, ZeroExtend take no operand words. + const uint32_t mask_bits_having_operands = + mask & ~uint32_t(SpvImageOperandsNonPrivateTexelKHRMask | + SpvImageOperandsVolatileTexelKHRMask | + SpvImageOperandsSignExtendMask | + SpvImageOperandsZeroExtendMask); + size_t expected_num_image_operand_words = + spvtools::utils::CountSetBits(mask_bits_having_operands); + if (mask & SpvImageOperandsGradMask) { + // Grad uses two words. + ++expected_num_image_operand_words; + } - if (expected_num_image_operand_words != num_words - word_index) { + if (expected_num_image_operand_words != num_words - word_index) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Number of image operand ids doesn't correspond to the bit " + "mask"; + } + } else if (num_words != word_index - 1) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Number of image operand ids doesn't correspond to the bit mask"; } + if (info.multisampled & (0 == (mask & SpvImageOperandsSampleMask))) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Image Operand Sample is required for operation on " + "multi-sampled image"; + } + + // After this point, only set bits in the image operands mask can cause + // the module to be invalid. + if (mask == 0) return SPV_SUCCESS; + if (spvtools::utils::CountSetBits( mask & (SpvImageOperandsOffsetMask | SpvImageOperandsConstOffsetMask | SpvImageOperandsConstOffsetsMask)) > 1) { @@ -296,10 +315,7 @@ spv_result_t ValidateImageOperands(ValidationState_t& _, "or Cube"; } - if (info.multisampled != 0) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Image Operand Bias requires 'MS' parameter to be 0"; - } + // Multisampled is already checked. } if (mask & SpvImageOperandsLodMask) { @@ -338,10 +354,7 @@ spv_result_t ValidateImageOperands(ValidationState_t& _, "or Cube"; } - if (info.multisampled != 0) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Image Operand Lod requires 'MS' parameter to be 0"; - } + // Multisampled is already checked. } if (mask & SpvImageOperandsGradMask) { @@ -374,10 +387,7 @@ spv_result_t ValidateImageOperands(ValidationState_t& _, << " components, but given " << dy_size; } - if (info.multisampled != 0) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Image Operand Grad requires 'MS' parameter to be 0"; - } + // Multisampled is already checked. } if (mask & SpvImageOperandsConstOffsetMask) { @@ -613,12 +623,12 @@ spv_result_t ValidateImageCommon(ValidationState_t& _, const Instruction* inst, if (info.multisampled != 0) { return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Image Image 'MS' parameter to be 0"; + << "Expected Image 'MS' parameter to be 0"; } if (info.arrayed != 0) { return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Image Image 'arrayed' parameter to be 0"; + << "Expected Image 'arrayed' parameter to be 0"; } } @@ -1122,6 +1132,14 @@ spv_result_t ValidateImageLod(ValidationState_t& _, const Instruction* inst) { if (spv_result_t result = ValidateImageCommon(_, inst, info)) return result; + if (info.multisampled) { + // When using image operands, the Sample image operand is required if and + // only if the image is multisampled (MS=1). The Sample image operand is + // only allowed for fetch, read, and write. + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Sampling operation is invalid for multisample image"; + } + if (_.GetIdOpcode(info.sampled_type) != SpvOpTypeVoid) { const uint32_t texel_component_type = _.GetComponentType(actual_result_type); @@ -1156,16 +1174,11 @@ spv_result_t ValidateImageLod(ValidationState_t& _, const Instruction* inst) { << " components, but given only " << actual_coord_size; } - if (inst->words().size() <= 5) { - assert(IsImplicitLod(opcode)); - return SPV_SUCCESS; - } - - const uint32_t mask = inst->word(5); + const uint32_t mask = inst->words().size() <= 5 ? 0 : inst->word(5); - if (spvIsOpenCLEnv(_.context()->target_env)) { - if (opcode == SpvOpImageSampleExplicitLod) { - if (mask & SpvImageOperandsConstOffsetMask) { + if (mask & SpvImageOperandsConstOffsetMask) { + if (spvIsOpenCLEnv(_.context()->target_env)) { + if (opcode == SpvOpImageSampleExplicitLod) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "ConstOffset image operand not allowed " << "in the OpenCL environment."; @@ -1174,7 +1187,7 @@ spv_result_t ValidateImageLod(ValidationState_t& _, const Instruction* inst) { } if (spv_result_t result = - ValidateImageOperands(_, inst, info, mask, /* word_index = */ 6)) + ValidateImageOperands(_, inst, info, /* word_index = */ 6)) return result; return SPV_SUCCESS; @@ -1209,6 +1222,14 @@ spv_result_t ValidateImageDrefLod(ValidationState_t& _, if (spv_result_t result = ValidateImageCommon(_, inst, info)) return result; + if (info.multisampled) { + // When using image operands, the Sample image operand is required if and + // only if the image is multisampled (MS=1). The Sample image operand is + // only allowed for fetch, read, and write. + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Dref sampling operation is invalid for multisample image"; + } + if (actual_result_type != info.sampled_type) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected Image 'Sampled Type' to be the same as " @@ -1235,14 +1256,8 @@ spv_result_t ValidateImageDrefLod(ValidationState_t& _, << "Expected Dref to be of 32-bit float type"; } - if (inst->words().size() <= 6) { - assert(IsImplicitLod(opcode)); - return SPV_SUCCESS; - } - - const uint32_t mask = inst->word(6); if (spv_result_t result = - ValidateImageOperands(_, inst, info, mask, /* word_index = */ 7)) + ValidateImageOperands(_, inst, info, /* word_index = */ 7)) return result; return SPV_SUCCESS; @@ -1313,11 +1328,8 @@ spv_result_t ValidateImageFetch(ValidationState_t& _, const Instruction* inst) { << " components, but given only " << actual_coord_size; } - if (inst->words().size() <= 5) return SPV_SUCCESS; - - const uint32_t mask = inst->word(5); if (spv_result_t result = - ValidateImageOperands(_, inst, info, mask, /* word_index = */ 6)) + ValidateImageOperands(_, inst, info, /* word_index = */ 6)) return result; return SPV_SUCCESS; @@ -1355,6 +1367,14 @@ spv_result_t ValidateImageGather(ValidationState_t& _, << "Corrupt image type definition"; } + if (info.multisampled) { + // When using image operands, the Sample image operand is required if and + // only if the image is multisampled (MS=1). The Sample image operand is + // only allowed for fetch, read, and write. + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Gather operation is invalid for multisample image"; + } + if (opcode == SpvOpImageDrefGather || opcode == SpvOpImageSparseDrefGather || _.GetIdOpcode(info.sampled_type) != SpvOpTypeVoid) { const uint32_t result_component_type = @@ -1403,11 +1423,8 @@ spv_result_t ValidateImageGather(ValidationState_t& _, } } - if (inst->words().size() <= 6) return SPV_SUCCESS; - - const uint32_t mask = inst->word(6); if (spv_result_t result = - ValidateImageOperands(_, inst, info, mask, /* word_index = */ 7)) + ValidateImageOperands(_, inst, info, /* word_index = */ 7)) return result; return SPV_SUCCESS; @@ -1496,12 +1513,10 @@ spv_result_t ValidateImageRead(ValidationState_t& _, const Instruction* inst) { } } - if (inst->words().size() <= 5) return SPV_SUCCESS; + const uint32_t mask = inst->words().size() <= 5 ? 0 : inst->word(5); - const uint32_t mask = inst->word(5); - - if (spvIsOpenCLEnv(_.context()->target_env)) { - if (mask & SpvImageOperandsConstOffsetMask) { + if (mask & SpvImageOperandsConstOffsetMask) { + if (spvIsOpenCLEnv(_.context()->target_env)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "ConstOffset image operand not allowed " << "in the OpenCL environment."; @@ -1509,7 +1524,7 @@ spv_result_t ValidateImageRead(ValidationState_t& _, const Instruction* inst) { } if (spv_result_t result = - ValidateImageOperands(_, inst, info, mask, /* word_index = */ 6)) + ValidateImageOperands(_, inst, info, /* word_index = */ 6)) return result; return SPV_SUCCESS; @@ -1585,9 +1600,7 @@ spv_result_t ValidateImageWrite(ValidationState_t& _, const Instruction* inst) { } } - if (inst->words().size() <= 4) { - return SPV_SUCCESS; - } else { + if (inst->words().size() > 4) { if (spvIsOpenCLEnv(_.context()->target_env)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Optional Image Operands are not allowed in the OpenCL " @@ -1595,9 +1608,8 @@ spv_result_t ValidateImageWrite(ValidationState_t& _, const Instruction* inst) { } } - const uint32_t mask = inst->word(4); if (spv_result_t result = - ValidateImageOperands(_, inst, info, mask, /* word_index = */ 5)) + ValidateImageOperands(_, inst, info, /* word_index = */ 5)) return result; return SPV_SUCCESS; diff --git a/test/val/val_image_test.cpp b/test/val/val_image_test.cpp index 31f93752..e9159a1e 100644 --- a/test/val/val_image_test.cpp +++ b/test/val/val_image_test.cpp @@ -66,7 +66,7 @@ OpCapability ImageBuffer %uniform_image_f32_1d_0001 %uniform_image_f32_1d_0002_rgba32f %uniform_image_f32_2d_0001 -%uniform_image_f32_2d_0011 +%uniform_image_f32_2d_0011 ; multisampled sampled %uniform_image_u32_2d_0001 %uniform_image_u32_2d_0002 %uniform_image_s32_3d_0001 @@ -1080,6 +1080,20 @@ TEST_F(ValidateImage, SampleImplicitLodNotSampledImage) { HasSubstr("Expected Sampled Image to be of type OpTypeSampledImage")); } +TEST_F(ValidateImage, SampleImplicitLodMultisampleError) { + const std::string body = R"( +%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011 +%sampler = OpLoad %type_sampler %uniform_sampler +%simg = OpSampledImage %type_sampled_image_f32_2d_0011 %img %sampler +%res1 = OpImageSampleExplicitLod %f32vec4 %simg %f32vec2_hh Sample %u32_1 +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Sampling operation is invalid for multisample image")); +} + TEST_F(ValidateImage, SampleImplicitLodWrongSampledType) { const std::string body = R"( %img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 @@ -1228,6 +1242,20 @@ TEST_F(ValidateImage, SampleExplicitLodNotSampledImage) { HasSubstr("Expected Sampled Image to be of type OpTypeSampledImage")); } +TEST_F(ValidateImage, SampleExplicitLodMultisampleError) { + const std::string body = R"( +%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011 +%sampler = OpLoad %type_sampler %uniform_sampler +%simg = OpSampledImage %type_sampled_image_f32_2d_0011 %img %sampler +%res1 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec2_hh Lod|Sample %f32_0 %u32_1 +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Sampling operation is invalid for multisample image")); +} + TEST_F(ValidateImage, SampleExplicitLodWrongSampledType) { const std::string body = R"( %img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 @@ -1360,19 +1388,6 @@ TEST_F(ValidateImage, LodWrongDim) { "2D, 3D or Cube")); } -TEST_F(ValidateImage, LodMultisampled) { - const std::string body = R"( -%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011 -%sampler = OpLoad %type_sampler %uniform_sampler -%simg = OpSampledImage %type_sampled_image_f32_2d_0011 %img %sampler -%res1 = OpImageSampleExplicitLod %f32vec4 %simg %f32vec2_00 Lod %f32_0)"; - - CompileSuccessfully(GenerateShaderCode(body).c_str()); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Image Operand Lod requires 'MS' parameter to be 0")); -} - TEST_F(ValidateImage, MinLodIncompatible) { const std::string body = R"( %img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 @@ -1405,20 +1420,6 @@ TEST_F(ValidateImage, ImplicitLodWithGrad) { "Image Operand Grad can only be used with ExplicitLod opcodes")); } -TEST_F(ValidateImage, SampleImplicitLod3DArrayedMultisampledSuccess) { - const std::string body = R"( -%img = OpLoad %type_image_f32_3d_0111 %uniform_image_f32_3d_0111 -%sampler = OpLoad %type_sampler %uniform_sampler -%simg = OpSampledImage %type_sampled_image_f32_3d_0111 %img %sampler -%res1 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec4_0000 -%res2 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec4_0000 ConstOffset %s32vec3_012 -%res3 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec4_0000 Offset %s32vec3_012 -)"; - - CompileSuccessfully(GenerateShaderCode(body).c_str()); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - TEST_F(ValidateImage, SampleImplicitLodCubeArrayedSuccess) { const std::string body = R"( %img = OpLoad %type_image_f32_cube_0101 %uniform_image_f32_cube_0101 @@ -1463,20 +1464,6 @@ TEST_F(ValidateImage, SampleImplicitLodBiasWrongDim) { "2D, 3D or Cube")); } -TEST_F(ValidateImage, SampleImplicitLodBiasMultisampled) { - const std::string body = R"( -%img = OpLoad %type_image_f32_3d_0111 %uniform_image_f32_3d_0111 -%sampler = OpLoad %type_sampler %uniform_sampler -%simg = OpSampledImage %type_sampled_image_f32_3d_0111 %img %sampler -%res1 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec4_0000 Bias %f32_0_25 -)"; - - CompileSuccessfully(GenerateShaderCode(body).c_str()); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Image Operand Bias requires 'MS' parameter to be 0")); -} - TEST_F(ValidateImage, SampleExplicitLodGradDxWrongType) { const std::string body = R"( %img = OpLoad %type_image_f32_cube_0101 %uniform_image_f32_cube_0101 @@ -1539,20 +1526,6 @@ TEST_F(ValidateImage, SampleExplicitLodGradDyWrongSize) { "Expected Image Operand Grad dy to have 3 components, but given 2")); } -TEST_F(ValidateImage, SampleExplicitLodGradMultisampled) { - const std::string body = R"( -%img = OpLoad %type_image_f32_3d_0111 %uniform_image_f32_3d_0111 -%sampler = OpLoad %type_sampler %uniform_sampler -%simg = OpSampledImage %type_sampled_image_f32_3d_0111 %img %sampler -%res1 = OpImageSampleExplicitLod %f32vec4 %simg %f32vec4_0000 Grad %f32vec3_000 %f32vec3_000 -)"; - - CompileSuccessfully(GenerateShaderCode(body).c_str()); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Image Operand Grad requires 'MS' parameter to be 0")); -} - TEST_F(ValidateImage, SampleImplicitLodConstOffsetCubeDim) { const std::string body = R"( %img = OpLoad %type_image_f32_cube_0101 %uniform_image_f32_cube_0101 @@ -1571,10 +1544,10 @@ TEST_F(ValidateImage, SampleImplicitLodConstOffsetCubeDim) { TEST_F(ValidateImage, SampleImplicitLodConstOffsetWrongType) { const std::string body = R"( -%img = OpLoad %type_image_f32_3d_0111 %uniform_image_f32_3d_0111 +%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 %sampler = OpLoad %type_sampler %uniform_sampler -%simg = OpSampledImage %type_sampled_image_f32_3d_0111 %img %sampler -%res4 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec4_0000 ConstOffset %f32vec3_000 +%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler +%res4 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec2_00 ConstOffset %f32vec2_00 )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); @@ -1587,26 +1560,26 @@ TEST_F(ValidateImage, SampleImplicitLodConstOffsetWrongType) { TEST_F(ValidateImage, SampleImplicitLodConstOffsetWrongSize) { const std::string body = R"( -%img = OpLoad %type_image_f32_3d_0111 %uniform_image_f32_3d_0111 +%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 %sampler = OpLoad %type_sampler %uniform_sampler -%simg = OpSampledImage %type_sampled_image_f32_3d_0111 %img %sampler -%res4 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec4_0000 ConstOffset %s32vec2_01 +%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler +%res4 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec2_00 ConstOffset %s32vec3_012 )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("Expected Image Operand ConstOffset to have 3 " - "components, but given 2")); + HasSubstr("Expected Image Operand ConstOffset to have 2 " + "components, but given 3")); } TEST_F(ValidateImage, SampleImplicitLodConstOffsetNotConst) { const std::string body = R"( -%img = OpLoad %type_image_f32_3d_0111 %uniform_image_f32_3d_0111 +%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 %sampler = OpLoad %type_sampler %uniform_sampler -%simg = OpSampledImage %type_sampled_image_f32_3d_0111 %img %sampler +%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler %offset = OpSNegate %s32vec3 %s32vec3_012 -%res4 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec4_0000 ConstOffset %offset +%res4 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec2_00 ConstOffset %offset )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); @@ -1633,10 +1606,10 @@ TEST_F(ValidateImage, SampleImplicitLodOffsetCubeDim) { TEST_F(ValidateImage, SampleImplicitLodOffsetWrongType) { const std::string body = R"( -%img = OpLoad %type_image_f32_3d_0111 %uniform_image_f32_3d_0111 +%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 %sampler = OpLoad %type_sampler %uniform_sampler -%simg = OpSampledImage %type_sampled_image_f32_3d_0111 %img %sampler -%res4 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec4_0000 Offset %f32vec3_000 +%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler +%res4 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec4_0000 Offset %f32vec2_00 )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); @@ -1648,10 +1621,10 @@ TEST_F(ValidateImage, SampleImplicitLodOffsetWrongType) { TEST_F(ValidateImage, SampleImplicitLodOffsetWrongSize) { const std::string body = R"( -%img = OpLoad %type_image_f32_3d_0111 %uniform_image_f32_3d_0111 +%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 %sampler = OpLoad %type_sampler %uniform_sampler -%simg = OpSampledImage %type_sampled_image_f32_3d_0111 %img %sampler -%res4 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec4_0000 Offset %s32vec2_01 +%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler +%res4 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec4_0000 Offset %s32vec3_012 )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); @@ -1659,15 +1632,15 @@ TEST_F(ValidateImage, SampleImplicitLodOffsetWrongSize) { EXPECT_THAT( getDiagnosticString(), HasSubstr( - "Expected Image Operand Offset to have 3 components, but given 2")); + "Expected Image Operand Offset to have 2 components, but given 3")); } TEST_F(ValidateImage, SampleImplicitLodMoreThanOneOffset) { const std::string body = R"( -%img = OpLoad %type_image_f32_3d_0111 %uniform_image_f32_3d_0111 +%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 %sampler = OpLoad %type_sampler %uniform_sampler -%simg = OpSampledImage %type_sampled_image_f32_3d_0111 %img %sampler -%res4 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec4_0000 ConstOffset|Offset %s32vec3_012 %s32vec3_012 +%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler +%res4 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec4_0000 ConstOffset|Offset %s32vec2_01 %s32vec2_01 )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); @@ -1706,21 +1679,6 @@ TEST_F(ValidateImage, SampleImplicitLodMinLodWrongDim) { "1D, 2D, 3D or Cube")); } -TEST_F(ValidateImage, SampleImplicitLodMinLodMultisampled) { - const std::string body = R"( -%img = OpLoad %type_image_f32_3d_0111 %uniform_image_f32_3d_0111 -%sampler = OpLoad %type_sampler %uniform_sampler -%simg = OpSampledImage %type_sampled_image_f32_3d_0111 %img %sampler -%res1 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec4_0000 MinLod %f32_0_25 -)"; - - CompileSuccessfully(GenerateShaderCode(body).c_str()); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("Image Operand MinLod requires 'MS' parameter to be 0")); -} - TEST_F(ValidateImage, SampleProjExplicitLodSuccess2D) { const std::string body = R"( %img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 @@ -1798,6 +1756,20 @@ TEST_F(ValidateImage, SampleProjExplicitLodNotSampledImage) { HasSubstr("Expected Sampled Image to be of type OpTypeSampledImage")); } +TEST_F(ValidateImage, SampleProjExplicitLodMultisampleError) { + const std::string body = R"( +%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011 +%sampler = OpLoad %type_sampler %uniform_sampler +%simg = OpSampledImage %type_sampled_image_f32_2d_0011 %img %sampler +%res1 = OpImageSampleProjExplicitLod %f32vec4 %simg %f32vec2_hh Lod|Sample %f32_1 %u32_1 +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Expected Image 'MS' parameter to be 0")); +} + TEST_F(ValidateImage, SampleProjExplicitLodWrongSampledType) { const std::string body = R"( %img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 @@ -1919,6 +1891,20 @@ TEST_F(ValidateImage, SampleProjImplicitLodNotSampledImage) { HasSubstr("Expected Sampled Image to be of type OpTypeSampledImage")); } +TEST_F(ValidateImage, SampleProjImplicitLodMultisampleError) { + const std::string body = R"( +%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011 +%sampler = OpLoad %type_sampler %uniform_sampler +%simg = OpSampledImage %type_sampled_image_f32_2d_0011 %img %sampler +%res1 = OpImageSampleProjImplicitLod %f32vec4 %simg %f32vec2_hh Sample %u32_1 +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Expected Image 'MS' parameter to be 0")); +} + TEST_F(ValidateImage, SampleProjImplicitLodWrongSampledType) { const std::string body = R"( %img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 @@ -2026,6 +2012,21 @@ TEST_F(ValidateImage, SampleDrefImplicitLodNotSampledImage) { HasSubstr("Expected Sampled Image to be of type OpTypeSampledImage")); } +TEST_F(ValidateImage, SampleDrefImplicitLodMultisampleError) { + const std::string body = R"( +%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011 +%sampler = OpLoad %type_sampler %uniform_sampler +%simg = OpSampledImage %type_sampled_image_f32_2d_0011 %img %sampler +%res1 = OpImageSampleDrefImplicitLod %f32 %simg %f32vec2_hh %f32_1 Sample %u32_1 +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Dref sampling operation is invalid for multisample image")); +} + TEST_F(ValidateImage, SampleDrefImplicitLodWrongSampledType) { const std::string body = R"( %img = OpLoad %type_image_u32_2d_0001 %uniform_image_u32_2d_0001 @@ -2149,6 +2150,21 @@ TEST_F(ValidateImage, SampleDrefExplicitLodNotSampledImage) { HasSubstr("Expected Sampled Image to be of type OpTypeSampledImage")); } +TEST_F(ValidateImage, SampleDrefExplicitLodMultisampleError) { + const std::string body = R"( +%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011 +%sampler = OpLoad %type_sampler %uniform_sampler +%simg = OpSampledImage %type_sampled_image_f32_2d_0011 %img %sampler +%res1 = OpImageSampleDrefExplicitLod %f32 %simg %f32vec2_hh %f32_1 Lod|Sample %f32_1 %u32_1 +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Dref sampling operation is invalid for multisample image")); +} + TEST_F(ValidateImage, SampleDrefExplicitLodWrongSampledType) { const std::string body = R"( %img = OpLoad %type_image_s32_3d_0001 %uniform_image_s32_3d_0001 @@ -2273,6 +2289,21 @@ TEST_F(ValidateImage, SampleProjDrefImplicitLodNotSampledImage) { HasSubstr("Expected Sampled Image to be of type OpTypeSampledImage")); } +TEST_F(ValidateImage, SampleProjDrefImplicitLodMultisampleError) { + const std::string body = R"( +%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011 +%sampler = OpLoad %type_sampler %uniform_sampler +%simg = OpSampledImage %type_sampled_image_f32_2d_0011 %img %sampler +%res1 = OpImageSampleDrefExplicitLod %f32 %simg %f32vec2_hh %f32_1 Sample %u32_1 +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Dref sampling operation is invalid for multisample image")); +} + TEST_F(ValidateImage, SampleProjDrefImplicitLodWrongSampledType) { const std::string body = R"( %img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 @@ -2396,6 +2427,21 @@ TEST_F(ValidateImage, SampleProjDrefExplicitLodNotSampledImage) { HasSubstr("Expected Sampled Image to be of type OpTypeSampledImage")); } +TEST_F(ValidateImage, SampleProjDrefExplicitLodMultisampleError) { + const std::string body = R"( +%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011 +%sampler = OpLoad %type_sampler %uniform_sampler +%simg = OpSampledImage %type_sampled_image_f32_2d_0011 %img %sampler +%res1 = OpImageSampleDrefExplicitLod %f32 %simg %f32vec2_hh %f32_1 Lod|Sample %f32_1 %u32_1 +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Dref sampling operation is invalid for multisample image")); +} + TEST_F(ValidateImage, SampleProjDrefExplicitLodWrongSampledType) { const std::string body = R"( %img = OpLoad %type_image_f32_1d_0001 %uniform_image_f32_1d_0001 @@ -2472,6 +2518,23 @@ OpExtension "SPV_KHR_vulkan_memory_model" ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); } +TEST_F(ValidateImage, FetchMultisampledSuccess) { + const std::string body = R"( +%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011 +%res1 = OpImageFetch %f32vec4 %img %u32vec2_01 Sample %u32_1 +%res2 = OpImageFetch %f32vec4 %img %u32vec2_01 Sample|NonPrivateTexelKHR %u32_1 +)"; + + const std::string extra = R"( +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "", + SPV_ENV_UNIVERSAL_1_3, "VulkanKHR") + .c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + TEST_F(ValidateImage, FetchWrongResultType) { const std::string body = R"( %img = OpLoad %type_image_f32_rect_0001 %uniform_image_f32_rect_0001 @@ -2611,6 +2674,21 @@ TEST_F(ValidateImage, FetchLodNotInt) { "with OpImageFetch")); } +TEST_F(ValidateImage, FetchMultisampledMissingSample) { + const std::string body = R"( +%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011 +%res1 = OpImageFetch %f32vec4 %img %u32vec2_01 +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()) + << GenerateShaderCode(body); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Image Operand Sample is required for operation on " + "multi-sampled image")) + << getDiagnosticString(); +} + TEST_F(ValidateImage, GatherSuccess) { const std::string body = R"( %img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 @@ -2672,6 +2750,20 @@ TEST_F(ValidateImage, GatherNotSampledImage) { HasSubstr("Expected Sampled Image to be of type OpTypeSampledImage")); } +TEST_F(ValidateImage, GatherMultisampleError) { + const std::string body = R"( +%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011 +%sampler = OpLoad %type_sampler %uniform_sampler +%simg = OpSampledImage %type_sampled_image_f32_2d_0011 %img %sampler +%res1 = OpImageGather %f32vec4 %simg %f32vec4_0000 %u32_1 Sample %u32_1 +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Gather operation is invalid for multisample image")); +} + TEST_F(ValidateImage, GatherWrongSampledType) { const std::string body = R"( %img = OpLoad %type_image_f32_cube_0101 %uniform_image_f32_cube_0101 @@ -2887,6 +2979,20 @@ OpExtension "SPV_KHR_vulkan_memory_model" ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); } +TEST_F(ValidateImage, DrefGatherMultisampleError) { + const std::string body = R"( +%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011 +%sampler = OpLoad %type_sampler %uniform_sampler +%simg = OpSampledImage %type_sampled_image_f32_2d_0011 %img %sampler +%res1 = OpImageDrefGather %f32vec4 %simg %f32vec4_0000 %f32_1 Sample %u32_1 +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Gather operation is invalid for multisample image")); +} + TEST_F(ValidateImage, DrefGatherVoidSampledType) { const std::string body = R"( %img = OpLoad %type_image_void_2d_0001 %uniform_image_void_2d_0001 @@ -3360,7 +3466,7 @@ OpImageWrite %img %u32vec2_01 %f32vec4_0000 Sample %f32_1 HasSubstr("Expected Image Operand Sample to be int scalar")); } -TEST_F(ValidateImage, SampleNotMultisampled) { +TEST_F(ValidateImage, WriteSampleNotMultisampled) { const std::string body = R"( %img = OpLoad %type_image_f32_2d_0002 %uniform_image_f32_2d_0002 OpImageWrite %img %u32vec2_01 %f32vec4_0000 Sample %u32_1 @@ -3385,9 +3491,7 @@ TEST_F(ValidateImage, SampleWrongOpcode) { CompileSuccessfully(GenerateShaderCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("Image Operand Sample can only be used with " - "OpImageFetch, OpImageRead, OpImageWrite, " - "OpImageSparseFetch and OpImageSparseRead")); + HasSubstr("Sampling operation is invalid for multisample image")); } TEST_F(ValidateImage, SampleImageToImageSuccess) { @@ -3592,17 +3696,6 @@ TEST_F(ValidateImage, QuerySizeLodWrongImageDim) { HasSubstr("Image 'Dim' must be 1D, 2D, 3D or Cube")); } -TEST_F(ValidateImage, QuerySizeLodMultisampled) { - const std::string body = R"( -%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011 -%res1 = OpImageQuerySizeLod %u32vec2 %img %u32_1 -)"; - - CompileSuccessfully(GenerateKernelCode(body).c_str()); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), HasSubstr("Image 'MS' must be 0")); -} - TEST_F(ValidateImage, QuerySizeLodWrongLodType) { const std::string body = R"( %img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 -- cgit v1.2.3 From ad898cb9498c65cac7c5b6f9ebddb610bd0852ad Mon Sep 17 00:00:00 2001 From: David Neto Date: Tue, 15 Dec 2020 12:00:59 -0500 Subject: validation: validate return type of OpImageRead (#4072) Vulkan: must be 4-element vector WebGPU: must be 4-element vector OpenCL: - must be scalar float for depth image - must be 4-element vector otherwise --- source/val/validate_image.cpp | 41 +++++-- test/val/val_image_test.cpp | 60 +++++++++- test/val/val_opencl_test.cpp | 265 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 350 insertions(+), 16 deletions(-) diff --git a/source/val/validate_image.cpp b/source/val/validate_image.cpp index 1961a74d..561a5a10 100644 --- a/source/val/validate_image.cpp +++ b/source/val/validate_image.cpp @@ -1444,14 +1444,16 @@ spv_result_t ValidateImageRead(ValidationState_t& _, const Instruction* inst) { << " to be int or float scalar or vector type"; } -#if 0 - // TODO(atgoo@github.com) Disabled until the spec is clarified. - if (_.GetDimension(actual_result_type) != 4) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Expected " << GetActualResultTypeStr(opcode) - << " to have 4 components"; - } -#endif + const auto target_env = _.context()->target_env; + // Vulkan and WebGPU require the result to be a 4-element int or float + // vector. + if (spvIsVulkanEnv(target_env) || spvIsWebGPUEnv(target_env)) { + if (_.GetDimension(actual_result_type) != 4) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected " << GetActualResultTypeStr(opcode) + << " to have 4 components"; + } + } // Check OpenCL below, after we get the image info. const uint32_t image_type = _.GetOperandTypeId(inst, 2); if (_.GetIdOpcode(image_type) != SpvOpTypeImage) { @@ -1465,6 +1467,29 @@ spv_result_t ValidateImageRead(ValidationState_t& _, const Instruction* inst) { << "Corrupt image type definition"; } + if (spvIsOpenCLEnv(target_env)) { + // In OpenCL, a read from a depth image returns a scalar float. In other + // cases, the result is always a 4-element vector. + // https://www.khronos.org/registry/OpenCL/specs/3.0-unified/html/OpenCL_Env.html#_data_format_for_reading_and_writing_images + // https://www.khronos.org/registry/OpenCL/specs/3.0-unified/html/OpenCL_C.html#image-read-and-write-functions + // The builtins for reading depth images are: + // float read_imagef(aQual image2d_depth_t image, int2 coord) + // float read_imagef(aQual image2d_array_depth_t image, int4 coord) + if (info.depth) { + if (!_.IsFloatScalarType(actual_result_type)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected " << GetActualResultTypeStr(opcode) + << " from a depth image read to result in a scalar float value"; + } + } else { + if (_.GetDimension(actual_result_type) != 4) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected " << GetActualResultTypeStr(opcode) + << " to have 4 components"; + } + } + } + if (info.dim == SpvDimSubpassData) { if (opcode == SpvOpImageSparseRead) { return _.diag(SPV_ERROR_INVALID_DATA, inst) diff --git a/test/val/val_image_test.cpp b/test/val/val_image_test.cpp index e9159a1e..4b2c68fb 100644 --- a/test/val/val_image_test.cpp +++ b/test/val/val_image_test.cpp @@ -463,6 +463,13 @@ std::string GetWebGPUShaderHeader() { %func = OpTypeFunction %void %f32 = OpTypeFloat 32 %u32 = OpTypeInt 32 0 + %f32vec2 = OpTypeVector %f32 2 + %f32vec3 = OpTypeVector %f32 3 + %f32vec4 = OpTypeVector %f32 4 + %u32vec2 = OpTypeVector %u32 2 + %u32vec3 = OpTypeVector %u32 3 + %u32vec4 = OpTypeVector %u32 4 + %u32vec2null = OpConstantNull %u32vec2 )"; } @@ -3131,16 +3138,61 @@ TEST_F(ValidateImage, DISABLED_ReadWrongResultType) { HasSubstr("Expected Result Type to be int or float vector type")); } -// TODO(atgoo@github.com) Disabled until the spec is clarified. -TEST_F(ValidateImage, DISABLED_ReadWrongNumComponentsResultType) { +TEST_F(ValidateImage, ReadScalarResultType_Universal) { const std::string body = R"( %img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 -%res1 = OpImageRead %f32vec3 %img %u32vec2_01 +%res1 = OpImageRead %u32 %img %u32vec2_01 )"; const std::string extra = "\nOpCapability StorageImageReadWithoutFormat\n"; CompileSuccessfully(GenerateShaderCode(body, extra).c_str()); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_0)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateImage, ReadUnusualNumComponentsResultType_Universal) { + const std::string body = R"( +%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 +%res1 = OpImageRead %u32vec3 %img %u32vec2_01 +)"; + + const std::string extra = "\nOpCapability StorageImageReadWithoutFormat\n"; + CompileSuccessfully(GenerateShaderCode(body, extra).c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_0)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateImage, ReadWrongNumComponentsResultType_Vulkan) { + const std::string body = R"( +%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 +%res1 = OpImageRead %u32vec3 %img %u32vec2_01 +)"; + + const std::string extra = "\nOpCapability StorageImageReadWithoutFormat\n"; + CompileSuccessfully( + GenerateShaderCode(body, extra, "Fragment", "", SPV_ENV_VULKAN_1_0) + .c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Expected Result Type to have 4 components")); +} + +TEST_F(ValidateImage, ReadWrongNumComponentsResultType_WebGPU) { + const std::string code = GetWebGPUShaderHeader() + R"( +%img_type = OpTypeImage %f32 2D 0 0 0 2 Unknown +%ptr_type = OpTypePointer UniformConstant %img_type +%var = OpVariable %ptr_type UniformConstant +%main = OpFunction %void None %func +%entry = OpLabel +%img = OpLoad %img_type %var +%res1 = OpImageRead %u32vec3 %img %u32vec2null +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(code.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)) + << getDiagnosticString(); EXPECT_THAT(getDiagnosticString(), HasSubstr("Expected Result Type to have 4 components")); } diff --git a/test/val/val_opencl_test.cpp b/test/val/val_opencl_test.cpp index e5e3b12b..9dab931a 100644 --- a/test/val/val_opencl_test.cpp +++ b/test/val/val_opencl_test.cpp @@ -23,6 +23,7 @@ namespace spvtools { namespace val { namespace { +using testing::Eq; using testing::HasSubstr; using ValidateOpenCL = spvtest::ValidateBase; @@ -224,6 +225,264 @@ TEST_F(ValidateOpenCL, ImageReadWithConstOffsetBad) { "\n %call = OpImageRead %v4uint %img %coord ConstOffset %coord\n")); } +TEST_F(ValidateOpenCL, ImageRead_NonDepthScalarFloatResult_Bad) { + std::string spirv = R"( + OpCapability Addresses + OpCapability Kernel + OpCapability ImageBasic + OpMemoryModel Physical64 OpenCL + OpEntryPoint Kernel %5 "image_kernel" + OpName %img "img" + OpName %coord "coord" + OpName %call "call" + %uint = OpTypeInt 32 0 + %v2uint = OpTypeVector %uint 2 + %coord = OpConstantNull %v2uint + %void = OpTypeVoid + %float = OpTypeFloat 32 + %3 = OpTypeImage %void 2D 0 0 0 0 Unknown ReadOnly + %4 = OpTypeFunction %void %3 + %5 = OpFunction %void None %4 + %img = OpFunctionParameter %3 + %entry = OpLabel + %call = OpImageRead %float %img %coord + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Expected Result Type to have 4 components")); +} + +TEST_F(ValidateOpenCL, ImageRead_NonDepthScalarIntResult_Bad) { + std::string spirv = R"( + OpCapability Addresses + OpCapability Kernel + OpCapability ImageBasic + OpMemoryModel Physical64 OpenCL + OpEntryPoint Kernel %5 "image_kernel" + OpName %img "img" + OpName %coord "coord" + OpName %call "call" + %uint = OpTypeInt 32 0 + %v2uint = OpTypeVector %uint 2 + %coord = OpConstantNull %v2uint + %void = OpTypeVoid + %float = OpTypeFloat 32 + %3 = OpTypeImage %void 2D 0 0 0 0 Unknown ReadOnly + %4 = OpTypeFunction %void %3 + %5 = OpFunction %void None %4 + %img = OpFunctionParameter %3 + %entry = OpLabel + %call = OpImageRead %uint %img %coord + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Expected Result Type to have 4 components")); +} + +TEST_F(ValidateOpenCL, ImageRead_NonDepthVector3FloatResult_Bad) { + std::string spirv = R"( + OpCapability Addresses + OpCapability Kernel + OpCapability ImageBasic + OpMemoryModel Physical64 OpenCL + OpEntryPoint Kernel %5 "image_kernel" + OpName %img "img" + OpName %coord "coord" + OpName %call "call" + %uint = OpTypeInt 32 0 + %v2uint = OpTypeVector %uint 2 + %coord = OpConstantNull %v2uint + %void = OpTypeVoid + %float = OpTypeFloat 32 + %v3float = OpTypeVector %float 3 + %3 = OpTypeImage %void 2D 0 0 0 0 Unknown ReadOnly + %4 = OpTypeFunction %void %3 + %5 = OpFunction %void None %4 + %img = OpFunctionParameter %3 + %entry = OpLabel + %call = OpImageRead %v3float %img %coord + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Expected Result Type to have 4 components")); +} + +TEST_F(ValidateOpenCL, ImageRead_NonDepthVector4FloatResult_Ok) { + std::string spirv = R"( + OpCapability Addresses + OpCapability Kernel + OpCapability ImageBasic + OpMemoryModel Physical64 OpenCL + OpEntryPoint Kernel %5 "image_kernel" + OpName %img "img" + OpName %coord "coord" + OpName %call "call" + %uint = OpTypeInt 32 0 + %v2uint = OpTypeVector %uint 2 + %coord = OpConstantNull %v2uint + %void = OpTypeVoid + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 + %3 = OpTypeImage %void 2D 0 0 0 0 Unknown ReadOnly + %4 = OpTypeFunction %void %3 + %5 = OpFunction %void None %4 + %img = OpFunctionParameter %3 + %entry = OpLabel + %call = OpImageRead %v4float %img %coord + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_OPENCL_1_2)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateOpenCL, ImageRead_NonDepthVector4IntResult_Ok) { + std::string spirv = R"( + OpCapability Addresses + OpCapability Kernel + OpCapability ImageBasic + OpMemoryModel Physical64 OpenCL + OpEntryPoint Kernel %5 "image_kernel" + OpName %img "img" + OpName %coord "coord" + OpName %call "call" + %uint = OpTypeInt 32 0 + %v2uint = OpTypeVector %uint 2 + %coord = OpConstantNull %v2uint + %void = OpTypeVoid + %v4uint = OpTypeVector %uint 4 + %3 = OpTypeImage %void 2D 0 0 0 0 Unknown ReadOnly + %4 = OpTypeFunction %void %3 + %5 = OpFunction %void None %4 + %img = OpFunctionParameter %3 + %entry = OpLabel + %call = OpImageRead %v4uint %img %coord + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_OPENCL_1_2)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateOpenCL, ImageRead_DepthScalarFloatResult_Ok) { + std::string spirv = R"( + OpCapability Addresses + OpCapability Kernel + OpCapability ImageBasic + OpMemoryModel Physical64 OpenCL + OpEntryPoint Kernel %5 "image_kernel" + OpName %img "img" + OpName %coord "coord" + OpName %call "call" + %uint = OpTypeInt 32 0 + %v2uint = OpTypeVector %uint 2 + %coord = OpConstantNull %v2uint + %void = OpTypeVoid + %float = OpTypeFloat 32 + %3 = OpTypeImage %void 2D 1 0 0 0 Unknown ReadOnly + %4 = OpTypeFunction %void %3 + %5 = OpFunction %void None %4 + %img = OpFunctionParameter %3 + %entry = OpLabel + %call = OpImageRead %float %img %coord + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_OPENCL_1_2)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateOpenCL, ImageRead_DepthScalarIntResult_Bad) { + std::string spirv = R"( + OpCapability Addresses + OpCapability Kernel + OpCapability ImageBasic + OpMemoryModel Physical64 OpenCL + OpEntryPoint Kernel %5 "image_kernel" + OpName %img "img" + OpName %coord "coord" + OpName %call "call" + %uint = OpTypeInt 32 0 + %v2uint = OpTypeVector %uint 2 + %coord = OpConstantNull %v2uint + %void = OpTypeVoid + %float = OpTypeFloat 32 + %3 = OpTypeImage %void 2D 1 0 0 0 Unknown ReadOnly + %4 = OpTypeFunction %void %3 + %5 = OpFunction %void None %4 + %img = OpFunctionParameter %3 + %entry = OpLabel + %call = OpImageRead %uint %img %coord + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Expected Result Type from a depth image " + "read to result in a scalar float value")); +} + +TEST_F(ValidateOpenCL, ImageRead_DepthVectorFloatResult_Bad) { + std::string spirv = R"( + OpCapability Addresses + OpCapability Kernel + OpCapability ImageBasic + OpMemoryModel Physical64 OpenCL + OpEntryPoint Kernel %5 "image_kernel" + OpName %img "img" + OpName %coord "coord" + OpName %call "call" + %uint = OpTypeInt 32 0 + %v2uint = OpTypeVector %uint 2 + %coord = OpConstantNull %v2uint + %void = OpTypeVoid + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 + %3 = OpTypeImage %void 2D 1 0 0 0 Unknown ReadOnly + %4 = OpTypeFunction %void %3 + %5 = OpFunction %void None %4 + %img = OpFunctionParameter %3 + %entry = OpLabel + %call = OpImageRead %v4float %img %coord + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Expected Result Type from a depth image " + "read to result in a scalar float value")); +} + TEST_F(ValidateOpenCL, ImageSampleExplicitLodWithConstOffsetBad) { std::string spirv = R"( OpCapability Addresses @@ -236,18 +495,16 @@ TEST_F(ValidateOpenCL, ImageSampleExplicitLodWithConstOffsetBad) { OpName %coord "coord" OpName %call "call" %uint = OpTypeInt 32 0 - %uint_7 = OpConstant %uint 7 - %uint_3 = OpConstant %uint 3 + %v2uint = OpTypeVector %uint 2 + %coord = OpConstantNull %v2uint %void = OpTypeVoid %3 = OpTypeImage %void 2D 0 0 0 0 Unknown ReadOnly %4 = OpTypeFunction %void %3 %8 = OpTypeSampler %10 = OpTypeSampledImage %3 %v4uint = OpTypeVector %uint 4 - %v2uint = OpTypeVector %uint 2 %float = OpTypeFloat 32 %9 = OpConstantSampler %8 None 0 Nearest - %coord = OpConstantComposite %v2uint %uint_7 %uint_3 %float_0 = OpConstant %float 0 %5 = OpFunction %void None %4 %6 = OpFunctionParameter %3 -- cgit v1.2.3 From 4e31fdd4aa1f94dbd60b1d7374089ff7258e3b39 Mon Sep 17 00:00:00 2001 From: Alastair Donaldson Date: Thu, 17 Dec 2020 11:45:52 +0000 Subject: spirv-fuzz: Fix OpPhi handling in DuplicateRegionWithSelection (#4065) Avoid generating OpPhi on void types, and allow the transformation to take place on regions that produce pointer and sampled image result ids if such ids are not used after the region. Fixes #3787. --- ...nsformation_duplicate_region_with_selection.cpp | 156 ++++++++++------ ...ransformation_duplicate_region_with_selection.h | 11 ++ ...mation_duplicate_region_with_selection_test.cpp | 204 +++++++++++++++++++++ 3 files changed, 313 insertions(+), 58 deletions(-) diff --git a/source/fuzz/transformation_duplicate_region_with_selection.cpp b/source/fuzz/transformation_duplicate_region_with_selection.cpp index 07758cd3..2ac6259d 100644 --- a/source/fuzz/transformation_duplicate_region_with_selection.cpp +++ b/source/fuzz/transformation_duplicate_region_with_selection.cpp @@ -209,7 +209,7 @@ bool TransformationDuplicateRegionWithSelection::IsApplicable( return false; } } else { - auto duplicate_label = original_label_to_duplicate_label[block->id()]; + auto duplicate_label = original_label_to_duplicate_label.at(block->id()); // Each id assigned to labels in the region must be distinct and fresh. if (!duplicate_label || !CheckIdIsFreshAndNotUsedByThisTransformation( @@ -217,7 +217,7 @@ bool TransformationDuplicateRegionWithSelection::IsApplicable( return false; } } - for (auto instr : *block) { + for (auto& instr : *block) { if (!instr.HasResultId()) { continue; } @@ -228,7 +228,7 @@ bool TransformationDuplicateRegionWithSelection::IsApplicable( return false; } } else { - auto duplicate_id = original_id_to_duplicate_id[instr.result_id()]; + auto duplicate_id = original_id_to_duplicate_id.at(instr.result_id()); // Id assigned to this result id in the region must be distinct and // fresh. if (!duplicate_id || @@ -237,43 +237,48 @@ bool TransformationDuplicateRegionWithSelection::IsApplicable( return false; } } - if (&instr == &*exit_block->tail() || - fuzzerutil::IdIsAvailableBeforeInstruction( - ir_context, &*exit_block->tail(), instr.result_id())) { - // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3787): - // Consider not adding OpPhi instructions for the pointers and - // sampled images which are unused after the region, so that the - // transformation could be still applicable. - - // Using pointers with OpPhi requires capability VariablePointers. - if (ir_context->get_def_use_mgr()->GetDef(instr.type_id())->opcode() == - SpvOpTypePointer && - !ir_context->get_feature_mgr()->HasCapability( - SpvCapabilityVariablePointers)) { - return false; - } - - // OpTypeSampledImage cannot be the result type of an OpPhi instruction. - if (ir_context->get_def_use_mgr()->GetDef(instr.type_id())->opcode() == - SpvOpTypeSampledImage) { - return false; - } - - // Every instruction with a result id available at the end of the region - // must be present in the map |original_id_to_phi_id|, unless overflow - // ids are present. - if (original_id_to_phi_id.count(instr.result_id()) == 0) { - if (!transformation_context.GetOverflowIdSource()->HasOverflowIds()) { + // If the instruction is available at the end of the region then we would + // like to be able to add an OpPhi instruction at the merge point of the + // duplicated region to capture the values computed by both duplicates of + // the instruction, so that this is also available after the region. We + // do this not just for instructions that are already used after the + // region, but for all instructions so that the phi is available to future + // transformations. + if (AvailableAfterRegion(instr, exit_block, ir_context)) { + if (!ValidOpPhiArgument(instr, ir_context)) { + // The instruction cannot be used as an OpPhi argument. This is a + // blocker if there are uses of the instruction after the region. + // Otherwise we can simply avoid generating an OpPhi for this + // instruction and its duplicate. + if (!ir_context->get_def_use_mgr()->WhileEachUser( + &instr, + [ir_context, + ®ion_set](opt::Instruction* use_instr) -> bool { + opt::BasicBlock* use_block = + ir_context->get_instr_block(use_instr); + return use_block == nullptr || + region_set.count(use_block) > 0; + })) { return false; } } else { - auto phi_id = original_id_to_phi_id[instr.result_id()]; - // Id assigned to this result id in the region must be distinct and - // fresh. - if (!phi_id || - !CheckIdIsFreshAndNotUsedByThisTransformation( - phi_id, ir_context, &ids_used_by_this_transformation)) { - return false; + // Every instruction with a result id available at the end of the + // region must be present in the map |original_id_to_phi_id|, unless + // overflow ids are present. + if (original_id_to_phi_id.count(instr.result_id()) == 0) { + if (!transformation_context.GetOverflowIdSource() + ->HasOverflowIds()) { + return false; + } + } else { + auto phi_id = original_id_to_phi_id.at(instr.result_id()); + // Id assigned to this result id in the region must be distinct and + // fresh. + if (!phi_id || + !CheckIdIsFreshAndNotUsedByThisTransformation( + phi_id, ir_context, &ids_used_by_this_transformation)) { + return false; + } } } } @@ -329,7 +334,7 @@ void TransformationDuplicateRegionWithSelection::Apply( {block->id(), transformation_context->GetOverflowIdSource()->GetNextOverflowId()}); } - for (auto instr : *block) { + for (auto& instr : *block) { if (!instr.HasResultId()) { continue; } @@ -338,9 +343,8 @@ void TransformationDuplicateRegionWithSelection::Apply( {instr.result_id(), transformation_context->GetOverflowIdSource() ->GetNextOverflowId()}); } - if (&instr == &*exit_block->tail() || - fuzzerutil::IdIsAvailableBeforeInstruction( - ir_context, &*exit_block->tail(), instr.result_id())) { + if (AvailableAfterRegion(instr, exit_block, ir_context) && + ValidOpPhiArgument(instr, ir_context)) { if (original_id_to_phi_id.count(instr.result_id()) == 0) { original_id_to_phi_id.insert( {instr.result_id(), transformation_context->GetOverflowIdSource() @@ -414,12 +418,12 @@ void TransformationDuplicateRegionWithSelection::Apply( } fuzzerutil::UpdateModuleIdBound( - ir_context, original_label_to_duplicate_label[block->id()]); + ir_context, original_label_to_duplicate_label.at(block->id())); std::unique_ptr duplicated_block = MakeUnique(MakeUnique( ir_context, SpvOpLabel, 0, - original_label_to_duplicate_label[block->id()], + original_label_to_duplicate_label.at(block->id()), opt::Instruction::OperandList())); for (auto& instr : *block) { @@ -444,8 +448,10 @@ void TransformationDuplicateRegionWithSelection::Apply( duplicated_block->AddInstruction( std::unique_ptr(cloned_instr)); - fuzzerutil::UpdateModuleIdBound( - ir_context, original_id_to_duplicate_id[instr.result_id()]); + if (instr.HasResultId()) { + fuzzerutil::UpdateModuleIdBound( + ir_context, original_id_to_duplicate_id.at(instr.result_id())); + } // If an id from the original region was used in this instruction, // replace it with the value from |original_id_to_duplicate_id|. @@ -456,8 +462,7 @@ void TransformationDuplicateRegionWithSelection::Apply( original_label_to_duplicate_label](uint32_t* op) { if (original_id_to_duplicate_id.count(*op) != 0) { *op = original_id_to_duplicate_id.at(*op); - } - if (original_label_to_duplicate_label.count(*op) != 0) { + } else if (original_label_to_duplicate_label.count(*op) != 0) { *op = original_label_to_duplicate_label.at(*op); } }); @@ -484,26 +489,27 @@ void TransformationDuplicateRegionWithSelection::Apply( for (auto& block : region_blocks) { for (auto& instr : *block) { - if (instr.result_id() != 0 && - (&instr == &*exit_block->tail() || - fuzzerutil::IdIsAvailableBeforeInstruction( - ir_context, &*exit_block->tail(), instr.result_id()))) { - // Add the OpPhi instruction for every result id that is - // available at the end of the region (the last instruction - // of the |exit_block|) + if (instr.result_id() == 0) { + continue; + } + if (AvailableAfterRegion(instr, exit_block, ir_context) && + ValidOpPhiArgument(instr, ir_context)) { + // Add an OpPhi instruction for every result id that is available at + // the end of the region, as long as the result id is valid for use + // with OpPhi. merge_block->AddInstruction(MakeUnique( ir_context, SpvOpPhi, instr.type_id(), - original_id_to_phi_id[instr.result_id()], + original_id_to_phi_id.at(instr.result_id()), opt::Instruction::OperandList({ {SPV_OPERAND_TYPE_ID, {instr.result_id()}}, {SPV_OPERAND_TYPE_ID, {exit_block->id()}}, {SPV_OPERAND_TYPE_ID, - {original_id_to_duplicate_id[instr.result_id()]}}, + {original_id_to_duplicate_id.at(instr.result_id())}}, {SPV_OPERAND_TYPE_ID, {duplicated_exit_block->id()}}, }))); fuzzerutil::UpdateModuleIdBound( - ir_context, original_id_to_phi_id[instr.result_id()]); + ir_context, original_id_to_phi_id.at(instr.result_id())); // If the instruction has been remapped by an OpPhi, look // for all its uses outside of the region and outside of the @@ -544,7 +550,8 @@ void TransformationDuplicateRegionWithSelection::Apply( {{SPV_OPERAND_TYPE_ID, {message_.condition_id()}}, {SPV_OPERAND_TYPE_ID, {message_.entry_block_id()}}, {SPV_OPERAND_TYPE_ID, - {original_label_to_duplicate_label[message_.entry_block_id()]}}}))); + {original_label_to_duplicate_label.at( + message_.entry_block_id())}}}))); // Move the terminator of |exit_block| to the end of // |merge_block|. @@ -678,5 +685,38 @@ TransformationDuplicateRegionWithSelection::GetFreshIds() const { return result; } +bool TransformationDuplicateRegionWithSelection::AvailableAfterRegion( + const opt::Instruction& instr, opt::BasicBlock* exit_block, + opt::IRContext* ir_context) { + opt::Instruction* final_instruction_in_region = &*exit_block->tail(); + return &instr == final_instruction_in_region || + fuzzerutil::IdIsAvailableBeforeInstruction( + ir_context, final_instruction_in_region, instr.result_id()); +} + +bool TransformationDuplicateRegionWithSelection::ValidOpPhiArgument( + const opt::Instruction& instr, opt::IRContext* ir_context) { + opt::Instruction* instr_type = + ir_context->get_def_use_mgr()->GetDef(instr.type_id()); + + // It is invalid to apply OpPhi to void-typed values. + if (instr_type->opcode() == SpvOpTypeVoid) { + return false; + } + + // Using pointers with OpPhi requires capability VariablePointers. + if (instr_type->opcode() == SpvOpTypePointer && + !ir_context->get_feature_mgr()->HasCapability( + SpvCapabilityVariablePointers)) { + return false; + } + + // OpTypeSampledImage cannot be the result type of an OpPhi instruction. + if (instr_type->opcode() == SpvOpTypeSampledImage) { + return false; + } + return true; +} + } // namespace fuzz } // namespace spvtools diff --git a/source/fuzz/transformation_duplicate_region_with_selection.h b/source/fuzz/transformation_duplicate_region_with_selection.h index d6f0ad9a..a2b9a433 100644 --- a/source/fuzz/transformation_duplicate_region_with_selection.h +++ b/source/fuzz/transformation_duplicate_region_with_selection.h @@ -66,6 +66,17 @@ class TransformationDuplicateRegionWithSelection : public Transformation { opt::IRContext* ir_context, opt::BasicBlock* entry_block, opt::BasicBlock* exit_block); + // Returns true if and only if |instr| is available at the end of the region + // for which |exit_block| is the final block. + static bool AvailableAfterRegion(const opt::Instruction& instr, + opt::BasicBlock* exit_block, + opt::IRContext* ir_context); + + // Returns true if and only if |instr| is valid as an argument to an OpPhi + // instruction. + static bool ValidOpPhiArgument(const opt::Instruction& instr, + opt::IRContext* ir_context); + std::unordered_set GetFreshIds() const override; protobufs::Transformation ToMessage() const override; diff --git a/test/fuzz/transformation_duplicate_region_with_selection_test.cpp b/test/fuzz/transformation_duplicate_region_with_selection_test.cpp index f3738e74..31fb9a2f 100644 --- a/test/fuzz/transformation_duplicate_region_with_selection_test.cpp +++ b/test/fuzz/transformation_duplicate_region_with_selection_test.cpp @@ -1334,6 +1334,9 @@ TEST(TransformationDuplicateRegionWithSelectionTest, OpBranch %50 %50 = OpLabel %51 = OpCopyObject %7 %12 + OpBranch %52 + %52 = OpLabel + %53 = OpCopyObject %7 %51 OpReturn OpFunctionEnd )"; @@ -2275,6 +2278,207 @@ TEST(TransformationDuplicateRegionWithSelectionTest, .IsApplicable(context.get(), transformation_context)); } +TEST(TransformationDuplicateRegionWithSelectionTest, + DoNotProduceOpPhiWithVoidType) { + std::string reference_shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 320 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %10 = OpTypeBool + %11 = OpConstantTrue %10 + %4 = OpFunction %2 None %3 + %12 = OpLabel + OpBranch %5 + %5 = OpLabel + %8 = OpFunctionCall %2 %6 + OpReturn + OpFunctionEnd + %6 = OpFunction %2 None %3 + %7 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = + BuildModule(env, consumer, reference_shader, kFuzzAssembleOption); + spvtools::ValidatorOptions validator_options; + ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, + kConsoleMessageConsumer)); + TransformationContext transformation_context( + MakeUnique(context.get()), validator_options); + + TransformationDuplicateRegionWithSelection transformation( + 100, 11, 101, 5, 5, {{5, 102}}, {{8, 103}}, {}); + ASSERT_TRUE( + transformation.IsApplicable(context.get(), transformation_context)); + ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context); + ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, + kConsoleMessageConsumer)); + + std::string expected_shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 320 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %10 = OpTypeBool + %11 = OpConstantTrue %10 + %4 = OpFunction %2 None %3 + %12 = OpLabel + OpBranch %100 + %100 = OpLabel + OpSelectionMerge %101 None + OpBranchConditional %11 %5 %102 + %5 = OpLabel + %8 = OpFunctionCall %2 %6 + OpBranch %101 + %102 = OpLabel + %103 = OpFunctionCall %2 %6 + OpBranch %101 + %101 = OpLabel + OpReturn + OpFunctionEnd + %6 = OpFunction %2 None %3 + %7 = OpLabel + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, expected_shader, context.get())); +} + +TEST(TransformationDuplicateRegionWithSelectionTest, + DoNotProduceOpPhiWithDisallowedType) { + std::string reference_shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 320 + OpDecorate %13 DescriptorSet 0 + OpDecorate %13 Binding 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeVector %6 2 + %8 = OpTypePointer Function %7 + %10 = OpTypeImage %6 2D 0 0 0 1 Unknown + %11 = OpTypeSampledImage %10 + %12 = OpTypePointer UniformConstant %11 + %13 = OpVariable %12 UniformConstant + %15 = OpConstant %6 1 + %16 = OpConstantComposite %7 %15 %15 + %17 = OpTypeVector %6 4 + %19 = OpTypeInt 32 0 + %20 = OpConstant %19 0 + %22 = OpTypePointer Function %6 + %90 = OpTypeBool + %91 = OpConstantTrue %90 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %9 = OpVariable %8 Function + OpBranch %81 + %81 = OpLabel + %14 = OpLoad %11 %13 + %18 = OpImageSampleImplicitLod %17 %14 %16 + %21 = OpCompositeExtract %6 %18 0 + %23 = OpAccessChain %22 %9 %20 + OpStore %23 %21 + OpBranch %80 + %80 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = + BuildModule(env, consumer, reference_shader, kFuzzAssembleOption); + spvtools::ValidatorOptions validator_options; + ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, + kConsoleMessageConsumer)); + TransformationContext transformation_context( + MakeUnique(context.get()), validator_options); + + TransformationDuplicateRegionWithSelection transformation( + 100, 91, 101, 81, 81, {{81, 102}}, + {{14, 103}, {18, 104}, {21, 105}, {23, 106}}, {{18, 107}, {21, 108}}); + ASSERT_TRUE( + transformation.IsApplicable(context.get(), transformation_context)); + ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context); + ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, + kConsoleMessageConsumer)); + + std::string expected_shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 320 + OpDecorate %13 DescriptorSet 0 + OpDecorate %13 Binding 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeVector %6 2 + %8 = OpTypePointer Function %7 + %10 = OpTypeImage %6 2D 0 0 0 1 Unknown + %11 = OpTypeSampledImage %10 + %12 = OpTypePointer UniformConstant %11 + %13 = OpVariable %12 UniformConstant + %15 = OpConstant %6 1 + %16 = OpConstantComposite %7 %15 %15 + %17 = OpTypeVector %6 4 + %19 = OpTypeInt 32 0 + %20 = OpConstant %19 0 + %22 = OpTypePointer Function %6 + %90 = OpTypeBool + %91 = OpConstantTrue %90 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %9 = OpVariable %8 Function + OpBranch %100 + %100 = OpLabel + OpSelectionMerge %101 None + OpBranchConditional %91 %81 %102 + %81 = OpLabel + %14 = OpLoad %11 %13 + %18 = OpImageSampleImplicitLod %17 %14 %16 + %21 = OpCompositeExtract %6 %18 0 + %23 = OpAccessChain %22 %9 %20 + OpStore %23 %21 + OpBranch %101 + %102 = OpLabel + %103 = OpLoad %11 %13 + %104 = OpImageSampleImplicitLod %17 %103 %16 + %105 = OpCompositeExtract %6 %104 0 + %106 = OpAccessChain %22 %9 %20 + OpStore %106 %105 + OpBranch %101 + %101 = OpLabel + %107 = OpPhi %17 %18 %81 %104 %102 + %108 = OpPhi %6 %21 %81 %105 %102 + OpBranch %80 + %80 = OpLabel + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, expected_shader, context.get())); +} + } // namespace } // namespace fuzz } // namespace spvtools -- cgit v1.2.3 From 8f4b35c332e1b8dab2b5b8c56363bb106d335998 Mon Sep 17 00:00:00 2001 From: sfricke-samsung <46493288+sfricke-samsung@users.noreply.github.com> Date: Thu, 17 Dec 2020 05:37:43 -0800 Subject: spirv-val: Add Subgroup VUIDs (#4074) --- source/val/validate_builtins.cpp | 157 ++++++++++++++++----------------------- source/val/validation_state.cpp | 40 ++++++++++ test/val/val_builtins_test.cpp | 50 +++++++++++-- 3 files changed, 149 insertions(+), 98 deletions(-) diff --git a/source/val/validate_builtins.cpp b/source/val/validate_builtins.cpp index d85d1f0b..4f2a3b11 100644 --- a/source/val/validate_builtins.cpp +++ b/source/val/validate_builtins.cpp @@ -142,15 +142,28 @@ typedef enum VUIDError_ { VUIDErrorMax, } VUIDError; -const static uint32_t NumRtBuiltins = 16; +const static uint32_t NumVUIDBuiltins = 29; typedef struct { SpvBuiltIn builtIn; uint32_t vuid[VUIDErrorMax]; // execution mode, storage class, type VUIDs -} RtBuiltinVUIDMapping; +} BuiltinVUIDMapping; -std::array rtBuiltinInfo = {{ +std::array builtinVUIDInfo = {{ // clang-format off + {SpvBuiltInSubgroupEqMask, {0, 4370, 4371}}, + {SpvBuiltInSubgroupGeMask, {0, 4372, 4373}}, + {SpvBuiltInSubgroupGtMask, {0, 4374, 4375}}, + {SpvBuiltInSubgroupLeMask, {0, 4376, 4377}}, + {SpvBuiltInSubgroupLtMask, {0, 4378, 4379}}, + {SpvBuiltInSubgroupLocalInvocationId, {0, 4380, 4381}}, + {SpvBuiltInSubgroupSize, {0, 4382, 4383}}, + {SpvBuiltInGlobalInvocationId, {4236, 4237, 4238}}, + {SpvBuiltInLocalInvocationId, {4281, 4282, 4283}}, + {SpvBuiltInNumWorkgroups, {4296, 4297, 4298}}, + {SpvBuiltInNumSubgroups, {4293, 4294, 4295}}, + {SpvBuiltInSubgroupId, {4367, 4368, 4369}}, + {SpvBuiltInWorkgroupId, {4422, 4423, 4424}}, {SpvBuiltInHitKindKHR, {4242, 4243, 4244}}, {SpvBuiltInHitTNV, {4245, 4246, 4247}}, {SpvBuiltInInstanceCustomIndexKHR, {4251, 4252, 4253}}, @@ -170,9 +183,9 @@ std::array rtBuiltinInfo = {{ // clang-format off } }; -uint32_t GetVUIDForRTBuiltin(SpvBuiltIn builtIn, VUIDError type) { +uint32_t GetVUIDForBuiltin(SpvBuiltIn builtIn, VUIDError type) { uint32_t vuid = 0; - for (const auto& iter: rtBuiltinInfo) { + for (const auto& iter: builtinVUIDInfo) { if (iter.builtIn == builtIn) { assert(type < VUIDErrorMax); vuid = iter.vuid[type]; @@ -2826,32 +2839,17 @@ spv_result_t BuiltInsValidator::ValidateLayerOrViewportIndexAtReference( spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtDefinition( const Decoration& decoration, const Instruction& inst) { if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { + const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]); if (spv_result_t error = ValidateI32Vec( decoration, inst, 3, - [this, &decoration, - &inst](const std::string& message) -> spv_result_t { - uint32_t operand = decoration.params()[0]; - uint32_t vuid = 0; - switch (operand) { - case SpvBuiltInGlobalInvocationId: - vuid = 4238; - break; - case SpvBuiltInLocalInvocationId: - vuid = 4283; - break; - case SpvBuiltInNumWorkgroups: - vuid = 4298; - break; - case SpvBuiltInWorkgroupId: - vuid = 4424; - break; - }; + [this, &inst, builtin](const std::string& message) -> spv_result_t { + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType); return _.diag(SPV_ERROR_INVALID_DATA, &inst) << _.VkErrorID(vuid) << "According to the " << spvLogStringForEnv(_.context()->target_env) << " spec BuiltIn " << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - operand) + builtin) << " variable needs to be a 3-component 32-bit int " "vector. " << message; @@ -2869,31 +2867,16 @@ spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtReference( const Decoration& decoration, const Instruction& built_in_inst, const Instruction& referenced_inst, const Instruction& referenced_from_inst) { - uint32_t operand = decoration.params()[0]; if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { + const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]); const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); if (storage_class != SpvStorageClassMax && storage_class != SpvStorageClassInput) { - uint32_t vuid = 0; - switch (operand) { - case SpvBuiltInGlobalInvocationId: - vuid = 4237; - break; - case SpvBuiltInLocalInvocationId: - vuid = 4282; - break; - case SpvBuiltInNumWorkgroups: - vuid = 4297; - break; - case SpvBuiltInWorkgroupId: - vuid = 4423; - break; - }; + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass); return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) << _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env) << " spec allows BuiltIn " - << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin) << " to be only used for variables with Input storage class. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, referenced_from_inst) @@ -2907,27 +2890,12 @@ spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtReference( bool has_webgpu_model = execution_model == SpvExecutionModelGLCompute; if ((spvIsVulkanEnv(_.context()->target_env) && !has_vulkan_model) || (spvIsWebGPUEnv(_.context()->target_env) && !has_webgpu_model)) { - uint32_t vuid = 0; - switch (operand) { - case SpvBuiltInGlobalInvocationId: - vuid = 4236; - break; - case SpvBuiltInLocalInvocationId: - vuid = 4281; - break; - case SpvBuiltInNumWorkgroups: - vuid = 4296; - break; - case SpvBuiltInWorkgroupId: - vuid = 4422; - break; - }; + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel); return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) << _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env) << " spec allows BuiltIn " - << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin) << " to be used only with GLCompute execution model. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, referenced_from_inst, execution_model); @@ -2949,23 +2917,23 @@ spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtReference( spv_result_t BuiltInsValidator::ValidateComputeI32InputAtDefinition( const Decoration& decoration, const Instruction& inst) { if (spvIsVulkanEnv(_.context()->target_env)) { + const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]); if (decoration.struct_member_index() != Decoration::kInvalidMember) { return _.diag(SPV_ERROR_INVALID_DATA, &inst) << "BuiltIn " - << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin) << " cannot be used as a member decoration "; } if (spv_result_t error = ValidateI32( decoration, inst, - [this, &decoration, - &inst](const std::string& message) -> spv_result_t { + [this, &inst, builtin](const std::string& message) -> spv_result_t { + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType); return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(vuid) << "According to the " << spvLogStringForEnv(_.context()->target_env) << " spec BuiltIn " - << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin) << " variable needs to be a 32-bit int " "vector. " << message; @@ -2983,14 +2951,16 @@ spv_result_t BuiltInsValidator::ValidateComputeI32InputAtReference( const Instruction& referenced_inst, const Instruction& referenced_from_inst) { if (spvIsVulkanEnv(_.context()->target_env)) { + const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]); const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); if (storage_class != SpvStorageClassMax && storage_class != SpvStorageClassInput) { + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass); return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env) << " spec allows BuiltIn " - << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin) << " to be only used for variables with Input storage class. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, referenced_from_inst) @@ -3002,11 +2972,12 @@ spv_result_t BuiltInsValidator::ValidateComputeI32InputAtReference( execution_model == SpvExecutionModelTaskNV || execution_model == SpvExecutionModelMeshNV; if (spvIsVulkanEnv(_.context()->target_env) && !has_vulkan_model) { + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel); return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env) << " spec allows BuiltIn " - << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin) << " to be used only with GLCompute execution model. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, referenced_from_inst, execution_model); @@ -3028,23 +2999,23 @@ spv_result_t BuiltInsValidator::ValidateComputeI32InputAtReference( spv_result_t BuiltInsValidator::ValidateI32InputAtDefinition( const Decoration& decoration, const Instruction& inst) { if (spvIsVulkanEnv(_.context()->target_env)) { + const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]); if (decoration.struct_member_index() != Decoration::kInvalidMember) { return _.diag(SPV_ERROR_INVALID_DATA, &inst) << "BuiltIn " - << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin) << " cannot be used as a member decoration "; } if (spv_result_t error = ValidateI32( decoration, inst, - [this, &decoration, - &inst](const std::string& message) -> spv_result_t { + [this, &inst, builtin](const std::string& message) -> spv_result_t { + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType); return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(vuid) << "According to the " << spvLogStringForEnv(_.context()->target_env) << " spec BuiltIn " - << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin) << " variable needs to be a 32-bit int. " << message; })) { return error; @@ -3053,11 +3024,12 @@ spv_result_t BuiltInsValidator::ValidateI32InputAtDefinition( const SpvStorageClass storage_class = GetStorageClass(inst); if (storage_class != SpvStorageClassMax && storage_class != SpvStorageClassInput) { + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass); return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env) << " spec allows BuiltIn " - << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin) << " to be only used for variables with Input storage class. " << GetReferenceDesc(decoration, inst, inst, inst) << " " << GetStorageClassDesc(inst); @@ -3070,23 +3042,23 @@ spv_result_t BuiltInsValidator::ValidateI32InputAtDefinition( spv_result_t BuiltInsValidator::ValidateI32Vec4InputAtDefinition( const Decoration& decoration, const Instruction& inst) { if (spvIsVulkanEnv(_.context()->target_env)) { + const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]); if (decoration.struct_member_index() != Decoration::kInvalidMember) { return _.diag(SPV_ERROR_INVALID_DATA, &inst) << "BuiltIn " - << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin) << " cannot be used as a member decoration "; } if (spv_result_t error = ValidateI32Vec( decoration, inst, 4, - [this, &decoration, - &inst](const std::string& message) -> spv_result_t { + [this, &inst, builtin](const std::string& message) -> spv_result_t { + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType); return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(vuid) << "According to the " << spvLogStringForEnv(_.context()->target_env) << " spec BuiltIn " - << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin) << " variable needs to be a 4-component 32-bit int " "vector. " << message; @@ -3097,11 +3069,12 @@ spv_result_t BuiltInsValidator::ValidateI32Vec4InputAtDefinition( const SpvStorageClass storage_class = GetStorageClass(inst); if (storage_class != SpvStorageClassMax && storage_class != SpvStorageClassInput) { + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass); return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env) << " spec allows BuiltIn " - << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin) << " to be only used for variables with Input storage class. " << GetReferenceDesc(decoration, inst, inst, inst) << " " << GetStorageClassDesc(inst); @@ -3628,7 +3601,7 @@ spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtDefinition( decoration, inst, [this, &inst, builtin](const std::string& message) -> spv_result_t { - uint32_t vuid = GetVUIDForRTBuiltin(builtin, VUIDErrorType); + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType); return _.diag(SPV_ERROR_INVALID_DATA, &inst) << _.VkErrorID(vuid) << "According to the Vulkan spec BuiltIn " @@ -3650,7 +3623,7 @@ spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtDefinition( decoration, inst, [this, &inst, builtin](const std::string& message) -> spv_result_t { - uint32_t vuid = GetVUIDForRTBuiltin(builtin, VUIDErrorType); + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType); return _.diag(SPV_ERROR_INVALID_DATA, &inst) << _.VkErrorID(vuid) << "According to the Vulkan spec BuiltIn " @@ -3671,7 +3644,7 @@ spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtDefinition( decoration, inst, 3, [this, &inst, builtin](const std::string& message) -> spv_result_t { - uint32_t vuid = GetVUIDForRTBuiltin(builtin, VUIDErrorType); + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType); return _.diag(SPV_ERROR_INVALID_DATA, &inst) << _.VkErrorID(vuid) << "According to the Vulkan spec BuiltIn " @@ -3691,7 +3664,7 @@ spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtDefinition( decoration, inst, 3, [this, &inst, builtin](const std::string& message) -> spv_result_t { - uint32_t vuid = GetVUIDForRTBuiltin(builtin, VUIDErrorType); + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType); return _.diag(SPV_ERROR_INVALID_DATA, &inst) << _.VkErrorID(vuid) << "According to the Vulkan spec BuiltIn " @@ -3711,7 +3684,7 @@ spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtDefinition( decoration, inst, 3, 4, [this, &inst, builtin](const std::string& message) -> spv_result_t { - uint32_t vuid = GetVUIDForRTBuiltin(builtin, VUIDErrorType); + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType); return _.diag(SPV_ERROR_INVALID_DATA, &inst) << _.VkErrorID(vuid) << "According to the Vulkan spec BuiltIn " @@ -3744,7 +3717,7 @@ spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtReference( const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); if (storage_class != SpvStorageClassMax && storage_class != SpvStorageClassInput) { - uint32_t vuid = GetVUIDForRTBuiltin(builtin, VUIDErrorStorageClass); + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass); return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) << _.VkErrorID(vuid) << "Vulkan spec allows BuiltIn " << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, @@ -3757,7 +3730,7 @@ spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtReference( for (const SpvExecutionModel execution_model : execution_models_) { if (!IsExecutionModelValidForRtBuiltIn(builtin, execution_model)) { - uint32_t vuid = GetVUIDForRTBuiltin(builtin, VUIDErrorExecutionModel); + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel); return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) << _.VkErrorID(vuid) << "Vulkan spec does not allow BuiltIn " << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index 1d67345b..d59f3883 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -1445,6 +1445,12 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-LocalInvocationId-LocalInvocationId-04282); case 4283: return VUID_WRAP(VUID-LocalInvocationId-LocalInvocationId-04283); + case 4293: + return VUID_WRAP(VUID-NumSubgroups-NumSubgroups-04293); + case 4294: + return VUID_WRAP(VUID-NumSubgroups-NumSubgroups-04294); + case 4295: + return VUID_WRAP(VUID-NumSubgroups-NumSubgroups-04295); case 4296: return VUID_WRAP(VUID-NumWorkgroups-NumWorkgroups-04296); case 4297: @@ -1539,6 +1545,40 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-SamplePosition-SamplePosition-04361); case 4362: return VUID_WRAP(VUID-SamplePosition-SamplePosition-04362); + case 4367: + return VUID_WRAP(VUID-SubgroupId-SubgroupId-04367); + case 4368: + return VUID_WRAP(VUID-SubgroupId-SubgroupId-04368); + case 4369: + return VUID_WRAP(VUID-SubgroupId-SubgroupId-04369); + case 4370: + return VUID_WRAP(VUID-SubgroupEqMask-SubgroupEqMask-04370); + case 4371: + return VUID_WRAP(VUID-SubgroupEqMask-SubgroupEqMask-04371); + case 4372: + return VUID_WRAP(VUID-SubgroupGeMask-SubgroupGeMask-04372); + case 4373: + return VUID_WRAP(VUID-SubgroupGeMask-SubgroupGeMask-04373); + case 4374: + return VUID_WRAP(VUID-SubgroupGtMask-SubgroupGtMask-04374); + case 4375: + return VUID_WRAP(VUID-SubgroupGtMask-SubgroupGtMask-04375); + case 4376: + return VUID_WRAP(VUID-SubgroupLeMask-SubgroupLeMask-04376); + case 4377: + return VUID_WRAP(VUID-SubgroupLeMask-SubgroupLeMask-04377); + case 4378: + return VUID_WRAP(VUID-SubgroupLtMask-SubgroupLtMask-04378); + case 4379: + return VUID_WRAP(VUID-SubgroupLtMask-SubgroupLtMask-04379); + case 4380: + return VUID_WRAP(VUID-SubgroupLocalInvocationId-SubgroupLocalInvocationId-04380); + case 4381: + return VUID_WRAP(VUID-SubgroupLocalInvocationId-SubgroupLocalInvocationId-04381); + case 4382: + return VUID_WRAP(VUID-SubgroupSize-SubgroupSize-04382); + case 4383: + return VUID_WRAP(VUID-SubgroupSize-SubgroupSize-04383); case 4387: return VUID_WRAP(VUID-TessCoord-TessCoord-04387); case 4388: diff --git a/test/val/val_builtins_test.cpp b/test/val/val_builtins_test.cpp index cce3cd54..eac38344 100644 --- a/test/val/val_builtins_test.cpp +++ b/test/val/val_builtins_test.cpp @@ -54,8 +54,9 @@ using ::testing::Values; using ::testing::ValuesIn; using ValidateBuiltIns = spvtest::ValidateBase; -using ValidateVulkanSubgroupBuiltIns = spvtest::ValidateBase< - std::tuple>; +using ValidateVulkanSubgroupBuiltIns = + spvtest::ValidateBase>; using ValidateVulkanCombineBuiltInExecutionModelDataTypeResult = spvtest::ValidateBase>; @@ -4082,7 +4083,8 @@ TEST_P(ValidateVulkanSubgroupBuiltIns, InMain) { const char* const execution_model = std::get<1>(GetParam()); const char* const storage_class = std::get<2>(GetParam()); const char* const data_type = std::get<3>(GetParam()); - const TestResult& test_result = std::get<4>(GetParam()); + const char* const vuid = std::get<4>(GetParam()); + const TestResult& test_result = std::get<5>(GetParam()); CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator(); generator.capabilities_ += R"( @@ -4142,6 +4144,9 @@ OpCapability GroupNonUniformBallot if (test_result.error_str2) { EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str2)); } + if (vuid) { + EXPECT_THAT(getDiagnosticString(), AnyVUID(vuid)); + } } INSTANTIATE_TEST_SUITE_P( @@ -4149,6 +4154,11 @@ INSTANTIATE_TEST_SUITE_P( Combine(Values("SubgroupEqMask", "SubgroupGeMask", "SubgroupGtMask", "SubgroupLeMask", "SubgroupLtMask"), Values("GLCompute"), Values("Input"), Values("%u32vec3"), + Values("VUID-SubgroupEqMask-SubgroupEqMask-04371 " + "VUID-SubgroupGeMask-SubgroupGeMask-04373 " + "VUID-SubgroupGtMask-SubgroupGtMask-04375 " + "VUID-SubgroupLeMask-SubgroupLeMask-04377 " + "VUID-SubgroupLtMask-SubgroupLtMask-04379"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 4-component 32-bit int vector")))); @@ -4157,6 +4167,11 @@ INSTANTIATE_TEST_SUITE_P( Combine(Values("SubgroupEqMask", "SubgroupGeMask", "SubgroupGtMask", "SubgroupLeMask", "SubgroupLtMask"), Values("GLCompute"), Values("Input"), Values("%f32vec4"), + Values("VUID-SubgroupEqMask-SubgroupEqMask-04371 " + "VUID-SubgroupGeMask-SubgroupGeMask-04373 " + "VUID-SubgroupGtMask-SubgroupGtMask-04375 " + "VUID-SubgroupLeMask-SubgroupLeMask-04377 " + "VUID-SubgroupLtMask-SubgroupLtMask-04379"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 4-component 32-bit int vector")))); @@ -4166,6 +4181,11 @@ INSTANTIATE_TEST_SUITE_P( "SubgroupLeMask", "SubgroupLtMask"), Values("GLCompute"), Values("Output", "Workgroup", "Private"), Values("%u32vec4"), + Values("VUID-SubgroupEqMask-SubgroupEqMask-04370 " + "VUID-SubgroupGeMask-SubgroupGeMask-04372 " + "VUID-SubgroupGtMask-SubgroupGtMask-04374 " + "VUID-SubgroupLeMask-SubgroupLeMask-04376 " + "VUID-SubgroupLtMask-SubgroupLtMask-04378"), Values(TestResult( SPV_ERROR_INVALID_DATA, "to be only used for variables with Input storage class")))); @@ -4175,7 +4195,7 @@ INSTANTIATE_TEST_SUITE_P(SubgroupMaskOk, ValidateVulkanSubgroupBuiltIns, "SubgroupGtMask", "SubgroupLeMask", "SubgroupLtMask"), Values("GLCompute"), Values("Input"), - Values("%u32vec4"), + Values("%u32vec4"), Values(nullptr), Values(TestResult(SPV_SUCCESS, "")))); TEST_F(ValidateBuiltIns, SubgroupMaskMemberDecorate) { @@ -4208,6 +4228,8 @@ INSTANTIATE_TEST_SUITE_P( SubgroupInvocationIdAndSizeNotU32, ValidateVulkanSubgroupBuiltIns, Combine(Values("SubgroupLocalInvocationId", "SubgroupSize"), Values("GLCompute"), Values("Input"), Values("%f32"), + Values("VUID-SubgroupLocalInvocationId-SubgroupLocalInvocationId-" + "04381 VUID-SubgroupSize-SubgroupSize-04383"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 32-bit int")))); @@ -4216,6 +4238,8 @@ INSTANTIATE_TEST_SUITE_P( Combine(Values("SubgroupLocalInvocationId", "SubgroupSize"), Values("GLCompute"), Values("Output", "Workgroup", "Private"), Values("%u32"), + Values("VUID-SubgroupLocalInvocationId-SubgroupLocalInvocationId-" + "04380 VUID-SubgroupSize-SubgroupSize-04382"), Values(TestResult( SPV_ERROR_INVALID_DATA, "to be only used for variables with Input storage class")))); @@ -4224,7 +4248,7 @@ INSTANTIATE_TEST_SUITE_P( SubgroupInvocationIdAndSizeOk, ValidateVulkanSubgroupBuiltIns, Combine(Values("SubgroupLocalInvocationId", "SubgroupSize"), Values("GLCompute"), Values("Input"), Values("%u32"), - Values(TestResult(SPV_SUCCESS, "")))); + Values(nullptr), Values(TestResult(SPV_SUCCESS, "")))); TEST_F(ValidateBuiltIns, SubgroupSizeMemberDecorate) { const std::string text = R"( @@ -4251,10 +4275,22 @@ OpFunctionEnd HasSubstr("BuiltIn SubgroupSize cannot be used as a member decoration")); } +INSTANTIATE_TEST_SUITE_P( + SubgroupNumAndIdNotCompute, ValidateVulkanSubgroupBuiltIns, + Combine( + Values("SubgroupId", "NumSubgroups"), Values("Vertex"), Values("Input"), + Values("%u32"), + Values("VUID-SubgroupId-SubgroupId-04367 " + "VUID-NumSubgroups-NumSubgroups-04293"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "to be used only with GLCompute execution model")))); + INSTANTIATE_TEST_SUITE_P( SubgroupNumAndIdNotU32, ValidateVulkanSubgroupBuiltIns, Combine(Values("SubgroupId", "NumSubgroups"), Values("GLCompute"), Values("Input"), Values("%f32"), + Values("VUID-SubgroupId-SubgroupId-04369 " + "VUID-NumSubgroups-NumSubgroups-04295"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 32-bit int")))); @@ -4262,6 +4298,8 @@ INSTANTIATE_TEST_SUITE_P( SubgroupNumAndIdNotInput, ValidateVulkanSubgroupBuiltIns, Combine(Values("SubgroupId", "NumSubgroups"), Values("GLCompute"), Values("Output", "Workgroup", "Private"), Values("%u32"), + Values("VUID-SubgroupId-SubgroupId-04368 " + "VUID-NumSubgroups-NumSubgroups-04294"), Values(TestResult( SPV_ERROR_INVALID_DATA, "to be only used for variables with Input storage class")))); @@ -4269,7 +4307,7 @@ INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P(SubgroupNumAndIdOk, ValidateVulkanSubgroupBuiltIns, Combine(Values("SubgroupId", "NumSubgroups"), Values("GLCompute"), Values("Input"), - Values("%u32"), + Values("%u32"), Values(nullptr), Values(TestResult(SPV_SUCCESS, "")))); TEST_F(ValidateBuiltIns, SubgroupIdMemberDecorate) { -- cgit v1.2.3 From 17ffa89097b26efeb323e6963220326b5ffb2baf Mon Sep 17 00:00:00 2001 From: sfricke-samsung <46493288+sfricke-samsung@users.noreply.github.com> Date: Thu, 17 Dec 2020 10:51:17 -0800 Subject: spirv-val: Add first StandAlone VUID 04633 (#4077) --- source/val/validate_mode_setting.cpp | 6 ++-- source/val/validation_state.cpp | 2 ++ test/val/val_builtins_test.cpp | 38 ------------------------ test/val/val_fixtures.h | 39 ++++++++++++++++++++++++ test/val/val_id_test.cpp | 57 ++++++++++++++++++++++++++++++------ 5 files changed, 93 insertions(+), 49 deletions(-) diff --git a/source/val/validate_mode_setting.cpp b/source/val/validate_mode_setting.cpp index a7f8d339..1db1d4c4 100644 --- a/source/val/validate_mode_setting.cpp +++ b/source/val/validate_mode_setting.cpp @@ -42,7 +42,8 @@ spv_result_t ValidateEntryPoint(ValidationState_t& _, const Instruction* inst) { const auto entry_point_type = _.FindDef(entry_point_type_id); if (!entry_point_type || 3 != entry_point_type->words().size()) { return _.diag(SPV_ERROR_INVALID_ID, inst) - << "OpEntryPoint Entry Point '" << _.getIdName(entry_point_id) + << _.VkErrorID(4633) << "OpEntryPoint Entry Point '" + << _.getIdName(entry_point_id) << "'s function parameter count is not zero."; } } @@ -50,7 +51,8 @@ spv_result_t ValidateEntryPoint(ValidationState_t& _, const Instruction* inst) { auto return_type = _.FindDef(entry_point->type_id()); if (!return_type || SpvOpTypeVoid != return_type->opcode()) { return _.diag(SPV_ERROR_INVALID_ID, inst) - << "OpEntryPoint Entry Point '" << _.getIdName(entry_point_id) + << _.VkErrorID(4633) << "OpEntryPoint Entry Point '" + << _.getIdName(entry_point_id) << "'s function return type is not void."; } diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index d59f3883..539fbb97 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -1665,6 +1665,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-ShadingRateKHR-ShadingRateKHR-04491); case 4492: return VUID_WRAP(VUID-ShadingRateKHR-ShadingRateKHR-04492); + case 4633: + return VUID_WRAP(VUID-StandaloneSpirv-None-04633); default: return ""; // unknown id }; diff --git a/test/val/val_builtins_test.cpp b/test/val/val_builtins_test.cpp index eac38344..7d12aaca 100644 --- a/test/val/val_builtins_test.cpp +++ b/test/val/val_builtins_test.cpp @@ -159,44 +159,6 @@ CodeGenerator GetInMainCodeGenerator(spv_target_env env, return generator; } -// Allows test parameter test to list all possible VUIDs with a delimiter that -// is then split here to check if one VUID was in the error message -MATCHER_P(AnyVUID, vuid_set, "VUID from the set is in error message") { - // use space as delimiter because clang-format will properly line break VUID - // strings which is important the entire VUID is in a single line for script - // to scan - std::string delimiter = " "; - std::string token; - std::string vuids = std::string(vuid_set); - size_t position; - - // Catch case were someone accidentally left spaces by trimming string - // clang-format off - vuids.erase(std::find_if(vuids.rbegin(), vuids.rend(), [](unsigned char c) { - return (c != ' '); - }).base(), vuids.end()); - vuids.erase(vuids.begin(), std::find_if(vuids.begin(), vuids.end(), [](unsigned char c) { - return (c != ' '); - })); - // clang-format on - - do { - position = vuids.find(delimiter); - if (position != std::string::npos) { - token = vuids.substr(0, position); - vuids.erase(0, position + delimiter.length()); - } else { - token = vuids.substr(0); // last item - } - - // arg contains diagnostic message - if (arg.find(token) != std::string::npos) { - return true; - } - } while (position != std::string::npos); - return false; -} - TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, InMain) { const char* const built_in = std::get<0>(GetParam()); const char* const execution_model = std::get<1>(GetParam()); diff --git a/test/val/val_fixtures.h b/test/val/val_fixtures.h index 5635c781..acbe0e57 100644 --- a/test/val/val_fixtures.h +++ b/test/val/val_fixtures.h @@ -183,4 +183,43 @@ spv_position_t ValidateBase::getErrorPosition() { } // namespace spvtest +// For Vulkan testing. +// Allows test parameter test to list all possible VUIDs with a delimiter that +// is then split here to check if one VUID was in the error message +MATCHER_P(AnyVUID, vuid_set, "VUID from the set is in error message") { + // use space as delimiter because clang-format will properly line break VUID + // strings which is important the entire VUID is in a single line for script + // to scan + std::string delimiter = " "; + std::string token; + std::string vuids = std::string(vuid_set); + size_t position; + + // Catch case were someone accidentally left spaces by trimming string + // clang-format off + vuids.erase(std::find_if(vuids.rbegin(), vuids.rend(), [](unsigned char c) { + return (c != ' '); + }).base(), vuids.end()); + vuids.erase(vuids.begin(), std::find_if(vuids.begin(), vuids.end(), [](unsigned char c) { + return (c != ' '); + })); + // clang-format on + + do { + position = vuids.find(delimiter); + if (position != std::string::npos) { + token = vuids.substr(0, position); + vuids.erase(0, position + delimiter.length()); + } else { + token = vuids.substr(0); // last item + } + + // arg contains diagnostic message + if (arg.find(token) != std::string::npos) { + return true; + } + } while (position != std::string::npos); + return false; +} + #endif // TEST_VAL_VAL_FIXTURES_H_ diff --git a/test/val/val_id_test.cpp b/test/val/val_id_test.cpp index 069e8f20..ad8ebfc6 100644 --- a/test/val/val_id_test.cpp +++ b/test/val/val_id_test.cpp @@ -411,10 +411,10 @@ TEST_F(ValidateIdWithMessage, OpEntryPointFunctionBad) { } TEST_F(ValidateIdWithMessage, OpEntryPointParameterCountBad) { std::string spirv = kGLSL450MemoryModel + R"( - OpEntryPoint GLCompute %3 "" -%1 = OpTypeVoid -%2 = OpTypeFunction %1 %1 -%3 = OpFunction %1 None %2 + OpEntryPoint GLCompute %1 "" +%2 = OpTypeVoid +%3 = OpTypeFunction %2 %2 +%1 = OpFunction %2 None %3 %4 = OpLabel OpReturn OpFunctionEnd)"; @@ -426,11 +426,11 @@ TEST_F(ValidateIdWithMessage, OpEntryPointParameterCountBad) { } TEST_F(ValidateIdWithMessage, OpEntryPointReturnTypeBad) { std::string spirv = kGLSL450MemoryModel + R"( - OpEntryPoint GLCompute %3 "" -%1 = OpTypeInt 32 0 -%ret = OpConstant %1 0 -%2 = OpTypeFunction %1 -%3 = OpFunction %1 None %2 + OpEntryPoint GLCompute %1 "" +%2 = OpTypeInt 32 0 +%ret = OpConstant %2 0 +%3 = OpTypeFunction %2 +%1 = OpFunction %2 None %3 %4 = OpLabel OpReturnValue %ret OpFunctionEnd)"; @@ -440,6 +440,45 @@ TEST_F(ValidateIdWithMessage, OpEntryPointReturnTypeBad) { HasSubstr("OpEntryPoint Entry Point '1[%1]'s function " "return type is not void.")); } +TEST_F(ValidateIdWithMessage, OpEntryPointParameterCountBadInVulkan) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "" +%2 = OpTypeVoid +%3 = OpTypeFunction %2 %2 +%1 = OpFunction %2 None %3 +%4 = OpLabel + OpReturn + OpFunctionEnd)"; + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-None-04633")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpEntryPoint Entry Point '1[%1]'s function " + "parameter count is not zero")); +} +TEST_F(ValidateIdWithMessage, OpEntryPointReturnTypeBadInVulkan) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "" +%2 = OpTypeInt 32 0 +%ret = OpConstant %2 0 +%3 = OpTypeFunction %2 +%1 = OpFunction %2 None %3 +%4 = OpLabel + OpReturnValue %ret + OpFunctionEnd)"; + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-None-04633")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpEntryPoint Entry Point '1[%1]'s function " + "return type is not void.")); +} TEST_F(ValidateIdWithMessage, OpEntryPointInterfaceIsNotVariableTypeBad) { std::string spirv = R"( -- cgit v1.2.3 From 1bb80d2778a3d0362365b2490e2174bd56453036 Mon Sep 17 00:00:00 2001 From: sfricke-samsung <46493288+sfricke-samsung@users.noreply.github.com> Date: Tue, 5 Jan 2021 06:51:07 -0800 Subject: spirv-val: Add Vulkan Group Operation VUID (#4086) --- source/val/validate_non_uniform.cpp | 13 +++++++++++++ source/val/validation_state.cpp | 2 ++ test/val/val_non_uniform_test.cpp | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/source/val/validate_non_uniform.cpp b/source/val/validate_non_uniform.cpp index 8dcf9743..2b6eb8b5 100644 --- a/source/val/validate_non_uniform.cpp +++ b/source/val/validate_non_uniform.cpp @@ -47,6 +47,19 @@ spv_result_t ValidateGroupNonUniformBallotBitCount(ValidationState_t& _, "vector of four components " "of integer type scalar"; } + + const auto group = inst->GetOperandAs(3); + if (spvIsVulkanEnv(_.context()->target_env)) { + if ((group != SpvGroupOperationReduce) && + (group != SpvGroupOperationInclusiveScan) && + (group != SpvGroupOperationExclusiveScan)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << _.VkErrorID(4685) + << "In Vulkan: The OpGroupNonUniformBallotBitCount group " + "operation must be only: Reduce, InclusiveScan, or " + "ExclusiveScan."; + } + } return SPV_SUCCESS; } diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index 539fbb97..f458d4f9 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -1667,6 +1667,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-ShadingRateKHR-ShadingRateKHR-04492); case 4633: return VUID_WRAP(VUID-StandaloneSpirv-None-04633); + case 4685: + return VUID_WRAP(VUID-StandaloneSpirv-OpGroupNonUniformBallotBitCount-04685); default: return ""; // unknown id }; diff --git a/test/val/val_non_uniform_test.cpp b/test/val/val_non_uniform_test.cpp index fbd11a9e..352c3496 100644 --- a/test/val/val_non_uniform_test.cpp +++ b/test/val/val_non_uniform_test.cpp @@ -100,6 +100,7 @@ OpFunctionEnd)"; SpvScope scopes[] = {SpvScopeCrossDevice, SpvScopeDevice, SpvScopeWorkgroup, SpvScopeSubgroup, SpvScopeInvocation}; +using ValidateGroupNonUniform = spvtest::ValidateBase; using GroupNonUniform = spvtest::ValidateBase< std::tuple>; @@ -288,6 +289,41 @@ INSTANTIATE_TEST_SUITE_P(GroupNonUniformBallotBitCountBadValue, GroupNonUniform, Values("Expected Value to be a vector of four " "components of integer type scalar"))); +TEST_F(ValidateGroupNonUniform, VulkanGroupNonUniformBallotBitCountOperation) { + std::string test = R"( +OpCapability Shader +OpCapability GroupNonUniform +OpCapability GroupNonUniformBallot +OpCapability GroupNonUniformClustered +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +%void = OpTypeVoid +%func = OpTypeFunction %void +%u32 = OpTypeInt 32 0 +%u32vec4 = OpTypeVector %u32 4 +%u32_0 = OpConstant %u32 0 +%u32vec4_null = OpConstantComposite %u32vec4 %u32_0 %u32_0 %u32_0 %u32_0 +%subgroup = OpConstant %u32 3 +%main = OpFunction %void None %func +%main_entry = OpLabel +%result = OpGroupNonUniformBallotBitCount %u32 %subgroup ClusteredReduce %u32vec4_null +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(test, SPV_ENV_VULKAN_1_1); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpGroupNonUniformBallotBitCount-04685")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "In Vulkan: The OpGroupNonUniformBallotBitCount group operation must " + "be only: Reduce, InclusiveScan, or ExclusiveScan.")); +} + } // namespace } // namespace val } // namespace spvtools -- cgit v1.2.3 From d630e5f8c10c2370ec1671d45a20bc877384ba40 Mon Sep 17 00:00:00 2001 From: sfricke-samsung <46493288+sfricke-samsung@users.noreply.github.com> Date: Wed, 6 Jan 2021 05:51:15 -0800 Subject: spirv-val: Add Vulkan ImageTexelPointer format check (#4087) --- source/val/validate_image.cpp | 14 ++++ source/val/validation_state.cpp | 2 + test/val/val_image_test.cpp | 137 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 152 insertions(+), 1 deletion(-) diff --git a/source/val/validate_image.cpp b/source/val/validate_image.cpp index 561a5a10..e8f65cff 100644 --- a/source/val/validate_image.cpp +++ b/source/val/validate_image.cpp @@ -1095,6 +1095,20 @@ spv_result_t ValidateImageTexelPointer(ValidationState_t& _, "the value 0"; } } + + if (spvIsVulkanEnv(_.context()->target_env)) { + if ((info.format != SpvImageFormatR64i) && + (info.format != SpvImageFormatR64ui) && + (info.format != SpvImageFormatR32f) && + (info.format != SpvImageFormatR32i) && + (info.format != SpvImageFormatR32ui)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << _.VkErrorID(4658) + << "Expected the Image Format in Image to be R64i, R64ui, R32f, " + "R32i, or R32ui for Vulkan environment"; + } + } + return SPV_SUCCESS; } diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index f458d4f9..e168c019 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -1667,6 +1667,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-ShadingRateKHR-ShadingRateKHR-04492); case 4633: return VUID_WRAP(VUID-StandaloneSpirv-None-04633); + case 4658: + return VUID_WRAP(VUID-StandaloneSpirv-OpImageTexelPointer-04658); case 4685: return VUID_WRAP(VUID-StandaloneSpirv-OpGroupNonUniformBallotBitCount-04685); default: diff --git a/test/val/val_image_test.cpp b/test/val/val_image_test.cpp index 4b2c68fb..76663482 100644 --- a/test/val/val_image_test.cpp +++ b/test/val/val_image_test.cpp @@ -133,6 +133,7 @@ OpDecorate %uniform_sampler Binding 0 %u32 = OpTypeInt 32 0 %s32 = OpTypeInt 32 1 %u64 = OpTypeInt 64 0 +%s64 = OpTypeInt 64 1 %s32vec2 = OpTypeVector %s32 2 %u32vec2 = OpTypeVector %u32 2 %f32vec2 = OpTypeVector %f32 2 @@ -928,7 +929,7 @@ TEST_F(ValidateImage, ImageTexelPointerImageNotResultTypePointer) { CompileSuccessfully(GenerateShaderCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand 141[%141] cannot be a " + EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand 142[%142] cannot be a " "type")); } @@ -5434,6 +5435,12 @@ static const std::string declarations_image64 = R"( %ptr_image_u64_buffer_0002_r64ui = OpTypePointer Private %type_image_u64_buffer_0002_r64ui %private_image_u64_buffer_0002_r64ui = OpVariable %ptr_image_u64_buffer_0002_r64ui Private )"; +static const std::string declarations_image64i = R"( +%type_image_s64_buffer_0002_r64i = OpTypeImage %s64 Buffer 0 0 0 2 R64i +%ptr_Image_s64 = OpTypePointer Image %s64 +%ptr_image_s64_buffer_0002_r64i = OpTypePointer Private %type_image_s64_buffer_0002_r64i +%private_image_s64_buffer_0002_r64i = OpVariable %ptr_image_s64_buffer_0002_r64i Private +)"; TEST_F(ValidateImage, Image64MissingCapability) { CompileSuccessfully(GenerateShaderCode("", "", "Fragment", "", @@ -5519,6 +5526,134 @@ TEST_F(ValidateImage, ImageTexelPointer64SampleNotZeroForImageWithMSZero) { " for the value 0")); } +TEST_F(ValidateImage, ImageTexelPointerR32uiSuccessVulkan) { + const std::string body = R"( +%texel_ptr = OpImageTexelPointer %ptr_Image_u32 %private_image_u32_buffer_0002_r32ui %u32_0 %u32_0 +)"; + + spv_target_env env = SPV_ENV_VULKAN_1_0; + CompileSuccessfully(GenerateShaderCode(body, "", "Fragment", "", env).c_str(), + env); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(env)); +} + +TEST_F(ValidateImage, ImageTexelPointerR32iSuccessVulkan) { + const std::string& declarations = R"( +%type_image_s32_buffer_0002_r32i = OpTypeImage %s32 Buffer 0 0 0 2 R32i +%ptr_Image_s32 = OpTypePointer Image %s32 +%ptr_image_s32_buffer_0002_r32i = OpTypePointer Private %type_image_s32_buffer_0002_r32i +%private_image_s32_buffer_0002_r32i = OpVariable %ptr_image_s32_buffer_0002_r32i Private +)"; + + const std::string body = R"( +%texel_ptr = OpImageTexelPointer %ptr_Image_s32 %private_image_s32_buffer_0002_r32i %u32_0 %u32_0 +)"; + + spv_target_env env = SPV_ENV_VULKAN_1_0; + CompileSuccessfully( + GenerateShaderCode(body, "", "Fragment", "", env, "GLSL450", declarations) + .c_str(), + env); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(env)); +} + +TEST_F(ValidateImage, ImageTexelPointerR64uiSuccessVulkan) { + const std::string body = R"( +%texel_ptr = OpImageTexelPointer %ptr_Image_u64 %private_image_u64_buffer_0002_r64ui %u32_0 %u32_0 +)"; + + spv_target_env env = SPV_ENV_VULKAN_1_0; + CompileSuccessfully( + GenerateShaderCode(body, capabilities_and_extensions_image64, "Fragment", + "", env, "GLSL450", declarations_image64) + .c_str(), + env); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(env)); +} + +TEST_F(ValidateImage, ImageTexelPointerR64iSuccessVulkan) { + const std::string body = R"( +%texel_ptr = OpImageTexelPointer %ptr_Image_s64 %private_image_s64_buffer_0002_r64i %u32_0 %u32_0 +)"; + + spv_target_env env = SPV_ENV_VULKAN_1_0; + CompileSuccessfully( + GenerateShaderCode(body, capabilities_and_extensions_image64, "Fragment", + "", env, "GLSL450", declarations_image64i) + .c_str(), + env); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(env)); +} + +TEST_F(ValidateImage, ImageTexelPointerR32fSuccessVulkan) { + const std::string& declarations = R"( +%type_image_f32_buffer_0002_r32f = OpTypeImage %f32 Buffer 0 0 0 2 R32f +%ptr_image_f32_buffer_0002_r32f = OpTypePointer Private %type_image_f32_buffer_0002_r32f +%private_image_f32_buffer_0002_r32f = OpVariable %ptr_image_f32_buffer_0002_r32f Private +)"; + + const std::string body = R"( +%texel_ptr = OpImageTexelPointer %ptr_Image_f32 %private_image_f32_buffer_0002_r32f %u32_0 %u32_0 +)"; + + spv_target_env env = SPV_ENV_VULKAN_1_0; + CompileSuccessfully( + GenerateShaderCode(body, "", "Fragment", "", env, "GLSL450", declarations) + .c_str(), + env); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(env)); +} + +TEST_F(ValidateImage, ImageTexelPointerRgba32iVulkan) { + const std::string& declarations = R"( +%type_image_s32_buffer_0002_rgba32i = OpTypeImage %s32 Buffer 0 0 0 2 Rgba32i +%ptr_Image_s32 = OpTypePointer Image %s32 +%ptr_image_s32_buffer_0002_rgba32i = OpTypePointer Private %type_image_s32_buffer_0002_rgba32i +%private_image_s32_buffer_0002_rgba32i = OpVariable %ptr_image_s32_buffer_0002_rgba32i Private +)"; + + const std::string body = R"( +%texel_ptr = OpImageTexelPointer %ptr_Image_s32 %private_image_s32_buffer_0002_rgba32i %u32_0 %u32_0 +)"; + + spv_target_env env = SPV_ENV_VULKAN_1_0; + CompileSuccessfully( + GenerateShaderCode(body, "", "Fragment", "", env, "GLSL450", declarations) + .c_str(), + env); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(env)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpImageTexelPointer-04658")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Expected the Image Format in Image to be R64i, R64ui, " + "R32f, R32i, or R32ui for Vulkan environment")); +} + +TEST_F(ValidateImage, ImageTexelPointerRgba16fVulkan) { + const std::string& declarations = R"( +%type_image_s32_buffer_0002_rgba16f = OpTypeImage %s32 Buffer 0 0 0 2 Rgba16f +%ptr_Image_s32 = OpTypePointer Image %s32 +%ptr_image_s32_buffer_0002_rgba16f = OpTypePointer Private %type_image_s32_buffer_0002_rgba16f +%private_image_s32_buffer_0002_rgba16f = OpVariable %ptr_image_s32_buffer_0002_rgba16f Private +)"; + + const std::string body = R"( +%texel_ptr = OpImageTexelPointer %ptr_Image_s32 %private_image_s32_buffer_0002_rgba16f %u32_0 %u32_0 +)"; + + spv_target_env env = SPV_ENV_VULKAN_1_0; + CompileSuccessfully( + GenerateShaderCode(body, "", "Fragment", "", env, "GLSL450", declarations) + .c_str(), + env); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(env)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpImageTexelPointer-04658")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Expected the Image Format in Image to be R64i, R64ui, " + "R32f, R32i, or R32ui for Vulkan environment")); +} + } // namespace } // namespace val } // namespace spvtools -- cgit v1.2.3 From 37c03859de9e13a6d4374fc9be9c90d2e22e3747 Mon Sep 17 00:00:00 2001 From: sfricke-samsung <46493288+sfricke-samsung@users.noreply.github.com> Date: Wed, 6 Jan 2021 08:26:58 -0800 Subject: spirv-val: Add Vulkan ForwardPointer VUID (#4089) --- source/val/validate_type.cpp | 13 +++++++++++-- source/val/validation_state.cpp | 2 ++ test/val/val_data_test.cpp | 20 ++++++++++++++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/source/val/validate_type.cpp b/source/val/validate_type.cpp index 5924c69f..8352301b 100644 --- a/source/val/validate_type.cpp +++ b/source/val/validate_type.cpp @@ -555,8 +555,8 @@ spv_result_t ValidateTypeForwardPointer(ValidationState_t& _, << "Pointer type in OpTypeForwardPointer is not a pointer type."; } - if (inst->GetOperandAs(1) != - pointer_type_inst->GetOperandAs(1)) { + const auto storage_class = inst->GetOperandAs(1); + if (storage_class != pointer_type_inst->GetOperandAs(1)) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "Storage class in OpTypeForwardPointer does not match the " << "pointer definition."; @@ -569,6 +569,15 @@ spv_result_t ValidateTypeForwardPointer(ValidationState_t& _, << "Forward pointers must point to a structure"; } + if (spvIsVulkanEnv(_.context()->target_env)) { + if (storage_class != SpvStorageClassPhysicalStorageBuffer) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << _.VkErrorID(4711) + << "In Vulkan, OpTypeForwardPointer must have " + << "a storage class of PhysicalStorageBuffer."; + } + } + return SPV_SUCCESS; } diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index e168c019..0fe90828 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -1671,6 +1671,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-OpImageTexelPointer-04658); case 4685: return VUID_WRAP(VUID-StandaloneSpirv-OpGroupNonUniformBallotBitCount-04685); + case 4711: + return VUID_WRAP(VUID-StandaloneSpirv-OpTypeForwardPointer-04711); default: return ""; // unknown id }; diff --git a/test/val/val_data_test.cpp b/test/val/val_data_test.cpp index 1080a59f..99a9aa09 100644 --- a/test/val/val_data_test.cpp +++ b/test/val/val_data_test.cpp @@ -960,6 +960,26 @@ OpTypeForwardPointer %1 PhysicalStorageBuffer ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5)); } +TEST_F(ValidateData, VulkanTypeForwardStorageClass) { + std::string test = R"( +OpCapability Shader +OpCapability PhysicalStorageBufferAddresses +OpMemoryModel Logical GLSL450 +OpTypeForwardPointer %1 Uniform +%2 = OpTypeStruct +%3 = OpTypeRuntimeArray %1 +%1 = OpTypePointer Uniform %2 +)"; + + CompileSuccessfully(test, SPV_ENV_VULKAN_1_2); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpTypeForwardPointer-04711")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("In Vulkan, OpTypeForwardPointer must have " + "a storage class of PhysicalStorageBuffer.")); +} + TEST_F(ValidateData, TypeForwardReferenceMustBeForwardPointer) { std::string test = R"( OpCapability Shader -- cgit v1.2.3 From 6d05ed8410b4acb575398a9c297f0e9741bd2bed Mon Sep 17 00:00:00 2001 From: sfricke-samsung <46493288+sfricke-samsung@users.noreply.github.com> Date: Wed, 6 Jan 2021 09:36:13 -0800 Subject: spirv-val: Fix Vulkan image sampled check (#4085) * Fix SampledType logic --- source/val/validate_image.cpp | 22 ++++-- source/val/validation_state.cpp | 2 + test/val/val_image_test.cpp | 160 +++++++++++++++++++++++++++++++++++++--- 3 files changed, 169 insertions(+), 15 deletions(-) diff --git a/source/val/validate_image.cpp b/source/val/validate_image.cpp index e8f65cff..2d293140 100644 --- a/source/val/validate_image.cpp +++ b/source/val/validate_image.cpp @@ -746,16 +746,26 @@ spv_result_t ValidateTypeImage(ValidationState_t& _, const Instruction* inst) { << "Corrupt image type definition"; } + if (_.IsIntScalarType(info.sampled_type) && + (64 == _.GetBitWidth(info.sampled_type)) && + !_.HasCapability(SpvCapabilityInt64ImageEXT)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Capability Int64ImageEXT is required when using Sampled Type of " + "64-bit int"; + } + const auto target_env = _.context()->target_env; if (spvIsVulkanEnv(target_env)) { if ((!_.IsFloatScalarType(info.sampled_type) && !_.IsIntScalarType(info.sampled_type)) || - (32 != _.GetBitWidth(info.sampled_type) && - (64 != _.GetBitWidth(info.sampled_type) || - !_.HasCapability(SpvCapabilityInt64ImageEXT)))) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Expected Sampled Type to be a 32-bit int or float " - "scalar type for Vulkan environment"; + ((32 != _.GetBitWidth(info.sampled_type)) && + (64 != _.GetBitWidth(info.sampled_type))) || + ((64 == _.GetBitWidth(info.sampled_type)) && + _.IsFloatScalarType(info.sampled_type))) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << _.VkErrorID(4656) + << "Expected Sampled Type to be a 32-bit int, 64-bit int or " + "32-bit float scalar type for Vulkan environment"; } } else if (spvIsOpenCLEnv(target_env)) { if (!_.IsVoidType(info.sampled_type)) { diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index 0fe90828..ae34185a 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -1667,6 +1667,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-ShadingRateKHR-ShadingRateKHR-04492); case 4633: return VUID_WRAP(VUID-StandaloneSpirv-None-04633); + case 4656: + return VUID_WRAP(VUID-StandaloneSpirv-OpTypeImage-04656); case 4658: return VUID_WRAP(VUID-StandaloneSpirv-OpImageTexelPointer-04658); case 4685: diff --git a/test/val/val_image_test.cpp b/test/val/val_image_test.cpp index 76663482..c5c92c4c 100644 --- a/test/val/val_image_test.cpp +++ b/test/val/val_image_test.cpp @@ -480,6 +480,7 @@ std::string GetShaderHeader(const std::string& capabilities_and_extensions = "", ss << R"( OpCapability Shader OpCapability Int64 +OpCapability Float64 )"; ss << capabilities_and_extensions; @@ -500,9 +501,11 @@ OpMemoryModel Logical GLSL450 %func = OpTypeFunction %void %bool = OpTypeBool %f32 = OpTypeFloat 32 +%f64 = OpTypeFloat 64 %u32 = OpTypeInt 32 0 %u64 = OpTypeInt 64 0 %s32 = OpTypeInt 32 1 +%s64 = OpTypeInt 64 1 )"; return ss.str(); @@ -524,8 +527,7 @@ TEST_F(ValidateImage, TypeImageWrongSampledType) { TEST_F(ValidateImage, TypeImageVoidSampledTypeVulkan) { const std::string code = GetShaderHeader() + R"( %img_type = OpTypeImage %void 2D 0 0 0 1 Unknown -%void_func = OpTypeFunction %void -%main = OpFunction %void None %void_func +%main = OpFunction %void None %func %main_lab = OpLabel OpReturn OpFunctionEnd @@ -535,15 +537,131 @@ OpFunctionEnd CompileSuccessfully(code, env); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(env)); EXPECT_THAT(getDiagnosticString(), - HasSubstr("Expected Sampled Type to be a 32-bit int " - "or float scalar type for Vulkan environment")); + AnyVUID("VUID-StandaloneSpirv-OpTypeImage-04656")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Expected Sampled Type to be a 32-bit int, 64-bit int " + "or 32-bit float scalar type for Vulkan environment")); } -TEST_F(ValidateImage, TypeImageU64SampledTypeVulkan) { +TEST_F(ValidateImage, TypeImageU32SampledTypeVulkan) { + const std::string code = GetShaderHeader() + R"( +%img_type = OpTypeImage %u32 2D 0 0 0 1 Unknown +%main = OpFunction %void None %func +%main_lab = OpLabel +OpReturn +OpFunctionEnd +)"; + + const spv_target_env env = SPV_ENV_VULKAN_1_0; + CompileSuccessfully(code, env); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(env)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateImage, TypeImageI32SampledTypeVulkan) { + const std::string code = GetShaderHeader() + R"( +%img_type = OpTypeImage %s32 2D 0 0 0 1 Unknown +%main = OpFunction %void None %func +%main_lab = OpLabel +OpReturn +OpFunctionEnd +)"; + + const spv_target_env env = SPV_ENV_VULKAN_1_0; + CompileSuccessfully(code, env); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(env)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateImage, TypeImageI64SampledTypeNoCapabilityVulkan) { + const std::string code = GetShaderHeader() + R"( +%img_type = OpTypeImage %s64 2D 0 0 0 1 Unknown +%main = OpFunction %void None %func +%main_lab = OpLabel +OpReturn +OpFunctionEnd +)"; + + const spv_target_env env = SPV_ENV_VULKAN_1_0; + CompileSuccessfully(code, env); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(env)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Capability Int64ImageEXT is required when using " + "Sampled Type of 64-bit int")); +} + +TEST_F(ValidateImage, TypeImageI64SampledTypeVulkan) { + const std::string code = GetShaderHeader( + "OpCapability Int64ImageEXT\nOpExtension " + "\"SPV_EXT_shader_image_int64\"\n") + + R"( +%img_type = OpTypeImage %s64 2D 0 0 0 1 Unknown +%main = OpFunction %void None %func +%main_lab = OpLabel +OpReturn +OpFunctionEnd +)"; + + const spv_target_env env = SPV_ENV_VULKAN_1_0; + CompileSuccessfully(code, env); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(env)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateImage, TypeImageU64SampledTypeNoCapabilityVulkan) { const std::string code = GetShaderHeader() + R"( %img_type = OpTypeImage %u64 2D 0 0 0 1 Unknown -%void_func = OpTypeFunction %void -%main = OpFunction %void None %void_func +%main = OpFunction %void None %func +%main_lab = OpLabel +OpReturn +OpFunctionEnd +)"; + + const spv_target_env env = SPV_ENV_VULKAN_1_0; + CompileSuccessfully(code, env); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(env)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Capability Int64ImageEXT is required when using " + "Sampled Type of 64-bit int")); +} + +TEST_F(ValidateImage, TypeImageU64SampledTypeVulkan) { + const std::string code = GetShaderHeader( + "OpCapability Int64ImageEXT\nOpExtension " + "\"SPV_EXT_shader_image_int64\"\n") + + R"( +%img_type = OpTypeImage %u64 2D 0 0 0 1 Unknown +%main = OpFunction %void None %func +%main_lab = OpLabel +OpReturn +OpFunctionEnd +)"; + + const spv_target_env env = SPV_ENV_VULKAN_1_0; + CompileSuccessfully(code, env); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(env)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateImage, TypeImageF32SampledTypeVulkan) { + const std::string code = GetShaderHeader() + R"( +%img_type = OpTypeImage %f32 2D 0 0 0 1 Unknown +%main = OpFunction %void None %func +%main_lab = OpLabel +OpReturn +OpFunctionEnd +)"; + + const spv_target_env env = SPV_ENV_VULKAN_1_0; + CompileSuccessfully(code, env); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(env)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateImage, TypeImageF64SampledTypeVulkan) { + const std::string code = GetShaderHeader() + R"( +%img_type = OpTypeImage %f64 2D 0 0 0 1 Unknown +%main = OpFunction %void None %func %main_lab = OpLabel OpReturn OpFunctionEnd @@ -553,8 +671,32 @@ OpFunctionEnd CompileSuccessfully(code, env); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(env)); EXPECT_THAT(getDiagnosticString(), - HasSubstr("Expected Sampled Type to be a 32-bit int " - "or float scalar type for Vulkan environment")); + AnyVUID("VUID-StandaloneSpirv-OpTypeImage-04656")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Expected Sampled Type to be a 32-bit int, 64-bit int " + "or 32-bit float scalar type for Vulkan environment")); +} + +TEST_F(ValidateImage, TypeImageF64SampledTypeWithInt64Vulkan) { + const std::string code = GetShaderHeader( + "OpCapability Int64ImageEXT\nOpExtension " + "\"SPV_EXT_shader_image_int64\"\n") + + R"( +%img_type = OpTypeImage %f64 2D 0 0 0 1 Unknown +%main = OpFunction %void None %func +%main_lab = OpLabel +OpReturn +OpFunctionEnd +)"; + + const spv_target_env env = SPV_ENV_VULKAN_1_0; + CompileSuccessfully(code, env); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(env)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpTypeImage-04656")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Expected Sampled Type to be a 32-bit int, 64-bit int " + "or 32-bit float scalar type for Vulkan environment")); } TEST_F(ValidateImage, TypeImageWrongDepth) { -- cgit v1.2.3 From 94d1a80159e37c5cc7965dae0c55c2b60f198d8f Mon Sep 17 00:00:00 2001 From: sfricke-samsung <46493288+sfricke-samsung@users.noreply.github.com> Date: Wed, 6 Jan 2021 09:45:28 -0800 Subject: spirv-val: Add Vulkan FP Mode VUID (#4088) --- source/val/validate_decorations.cpp | 15 ++++++- source/val/validation_state.cpp | 2 + test/val/val_decoration_test.cpp | 89 +++++++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 2 deletions(-) diff --git a/source/val/validate_decorations.cpp b/source/val/validate_decorations.cpp index d3812766..01b0ecab 100644 --- a/source/val/validate_decorations.cpp +++ b/source/val/validate_decorations.cpp @@ -1260,7 +1260,8 @@ spv_result_t CheckVulkanMemoryModelDeprecatedDecorations( // decorations. Otherwise emits a diagnostic and returns something other than // SPV_SUCCESS. spv_result_t CheckFPRoundingModeForShaders(ValidationState_t& vstate, - const Instruction& inst) { + const Instruction& inst, + const Decoration& decoration) { // Validates width-only conversion instruction for floating-point object // i.e., OpFConvert if (inst.opcode() != SpvOpFConvert) { @@ -1270,6 +1271,15 @@ spv_result_t CheckFPRoundingModeForShaders(ValidationState_t& vstate, "object."; } + if (spvIsVulkanEnv(vstate.context()->target_env)) { + const auto mode = decoration.params()[0]; + if ((mode != SpvFPRoundingModeRTE) && (mode != SpvFPRoundingModeRTZ)) { + return vstate.diag(SPV_ERROR_INVALID_ID, &inst) + << vstate.VkErrorID(4675) + << "In Vulkan, the FPRoundingMode mode must only by RTE or RTZ."; + } + } + // Validates Object operand of an OpStore for (const auto& use : inst.uses()) { const auto store = use.first; @@ -1588,7 +1598,8 @@ spv_result_t CheckDecorationsFromDecoration(ValidationState_t& vstate) { break; case SpvDecorationFPRoundingMode: if (is_shader) - PASS_OR_BAIL(CheckFPRoundingModeForShaders(vstate, *inst)); + PASS_OR_BAIL( + CheckFPRoundingModeForShaders(vstate, *inst, decoration)); break; case SpvDecorationNonWritable: PASS_OR_BAIL(CheckNonWritableDecoration(vstate, *inst, decoration)); diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index ae34185a..f56d10f2 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -1671,6 +1671,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-OpTypeImage-04656); case 4658: return VUID_WRAP(VUID-StandaloneSpirv-OpImageTexelPointer-04658); + case 4675: + return VUID_WRAP(VUID-StandaloneSpirv-FPRoundingMode-04675); case 4685: return VUID_WRAP(VUID-StandaloneSpirv-OpGroupNonUniformBallotBitCount-04685); case 4711: diff --git a/test/val/val_decoration_test.cpp b/test/val/val_decoration_test.cpp index e6461624..cacf999c 100644 --- a/test/val/val_decoration_test.cpp +++ b/test/val/val_decoration_test.cpp @@ -4679,6 +4679,95 @@ OpFunctionEnd "Object operand of an OpStore.")); } +TEST_F(ValidateDecorations, VulkanFPRoundingModeGood) { + std::string spirv = R"( + OpCapability Shader + OpCapability StorageBuffer16BitAccess + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" %_ + OpExecutionMode %main LocalSize 1 1 1 + OpMemberDecorate %ssbo 0 Offset 0 + OpDecorate %ssbo Block + OpDecorate %_ DescriptorSet 0 + OpDecorate %_ Binding 0 + OpDecorate %17 FPRoundingMode RTE + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 +%_ptr_Function_float = OpTypePointer Function %float + %float_1 = OpConstant %float 1 + %half = OpTypeFloat 16 + %ssbo = OpTypeStruct %half +%_ptr_StorageBuffer_ssbo = OpTypePointer StorageBuffer %ssbo + %_ = OpVariable %_ptr_StorageBuffer_ssbo StorageBuffer + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 +%_ptr_StorageBuffer_half = OpTypePointer StorageBuffer %half + %main = OpFunction %void None %3 + %5 = OpLabel + %b = OpVariable %_ptr_Function_float Function + OpStore %b %float_1 + %16 = OpLoad %float %b + %17 = OpFConvert %half %16 + %19 = OpAccessChain %_ptr_StorageBuffer_half %_ %int_0 + OpStore %19 %17 + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_2); + EXPECT_EQ(SPV_SUCCESS, + ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_2)); +} + +TEST_F(ValidateDecorations, VulkanFPRoundingModeBadMode) { + std::string spirv = R"( + OpCapability Shader + OpCapability StorageBuffer16BitAccess + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" %_ + OpExecutionMode %main LocalSize 1 1 1 + OpMemberDecorate %ssbo 0 Offset 0 + OpDecorate %ssbo Block + OpDecorate %_ DescriptorSet 0 + OpDecorate %_ Binding 0 + OpDecorate %17 FPRoundingMode RTP + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 +%_ptr_Function_float = OpTypePointer Function %float + %float_1 = OpConstant %float 1 + %half = OpTypeFloat 16 + %ssbo = OpTypeStruct %half +%_ptr_StorageBuffer_ssbo = OpTypePointer StorageBuffer %ssbo + %_ = OpVariable %_ptr_StorageBuffer_ssbo StorageBuffer + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 +%_ptr_StorageBuffer_half = OpTypePointer StorageBuffer %half + %main = OpFunction %void None %3 + %5 = OpLabel + %b = OpVariable %_ptr_Function_float Function + OpStore %b %float_1 + %16 = OpLoad %float %b + %17 = OpFConvert %half %16 + %19 = OpAccessChain %_ptr_StorageBuffer_half %_ %int_0 + OpStore %19 %17 + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_2); + EXPECT_EQ(SPV_ERROR_INVALID_ID, + ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_2)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-FPRoundingMode-04675")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("In Vulkan, the FPRoundingMode mode must only by RTE or RTZ.")); +} + TEST_F(ValidateDecorations, GroupDecorateTargetsDecorationGroup) { std::string spirv = R"( OpCapability Shader -- cgit v1.2.3 From af3a3d481f6e67e5658406a5ecf6c624b3e821cc Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Wed, 6 Jan 2021 13:32:11 -0500 Subject: Build deps: dump ini from 1.3.5 to 1.3.7 in tools/sva (#4092) --- tools/sva/yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/sva/yarn.lock b/tools/sva/yarn.lock index 34a1808e..c46b9017 100644 --- a/tools/sva/yarn.lock +++ b/tools/sva/yarn.lock @@ -795,9 +795,9 @@ inherits@2: integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== ini@~1.3.0: - version "1.3.5" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" - integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== + version "1.3.7" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.7.tgz#a09363e1911972ea16d7a8851005d84cf09a9a84" + integrity sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ== inquirer@^6.4.1: version "6.5.2" -- cgit v1.2.3 From 4ed1f4fce9e73dbe67e6e757e41133385d616dd5 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Wed, 6 Jan 2021 13:59:04 -0500 Subject: Fix binding number calculation in desc sroa (#4095) When there is an array of strutured buffers, desc sroa will only split the array, but not a struct type in the structured buffer. However, the calcualtion of the number of binding a struct requires does not take this into consideration. This commit will fix that. --- source/opt/desc_sroa.cpp | 31 ++++++++++++++++++++----------- source/opt/desc_sroa.h | 5 +++++ test/opt/desc_sroa_test.cpp | 41 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 11 deletions(-) diff --git a/source/opt/desc_sroa.cpp b/source/opt/desc_sroa.cpp index b68549a0..5e950069 100644 --- a/source/opt/desc_sroa.cpp +++ b/source/opt/desc_sroa.cpp @@ -63,16 +63,7 @@ bool DescriptorScalarReplacement::IsCandidate(Instruction* var) { // All structures with descriptor assignments must be replaced by variables, // one for each of their members - with the exceptions of buffers. - // Buffers are represented as structures, but we shouldn't replace a buffer - // with its elements. All buffers have offset decorations for members of their - // structure types. - bool has_offset_decoration = false; - context()->get_decoration_mgr()->ForEachDecoration( - var_type_inst->result_id(), SpvDecorationOffset, - [&has_offset_decoration](const Instruction&) { - has_offset_decoration = true; - }); - if (has_offset_decoration) { + if (IsTypeOfStructuredBuffer(var_type_inst)) { return false; } @@ -99,6 +90,23 @@ bool DescriptorScalarReplacement::IsCandidate(Instruction* var) { return true; } +bool DescriptorScalarReplacement::IsTypeOfStructuredBuffer( + const Instruction* type) const { + if (type->opcode() != SpvOpTypeStruct) { + return false; + } + + // All buffers have offset decorations for members of their structure types. + // This is how we distinguish it from a structure of descriptors. + bool has_offset_decoration = false; + context()->get_decoration_mgr()->ForEachDecoration( + type->result_id(), SpvDecorationOffset, + [&has_offset_decoration](const Instruction&) { + has_offset_decoration = true; + }); + return has_offset_decoration; +} + bool DescriptorScalarReplacement::ReplaceCandidate(Instruction* var) { std::vector access_chain_work_list; std::vector load_work_list; @@ -368,7 +376,8 @@ uint32_t DescriptorScalarReplacement::GetNumBindingsUsedByType( // The number of bindings consumed by a structure is the sum of the bindings // used by its members. - if (type_inst->opcode() == SpvOpTypeStruct) { + if (type_inst->opcode() == SpvOpTypeStruct && + !IsTypeOfStructuredBuffer(type_inst)) { uint32_t sum = 0; for (uint32_t i = 0; i < type_inst->NumInOperands(); i++) sum += GetNumBindingsUsedByType(type_inst->GetSingleWordInOperand(i)); diff --git a/source/opt/desc_sroa.h b/source/opt/desc_sroa.h index c3aa0ea2..cd72fd30 100644 --- a/source/opt/desc_sroa.h +++ b/source/opt/desc_sroa.h @@ -93,6 +93,11 @@ class DescriptorScalarReplacement : public Pass { // bindings used by its members. uint32_t GetNumBindingsUsedByType(uint32_t type_id); + // Returns true if |type| is a type that could be used for a structured buffer + // as opposed to a type that would be used for a structure of resource + // descriptors. + bool IsTypeOfStructuredBuffer(const Instruction* type) const; + // A map from an OpVariable instruction to the set of variables that will be // used to replace it. The entry |replacement_variables_[var][i]| is the id of // a variable that will be used in the place of the the ith element of the diff --git a/test/opt/desc_sroa_test.cpp b/test/opt/desc_sroa_test.cpp index cdcc9a83..b35ad474 100644 --- a/test/opt/desc_sroa_test.cpp +++ b/test/opt/desc_sroa_test.cpp @@ -729,6 +729,47 @@ TEST_F(DescriptorScalarReplacementTest, ResourceStructAsFunctionParam) { SinglePassRunAndMatch(checks + shader, true); } +TEST_F(DescriptorScalarReplacementTest, BindingForResourceArrayOfStructs) { + // Check that correct binding numbers are given to an array of descriptors + // to structs. + + const std::string shader = R"( +; CHECK: OpDecorate {{%\w+}} Binding 0 +; CHECK: OpDecorate {{%\w+}} Binding 1 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "psmain" + OpExecutionMode %2 OriginUpperLeft + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 0 + OpMemberDecorate %_struct_4 0 Offset 0 + OpMemberDecorate %_struct_4 1 Offset 4 + OpDecorate %_struct_4 Block + %float = OpTypeFloat 32 + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %int_1 = OpConstant %int 1 + %uint = OpTypeInt 32 0 + %uint_2 = OpConstant %uint 2 + %_struct_4 = OpTypeStruct %float %int +%_arr__struct_4_uint_2 = OpTypeArray %_struct_4 %uint_2 +%_ptr_Uniform__arr__struct_4_uint_2 = OpTypePointer Uniform %_arr__struct_4_uint_2 + %void = OpTypeVoid + %25 = OpTypeFunction %void +%_ptr_Uniform_int = OpTypePointer Uniform %int + %5 = OpVariable %_ptr_Uniform__arr__struct_4_uint_2 Uniform + %2 = OpFunction %void None %25 + %29 = OpLabel + %40 = OpAccessChain %_ptr_Uniform_int %5 %int_0 %int_1 + %41 = OpAccessChain %_ptr_Uniform_int %5 %int_1 %int_1 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(shader, true); +} + } // namespace } // namespace opt } // namespace spvtools -- cgit v1.2.3 From aa005e8bd435fc52249a9975e835d8ba93cda7e2 Mon Sep 17 00:00:00 2001 From: sfricke-samsung <46493288+sfricke-samsung@users.noreply.github.com> Date: Wed, 6 Jan 2021 11:30:56 -0800 Subject: spirv-val: Add Vulkan decroation VUID (#4090) --- source/val/validate_annotation.cpp | 10 ++++++++++ source/val/validation_state.cpp | 2 ++ test/val/val_decoration_test.cpp | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/source/val/validate_annotation.cpp b/source/val/validate_annotation.cpp index df38f1b1..8acdb984 100644 --- a/source/val/validate_annotation.cpp +++ b/source/val/validate_annotation.cpp @@ -219,6 +219,16 @@ spv_result_t ValidateDecorate(ValidationState_t& _, const Instruction* inst) { << "' is not valid for the WebGPU execution environment."; } + if (spvIsVulkanEnv(_.context()->target_env)) { + if ((decoration == SpvDecorationGLSLShared) || + (decoration == SpvDecorationGLSLPacked)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << _.VkErrorID(4669) << "OpDecorate decoration '" + << LogStringForDecoration(decoration) + << "' is not valid for the Vulkan execution environment."; + } + } + if (DecorationTakesIdParameters(decoration)) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "Decorations taking ID parameters may not be used with " diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index f56d10f2..1b7a2ad7 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -1671,6 +1671,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-OpTypeImage-04656); case 4658: return VUID_WRAP(VUID-StandaloneSpirv-OpImageTexelPointer-04658); + case 4669: + return VUID_WRAP(VUID-StandaloneSpirv-GLSLShared-04669); case 4675: return VUID_WRAP(VUID-StandaloneSpirv-FPRoundingMode-04675); case 4685: diff --git a/test/val/val_decoration_test.cpp b/test/val/val_decoration_test.cpp index cacf999c..735f6a12 100644 --- a/test/val/val_decoration_test.cpp +++ b/test/val/val_decoration_test.cpp @@ -44,6 +44,8 @@ struct TestResult { using ValidateDecorations = spvtest::ValidateBase; using ValidateWebGPUCombineDecorationResult = spvtest::ValidateBase>; +using ValidateVulkanCombineDecorationResult = + spvtest::ValidateBase>; TEST_F(ValidateDecorations, ValidateOpDecorateRegistration) { std::string spirv = R"( @@ -6449,6 +6451,40 @@ INSTANTIATE_TEST_SUITE_P( SPV_ERROR_INVALID_ID, "is not valid for the WebGPU execution environment.")))); +TEST_P(ValidateVulkanCombineDecorationResult, Decorate) { + const char* const decoration = std::get<0>(GetParam()); + const char* const vuid = std::get<1>(GetParam()); + const TestResult& test_result = std::get<2>(GetParam()); + + CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator(); + generator.before_types_ = "OpDecorate %u32 "; + generator.before_types_ += decoration; + generator.before_types_ += "\n"; + + EntryPoint entry_point; + entry_point.name = "main"; + entry_point.execution_model = "Vertex"; + generator.entry_points_.push_back(std::move(entry_point)); + + CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); + ASSERT_EQ(test_result.validation_result, + ValidateInstructions(SPV_ENV_VULKAN_1_0)); + if (test_result.error_str != "") { + EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str)); + } + if (vuid) { + EXPECT_THAT(getDiagnosticString(), AnyVUID(vuid)); + } +} + +INSTANTIATE_TEST_SUITE_P( + DecorationAllowListFailure, ValidateVulkanCombineDecorationResult, + Combine(Values("GLSLShared", "GLSLPacked"), + Values("VUID-StandaloneSpirv-GLSLShared-04669"), + Values(TestResult( + SPV_ERROR_INVALID_ID, + "is not valid for the Vulkan execution environment.")))); + TEST_F(ValidateDecorations, NonWritableVarFunctionV13Bad) { std::string spirv = ShaderWithNonWritableTarget("%var_func"); -- cgit v1.2.3 From ad77ed7a8d52c03f392cbce9a19e87288cab1fb2 Mon Sep 17 00:00:00 2001 From: sfricke-samsung <46493288+sfricke-samsung@users.noreply.github.com> Date: Thu, 7 Jan 2021 06:00:05 -0800 Subject: spirv-val: Label standalone Vulkan VUID (#4091) --- source/val/validate_image.cpp | 2 +- source/val/validate_memory.cpp | 3 ++- source/val/validate_memory_semantics.cpp | 4 ++-- source/val/validate_misc.cpp | 2 +- source/val/validate_mode_setting.cpp | 2 ++ source/val/validate_scopes.cpp | 2 +- source/val/validation_state.cpp | 14 ++++++++++++++ test/val/val_barriers_test.cpp | 6 ++++++ test/val/val_image_test.cpp | 2 ++ test/val/val_memory_test.cpp | 2 ++ test/val/val_misc_test.cpp | 24 ++++++++++++++++++++++++ test/val/val_modes_test.cpp | 4 ++++ test/val/val_non_uniform_test.cpp | 2 ++ 13 files changed, 63 insertions(+), 6 deletions(-) diff --git a/source/val/validate_image.cpp b/source/val/validate_image.cpp index 2d293140..9597630b 100644 --- a/source/val/validate_image.cpp +++ b/source/val/validate_image.cpp @@ -824,7 +824,7 @@ spv_result_t ValidateTypeImage(ValidationState_t& _, const Instruction* inst) { if (spvIsVulkanEnv(target_env) || spvIsWebGPUEnv(target_env)) { if (info.sampled == 0) { return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Sampled must be 1 or 2 in the " + << _.VkErrorID(4657) << "Sampled must be 1 or 2 in the " << (spvIsVulkanEnv(target_env) ? "Vulkan" : "WebGPU") << " environment."; } diff --git a/source/val/validate_memory.cpp b/source/val/validate_memory.cpp index d9f8b991..34ca301b 100644 --- a/source/val/validate_memory.cpp +++ b/source/val/validate_memory.cpp @@ -585,7 +585,8 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { storage_class != SpvStorageClassFunction) { if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { return _.diag(SPV_ERROR_INVALID_ID, inst) - << "OpVariable, '" << _.getIdName(inst->id()) + << _.VkErrorID(4651) << "OpVariable, '" + << _.getIdName(inst->id()) << "', has a disallowed initializer & storage class " << "combination.\n" << "From " << spvLogStringForEnv(_.context()->target_env) diff --git a/source/val/validate_memory_semantics.cpp b/source/val/validate_memory_semantics.cpp index 4c582f09..6af720f5 100644 --- a/source/val/validate_memory_semantics.cpp +++ b/source/val/validate_memory_semantics.cpp @@ -221,7 +221,7 @@ spv_result_t ValidateMemorySemantics(ValidationState_t& _, if (opcode == SpvOpMemoryBarrier && !num_memory_order_set_bits) { return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) + << _.VkErrorID(4649) << spvOpcodeString(opcode) << ": Vulkan specification requires Memory Semantics to have " "one " "of the following bits set: Acquire, Release, " @@ -231,7 +231,7 @@ spv_result_t ValidateMemorySemantics(ValidationState_t& _, if (opcode == SpvOpMemoryBarrier && !includes_storage_class) { return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) + << _.VkErrorID(4649) << spvOpcodeString(opcode) << ": expected Memory Semantics to include a Vulkan-supported " "storage class"; } diff --git a/source/val/validate_misc.cpp b/source/val/validate_misc.cpp index 8cccd4c5..b0bc9219 100644 --- a/source/val/validate_misc.cpp +++ b/source/val/validate_misc.cpp @@ -56,7 +56,7 @@ spv_result_t ValidateShaderClock(ValidationState_t& _, std::tie(is_int32, is_const_int32, value) = _.EvalInt32IfConst(scope); if (is_const_int32 && value != SpvScopeSubgroup && value != SpvScopeDevice) { return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Scope must be Subgroup or Device"; + << _.VkErrorID(4652) << "Scope must be Subgroup or Device"; } // Result Type must be a 64 - bit unsigned integer type or diff --git a/source/val/validate_mode_setting.cpp b/source/val/validate_mode_setting.cpp index 1db1d4c4..6facd1de 100644 --- a/source/val/validate_mode_setting.cpp +++ b/source/val/validate_mode_setting.cpp @@ -459,11 +459,13 @@ spv_result_t ValidateExecutionMode(ValidationState_t& _, if (spvIsVulkanEnv(_.context()->target_env)) { if (mode == SpvExecutionModeOriginLowerLeft) { return _.diag(SPV_ERROR_INVALID_DATA, inst) + << _.VkErrorID(4653) << "In the Vulkan environment, the OriginLowerLeft execution mode " "must not be used."; } if (mode == SpvExecutionModePixelCenterInteger) { return _.diag(SPV_ERROR_INVALID_DATA, inst) + << _.VkErrorID(4654) << "In the Vulkan environment, the PixelCenterInteger execution " "mode must not be used."; } diff --git a/source/val/validate_scopes.cpp b/source/val/validate_scopes.cpp index a6fb26da..73cd6ca2 100644 --- a/source/val/validate_scopes.cpp +++ b/source/val/validate_scopes.cpp @@ -99,7 +99,7 @@ spv_result_t ValidateExecutionScope(ValidationState_t& _, if (spvOpcodeIsNonUniformGroupOperation(opcode) && value != SpvScopeSubgroup) { return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) + << _.VkErrorID(4642) << spvOpcodeString(opcode) << ": in Vulkan environment Execution scope is limited to " << "Subgroup"; } diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index 1b7a2ad7..fb1069de 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -1667,8 +1667,22 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-ShadingRateKHR-ShadingRateKHR-04492); case 4633: return VUID_WRAP(VUID-StandaloneSpirv-None-04633); + case 4642: + return VUID_WRAP(VUID-StandaloneSpirv-None-04642); + case 4649: + return VUID_WRAP(VUID-StandaloneSpirv-OpMemoryBarrier-04649); + case 4651: + return VUID_WRAP(VUID-StandaloneSpirv-OpVariable-04651); + case 4652: + return VUID_WRAP(VUID-StandaloneSpirv-OpReadClockKHR-04652); + case 4653: + return VUID_WRAP(VUID-StandaloneSpirv-OriginLowerLeft-04653); + case 4654: + return VUID_WRAP(VUID-StandaloneSpirv-PixelCenterInteger-04654); case 4656: return VUID_WRAP(VUID-StandaloneSpirv-OpTypeImage-04656); + case 4657: + return VUID_WRAP(VUID-StandaloneSpirv-OpTypeImage-04657); case 4658: return VUID_WRAP(VUID-StandaloneSpirv-OpImageTexelPointer-04658); case 4669: diff --git a/test/val/val_barriers_test.cpp b/test/val/val_barriers_test.cpp index 8bd10d42..d7ddb46b 100644 --- a/test/val/val_barriers_test.cpp +++ b/test/val/val_barriers_test.cpp @@ -920,6 +920,8 @@ OpMemoryBarrier %device %none CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpMemoryBarrier-04649")); EXPECT_THAT( getDiagnosticString(), HasSubstr("MemoryBarrier: Vulkan specification requires Memory Semantics " @@ -934,6 +936,8 @@ OpMemoryBarrier %device %acquire CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpMemoryBarrier-04649")); EXPECT_THAT(getDiagnosticString(), HasSubstr("MemoryBarrier: expected Memory Semantics to include a " "Vulkan-supported storage class")); @@ -946,6 +950,8 @@ OpMemoryBarrier %device %acquire_release_subgroup CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpMemoryBarrier-04649")); EXPECT_THAT(getDiagnosticString(), HasSubstr("MemoryBarrier: expected Memory Semantics to include a " "Vulkan-supported storage class")); diff --git a/test/val/val_image_test.cpp b/test/val/val_image_test.cpp index c5c92c4c..dc093213 100644 --- a/test/val/val_image_test.cpp +++ b/test/val/val_image_test.cpp @@ -827,6 +827,8 @@ TEST_F(ValidateImage, TypeImage_Vulkan_Sampled0_Invalid) { CompileSuccessfully(code.c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpTypeImage-04657")); EXPECT_THAT(getDiagnosticString(), HasSubstr("Sampled must be 1 or 2 in the Vulkan environment.")); } diff --git a/test/val/val_memory_test.cpp b/test/val/val_memory_test.cpp index e5418905..6d6b8983 100644 --- a/test/val/val_memory_test.cpp +++ b/test/val/val_memory_test.cpp @@ -630,6 +630,8 @@ OpFunctionEnd )"; CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpVariable-04651")); EXPECT_THAT( getDiagnosticString(), HasSubstr("OpVariable, '5[%5]', has a disallowed initializer & " diff --git a/test/val/val_misc_test.cpp b/test/val/val_misc_test.cpp index e181f8d1..499b5b28 100644 --- a/test/val/val_misc_test.cpp +++ b/test/val/val_misc_test.cpp @@ -227,6 +227,30 @@ OpFunctionEnd)"; HasSubstr("Scope must be Subgroup or Device")); } +TEST_F(ValidateMisc, VulkanShaderClockWorkgroupScope) { + const std::string spirv = ShaderClockSpriv + R"( +%3 = OpTypeFunction %void +%ulong = OpTypeInt 64 0 +%uint = OpTypeInt 32 0 +%_ptr_Function_ulong = OpTypePointer Function %ulong +%workgroup = OpConstant %uint 2 +%uint_1 = OpConstant %uint 1 +%main = OpFunction %void None %3 +%5 = OpLabel +%time1 = OpVariable %_ptr_Function_ulong Function +%11 = OpReadClockKHR %ulong %workgroup +OpStore %time1 %11 +OpReturn +OpFunctionEnd)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpReadClockKHR-04652")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Scope must be Subgroup or Device")); +} + TEST_F(ValidateMisc, UndefVoid) { const std::string spirv = R"( OpCapability Shader diff --git a/test/val/val_modes_test.cpp b/test/val/val_modes_test.cpp index 0a1476ee..7980c937 100644 --- a/test/val/val_modes_test.cpp +++ b/test/val/val_modes_test.cpp @@ -110,6 +110,8 @@ OpExecutionMode %main OriginLowerLeft spv_target_env env = SPV_ENV_VULKAN_1_0; CompileSuccessfully(spirv, env); EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OriginLowerLeft-04653")); EXPECT_THAT(getDiagnosticString(), HasSubstr("In the Vulkan environment, the OriginLowerLeft " "execution mode must not be used.")); @@ -127,6 +129,8 @@ OpExecutionMode %main PixelCenterInteger spv_target_env env = SPV_ENV_VULKAN_1_0; CompileSuccessfully(spirv, env); EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-PixelCenterInteger-04654")); EXPECT_THAT(getDiagnosticString(), HasSubstr("In the Vulkan environment, the PixelCenterInteger " "execution mode must not be used.")); diff --git a/test/val/val_non_uniform_test.cpp b/test/val/val_non_uniform_test.cpp index 352c3496..3840eec6 100644 --- a/test/val/val_non_uniform_test.cpp +++ b/test/val/val_non_uniform_test.cpp @@ -141,6 +141,8 @@ TEST_P(GroupNonUniform, Vulkan1p1) { EXPECT_EQ(SPV_SUCCESS, result); } else { EXPECT_EQ(SPV_ERROR_INVALID_DATA, result); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-None-04642")); EXPECT_THAT( getDiagnosticString(), HasSubstr( -- cgit v1.2.3 From f3ccb633dfd7c5de1f9f0a2d2e9d7a25f2478206 Mon Sep 17 00:00:00 2001 From: David Neto Date: Thu, 7 Jan 2021 14:30:16 -0500 Subject: use std::string::empty() to test for emptiness (#4098) Fixes a clang-tidy complaint --- test/val/val_decoration_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/val/val_decoration_test.cpp b/test/val/val_decoration_test.cpp index 735f6a12..1b68503d 100644 --- a/test/val/val_decoration_test.cpp +++ b/test/val/val_decoration_test.cpp @@ -6469,7 +6469,7 @@ TEST_P(ValidateVulkanCombineDecorationResult, Decorate) { CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); ASSERT_EQ(test_result.validation_result, ValidateInstructions(SPV_ENV_VULKAN_1_0)); - if (test_result.error_str != "") { + if (!test_result.error_str.empty()) { EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str)); } if (vuid) { -- cgit v1.2.3 From c32277c0ba0df26c8661a7daadc8743dc5a10bd3 Mon Sep 17 00:00:00 2001 From: greg-lunarg Date: Mon, 11 Jan 2021 06:42:48 -0700 Subject: Generate differentiated error codes for buffer oob checking (#4097) This allows the GPU-AV layer to differentiate between errors with uniform buffers versus storage buffers and map these to the relevant VUIDs. --- include/spirv-tools/instrument.hpp | 5 +- source/opt/inst_bindless_check_pass.cpp | 44 ++- source/opt/inst_bindless_check_pass.h | 1 + test/opt/inst_bindless_check_test.cpp | 506 ++++++++++++++++---------------- 4 files changed, 305 insertions(+), 251 deletions(-) diff --git a/include/spirv-tools/instrument.hpp b/include/spirv-tools/instrument.hpp index 2b47a564..05a0472e 100644 --- a/include/spirv-tools/instrument.hpp +++ b/include/spirv-tools/instrument.hpp @@ -170,7 +170,10 @@ static const int kInstMaxOutCnt = kInstStageOutCnt + 4; static const int kInstErrorBindlessBounds = 0; static const int kInstErrorBindlessUninit = 1; static const int kInstErrorBuffAddrUnallocRef = 2; -static const int kInstErrorBindlessBuffOOB = 3; +// Deleted: static const int kInstErrorBindlessBuffOOB = 3; +// This comment will will remain for 2 releases to allow +// for the transition of all builds. Buffer OOB is +// generating the following four differentiated codes instead: static const int kInstErrorBuffOOBUniform = 4; static const int kInstErrorBuffOOBStorage = 5; static const int kInstErrorBuffOOBUniformTexel = 6; diff --git a/source/opt/inst_bindless_check_pass.cpp b/source/opt/inst_bindless_check_pass.cpp index 00857343..5607239a 100644 --- a/source/opt/inst_bindless_check_pass.cpp +++ b/source/opt/inst_bindless_check_pass.cpp @@ -27,13 +27,16 @@ static const int kSpvCopyObjectOperandIdInIdx = 0; static const int kSpvLoadPtrIdInIdx = 0; static const int kSpvAccessChainBaseIdInIdx = 0; static const int kSpvAccessChainIndex0IdInIdx = 1; +static const int kSpvTypeArrayTypeIdInIdx = 0; static const int kSpvTypeArrayLengthIdInIdx = 1; static const int kSpvConstantValueInIdx = 0; static const int kSpvVariableStorageClassInIdx = 0; +static const int kSpvTypePtrTypeIdInIdx = 1; static const int kSpvTypeImageDim = 1; static const int kSpvTypeImageDepth = 2; static const int kSpvTypeImageArrayed = 3; static const int kSpvTypeImageMS = 4; +static const int kSpvTypeImageSampled = 5; } // anonymous namespace // Avoid unused variable warning/error on Linux @@ -206,13 +209,40 @@ bool InstBindlessCheckPass::AnalyzeDescriptorReference(Instruction* ref_inst, var_inst->GetSingleWordInOperand(kSpvVariableStorageClassInIdx); switch (storage_class) { case SpvStorageClassUniform: - case SpvStorageClassUniformConstant: case SpvStorageClassStorageBuffer: break; default: return false; break; } + // Check for deprecated storage block form + if (storage_class == SpvStorageClassUniform) { + uint32_t var_ty_id = var_inst->type_id(); + Instruction* var_ty_inst = get_def_use_mgr()->GetDef(var_ty_id); + uint32_t ptr_ty_id = + var_ty_inst->GetSingleWordInOperand(kSpvTypePtrTypeIdInIdx); + Instruction* ptr_ty_inst = get_def_use_mgr()->GetDef(ptr_ty_id); + SpvOp ptr_ty_op = ptr_ty_inst->opcode(); + uint32_t block_ty_id = + (ptr_ty_op == SpvOpTypeArray || ptr_ty_op == SpvOpTypeRuntimeArray) + ? ptr_ty_inst->GetSingleWordInOperand(kSpvTypeArrayTypeIdInIdx) + : ptr_ty_id; + assert(get_def_use_mgr()->GetDef(block_ty_id)->opcode() == + SpvOpTypeStruct && + "unexpected block type"); + bool block_found = get_decoration_mgr()->FindDecoration( + block_ty_id, SpvDecorationBlock, + [](const Instruction&) { return true; }); + if (!block_found) { + // If block decoration not found, verify deprecated form of SSBO + bool buffer_block_found = get_decoration_mgr()->FindDecoration( + block_ty_id, SpvDecorationBufferBlock, + [](const Instruction&) { return true; }); + USE_ASSERT(buffer_block_found && "block decoration not found"); + storage_class = SpvStorageClassStorageBuffer; + } + } + ref->strg_class = storage_class; Instruction* desc_type_inst = GetPointeeTypeInst(var_inst); switch (desc_type_inst->opcode()) { case SpvOpTypeArray: @@ -665,8 +695,10 @@ void InstBindlessCheckPass::GenDescInitCheckCode( // for the referenced value. Instruction* ult_inst = builder.AddBinaryOp(GetBoolId(), SpvOpULessThan, ref_id, init_id); - uint32_t error = - init_check ? kInstErrorBindlessUninit : kInstErrorBindlessBuffOOB; + uint32_t error = init_check ? kInstErrorBindlessUninit + : (ref.strg_class == SpvStorageClassUniform + ? kInstErrorBuffOOBUniform + : kInstErrorBuffOOBStorage); uint32_t error_id = builder.GetUintConstantId(error); GenCheckCode(ult_inst->result_id(), error_id, init_check ? 0 : ref_id, init_check ? builder.GetUintConstantId(0u) : init_id, stage_idx, @@ -732,7 +764,11 @@ void InstBindlessCheckPass::GenTexBuffCheckCode( // for the referenced value. Instruction* ult_inst = builder.AddBinaryOp(GetBoolId(), SpvOpULessThan, coord_id, size_id); - uint32_t error_id = builder.GetUintConstantId(kInstErrorBindlessBuffOOB); + uint32_t error = + (image_ty_inst->GetSingleWordInOperand(kSpvTypeImageSampled) == 2) + ? kInstErrorBuffOOBStorageTexel + : kInstErrorBuffOOBUniformTexel; + uint32_t error_id = builder.GetUintConstantId(error); GenCheckCode(ult_inst->result_id(), error_id, coord_id, size_id, stage_idx, &ref, new_blocks); // Move original block's remaining code into remainder/merge block and add diff --git a/source/opt/inst_bindless_check_pass.h b/source/opt/inst_bindless_check_pass.h index a7dff75f..cd961805 100644 --- a/source/opt/inst_bindless_check_pass.h +++ b/source/opt/inst_bindless_check_pass.h @@ -130,6 +130,7 @@ class InstBindlessCheckPass : public InstrumentPass { uint32_t ptr_id; uint32_t var_id; uint32_t desc_idx_id; + uint32_t strg_class; Instruction* ref_inst; } RefAnalysis; diff --git a/test/opt/inst_bindless_check_test.cpp b/test/opt/inst_bindless_check_test.cpp index f1899627..1a42329b 100644 --- a/test/opt/inst_bindless_check_test.cpp +++ b/test/opt/inst_bindless_check_test.cpp @@ -7308,15 +7308,15 @@ TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) { ;CHECK: %_ptr_StorageBuffer__struct_128 = OpTypePointer StorageBuffer %_struct_128 ;CHECK: %130 = OpVariable %_ptr_StorageBuffer__struct_128 StorageBuffer ;CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint - ;CHECK: %uint_3 = OpConstant %uint 3 + ;CHECK: %uint_4 = OpConstant %uint 4 ;CHECK: %148 = OpTypeFunction %void %uint %uint %uint %uint %uint ;CHECK: %_struct_155 = OpTypeStruct %uint %_runtimearr_uint ;CHECK: %_ptr_StorageBuffer__struct_155 = OpTypePointer StorageBuffer %_struct_155 ;CHECK: %157 = OpVariable %_ptr_StorageBuffer__struct_155 StorageBuffer ;CHECK: %uint_11 = OpConstant %uint 11 - ;CHECK: %uint_4 = OpConstant %uint 4 ;CHECK: %uint_23 = OpConstant %uint 23 ;CHECK: %uint_2 = OpConstant %uint 2 + ;CHECK: %uint_3 = OpConstant %uint 3 ;CHECK:%_ptr_Input_v4float = OpTypePointer Input %v4float ;CHECK:%gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: %v4uint = OpTypeVector %uint 4 @@ -7352,7 +7352,7 @@ TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) { ;CHECK: %146 = OpLoad %v2float %86 ;CHECK: OpBranch %143 ;CHECK: %145 = OpLabel - ;CHECK: %201 = OpFunctionCall %void %147 %uint_71 %uint_3 %uint_0 %119 %140 + ;CHECK: %201 = OpFunctionCall %void %147 %uint_71 %uint_4 %uint_0 %119 %140 ;CHECK: OpBranch %143 ;CHECK: %143 = OpLabel ;CHECK: %203 = OpPhi %v2float %146 %144 %202 %145 @@ -7369,7 +7369,7 @@ TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) { ;CHECK: %209 = OpLoad %v2float %89 ;CHECK: OpBranch %206 ;CHECK: %208 = OpLabel - ;CHECK: %211 = OpFunctionCall %void %147 %uint_75 %uint_3 %uint_0 %204 %140 + ;CHECK: %211 = OpFunctionCall %void %147 %uint_75 %uint_4 %uint_0 %204 %140 ;CHECK: OpBranch %206 ;CHECK: %206 = OpLabel ;CHECK: %212 = OpPhi %v2float %209 %207 %202 %208 @@ -7409,49 +7409,49 @@ TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) { ;CHECK: %153 = OpFunctionParameter %uint ;CHECK: %154 = OpLabel ;CHECK: %158 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_0 - ;CHECK: %161 = OpAtomicIAdd %uint %158 %uint_4 %uint_0 %uint_11 - ;CHECK: %162 = OpIAdd %uint %161 %uint_11 - ;CHECK: %163 = OpArrayLength %uint %157 1 - ;CHECK: %164 = OpULessThanEqual %bool %162 %163 - ;CHECK: OpSelectionMerge %165 None - ;CHECK: OpBranchConditional %164 %166 %165 - ;CHECK: %166 = OpLabel - ;CHECK: %167 = OpIAdd %uint %161 %uint_0 - ;CHECK: %168 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %167 - ;CHECK: OpStore %168 %uint_11 - ;CHECK: %170 = OpIAdd %uint %161 %uint_1 - ;CHECK: %171 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %170 - ;CHECK: OpStore %171 %uint_23 - ;CHECK: %173 = OpIAdd %uint %161 %uint_2 - ;CHECK: %174 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %173 - ;CHECK: OpStore %174 %149 - ;CHECK: %175 = OpIAdd %uint %161 %uint_3 + ;CHECK: %160 = OpAtomicIAdd %uint %158 %uint_4 %uint_0 %uint_11 + ;CHECK: %161 = OpIAdd %uint %160 %uint_11 + ;CHECK: %162 = OpArrayLength %uint %157 1 + ;CHECK: %163 = OpULessThanEqual %bool %161 %162 + ;CHECK: OpSelectionMerge %164 None + ;CHECK: OpBranchConditional %163 %165 %164 + ;CHECK: %165 = OpLabel + ;CHECK: %166 = OpIAdd %uint %160 %uint_0 + ;CHECK: %167 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %166 + ;CHECK: OpStore %167 %uint_11 + ;CHECK: %169 = OpIAdd %uint %160 %uint_1 + ;CHECK: %170 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %169 + ;CHECK: OpStore %170 %uint_23 + ;CHECK: %172 = OpIAdd %uint %160 %uint_2 + ;CHECK: %173 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %172 + ;CHECK: OpStore %173 %149 + ;CHECK: %175 = OpIAdd %uint %160 %uint_3 ;CHECK: %176 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %175 ;CHECK: OpStore %176 %uint_4 ;CHECK: %179 = OpLoad %v4float %gl_FragCoord ;CHECK: %181 = OpBitcast %v4uint %179 ;CHECK: %182 = OpCompositeExtract %uint %181 0 - ;CHECK: %183 = OpIAdd %uint %161 %uint_4 + ;CHECK: %183 = OpIAdd %uint %160 %uint_4 ;CHECK: %184 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %183 ;CHECK: OpStore %184 %182 ;CHECK: %185 = OpCompositeExtract %uint %181 1 - ;CHECK: %187 = OpIAdd %uint %161 %uint_5 + ;CHECK: %187 = OpIAdd %uint %160 %uint_5 ;CHECK: %188 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %187 ;CHECK: OpStore %188 %185 - ;CHECK: %189 = OpIAdd %uint %161 %uint_7 + ;CHECK: %189 = OpIAdd %uint %160 %uint_7 ;CHECK: %190 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %189 ;CHECK: OpStore %190 %150 - ;CHECK: %192 = OpIAdd %uint %161 %uint_8 + ;CHECK: %192 = OpIAdd %uint %160 %uint_8 ;CHECK: %193 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %192 ;CHECK: OpStore %193 %151 - ;CHECK: %195 = OpIAdd %uint %161 %uint_9 + ;CHECK: %195 = OpIAdd %uint %160 %uint_9 ;CHECK: %196 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %195 ;CHECK: OpStore %196 %152 - ;CHECK: %198 = OpIAdd %uint %161 %uint_10 + ;CHECK: %198 = OpIAdd %uint %160 %uint_10 ;CHECK: %199 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %198 ;CHECK: OpStore %199 %153 - ;CHECK: OpBranch %165 - ;CHECK: %165 = OpLabel + ;CHECK: OpBranch %164 + ;CHECK: %164 = OpLabel ;CHECK: OpReturn ;CHECK: OpFunctionEnd )"; @@ -7596,14 +7596,14 @@ TEST_F(InstBindlessTest, UniformArrayRefNoDescInit) { ;CHECK: %113 = OpVariable %_ptr_StorageBuffer__struct_111 StorageBuffer ;CHECK:%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint ;CHECK: %bool = OpTypeBool -;CHECK: %uint_3 = OpConstant %uint 3 +;CHECK: %uint_4 = OpConstant %uint 4 ;CHECK: %132 = OpTypeFunction %void %uint %uint %uint %uint %uint ;CHECK:%_struct_139 = OpTypeStruct %uint %_runtimearr_uint ;CHECK:%_ptr_StorageBuffer__struct_139 = OpTypePointer StorageBuffer %_struct_139 ;CHECK: %141 = OpVariable %_ptr_StorageBuffer__struct_139 StorageBuffer ;CHECK: %uint_11 = OpConstant %uint 11 -;CHECK: %uint_4 = OpConstant %uint 4 ;CHECK: %uint_23 = OpConstant %uint 23 +;CHECK: %uint_3 = OpConstant %uint 3 ;CHECK:%_ptr_Input_v4float = OpTypePointer Input %v4float ;CHECK:%gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: %v4uint = OpTypeVector %uint 4 @@ -7637,7 +7637,7 @@ TEST_F(InstBindlessTest, UniformArrayRefNoDescInit) { ;CHECK: %130 = OpLoad %v2float %81 ;CHECK: OpBranch %127 ;CHECK: %129 = OpLabel -;CHECK: %184 = OpFunctionCall %void %131 %uint_78 %uint_3 %uint_0 %101 %123 +;CHECK: %184 = OpFunctionCall %void %131 %uint_78 %uint_4 %uint_0 %101 %123 ;CHECK: OpBranch %127 ;CHECK: %127 = OpLabel ;CHECK: %186 = OpPhi %v2float %130 %128 %185 %129 @@ -7674,49 +7674,49 @@ TEST_F(InstBindlessTest, UniformArrayRefNoDescInit) { ;CHECK: %137 = OpFunctionParameter %uint ;CHECK: %138 = OpLabel ;CHECK: %142 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_0 -;CHECK: %145 = OpAtomicIAdd %uint %142 %uint_4 %uint_0 %uint_11 -;CHECK: %146 = OpIAdd %uint %145 %uint_11 -;CHECK: %147 = OpArrayLength %uint %141 1 -;CHECK: %148 = OpULessThanEqual %bool %146 %147 -;CHECK: OpSelectionMerge %149 None -;CHECK: OpBranchConditional %148 %150 %149 -;CHECK: %150 = OpLabel -;CHECK: %151 = OpIAdd %uint %145 %uint_0 -;CHECK: %152 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %151 -;CHECK: OpStore %152 %uint_11 -;CHECK: %154 = OpIAdd %uint %145 %uint_1 -;CHECK: %155 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %154 -;CHECK: OpStore %155 %uint_23 -;CHECK: %156 = OpIAdd %uint %145 %uint_2 -;CHECK: %157 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %156 -;CHECK: OpStore %157 %133 -;CHECK: %158 = OpIAdd %uint %145 %uint_3 +;CHECK: %144 = OpAtomicIAdd %uint %142 %uint_4 %uint_0 %uint_11 +;CHECK: %145 = OpIAdd %uint %144 %uint_11 +;CHECK: %146 = OpArrayLength %uint %141 1 +;CHECK: %147 = OpULessThanEqual %bool %145 %146 +;CHECK: OpSelectionMerge %148 None +;CHECK: OpBranchConditional %147 %149 %148 +;CHECK: %149 = OpLabel +;CHECK: %150 = OpIAdd %uint %144 %uint_0 +;CHECK: %151 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %150 +;CHECK: OpStore %151 %uint_11 +;CHECK: %153 = OpIAdd %uint %144 %uint_1 +;CHECK: %154 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %153 +;CHECK: OpStore %154 %uint_23 +;CHECK: %155 = OpIAdd %uint %144 %uint_2 +;CHECK: %156 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %155 +;CHECK: OpStore %156 %133 +;CHECK: %158 = OpIAdd %uint %144 %uint_3 ;CHECK: %159 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %158 ;CHECK: OpStore %159 %uint_4 ;CHECK: %162 = OpLoad %v4float %gl_FragCoord ;CHECK: %164 = OpBitcast %v4uint %162 ;CHECK: %165 = OpCompositeExtract %uint %164 0 -;CHECK: %166 = OpIAdd %uint %145 %uint_4 +;CHECK: %166 = OpIAdd %uint %144 %uint_4 ;CHECK: %167 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %166 ;CHECK: OpStore %167 %165 ;CHECK: %168 = OpCompositeExtract %uint %164 1 -;CHECK: %170 = OpIAdd %uint %145 %uint_5 +;CHECK: %170 = OpIAdd %uint %144 %uint_5 ;CHECK: %171 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %170 ;CHECK: OpStore %171 %168 -;CHECK: %172 = OpIAdd %uint %145 %uint_7 +;CHECK: %172 = OpIAdd %uint %144 %uint_7 ;CHECK: %173 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %172 ;CHECK: OpStore %173 %134 -;CHECK: %175 = OpIAdd %uint %145 %uint_8 +;CHECK: %175 = OpIAdd %uint %144 %uint_8 ;CHECK: %176 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %175 ;CHECK: OpStore %176 %135 -;CHECK: %178 = OpIAdd %uint %145 %uint_9 +;CHECK: %178 = OpIAdd %uint %144 %uint_9 ;CHECK: %179 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %178 ;CHECK: OpStore %179 %136 -;CHECK: %181 = OpIAdd %uint %145 %uint_10 +;CHECK: %181 = OpIAdd %uint %144 %uint_10 ;CHECK: %182 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %181 ;CHECK: OpStore %182 %137 -;CHECK: OpBranch %149 -;CHECK: %149 = OpLabel +;CHECK: OpBranch %148 +;CHECK: %148 = OpLabel ;CHECK: OpReturn ;CHECK: OpFunctionEnd )"; @@ -7743,11 +7743,11 @@ TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) { OpExecutionMode %MainPs OriginUpperLeft OpSource HLSL 500 OpName %MainPs "MainPs" - OpName %PerBatchEnvMapConstantBuffer_t -"PerBatchEnvMapConstantBuffer_t" OpMemberName %PerBatchEnvMapConstantBuffer_t 0 -"g_matEnvMapWorldToLocal" OpMemberName %PerBatchEnvMapConstantBuffer_t 1 -"g_vEnvironmentMapBoxMins" OpMemberName %PerBatchEnvMapConstantBuffer_t 2 -"g_TexOff" OpName %_BindlessFastEnvMapCB_PS_t "_BindlessFastEnvMapCB_PS_t" + OpName %PerBatchEnvMapConstantBuffer_t "PerBatchEnvMapConstantBuffer_t" + OpMemberName %PerBatchEnvMapConstantBuffer_t 0 "g_matEnvMapWorldToLocal" + OpMemberName %PerBatchEnvMapConstantBuffer_t 1 "g_vEnvironmentMapBoxMins" + OpMemberName %PerBatchEnvMapConstantBuffer_t 2 "g_TexOff" + OpName %_BindlessFastEnvMapCB_PS_t "_BindlessFastEnvMapCB_PS_t" OpMemberName %_BindlessFastEnvMapCB_PS_t 0 "g_envMapConstants" OpName %_ "" OpName %PerViewPushConst_t "PerViewPushConst_t" @@ -7831,15 +7831,15 @@ TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) { ;CHECK: %113 = OpVariable %_ptr_StorageBuffer__struct_111 StorageBuffer ;CHECK:%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint ;CHECK: %bool = OpTypeBool -;CHECK: %uint_3 = OpConstant %uint 3 +;CHECK: %uint_4 = OpConstant %uint 4 ;CHECK: %135 = OpTypeFunction %void %uint %uint %uint %uint %uint ;CHECK:%_struct_142 = OpTypeStruct %uint %_runtimearr_uint ;CHECK:%_ptr_StorageBuffer__struct_142 = OpTypePointer StorageBuffer %_struct_142 ;CHECK: %144 = OpVariable %_ptr_StorageBuffer__struct_142 StorageBuffer ;CHECK: %uint_11 = OpConstant %uint 11 -;CHECK: %uint_4 = OpConstant %uint 4 ;CHECK: %uint_1 = OpConstant %uint 1 ;CHECK: %uint_23 = OpConstant %uint 23 +;CHECK: %uint_3 = OpConstant %uint 3 ;CHECK:%_ptr_Input_v4float = OpTypePointer Input %v4float ;CHECK:%gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: %v4uint = OpTypeVector %uint 4 @@ -7878,13 +7878,15 @@ TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) { ;CHECK: %133 = OpLoad %v2float %81 ;CHECK: OpBranch %130 ;CHECK: %132 = OpLabel -;CHECK: %188 = OpFunctionCall %void %134 %uint_78 %uint_3 %uint_0 %101 %126 +;CHECK: %188 = OpFunctionCall %void %134 %uint_78 %uint_4 %uint_0 %101 %126 ;CHECK: OpBranch %130 ;CHECK: %130 = OpLabel ;CHECK: %190 = OpPhi %v2float %133 %131 %189 %132 ;CHECK: %86 = OpFAdd %v2float %66 %190 - %87 = OpLoad %46 %g_tColor %88 = OpLoad %50 %g_sAniso %89 = - OpSampledImage %54 %87 %88 %91 = OpImageSampleImplicitLod %v4float %89 %86 + %87 = OpLoad %46 %g_tColor + %88 = OpLoad %50 %g_sAniso + %89 = OpSampledImage %54 %87 %88 + %91 = OpImageSampleImplicitLod %v4float %89 %86 OpStore %_entryPointOutput_vColor %91 ;CHECK-NOT: %91 = OpImageSampleImplicitLod %v4float %89 %86 ;CHECK-NOT: OpStore %_entryPointOutput_vColor %91 @@ -7931,49 +7933,49 @@ TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) { ;CHECK: %140 = OpFunctionParameter %uint ;CHECK: %141 = OpLabel ;CHECK: %145 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_0 -;CHECK: %148 = OpAtomicIAdd %uint %145 %uint_4 %uint_0 %uint_11 -;CHECK: %149 = OpIAdd %uint %148 %uint_11 -;CHECK: %150 = OpArrayLength %uint %144 1 -;CHECK: %151 = OpULessThanEqual %bool %149 %150 -;CHECK: OpSelectionMerge %152 None -;CHECK: OpBranchConditional %151 %153 %152 -;CHECK: %153 = OpLabel -;CHECK: %154 = OpIAdd %uint %148 %uint_0 -;CHECK: %156 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %154 -;CHECK: OpStore %156 %uint_11 -;CHECK: %158 = OpIAdd %uint %148 %uint_1 -;CHECK: %159 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %158 -;CHECK: OpStore %159 %uint_23 -;CHECK: %160 = OpIAdd %uint %148 %uint_2 -;CHECK: %161 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %160 -;CHECK: OpStore %161 %136 -;CHECK: %162 = OpIAdd %uint %148 %uint_3 +;CHECK: %147 = OpAtomicIAdd %uint %145 %uint_4 %uint_0 %uint_11 +;CHECK: %148 = OpIAdd %uint %147 %uint_11 +;CHECK: %149 = OpArrayLength %uint %144 1 +;CHECK: %150 = OpULessThanEqual %bool %148 %149 +;CHECK: OpSelectionMerge %151 None +;CHECK: OpBranchConditional %150 %152 %151 +;CHECK: %152 = OpLabel +;CHECK: %153 = OpIAdd %uint %147 %uint_0 +;CHECK: %155 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %153 +;CHECK: OpStore %155 %uint_11 +;CHECK: %157 = OpIAdd %uint %147 %uint_1 +;CHECK: %158 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %157 +;CHECK: OpStore %158 %uint_23 +;CHECK: %159 = OpIAdd %uint %147 %uint_2 +;CHECK: %160 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %159 +;CHECK: OpStore %160 %136 +;CHECK: %162 = OpIAdd %uint %147 %uint_3 ;CHECK: %163 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %162 ;CHECK: OpStore %163 %uint_4 ;CHECK: %166 = OpLoad %v4float %gl_FragCoord ;CHECK: %168 = OpBitcast %v4uint %166 ;CHECK: %169 = OpCompositeExtract %uint %168 0 -;CHECK: %170 = OpIAdd %uint %148 %uint_4 +;CHECK: %170 = OpIAdd %uint %147 %uint_4 ;CHECK: %171 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %170 ;CHECK: OpStore %171 %169 ;CHECK: %172 = OpCompositeExtract %uint %168 1 -;CHECK: %174 = OpIAdd %uint %148 %uint_5 +;CHECK: %174 = OpIAdd %uint %147 %uint_5 ;CHECK: %175 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %174 ;CHECK: OpStore %175 %172 -;CHECK: %176 = OpIAdd %uint %148 %uint_7 +;CHECK: %176 = OpIAdd %uint %147 %uint_7 ;CHECK: %177 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %176 ;CHECK: OpStore %177 %137 -;CHECK: %179 = OpIAdd %uint %148 %uint_8 +;CHECK: %179 = OpIAdd %uint %147 %uint_8 ;CHECK: %180 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %179 ;CHECK: OpStore %180 %138 -;CHECK: %182 = OpIAdd %uint %148 %uint_9 +;CHECK: %182 = OpIAdd %uint %147 %uint_9 ;CHECK: %183 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %182 ;CHECK: OpStore %183 %139 -;CHECK: %185 = OpIAdd %uint %148 %uint_10 +;CHECK: %185 = OpIAdd %uint %147 %uint_10 ;CHECK: %186 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %185 ;CHECK: OpStore %186 %140 -;CHECK: OpBranch %152 -;CHECK: %152 = OpLabel +;CHECK: OpBranch %151 +;CHECK: %151 = OpLabel ;CHECK: OpReturn ;CHECK: OpFunctionEnd )"; @@ -8344,15 +8346,15 @@ TEST_F(InstBindlessTest, UniformArray16bitIdxRef) { ;CHECK: %69 = OpVariable %_ptr_StorageBuffer__struct_67 StorageBuffer ;CHECK:%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint ;CHECK: %bool = OpTypeBool -;CHECK: %uint_3 = OpConstant %uint 3 +;CHECK: %uint_4 = OpConstant %uint 4 ;CHECK: %88 = OpTypeFunction %void %uint %uint %uint %uint %uint ;CHECK: %_struct_95 = OpTypeStruct %uint %_runtimearr_uint ;CHECK:%_ptr_StorageBuffer__struct_95 = OpTypePointer StorageBuffer %_struct_95 ;CHECK: %97 = OpVariable %_ptr_StorageBuffer__struct_95 StorageBuffer ;CHECK: %uint_11 = OpConstant %uint 11 -;CHECK: %uint_4 = OpConstant %uint 4 ;CHECK: %uint_23 = OpConstant %uint 23 ;CHECK: %uint_2 = OpConstant %uint 2 +;CHECK: %uint_3 = OpConstant %uint 3 ;CHECK:%_ptr_Input_v4float = OpTypePointer Input %v4float ;CHECK:%gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: %v4uint = OpTypeVector %uint 4 @@ -8389,7 +8391,7 @@ TEST_F(InstBindlessTest, UniformArray16bitIdxRef) { ;CHECK: %86 = OpLoad %v2float %41 ;CHECK: OpBranch %83 ;CHECK: %85 = OpLabel -;CHECK: %141 = OpFunctionCall %void %87 %uint_81 %uint_3 %uint_0 %58 %79 +;CHECK: %141 = OpFunctionCall %void %87 %uint_81 %uint_4 %uint_0 %58 %79 ;CHECK: OpBranch %83 ;CHECK: %83 = OpLabel ;CHECK: %143 = OpPhi %v2float %86 %84 %142 %85 @@ -8424,49 +8426,49 @@ TEST_F(InstBindlessTest, UniformArray16bitIdxRef) { ;CHECK: %93 = OpFunctionParameter %uint ;CHECK: %94 = OpLabel ;CHECK: %98 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_0 -;CHECK: %101 = OpAtomicIAdd %uint %98 %uint_4 %uint_0 %uint_11 -;CHECK: %102 = OpIAdd %uint %101 %uint_11 -;CHECK: %103 = OpArrayLength %uint %97 1 -;CHECK: %104 = OpULessThanEqual %bool %102 %103 -;CHECK: OpSelectionMerge %105 None -;CHECK: OpBranchConditional %104 %106 %105 -;CHECK: %106 = OpLabel -;CHECK: %107 = OpIAdd %uint %101 %uint_0 -;CHECK: %108 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %107 -;CHECK: OpStore %108 %uint_11 -;CHECK: %110 = OpIAdd %uint %101 %uint_1 -;CHECK: %111 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %110 -;CHECK: OpStore %111 %uint_23 -;CHECK: %113 = OpIAdd %uint %101 %uint_2 -;CHECK: %114 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %113 -;CHECK: OpStore %114 %89 -;CHECK: %115 = OpIAdd %uint %101 %uint_3 +;CHECK: %100 = OpAtomicIAdd %uint %98 %uint_4 %uint_0 %uint_11 +;CHECK: %101 = OpIAdd %uint %100 %uint_11 +;CHECK: %102 = OpArrayLength %uint %97 1 +;CHECK: %103 = OpULessThanEqual %bool %101 %102 +;CHECK: OpSelectionMerge %104 None +;CHECK: OpBranchConditional %103 %105 %104 +;CHECK: %105 = OpLabel +;CHECK: %106 = OpIAdd %uint %100 %uint_0 +;CHECK: %107 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %106 +;CHECK: OpStore %107 %uint_11 +;CHECK: %109 = OpIAdd %uint %100 %uint_1 +;CHECK: %110 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %109 +;CHECK: OpStore %110 %uint_23 +;CHECK: %112 = OpIAdd %uint %100 %uint_2 +;CHECK: %113 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %112 +;CHECK: OpStore %113 %89 +;CHECK: %115 = OpIAdd %uint %100 %uint_3 ;CHECK: %116 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %115 ;CHECK: OpStore %116 %uint_4 ;CHECK: %119 = OpLoad %v4float %gl_FragCoord ;CHECK: %121 = OpBitcast %v4uint %119 ;CHECK: %122 = OpCompositeExtract %uint %121 0 -;CHECK: %123 = OpIAdd %uint %101 %uint_4 +;CHECK: %123 = OpIAdd %uint %100 %uint_4 ;CHECK: %124 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %123 ;CHECK: OpStore %124 %122 ;CHECK: %125 = OpCompositeExtract %uint %121 1 -;CHECK: %127 = OpIAdd %uint %101 %uint_5 +;CHECK: %127 = OpIAdd %uint %100 %uint_5 ;CHECK: %128 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %127 ;CHECK: OpStore %128 %125 -;CHECK: %129 = OpIAdd %uint %101 %uint_7 +;CHECK: %129 = OpIAdd %uint %100 %uint_7 ;CHECK: %130 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %129 ;CHECK: OpStore %130 %90 -;CHECK: %132 = OpIAdd %uint %101 %uint_8 +;CHECK: %132 = OpIAdd %uint %100 %uint_8 ;CHECK: %133 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %132 ;CHECK: OpStore %133 %91 -;CHECK: %135 = OpIAdd %uint %101 %uint_9 +;CHECK: %135 = OpIAdd %uint %100 %uint_9 ;CHECK: %136 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %135 ;CHECK: OpStore %136 %92 -;CHECK: %138 = OpIAdd %uint %101 %uint_10 +;CHECK: %138 = OpIAdd %uint %100 %uint_10 ;CHECK: %139 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %138 ;CHECK: OpStore %139 %93 -;CHECK: OpBranch %105 -;CHECK: %105 = OpLabel +;CHECK: OpBranch %104 +;CHECK: %104 = OpLabel ;CHECK: OpReturn ;CHECK: OpFunctionEnd )"; @@ -8557,6 +8559,7 @@ TEST_F(InstBindlessTest, UniformMatrixRefRowMajor) { %_ptr_Input_v4float = OpTypePointer Input %v4float %a_position = OpVariable %_ptr_Input_v4float Input ;CHECK; %uint_0 = OpConstant %uint 0 +;CHECK; %uint_16 = OpConstant %uint 16 ;CHECK; %uint_4 = OpConstant %uint 4 ;CHECK; %uint_3 = OpConstant %uint 3 ;CHECK; %37 = OpTypeFunction %uint %uint %uint %uint @@ -8583,10 +8586,13 @@ TEST_F(InstBindlessTest, UniformMatrixRefRowMajor) { ;CHECK; %uint_10 = OpConstant %uint 10 ;CHECK; %uint_45 = OpConstant %uint 45 ;CHECK; %115 = OpConstantNull %float -;CHECK; %uint_27 = OpConstant %uint 27 %main = OpFunction %void None %3 %5 = OpLabel ;CHECK: %55 = OpFunctionCall %uint %36 %uint_1 %uint_0 %uint_0 +;CHECK: OpBranch %26 +;CHECK: %26 = OpLabel +;CHECK: OpBranch %25 +;CHECK: %25 = OpLabel %20 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %int_2 %uint_1 %21 = OpLoad %float %20 ;CHECK-NOT: %21 = OpLoad %float %20 @@ -8602,7 +8608,7 @@ TEST_F(InstBindlessTest, UniformMatrixRefRowMajor) { ;CHECK: %61 = OpLoad %float %20 ;CHECK: OpBranch %58 ;CHECK: %60 = OpLabel -;CHECK: %114 = OpFunctionCall %void %62 %uint_45 %uint_3 %uint_0 %35 %55 +;CHECK: %114 = OpFunctionCall %void %62 %uint_45 %uint_4 %uint_0 %35 %55 ;CHECK: OpBranch %58 ;CHECK: %58 = OpLabel ;CHECK: %116 = OpPhi %float %61 %59 %115 %60 @@ -8790,9 +8796,14 @@ TEST_F(InstBindlessTest, UniformMatrixRefColumnMajor) { ;CHECK: %uint_9 = OpConstant %uint 9 ;CHECK: %uint_10 = OpConstant %uint 10 ;CHECK: %uint_45 = OpConstant %uint 45 +;CHECK: %114 = OpConstantNull %float %main = OpFunction %void None %3 %5 = OpLabel ;CHECK: %55 = OpFunctionCall %uint %36 %uint_1 %uint_0 %uint_0 +;CHECK: OpBranch %26 +;CHECK: %26 = OpLabel +;CHECK: OpBranch %25 +;CHECK: %25 = OpLabel %20 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %int_2 %uint_1 %21 = OpLoad %float %20 ;CHECK-NOT: %21 = OpLoad %float %20 @@ -8808,7 +8819,7 @@ TEST_F(InstBindlessTest, UniformMatrixRefColumnMajor) { ;CHECK: %61 = OpLoad %float %20 ;CHECK: OpBranch %58 ;CHECK: %60 = OpLabel -;CHECK: %113 = OpFunctionCall %void %62 %uint_45 %uint_3 %uint_0 %35 %55 +;CHECK: %113 = OpFunctionCall %void %62 %uint_45 %uint_4 %uint_0 %35 %55 ;CHECK: OpBranch %58 ;CHECK: %58 = OpLabel ;CHECK: %115 = OpPhi %float %61 %59 %114 %60 @@ -9032,7 +9043,7 @@ TEST_F(InstBindlessTest, UniformMatrixVecRefRowMajor) { ;CHECK: %70 = OpLoad %v2float %25 ;CHECK: OpBranch %67 ;CHECK: %69 = OpLabel -;CHECK: %123 = OpFunctionCall %void %71 %uint_51 %uint_3 %uint_0 %43 %64 +;CHECK: %123 = OpFunctionCall %void %71 %uint_51 %uint_4 %uint_0 %43 %64 ;CHECK: OpBranch %67 ;CHECK: %67 = OpLabel ;CHECK: %125 = OpPhi %v2float %70 %68 %124 %69 @@ -9167,7 +9178,7 @@ TEST_F(InstBindlessTest, ImageBufferOOBRead) { ;CHECK: %uint = OpTypeInt 32 0 ;CHECK: %uint_0 = OpConstant %uint 0 ;CHECK: %bool = OpTypeBool -;CHECK: %uint_3 = OpConstant %uint 3 +;CHECK: %uint_7 = OpConstant %uint 7 ;CHECK: %35 = OpTypeFunction %void %uint %uint %uint %uint %uint ;CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint ;CHECK: %_struct_43 = OpTypeStruct %uint %_runtimearr_uint @@ -9179,11 +9190,11 @@ TEST_F(InstBindlessTest, ImageBufferOOBRead) { ;CHECK: %uint_1 = OpConstant %uint 1 ;CHECK: %uint_23 = OpConstant %uint 23 ;CHECK: %uint_2 = OpConstant %uint 2 +;CHECK: %uint_3 = OpConstant %uint 3 ;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float ;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: %v4uint = OpTypeVector %uint 4 ;CHECK: %uint_5 = OpConstant %uint 5 -;CHECK: %uint_7 = OpConstant %uint 7 ;CHECK: %uint_8 = OpConstant %uint 8 ;CHECK: %uint_9 = OpConstant %uint 9 ;CHECK: %uint_10 = OpConstant %uint 10 @@ -9213,7 +9224,7 @@ TEST_F(InstBindlessTest, ImageBufferOOBRead) { ;CHECK: %33 = OpImageRead %v4float %32 %17 ;CHECK: OpBranch %29 ;CHECK: %31 = OpLabel -;CHECK: %92 = OpFunctionCall %void %34 %uint_33 %uint_3 %uint_0 %23 %25 +;CHECK: %92 = OpFunctionCall %void %34 %uint_33 %uint_7 %uint_0 %23 %25 ;CHECK: OpBranch %29 ;CHECK: %29 = OpLabel ;CHECK: %94 = OpPhi %v4float %33 %30 %93 %31 @@ -9244,19 +9255,19 @@ TEST_F(InstBindlessTest, ImageBufferOOBRead) { ;CHECK: %63 = OpIAdd %uint %50 %uint_2 ;CHECK: %64 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %63 ;CHECK: OpStore %64 %36 -;CHECK: %65 = OpIAdd %uint %50 %uint_3 -;CHECK: %66 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %65 -;CHECK: OpStore %66 %uint_4 -;CHECK: %69 = OpLoad %v4float %gl_FragCoord -;CHECK: %71 = OpBitcast %v4uint %69 -;CHECK: %72 = OpCompositeExtract %uint %71 0 -;CHECK: %73 = OpIAdd %uint %50 %uint_4 -;CHECK: %74 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %73 -;CHECK: OpStore %74 %72 -;CHECK: %75 = OpCompositeExtract %uint %71 1 -;CHECK: %77 = OpIAdd %uint %50 %uint_5 -;CHECK: %78 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %77 -;CHECK: OpStore %78 %75 +;CHECK: %66 = OpIAdd %uint %50 %uint_3 +;CHECK: %67 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %66 +;CHECK: OpStore %67 %uint_4 +;CHECK: %70 = OpLoad %v4float %gl_FragCoord +;CHECK: %72 = OpBitcast %v4uint %70 +;CHECK: %73 = OpCompositeExtract %uint %72 0 +;CHECK: %74 = OpIAdd %uint %50 %uint_4 +;CHECK: %75 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %74 +;CHECK: OpStore %75 %73 +;CHECK: %76 = OpCompositeExtract %uint %72 1 +;CHECK: %78 = OpIAdd %uint %50 %uint_5 +;CHECK: %79 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %78 +;CHECK: OpStore %79 %76 ;CHECK: %80 = OpIAdd %uint %50 %uint_7 ;CHECK: %81 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %80 ;CHECK: OpStore %81 %37 @@ -9336,7 +9347,7 @@ TEST_F(InstBindlessTest, ImageBufferOOBWrite) { ;CHECK: %uint = OpTypeInt 32 0 ;CHECK: %uint_0 = OpConstant %uint 0 ;CHECK: %bool = OpTypeBool -;CHECK: %uint_3 = OpConstant %uint 3 +;CHECK: %uint_7 = OpConstant %uint 7 ;CHECK: %34 = OpTypeFunction %void %uint %uint %uint %uint %uint ;CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint ;CHECK: %_struct_42 = OpTypeStruct %uint %_runtimearr_uint @@ -9348,11 +9359,11 @@ TEST_F(InstBindlessTest, ImageBufferOOBWrite) { ;CHECK: %uint_1 = OpConstant %uint 1 ;CHECK: %uint_23 = OpConstant %uint 23 ;CHECK: %uint_2 = OpConstant %uint 2 +;CHECK: %uint_3 = OpConstant %uint 3 ;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float ;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: %v4uint = OpTypeVector %uint 4 ;CHECK: %uint_5 = OpConstant %uint 5 -;CHECK: %uint_7 = OpConstant %uint 7 ;CHECK: %uint_8 = OpConstant %uint 8 ;CHECK: %uint_9 = OpConstant %uint 9 ;CHECK: %uint_10 = OpConstant %uint 10 @@ -9380,7 +9391,7 @@ TEST_F(InstBindlessTest, ImageBufferOOBWrite) { ;CHECK: OpImageWrite %32 %14 %18 ;CHECK: OpBranch %29 ;CHECK: %31 = OpLabel -;CHECK: %91 = OpFunctionCall %void %33 %uint_34 %uint_3 %uint_0 %23 %25 +;CHECK: %91 = OpFunctionCall %void %33 %uint_34 %uint_7 %uint_0 %23 %25 ;CHECK: OpBranch %29 ;CHECK: %29 = OpLabel OpReturn @@ -9409,19 +9420,19 @@ TEST_F(InstBindlessTest, ImageBufferOOBWrite) { ;CHECK: %62 = OpIAdd %uint %49 %uint_2 ;CHECK: %63 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %62 ;CHECK: OpStore %63 %35 -;CHECK: %64 = OpIAdd %uint %49 %uint_3 -;CHECK: %65 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %64 -;CHECK: OpStore %65 %uint_4 -;CHECK: %68 = OpLoad %v4float %gl_FragCoord -;CHECK: %70 = OpBitcast %v4uint %68 -;CHECK: %71 = OpCompositeExtract %uint %70 0 -;CHECK: %72 = OpIAdd %uint %49 %uint_4 -;CHECK: %73 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %72 -;CHECK: OpStore %73 %71 -;CHECK: %74 = OpCompositeExtract %uint %70 1 -;CHECK: %76 = OpIAdd %uint %49 %uint_5 -;CHECK: %77 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %76 -;CHECK: OpStore %77 %74 +;CHECK: %65 = OpIAdd %uint %49 %uint_3 +;CHECK: %66 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %65 +;CHECK: OpStore %66 %uint_4 +;CHECK: %69 = OpLoad %v4float %gl_FragCoord +;CHECK: %71 = OpBitcast %v4uint %69 +;CHECK: %72 = OpCompositeExtract %uint %71 0 +;CHECK: %73 = OpIAdd %uint %49 %uint_4 +;CHECK: %74 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %73 +;CHECK: OpStore %74 %72 +;CHECK: %75 = OpCompositeExtract %uint %71 1 +;CHECK: %77 = OpIAdd %uint %49 %uint_5 +;CHECK: %78 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %77 +;CHECK: OpStore %78 %75 ;CHECK: %79 = OpIAdd %uint %49 %uint_7 ;CHECK: %80 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %79 ;CHECK: OpStore %80 %36 @@ -9500,7 +9511,7 @@ TEST_F(InstBindlessTest, TextureBufferOOBFetch) { ;CHECK: %uint = OpTypeInt 32 0 ;CHECK: %uint_0 = OpConstant %uint 0 ;CHECK: %bool = OpTypeBool -;CHECK: %uint_3 = OpConstant %uint 3 +;CHECK: %uint_6 = OpConstant %uint 6 ;CHECK: %35 = OpTypeFunction %void %uint %uint %uint %uint %uint ;CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint ;CHECK: %_struct_43 = OpTypeStruct %uint %_runtimearr_uint @@ -9512,6 +9523,7 @@ TEST_F(InstBindlessTest, TextureBufferOOBFetch) { ;CHECK: %uint_1 = OpConstant %uint 1 ;CHECK: %uint_23 = OpConstant %uint 23 ;CHECK: %uint_2 = OpConstant %uint 2 +;CHECK: %uint_3 = OpConstant %uint 3 ;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float ;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: %v4uint = OpTypeVector %uint 4 @@ -9521,7 +9533,7 @@ TEST_F(InstBindlessTest, TextureBufferOOBFetch) { ;CHECK: %uint_9 = OpConstant %uint 9 ;CHECK: %uint_10 = OpConstant %uint 10 ;CHECK: %uint_32 = OpConstant %uint 32 -;CHECK: %93 = OpConstantNull %v4float +;CHECK: %94 = OpConstantNull %v4float %main = OpFunction %void None %3 %5 = OpLabel ;CHECK: OpBranch %21 @@ -9546,11 +9558,11 @@ TEST_F(InstBindlessTest, TextureBufferOOBFetch) { ;CHECK: %33 = OpImageFetch %v4float %32 %17 ;CHECK: OpBranch %29 ;CHECK: %31 = OpLabel -;CHECK: %92 = OpFunctionCall %void %34 %uint_32 %uint_3 %uint_0 %23 %25 +;CHECK: %93 = OpFunctionCall %void %34 %uint_32 %uint_6 %uint_0 %23 %25 ;CHECK: OpBranch %29 ;CHECK: %29 = OpLabel -;CHECK: %94 = OpPhi %v4float %33 %30 %93 %31 -;CHECK: OpStore %x %94 +;CHECK: %95 = OpPhi %v4float %33 %30 %94 %31 +;CHECK: OpStore %x %95 OpReturn OpFunctionEnd ;CHECK: %34 = OpFunction %void None %35 @@ -9577,31 +9589,31 @@ TEST_F(InstBindlessTest, TextureBufferOOBFetch) { ;CHECK: %63 = OpIAdd %uint %50 %uint_2 ;CHECK: %64 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %63 ;CHECK: OpStore %64 %36 -;CHECK: %65 = OpIAdd %uint %50 %uint_3 -;CHECK: %66 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %65 -;CHECK: OpStore %66 %uint_4 -;CHECK: %69 = OpLoad %v4float %gl_FragCoord -;CHECK: %71 = OpBitcast %v4uint %69 -;CHECK: %72 = OpCompositeExtract %uint %71 0 -;CHECK: %73 = OpIAdd %uint %50 %uint_4 -;CHECK: %74 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %73 -;CHECK: OpStore %74 %72 -;CHECK: %75 = OpCompositeExtract %uint %71 1 -;CHECK: %77 = OpIAdd %uint %50 %uint_5 -;CHECK: %78 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %77 -;CHECK: OpStore %78 %75 -;CHECK: %80 = OpIAdd %uint %50 %uint_7 -;CHECK: %81 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %80 -;CHECK: OpStore %81 %37 -;CHECK: %83 = OpIAdd %uint %50 %uint_8 -;CHECK: %84 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %83 -;CHECK: OpStore %84 %38 -;CHECK: %86 = OpIAdd %uint %50 %uint_9 -;CHECK: %87 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %86 -;CHECK: OpStore %87 %39 -;CHECK: %89 = OpIAdd %uint %50 %uint_10 -;CHECK: %90 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %89 -;CHECK: OpStore %90 %40 +;CHECK: %66 = OpIAdd %uint %50 %uint_3 +;CHECK: %67 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %66 +;CHECK: OpStore %67 %uint_4 +;CHECK: %70 = OpLoad %v4float %gl_FragCoord +;CHECK: %72 = OpBitcast %v4uint %70 +;CHECK: %73 = OpCompositeExtract %uint %72 0 +;CHECK: %74 = OpIAdd %uint %50 %uint_4 +;CHECK: %75 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %74 +;CHECK: OpStore %75 %73 +;CHECK: %76 = OpCompositeExtract %uint %72 1 +;CHECK: %78 = OpIAdd %uint %50 %uint_5 +;CHECK: %79 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %78 +;CHECK: OpStore %79 %76 +;CHECK: %81 = OpIAdd %uint %50 %uint_7 +;CHECK: %82 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %81 +;CHECK: OpStore %82 %37 +;CHECK: %84 = OpIAdd %uint %50 %uint_8 +;CHECK: %85 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %84 +;CHECK: OpStore %85 %38 +;CHECK: %87 = OpIAdd %uint %50 %uint_9 +;CHECK: %88 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %87 +;CHECK: OpStore %88 %39 +;CHECK: %90 = OpIAdd %uint %50 %uint_10 +;CHECK: %91 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %90 +;CHECK: OpStore %91 %40 ;CHECK: OpBranch %54 ;CHECK: %54 = OpLabel ;CHECK: OpReturn @@ -9669,7 +9681,7 @@ TEST_F(InstBindlessTest, SamplerBufferOOBFetch) { ;CHECK: %uint = OpTypeInt 32 0 ;CHECK: %uint_0 = OpConstant %uint 0 ;CHECK: %bool = OpTypeBool -;CHECK: %uint_3 = OpConstant %uint 3 +;CHECK: %uint_6 = OpConstant %uint 6 ;CHECK: %38 = OpTypeFunction %void %uint %uint %uint %uint %uint ;CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint ;CHECK: %_struct_46 = OpTypeStruct %uint %_runtimearr_uint @@ -9681,6 +9693,7 @@ TEST_F(InstBindlessTest, SamplerBufferOOBFetch) { ;CHECK: %uint_1 = OpConstant %uint 1 ;CHECK: %uint_23 = OpConstant %uint 23 ;CHECK: %uint_2 = OpConstant %uint 2 +;CHECK: %uint_3 = OpConstant %uint 3 ;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float ;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: %v4uint = OpTypeVector %uint 4 @@ -9690,7 +9703,7 @@ TEST_F(InstBindlessTest, SamplerBufferOOBFetch) { ;CHECK: %uint_9 = OpConstant %uint 9 ;CHECK: %uint_10 = OpConstant %uint 10 ;CHECK: %uint_34 = OpConstant %uint 34 -;CHECK: %96 = OpConstantNull %v4float +;CHECK: %97 = OpConstantNull %v4float %main = OpFunction %void None %3 %5 = OpLabel ;CHECK: OpBranch %23 @@ -9717,11 +9730,11 @@ TEST_F(InstBindlessTest, SamplerBufferOOBFetch) { ;CHECK: %36 = OpImageFetch %v4float %35 %18 ;CHECK: OpBranch %31 ;CHECK: %33 = OpLabel -;CHECK: %95 = OpFunctionCall %void %37 %uint_34 %uint_3 %uint_0 %25 %27 +;CHECK: %96 = OpFunctionCall %void %37 %uint_34 %uint_6 %uint_0 %25 %27 ;CHECK: OpBranch %31 ;CHECK: %31 = OpLabel -;CHECK: %97 = OpPhi %v4float %36 %32 %96 %33 -;CHECK: OpStore %x %97 +;CHECK: %98 = OpPhi %v4float %36 %32 %97 %33 +;CHECK: OpStore %x %98 OpReturn OpFunctionEnd ;CHECK: %37 = OpFunction %void None %38 @@ -9748,31 +9761,31 @@ TEST_F(InstBindlessTest, SamplerBufferOOBFetch) { ;CHECK: %66 = OpIAdd %uint %53 %uint_2 ;CHECK: %67 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %66 ;CHECK: OpStore %67 %39 -;CHECK: %68 = OpIAdd %uint %53 %uint_3 -;CHECK: %69 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %68 -;CHECK: OpStore %69 %uint_4 -;CHECK: %72 = OpLoad %v4float %gl_FragCoord -;CHECK: %74 = OpBitcast %v4uint %72 -;CHECK: %75 = OpCompositeExtract %uint %74 0 -;CHECK: %76 = OpIAdd %uint %53 %uint_4 -;CHECK: %77 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %76 -;CHECK: OpStore %77 %75 -;CHECK: %78 = OpCompositeExtract %uint %74 1 -;CHECK: %80 = OpIAdd %uint %53 %uint_5 -;CHECK: %81 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %80 -;CHECK: OpStore %81 %78 -;CHECK: %83 = OpIAdd %uint %53 %uint_7 -;CHECK: %84 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %83 -;CHECK: OpStore %84 %40 -;CHECK: %86 = OpIAdd %uint %53 %uint_8 -;CHECK: %87 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %86 -;CHECK: OpStore %87 %41 -;CHECK: %89 = OpIAdd %uint %53 %uint_9 -;CHECK: %90 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %89 -;CHECK: OpStore %90 %42 -;CHECK: %92 = OpIAdd %uint %53 %uint_10 -;CHECK: %93 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %92 -;CHECK: OpStore %93 %43 +;CHECK: %69 = OpIAdd %uint %53 %uint_3 +;CHECK: %70 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %69 +;CHECK: OpStore %70 %uint_4 +;CHECK: %73 = OpLoad %v4float %gl_FragCoord +;CHECK: %75 = OpBitcast %v4uint %73 +;CHECK: %76 = OpCompositeExtract %uint %75 0 +;CHECK: %77 = OpIAdd %uint %53 %uint_4 +;CHECK: %78 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %77 +;CHECK: OpStore %78 %76 +;CHECK: %79 = OpCompositeExtract %uint %75 1 +;CHECK: %81 = OpIAdd %uint %53 %uint_5 +;CHECK: %82 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %81 +;CHECK: OpStore %82 %79 +;CHECK: %84 = OpIAdd %uint %53 %uint_7 +;CHECK: %85 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %84 +;CHECK: OpStore %85 %40 +;CHECK: %87 = OpIAdd %uint %53 %uint_8 +;CHECK: %88 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %87 +;CHECK: OpStore %88 %41 +;CHECK: %90 = OpIAdd %uint %53 %uint_9 +;CHECK: %91 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %90 +;CHECK: OpStore %91 %42 +;CHECK: %93 = OpIAdd %uint %53 %uint_10 +;CHECK: %94 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %93 +;CHECK: OpStore %94 %43 ;CHECK: OpBranch %57 ;CHECK: %57 = OpLabel ;CHECK: OpReturn @@ -9847,7 +9860,7 @@ TEST_F(InstBindlessTest, SamplerBufferConstructorOOBFetch) { ;CHECK: %uint = OpTypeInt 32 0 ;CHECK: %uint_0 = OpConstant %uint 0 ;CHECK: %bool = OpTypeBool -;CHECK: %uint_3 = OpConstant %uint 3 +;CHECK: %uint_6 = OpConstant %uint 6 ;CHECK: %44 = OpTypeFunction %void %uint %uint %uint %uint %uint ;CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint ;CHECK: %_struct_52 = OpTypeStruct %uint %_runtimearr_uint @@ -9859,6 +9872,7 @@ TEST_F(InstBindlessTest, SamplerBufferConstructorOOBFetch) { ;CHECK: %uint_1 = OpConstant %uint 1 ;CHECK: %uint_23 = OpConstant %uint 23 ;CHECK: %uint_2 = OpConstant %uint 2 +;CHECK: %uint_3 = OpConstant %uint 3 ;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float ;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: %v4uint = OpTypeVector %uint 4 @@ -9868,7 +9882,7 @@ TEST_F(InstBindlessTest, SamplerBufferConstructorOOBFetch) { ;CHECK: %uint_9 = OpConstant %uint 9 ;CHECK: %uint_10 = OpConstant %uint 10 ;CHECK: %uint_42 = OpConstant %uint 42 -;CHECK: %102 = OpConstantNull %v4float +;CHECK: %103 = OpConstantNull %v4float %main = OpFunction %void None %3 %5 = OpLabel ;CHECK: OpBranch %28 @@ -9898,11 +9912,11 @@ TEST_F(InstBindlessTest, SamplerBufferConstructorOOBFetch) { ;CHECK: %42 = OpImageFetch %v4float %41 %23 ;CHECK: OpBranch %36 ;CHECK: %38 = OpLabel -;CHECK: %101 = OpFunctionCall %void %43 %uint_42 %uint_3 %uint_0 %30 %32 +;CHECK: %102 = OpFunctionCall %void %43 %uint_42 %uint_6 %uint_0 %30 %32 ;CHECK: OpBranch %36 ;CHECK: %36 = OpLabel -;CHECK: %103 = OpPhi %v4float %42 %37 %102 %38 -;CHECK: OpStore %x %103 +;CHECK: %104 = OpPhi %v4float %42 %37 %103 %38 +;CHECK: OpStore %x %104 OpReturn OpFunctionEnd ;CHECK: %43 = OpFunction %void None %44 @@ -9929,31 +9943,31 @@ TEST_F(InstBindlessTest, SamplerBufferConstructorOOBFetch) { ;CHECK: %72 = OpIAdd %uint %59 %uint_2 ;CHECK: %73 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %72 ;CHECK: OpStore %73 %45 -;CHECK: %74 = OpIAdd %uint %59 %uint_3 -;CHECK: %75 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %74 -;CHECK: OpStore %75 %uint_4 -;CHECK: %78 = OpLoad %v4float %gl_FragCoord -;CHECK: %80 = OpBitcast %v4uint %78 -;CHECK: %81 = OpCompositeExtract %uint %80 0 -;CHECK: %82 = OpIAdd %uint %59 %uint_4 -;CHECK: %83 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %82 -;CHECK: OpStore %83 %81 -;CHECK: %84 = OpCompositeExtract %uint %80 1 -;CHECK: %86 = OpIAdd %uint %59 %uint_5 -;CHECK: %87 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %86 -;CHECK: OpStore %87 %84 -;CHECK: %89 = OpIAdd %uint %59 %uint_7 -;CHECK: %90 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %89 -;CHECK: OpStore %90 %46 -;CHECK: %92 = OpIAdd %uint %59 %uint_8 -;CHECK: %93 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %92 -;CHECK: OpStore %93 %47 -;CHECK: %95 = OpIAdd %uint %59 %uint_9 -;CHECK: %96 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %95 -;CHECK: OpStore %96 %48 -;CHECK: %98 = OpIAdd %uint %59 %uint_10 -;CHECK: %99 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %98 -;CHECK: OpStore %99 %49 +;CHECK: %75 = OpIAdd %uint %59 %uint_3 +;CHECK: %76 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %75 +;CHECK: OpStore %76 %uint_4 +;CHECK: %79 = OpLoad %v4float %gl_FragCoord +;CHECK: %81 = OpBitcast %v4uint %79 +;CHECK: %82 = OpCompositeExtract %uint %81 0 +;CHECK: %83 = OpIAdd %uint %59 %uint_4 +;CHECK: %84 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %83 +;CHECK: OpStore %84 %82 +;CHECK: %85 = OpCompositeExtract %uint %81 1 +;CHECK: %87 = OpIAdd %uint %59 %uint_5 +;CHECK: %88 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %87 +;CHECK: OpStore %88 %85 +;CHECK: %90 = OpIAdd %uint %59 %uint_7 +;CHECK: %91 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %90 +;CHECK: OpStore %91 %46 +;CHECK: %93 = OpIAdd %uint %59 %uint_8 +;CHECK: %94 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %93 +;CHECK: OpStore %94 %47 +;CHECK: %96 = OpIAdd %uint %59 %uint_9 +;CHECK: %97 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %96 +;CHECK: OpStore %97 %48 +;CHECK: %99 = OpIAdd %uint %59 %uint_10 +;CHECK: %100 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %99 +;CHECK: OpStore %100 %49 ;CHECK: OpBranch %63 ;CHECK: %63 = OpLabel ;CHECK: OpReturn -- cgit v1.2.3 From 7bbe1a316419ee0c84cbb7141999dc70352307ee Mon Sep 17 00:00:00 2001 From: dan sinclair Date: Tue, 12 Jan 2021 11:36:31 -0500 Subject: Revert "Generate differentiated error codes for buffer oob checking (#4097)" (#4100) This reverts commit c32277c0ba0df26c8661a7daadc8743dc5a10bd3. --- include/spirv-tools/instrument.hpp | 5 +- source/opt/inst_bindless_check_pass.cpp | 44 +-- source/opt/inst_bindless_check_pass.h | 1 - test/opt/inst_bindless_check_test.cpp | 506 ++++++++++++++++---------------- 4 files changed, 251 insertions(+), 305 deletions(-) diff --git a/include/spirv-tools/instrument.hpp b/include/spirv-tools/instrument.hpp index 05a0472e..2b47a564 100644 --- a/include/spirv-tools/instrument.hpp +++ b/include/spirv-tools/instrument.hpp @@ -170,10 +170,7 @@ static const int kInstMaxOutCnt = kInstStageOutCnt + 4; static const int kInstErrorBindlessBounds = 0; static const int kInstErrorBindlessUninit = 1; static const int kInstErrorBuffAddrUnallocRef = 2; -// Deleted: static const int kInstErrorBindlessBuffOOB = 3; -// This comment will will remain for 2 releases to allow -// for the transition of all builds. Buffer OOB is -// generating the following four differentiated codes instead: +static const int kInstErrorBindlessBuffOOB = 3; static const int kInstErrorBuffOOBUniform = 4; static const int kInstErrorBuffOOBStorage = 5; static const int kInstErrorBuffOOBUniformTexel = 6; diff --git a/source/opt/inst_bindless_check_pass.cpp b/source/opt/inst_bindless_check_pass.cpp index 5607239a..00857343 100644 --- a/source/opt/inst_bindless_check_pass.cpp +++ b/source/opt/inst_bindless_check_pass.cpp @@ -27,16 +27,13 @@ static const int kSpvCopyObjectOperandIdInIdx = 0; static const int kSpvLoadPtrIdInIdx = 0; static const int kSpvAccessChainBaseIdInIdx = 0; static const int kSpvAccessChainIndex0IdInIdx = 1; -static const int kSpvTypeArrayTypeIdInIdx = 0; static const int kSpvTypeArrayLengthIdInIdx = 1; static const int kSpvConstantValueInIdx = 0; static const int kSpvVariableStorageClassInIdx = 0; -static const int kSpvTypePtrTypeIdInIdx = 1; static const int kSpvTypeImageDim = 1; static const int kSpvTypeImageDepth = 2; static const int kSpvTypeImageArrayed = 3; static const int kSpvTypeImageMS = 4; -static const int kSpvTypeImageSampled = 5; } // anonymous namespace // Avoid unused variable warning/error on Linux @@ -209,40 +206,13 @@ bool InstBindlessCheckPass::AnalyzeDescriptorReference(Instruction* ref_inst, var_inst->GetSingleWordInOperand(kSpvVariableStorageClassInIdx); switch (storage_class) { case SpvStorageClassUniform: + case SpvStorageClassUniformConstant: case SpvStorageClassStorageBuffer: break; default: return false; break; } - // Check for deprecated storage block form - if (storage_class == SpvStorageClassUniform) { - uint32_t var_ty_id = var_inst->type_id(); - Instruction* var_ty_inst = get_def_use_mgr()->GetDef(var_ty_id); - uint32_t ptr_ty_id = - var_ty_inst->GetSingleWordInOperand(kSpvTypePtrTypeIdInIdx); - Instruction* ptr_ty_inst = get_def_use_mgr()->GetDef(ptr_ty_id); - SpvOp ptr_ty_op = ptr_ty_inst->opcode(); - uint32_t block_ty_id = - (ptr_ty_op == SpvOpTypeArray || ptr_ty_op == SpvOpTypeRuntimeArray) - ? ptr_ty_inst->GetSingleWordInOperand(kSpvTypeArrayTypeIdInIdx) - : ptr_ty_id; - assert(get_def_use_mgr()->GetDef(block_ty_id)->opcode() == - SpvOpTypeStruct && - "unexpected block type"); - bool block_found = get_decoration_mgr()->FindDecoration( - block_ty_id, SpvDecorationBlock, - [](const Instruction&) { return true; }); - if (!block_found) { - // If block decoration not found, verify deprecated form of SSBO - bool buffer_block_found = get_decoration_mgr()->FindDecoration( - block_ty_id, SpvDecorationBufferBlock, - [](const Instruction&) { return true; }); - USE_ASSERT(buffer_block_found && "block decoration not found"); - storage_class = SpvStorageClassStorageBuffer; - } - } - ref->strg_class = storage_class; Instruction* desc_type_inst = GetPointeeTypeInst(var_inst); switch (desc_type_inst->opcode()) { case SpvOpTypeArray: @@ -695,10 +665,8 @@ void InstBindlessCheckPass::GenDescInitCheckCode( // for the referenced value. Instruction* ult_inst = builder.AddBinaryOp(GetBoolId(), SpvOpULessThan, ref_id, init_id); - uint32_t error = init_check ? kInstErrorBindlessUninit - : (ref.strg_class == SpvStorageClassUniform - ? kInstErrorBuffOOBUniform - : kInstErrorBuffOOBStorage); + uint32_t error = + init_check ? kInstErrorBindlessUninit : kInstErrorBindlessBuffOOB; uint32_t error_id = builder.GetUintConstantId(error); GenCheckCode(ult_inst->result_id(), error_id, init_check ? 0 : ref_id, init_check ? builder.GetUintConstantId(0u) : init_id, stage_idx, @@ -764,11 +732,7 @@ void InstBindlessCheckPass::GenTexBuffCheckCode( // for the referenced value. Instruction* ult_inst = builder.AddBinaryOp(GetBoolId(), SpvOpULessThan, coord_id, size_id); - uint32_t error = - (image_ty_inst->GetSingleWordInOperand(kSpvTypeImageSampled) == 2) - ? kInstErrorBuffOOBStorageTexel - : kInstErrorBuffOOBUniformTexel; - uint32_t error_id = builder.GetUintConstantId(error); + uint32_t error_id = builder.GetUintConstantId(kInstErrorBindlessBuffOOB); GenCheckCode(ult_inst->result_id(), error_id, coord_id, size_id, stage_idx, &ref, new_blocks); // Move original block's remaining code into remainder/merge block and add diff --git a/source/opt/inst_bindless_check_pass.h b/source/opt/inst_bindless_check_pass.h index cd961805..a7dff75f 100644 --- a/source/opt/inst_bindless_check_pass.h +++ b/source/opt/inst_bindless_check_pass.h @@ -130,7 +130,6 @@ class InstBindlessCheckPass : public InstrumentPass { uint32_t ptr_id; uint32_t var_id; uint32_t desc_idx_id; - uint32_t strg_class; Instruction* ref_inst; } RefAnalysis; diff --git a/test/opt/inst_bindless_check_test.cpp b/test/opt/inst_bindless_check_test.cpp index 1a42329b..f1899627 100644 --- a/test/opt/inst_bindless_check_test.cpp +++ b/test/opt/inst_bindless_check_test.cpp @@ -7308,15 +7308,15 @@ TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) { ;CHECK: %_ptr_StorageBuffer__struct_128 = OpTypePointer StorageBuffer %_struct_128 ;CHECK: %130 = OpVariable %_ptr_StorageBuffer__struct_128 StorageBuffer ;CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint - ;CHECK: %uint_4 = OpConstant %uint 4 + ;CHECK: %uint_3 = OpConstant %uint 3 ;CHECK: %148 = OpTypeFunction %void %uint %uint %uint %uint %uint ;CHECK: %_struct_155 = OpTypeStruct %uint %_runtimearr_uint ;CHECK: %_ptr_StorageBuffer__struct_155 = OpTypePointer StorageBuffer %_struct_155 ;CHECK: %157 = OpVariable %_ptr_StorageBuffer__struct_155 StorageBuffer ;CHECK: %uint_11 = OpConstant %uint 11 + ;CHECK: %uint_4 = OpConstant %uint 4 ;CHECK: %uint_23 = OpConstant %uint 23 ;CHECK: %uint_2 = OpConstant %uint 2 - ;CHECK: %uint_3 = OpConstant %uint 3 ;CHECK:%_ptr_Input_v4float = OpTypePointer Input %v4float ;CHECK:%gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: %v4uint = OpTypeVector %uint 4 @@ -7352,7 +7352,7 @@ TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) { ;CHECK: %146 = OpLoad %v2float %86 ;CHECK: OpBranch %143 ;CHECK: %145 = OpLabel - ;CHECK: %201 = OpFunctionCall %void %147 %uint_71 %uint_4 %uint_0 %119 %140 + ;CHECK: %201 = OpFunctionCall %void %147 %uint_71 %uint_3 %uint_0 %119 %140 ;CHECK: OpBranch %143 ;CHECK: %143 = OpLabel ;CHECK: %203 = OpPhi %v2float %146 %144 %202 %145 @@ -7369,7 +7369,7 @@ TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) { ;CHECK: %209 = OpLoad %v2float %89 ;CHECK: OpBranch %206 ;CHECK: %208 = OpLabel - ;CHECK: %211 = OpFunctionCall %void %147 %uint_75 %uint_4 %uint_0 %204 %140 + ;CHECK: %211 = OpFunctionCall %void %147 %uint_75 %uint_3 %uint_0 %204 %140 ;CHECK: OpBranch %206 ;CHECK: %206 = OpLabel ;CHECK: %212 = OpPhi %v2float %209 %207 %202 %208 @@ -7409,49 +7409,49 @@ TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) { ;CHECK: %153 = OpFunctionParameter %uint ;CHECK: %154 = OpLabel ;CHECK: %158 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_0 - ;CHECK: %160 = OpAtomicIAdd %uint %158 %uint_4 %uint_0 %uint_11 - ;CHECK: %161 = OpIAdd %uint %160 %uint_11 - ;CHECK: %162 = OpArrayLength %uint %157 1 - ;CHECK: %163 = OpULessThanEqual %bool %161 %162 - ;CHECK: OpSelectionMerge %164 None - ;CHECK: OpBranchConditional %163 %165 %164 - ;CHECK: %165 = OpLabel - ;CHECK: %166 = OpIAdd %uint %160 %uint_0 - ;CHECK: %167 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %166 - ;CHECK: OpStore %167 %uint_11 - ;CHECK: %169 = OpIAdd %uint %160 %uint_1 - ;CHECK: %170 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %169 - ;CHECK: OpStore %170 %uint_23 - ;CHECK: %172 = OpIAdd %uint %160 %uint_2 - ;CHECK: %173 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %172 - ;CHECK: OpStore %173 %149 - ;CHECK: %175 = OpIAdd %uint %160 %uint_3 + ;CHECK: %161 = OpAtomicIAdd %uint %158 %uint_4 %uint_0 %uint_11 + ;CHECK: %162 = OpIAdd %uint %161 %uint_11 + ;CHECK: %163 = OpArrayLength %uint %157 1 + ;CHECK: %164 = OpULessThanEqual %bool %162 %163 + ;CHECK: OpSelectionMerge %165 None + ;CHECK: OpBranchConditional %164 %166 %165 + ;CHECK: %166 = OpLabel + ;CHECK: %167 = OpIAdd %uint %161 %uint_0 + ;CHECK: %168 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %167 + ;CHECK: OpStore %168 %uint_11 + ;CHECK: %170 = OpIAdd %uint %161 %uint_1 + ;CHECK: %171 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %170 + ;CHECK: OpStore %171 %uint_23 + ;CHECK: %173 = OpIAdd %uint %161 %uint_2 + ;CHECK: %174 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %173 + ;CHECK: OpStore %174 %149 + ;CHECK: %175 = OpIAdd %uint %161 %uint_3 ;CHECK: %176 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %175 ;CHECK: OpStore %176 %uint_4 ;CHECK: %179 = OpLoad %v4float %gl_FragCoord ;CHECK: %181 = OpBitcast %v4uint %179 ;CHECK: %182 = OpCompositeExtract %uint %181 0 - ;CHECK: %183 = OpIAdd %uint %160 %uint_4 + ;CHECK: %183 = OpIAdd %uint %161 %uint_4 ;CHECK: %184 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %183 ;CHECK: OpStore %184 %182 ;CHECK: %185 = OpCompositeExtract %uint %181 1 - ;CHECK: %187 = OpIAdd %uint %160 %uint_5 + ;CHECK: %187 = OpIAdd %uint %161 %uint_5 ;CHECK: %188 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %187 ;CHECK: OpStore %188 %185 - ;CHECK: %189 = OpIAdd %uint %160 %uint_7 + ;CHECK: %189 = OpIAdd %uint %161 %uint_7 ;CHECK: %190 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %189 ;CHECK: OpStore %190 %150 - ;CHECK: %192 = OpIAdd %uint %160 %uint_8 + ;CHECK: %192 = OpIAdd %uint %161 %uint_8 ;CHECK: %193 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %192 ;CHECK: OpStore %193 %151 - ;CHECK: %195 = OpIAdd %uint %160 %uint_9 + ;CHECK: %195 = OpIAdd %uint %161 %uint_9 ;CHECK: %196 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %195 ;CHECK: OpStore %196 %152 - ;CHECK: %198 = OpIAdd %uint %160 %uint_10 + ;CHECK: %198 = OpIAdd %uint %161 %uint_10 ;CHECK: %199 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %198 ;CHECK: OpStore %199 %153 - ;CHECK: OpBranch %164 - ;CHECK: %164 = OpLabel + ;CHECK: OpBranch %165 + ;CHECK: %165 = OpLabel ;CHECK: OpReturn ;CHECK: OpFunctionEnd )"; @@ -7596,14 +7596,14 @@ TEST_F(InstBindlessTest, UniformArrayRefNoDescInit) { ;CHECK: %113 = OpVariable %_ptr_StorageBuffer__struct_111 StorageBuffer ;CHECK:%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint ;CHECK: %bool = OpTypeBool -;CHECK: %uint_4 = OpConstant %uint 4 +;CHECK: %uint_3 = OpConstant %uint 3 ;CHECK: %132 = OpTypeFunction %void %uint %uint %uint %uint %uint ;CHECK:%_struct_139 = OpTypeStruct %uint %_runtimearr_uint ;CHECK:%_ptr_StorageBuffer__struct_139 = OpTypePointer StorageBuffer %_struct_139 ;CHECK: %141 = OpVariable %_ptr_StorageBuffer__struct_139 StorageBuffer ;CHECK: %uint_11 = OpConstant %uint 11 +;CHECK: %uint_4 = OpConstant %uint 4 ;CHECK: %uint_23 = OpConstant %uint 23 -;CHECK: %uint_3 = OpConstant %uint 3 ;CHECK:%_ptr_Input_v4float = OpTypePointer Input %v4float ;CHECK:%gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: %v4uint = OpTypeVector %uint 4 @@ -7637,7 +7637,7 @@ TEST_F(InstBindlessTest, UniformArrayRefNoDescInit) { ;CHECK: %130 = OpLoad %v2float %81 ;CHECK: OpBranch %127 ;CHECK: %129 = OpLabel -;CHECK: %184 = OpFunctionCall %void %131 %uint_78 %uint_4 %uint_0 %101 %123 +;CHECK: %184 = OpFunctionCall %void %131 %uint_78 %uint_3 %uint_0 %101 %123 ;CHECK: OpBranch %127 ;CHECK: %127 = OpLabel ;CHECK: %186 = OpPhi %v2float %130 %128 %185 %129 @@ -7674,49 +7674,49 @@ TEST_F(InstBindlessTest, UniformArrayRefNoDescInit) { ;CHECK: %137 = OpFunctionParameter %uint ;CHECK: %138 = OpLabel ;CHECK: %142 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_0 -;CHECK: %144 = OpAtomicIAdd %uint %142 %uint_4 %uint_0 %uint_11 -;CHECK: %145 = OpIAdd %uint %144 %uint_11 -;CHECK: %146 = OpArrayLength %uint %141 1 -;CHECK: %147 = OpULessThanEqual %bool %145 %146 -;CHECK: OpSelectionMerge %148 None -;CHECK: OpBranchConditional %147 %149 %148 -;CHECK: %149 = OpLabel -;CHECK: %150 = OpIAdd %uint %144 %uint_0 -;CHECK: %151 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %150 -;CHECK: OpStore %151 %uint_11 -;CHECK: %153 = OpIAdd %uint %144 %uint_1 -;CHECK: %154 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %153 -;CHECK: OpStore %154 %uint_23 -;CHECK: %155 = OpIAdd %uint %144 %uint_2 -;CHECK: %156 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %155 -;CHECK: OpStore %156 %133 -;CHECK: %158 = OpIAdd %uint %144 %uint_3 +;CHECK: %145 = OpAtomicIAdd %uint %142 %uint_4 %uint_0 %uint_11 +;CHECK: %146 = OpIAdd %uint %145 %uint_11 +;CHECK: %147 = OpArrayLength %uint %141 1 +;CHECK: %148 = OpULessThanEqual %bool %146 %147 +;CHECK: OpSelectionMerge %149 None +;CHECK: OpBranchConditional %148 %150 %149 +;CHECK: %150 = OpLabel +;CHECK: %151 = OpIAdd %uint %145 %uint_0 +;CHECK: %152 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %151 +;CHECK: OpStore %152 %uint_11 +;CHECK: %154 = OpIAdd %uint %145 %uint_1 +;CHECK: %155 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %154 +;CHECK: OpStore %155 %uint_23 +;CHECK: %156 = OpIAdd %uint %145 %uint_2 +;CHECK: %157 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %156 +;CHECK: OpStore %157 %133 +;CHECK: %158 = OpIAdd %uint %145 %uint_3 ;CHECK: %159 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %158 ;CHECK: OpStore %159 %uint_4 ;CHECK: %162 = OpLoad %v4float %gl_FragCoord ;CHECK: %164 = OpBitcast %v4uint %162 ;CHECK: %165 = OpCompositeExtract %uint %164 0 -;CHECK: %166 = OpIAdd %uint %144 %uint_4 +;CHECK: %166 = OpIAdd %uint %145 %uint_4 ;CHECK: %167 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %166 ;CHECK: OpStore %167 %165 ;CHECK: %168 = OpCompositeExtract %uint %164 1 -;CHECK: %170 = OpIAdd %uint %144 %uint_5 +;CHECK: %170 = OpIAdd %uint %145 %uint_5 ;CHECK: %171 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %170 ;CHECK: OpStore %171 %168 -;CHECK: %172 = OpIAdd %uint %144 %uint_7 +;CHECK: %172 = OpIAdd %uint %145 %uint_7 ;CHECK: %173 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %172 ;CHECK: OpStore %173 %134 -;CHECK: %175 = OpIAdd %uint %144 %uint_8 +;CHECK: %175 = OpIAdd %uint %145 %uint_8 ;CHECK: %176 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %175 ;CHECK: OpStore %176 %135 -;CHECK: %178 = OpIAdd %uint %144 %uint_9 +;CHECK: %178 = OpIAdd %uint %145 %uint_9 ;CHECK: %179 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %178 ;CHECK: OpStore %179 %136 -;CHECK: %181 = OpIAdd %uint %144 %uint_10 +;CHECK: %181 = OpIAdd %uint %145 %uint_10 ;CHECK: %182 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %181 ;CHECK: OpStore %182 %137 -;CHECK: OpBranch %148 -;CHECK: %148 = OpLabel +;CHECK: OpBranch %149 +;CHECK: %149 = OpLabel ;CHECK: OpReturn ;CHECK: OpFunctionEnd )"; @@ -7743,11 +7743,11 @@ TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) { OpExecutionMode %MainPs OriginUpperLeft OpSource HLSL 500 OpName %MainPs "MainPs" - OpName %PerBatchEnvMapConstantBuffer_t "PerBatchEnvMapConstantBuffer_t" - OpMemberName %PerBatchEnvMapConstantBuffer_t 0 "g_matEnvMapWorldToLocal" - OpMemberName %PerBatchEnvMapConstantBuffer_t 1 "g_vEnvironmentMapBoxMins" - OpMemberName %PerBatchEnvMapConstantBuffer_t 2 "g_TexOff" - OpName %_BindlessFastEnvMapCB_PS_t "_BindlessFastEnvMapCB_PS_t" + OpName %PerBatchEnvMapConstantBuffer_t +"PerBatchEnvMapConstantBuffer_t" OpMemberName %PerBatchEnvMapConstantBuffer_t 0 +"g_matEnvMapWorldToLocal" OpMemberName %PerBatchEnvMapConstantBuffer_t 1 +"g_vEnvironmentMapBoxMins" OpMemberName %PerBatchEnvMapConstantBuffer_t 2 +"g_TexOff" OpName %_BindlessFastEnvMapCB_PS_t "_BindlessFastEnvMapCB_PS_t" OpMemberName %_BindlessFastEnvMapCB_PS_t 0 "g_envMapConstants" OpName %_ "" OpName %PerViewPushConst_t "PerViewPushConst_t" @@ -7831,15 +7831,15 @@ TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) { ;CHECK: %113 = OpVariable %_ptr_StorageBuffer__struct_111 StorageBuffer ;CHECK:%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint ;CHECK: %bool = OpTypeBool -;CHECK: %uint_4 = OpConstant %uint 4 +;CHECK: %uint_3 = OpConstant %uint 3 ;CHECK: %135 = OpTypeFunction %void %uint %uint %uint %uint %uint ;CHECK:%_struct_142 = OpTypeStruct %uint %_runtimearr_uint ;CHECK:%_ptr_StorageBuffer__struct_142 = OpTypePointer StorageBuffer %_struct_142 ;CHECK: %144 = OpVariable %_ptr_StorageBuffer__struct_142 StorageBuffer ;CHECK: %uint_11 = OpConstant %uint 11 +;CHECK: %uint_4 = OpConstant %uint 4 ;CHECK: %uint_1 = OpConstant %uint 1 ;CHECK: %uint_23 = OpConstant %uint 23 -;CHECK: %uint_3 = OpConstant %uint 3 ;CHECK:%_ptr_Input_v4float = OpTypePointer Input %v4float ;CHECK:%gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: %v4uint = OpTypeVector %uint 4 @@ -7878,15 +7878,13 @@ TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) { ;CHECK: %133 = OpLoad %v2float %81 ;CHECK: OpBranch %130 ;CHECK: %132 = OpLabel -;CHECK: %188 = OpFunctionCall %void %134 %uint_78 %uint_4 %uint_0 %101 %126 +;CHECK: %188 = OpFunctionCall %void %134 %uint_78 %uint_3 %uint_0 %101 %126 ;CHECK: OpBranch %130 ;CHECK: %130 = OpLabel ;CHECK: %190 = OpPhi %v2float %133 %131 %189 %132 ;CHECK: %86 = OpFAdd %v2float %66 %190 - %87 = OpLoad %46 %g_tColor - %88 = OpLoad %50 %g_sAniso - %89 = OpSampledImage %54 %87 %88 - %91 = OpImageSampleImplicitLod %v4float %89 %86 + %87 = OpLoad %46 %g_tColor %88 = OpLoad %50 %g_sAniso %89 = + OpSampledImage %54 %87 %88 %91 = OpImageSampleImplicitLod %v4float %89 %86 OpStore %_entryPointOutput_vColor %91 ;CHECK-NOT: %91 = OpImageSampleImplicitLod %v4float %89 %86 ;CHECK-NOT: OpStore %_entryPointOutput_vColor %91 @@ -7933,49 +7931,49 @@ TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) { ;CHECK: %140 = OpFunctionParameter %uint ;CHECK: %141 = OpLabel ;CHECK: %145 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_0 -;CHECK: %147 = OpAtomicIAdd %uint %145 %uint_4 %uint_0 %uint_11 -;CHECK: %148 = OpIAdd %uint %147 %uint_11 -;CHECK: %149 = OpArrayLength %uint %144 1 -;CHECK: %150 = OpULessThanEqual %bool %148 %149 -;CHECK: OpSelectionMerge %151 None -;CHECK: OpBranchConditional %150 %152 %151 -;CHECK: %152 = OpLabel -;CHECK: %153 = OpIAdd %uint %147 %uint_0 -;CHECK: %155 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %153 -;CHECK: OpStore %155 %uint_11 -;CHECK: %157 = OpIAdd %uint %147 %uint_1 -;CHECK: %158 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %157 -;CHECK: OpStore %158 %uint_23 -;CHECK: %159 = OpIAdd %uint %147 %uint_2 -;CHECK: %160 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %159 -;CHECK: OpStore %160 %136 -;CHECK: %162 = OpIAdd %uint %147 %uint_3 +;CHECK: %148 = OpAtomicIAdd %uint %145 %uint_4 %uint_0 %uint_11 +;CHECK: %149 = OpIAdd %uint %148 %uint_11 +;CHECK: %150 = OpArrayLength %uint %144 1 +;CHECK: %151 = OpULessThanEqual %bool %149 %150 +;CHECK: OpSelectionMerge %152 None +;CHECK: OpBranchConditional %151 %153 %152 +;CHECK: %153 = OpLabel +;CHECK: %154 = OpIAdd %uint %148 %uint_0 +;CHECK: %156 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %154 +;CHECK: OpStore %156 %uint_11 +;CHECK: %158 = OpIAdd %uint %148 %uint_1 +;CHECK: %159 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %158 +;CHECK: OpStore %159 %uint_23 +;CHECK: %160 = OpIAdd %uint %148 %uint_2 +;CHECK: %161 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %160 +;CHECK: OpStore %161 %136 +;CHECK: %162 = OpIAdd %uint %148 %uint_3 ;CHECK: %163 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %162 ;CHECK: OpStore %163 %uint_4 ;CHECK: %166 = OpLoad %v4float %gl_FragCoord ;CHECK: %168 = OpBitcast %v4uint %166 ;CHECK: %169 = OpCompositeExtract %uint %168 0 -;CHECK: %170 = OpIAdd %uint %147 %uint_4 +;CHECK: %170 = OpIAdd %uint %148 %uint_4 ;CHECK: %171 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %170 ;CHECK: OpStore %171 %169 ;CHECK: %172 = OpCompositeExtract %uint %168 1 -;CHECK: %174 = OpIAdd %uint %147 %uint_5 +;CHECK: %174 = OpIAdd %uint %148 %uint_5 ;CHECK: %175 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %174 ;CHECK: OpStore %175 %172 -;CHECK: %176 = OpIAdd %uint %147 %uint_7 +;CHECK: %176 = OpIAdd %uint %148 %uint_7 ;CHECK: %177 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %176 ;CHECK: OpStore %177 %137 -;CHECK: %179 = OpIAdd %uint %147 %uint_8 +;CHECK: %179 = OpIAdd %uint %148 %uint_8 ;CHECK: %180 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %179 ;CHECK: OpStore %180 %138 -;CHECK: %182 = OpIAdd %uint %147 %uint_9 +;CHECK: %182 = OpIAdd %uint %148 %uint_9 ;CHECK: %183 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %182 ;CHECK: OpStore %183 %139 -;CHECK: %185 = OpIAdd %uint %147 %uint_10 +;CHECK: %185 = OpIAdd %uint %148 %uint_10 ;CHECK: %186 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %185 ;CHECK: OpStore %186 %140 -;CHECK: OpBranch %151 -;CHECK: %151 = OpLabel +;CHECK: OpBranch %152 +;CHECK: %152 = OpLabel ;CHECK: OpReturn ;CHECK: OpFunctionEnd )"; @@ -8346,15 +8344,15 @@ TEST_F(InstBindlessTest, UniformArray16bitIdxRef) { ;CHECK: %69 = OpVariable %_ptr_StorageBuffer__struct_67 StorageBuffer ;CHECK:%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint ;CHECK: %bool = OpTypeBool -;CHECK: %uint_4 = OpConstant %uint 4 +;CHECK: %uint_3 = OpConstant %uint 3 ;CHECK: %88 = OpTypeFunction %void %uint %uint %uint %uint %uint ;CHECK: %_struct_95 = OpTypeStruct %uint %_runtimearr_uint ;CHECK:%_ptr_StorageBuffer__struct_95 = OpTypePointer StorageBuffer %_struct_95 ;CHECK: %97 = OpVariable %_ptr_StorageBuffer__struct_95 StorageBuffer ;CHECK: %uint_11 = OpConstant %uint 11 +;CHECK: %uint_4 = OpConstant %uint 4 ;CHECK: %uint_23 = OpConstant %uint 23 ;CHECK: %uint_2 = OpConstant %uint 2 -;CHECK: %uint_3 = OpConstant %uint 3 ;CHECK:%_ptr_Input_v4float = OpTypePointer Input %v4float ;CHECK:%gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: %v4uint = OpTypeVector %uint 4 @@ -8391,7 +8389,7 @@ TEST_F(InstBindlessTest, UniformArray16bitIdxRef) { ;CHECK: %86 = OpLoad %v2float %41 ;CHECK: OpBranch %83 ;CHECK: %85 = OpLabel -;CHECK: %141 = OpFunctionCall %void %87 %uint_81 %uint_4 %uint_0 %58 %79 +;CHECK: %141 = OpFunctionCall %void %87 %uint_81 %uint_3 %uint_0 %58 %79 ;CHECK: OpBranch %83 ;CHECK: %83 = OpLabel ;CHECK: %143 = OpPhi %v2float %86 %84 %142 %85 @@ -8426,49 +8424,49 @@ TEST_F(InstBindlessTest, UniformArray16bitIdxRef) { ;CHECK: %93 = OpFunctionParameter %uint ;CHECK: %94 = OpLabel ;CHECK: %98 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_0 -;CHECK: %100 = OpAtomicIAdd %uint %98 %uint_4 %uint_0 %uint_11 -;CHECK: %101 = OpIAdd %uint %100 %uint_11 -;CHECK: %102 = OpArrayLength %uint %97 1 -;CHECK: %103 = OpULessThanEqual %bool %101 %102 -;CHECK: OpSelectionMerge %104 None -;CHECK: OpBranchConditional %103 %105 %104 -;CHECK: %105 = OpLabel -;CHECK: %106 = OpIAdd %uint %100 %uint_0 -;CHECK: %107 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %106 -;CHECK: OpStore %107 %uint_11 -;CHECK: %109 = OpIAdd %uint %100 %uint_1 -;CHECK: %110 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %109 -;CHECK: OpStore %110 %uint_23 -;CHECK: %112 = OpIAdd %uint %100 %uint_2 -;CHECK: %113 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %112 -;CHECK: OpStore %113 %89 -;CHECK: %115 = OpIAdd %uint %100 %uint_3 +;CHECK: %101 = OpAtomicIAdd %uint %98 %uint_4 %uint_0 %uint_11 +;CHECK: %102 = OpIAdd %uint %101 %uint_11 +;CHECK: %103 = OpArrayLength %uint %97 1 +;CHECK: %104 = OpULessThanEqual %bool %102 %103 +;CHECK: OpSelectionMerge %105 None +;CHECK: OpBranchConditional %104 %106 %105 +;CHECK: %106 = OpLabel +;CHECK: %107 = OpIAdd %uint %101 %uint_0 +;CHECK: %108 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %107 +;CHECK: OpStore %108 %uint_11 +;CHECK: %110 = OpIAdd %uint %101 %uint_1 +;CHECK: %111 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %110 +;CHECK: OpStore %111 %uint_23 +;CHECK: %113 = OpIAdd %uint %101 %uint_2 +;CHECK: %114 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %113 +;CHECK: OpStore %114 %89 +;CHECK: %115 = OpIAdd %uint %101 %uint_3 ;CHECK: %116 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %115 ;CHECK: OpStore %116 %uint_4 ;CHECK: %119 = OpLoad %v4float %gl_FragCoord ;CHECK: %121 = OpBitcast %v4uint %119 ;CHECK: %122 = OpCompositeExtract %uint %121 0 -;CHECK: %123 = OpIAdd %uint %100 %uint_4 +;CHECK: %123 = OpIAdd %uint %101 %uint_4 ;CHECK: %124 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %123 ;CHECK: OpStore %124 %122 ;CHECK: %125 = OpCompositeExtract %uint %121 1 -;CHECK: %127 = OpIAdd %uint %100 %uint_5 +;CHECK: %127 = OpIAdd %uint %101 %uint_5 ;CHECK: %128 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %127 ;CHECK: OpStore %128 %125 -;CHECK: %129 = OpIAdd %uint %100 %uint_7 +;CHECK: %129 = OpIAdd %uint %101 %uint_7 ;CHECK: %130 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %129 ;CHECK: OpStore %130 %90 -;CHECK: %132 = OpIAdd %uint %100 %uint_8 +;CHECK: %132 = OpIAdd %uint %101 %uint_8 ;CHECK: %133 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %132 ;CHECK: OpStore %133 %91 -;CHECK: %135 = OpIAdd %uint %100 %uint_9 +;CHECK: %135 = OpIAdd %uint %101 %uint_9 ;CHECK: %136 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %135 ;CHECK: OpStore %136 %92 -;CHECK: %138 = OpIAdd %uint %100 %uint_10 +;CHECK: %138 = OpIAdd %uint %101 %uint_10 ;CHECK: %139 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %138 ;CHECK: OpStore %139 %93 -;CHECK: OpBranch %104 -;CHECK: %104 = OpLabel +;CHECK: OpBranch %105 +;CHECK: %105 = OpLabel ;CHECK: OpReturn ;CHECK: OpFunctionEnd )"; @@ -8559,7 +8557,6 @@ TEST_F(InstBindlessTest, UniformMatrixRefRowMajor) { %_ptr_Input_v4float = OpTypePointer Input %v4float %a_position = OpVariable %_ptr_Input_v4float Input ;CHECK; %uint_0 = OpConstant %uint 0 -;CHECK; %uint_16 = OpConstant %uint 16 ;CHECK; %uint_4 = OpConstant %uint 4 ;CHECK; %uint_3 = OpConstant %uint 3 ;CHECK; %37 = OpTypeFunction %uint %uint %uint %uint @@ -8586,13 +8583,10 @@ TEST_F(InstBindlessTest, UniformMatrixRefRowMajor) { ;CHECK; %uint_10 = OpConstant %uint 10 ;CHECK; %uint_45 = OpConstant %uint 45 ;CHECK; %115 = OpConstantNull %float +;CHECK; %uint_27 = OpConstant %uint 27 %main = OpFunction %void None %3 %5 = OpLabel ;CHECK: %55 = OpFunctionCall %uint %36 %uint_1 %uint_0 %uint_0 -;CHECK: OpBranch %26 -;CHECK: %26 = OpLabel -;CHECK: OpBranch %25 -;CHECK: %25 = OpLabel %20 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %int_2 %uint_1 %21 = OpLoad %float %20 ;CHECK-NOT: %21 = OpLoad %float %20 @@ -8608,7 +8602,7 @@ TEST_F(InstBindlessTest, UniformMatrixRefRowMajor) { ;CHECK: %61 = OpLoad %float %20 ;CHECK: OpBranch %58 ;CHECK: %60 = OpLabel -;CHECK: %114 = OpFunctionCall %void %62 %uint_45 %uint_4 %uint_0 %35 %55 +;CHECK: %114 = OpFunctionCall %void %62 %uint_45 %uint_3 %uint_0 %35 %55 ;CHECK: OpBranch %58 ;CHECK: %58 = OpLabel ;CHECK: %116 = OpPhi %float %61 %59 %115 %60 @@ -8796,14 +8790,9 @@ TEST_F(InstBindlessTest, UniformMatrixRefColumnMajor) { ;CHECK: %uint_9 = OpConstant %uint 9 ;CHECK: %uint_10 = OpConstant %uint 10 ;CHECK: %uint_45 = OpConstant %uint 45 -;CHECK: %114 = OpConstantNull %float %main = OpFunction %void None %3 %5 = OpLabel ;CHECK: %55 = OpFunctionCall %uint %36 %uint_1 %uint_0 %uint_0 -;CHECK: OpBranch %26 -;CHECK: %26 = OpLabel -;CHECK: OpBranch %25 -;CHECK: %25 = OpLabel %20 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %int_2 %uint_1 %21 = OpLoad %float %20 ;CHECK-NOT: %21 = OpLoad %float %20 @@ -8819,7 +8808,7 @@ TEST_F(InstBindlessTest, UniformMatrixRefColumnMajor) { ;CHECK: %61 = OpLoad %float %20 ;CHECK: OpBranch %58 ;CHECK: %60 = OpLabel -;CHECK: %113 = OpFunctionCall %void %62 %uint_45 %uint_4 %uint_0 %35 %55 +;CHECK: %113 = OpFunctionCall %void %62 %uint_45 %uint_3 %uint_0 %35 %55 ;CHECK: OpBranch %58 ;CHECK: %58 = OpLabel ;CHECK: %115 = OpPhi %float %61 %59 %114 %60 @@ -9043,7 +9032,7 @@ TEST_F(InstBindlessTest, UniformMatrixVecRefRowMajor) { ;CHECK: %70 = OpLoad %v2float %25 ;CHECK: OpBranch %67 ;CHECK: %69 = OpLabel -;CHECK: %123 = OpFunctionCall %void %71 %uint_51 %uint_4 %uint_0 %43 %64 +;CHECK: %123 = OpFunctionCall %void %71 %uint_51 %uint_3 %uint_0 %43 %64 ;CHECK: OpBranch %67 ;CHECK: %67 = OpLabel ;CHECK: %125 = OpPhi %v2float %70 %68 %124 %69 @@ -9178,7 +9167,7 @@ TEST_F(InstBindlessTest, ImageBufferOOBRead) { ;CHECK: %uint = OpTypeInt 32 0 ;CHECK: %uint_0 = OpConstant %uint 0 ;CHECK: %bool = OpTypeBool -;CHECK: %uint_7 = OpConstant %uint 7 +;CHECK: %uint_3 = OpConstant %uint 3 ;CHECK: %35 = OpTypeFunction %void %uint %uint %uint %uint %uint ;CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint ;CHECK: %_struct_43 = OpTypeStruct %uint %_runtimearr_uint @@ -9190,11 +9179,11 @@ TEST_F(InstBindlessTest, ImageBufferOOBRead) { ;CHECK: %uint_1 = OpConstant %uint 1 ;CHECK: %uint_23 = OpConstant %uint 23 ;CHECK: %uint_2 = OpConstant %uint 2 -;CHECK: %uint_3 = OpConstant %uint 3 ;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float ;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: %v4uint = OpTypeVector %uint 4 ;CHECK: %uint_5 = OpConstant %uint 5 +;CHECK: %uint_7 = OpConstant %uint 7 ;CHECK: %uint_8 = OpConstant %uint 8 ;CHECK: %uint_9 = OpConstant %uint 9 ;CHECK: %uint_10 = OpConstant %uint 10 @@ -9224,7 +9213,7 @@ TEST_F(InstBindlessTest, ImageBufferOOBRead) { ;CHECK: %33 = OpImageRead %v4float %32 %17 ;CHECK: OpBranch %29 ;CHECK: %31 = OpLabel -;CHECK: %92 = OpFunctionCall %void %34 %uint_33 %uint_7 %uint_0 %23 %25 +;CHECK: %92 = OpFunctionCall %void %34 %uint_33 %uint_3 %uint_0 %23 %25 ;CHECK: OpBranch %29 ;CHECK: %29 = OpLabel ;CHECK: %94 = OpPhi %v4float %33 %30 %93 %31 @@ -9255,19 +9244,19 @@ TEST_F(InstBindlessTest, ImageBufferOOBRead) { ;CHECK: %63 = OpIAdd %uint %50 %uint_2 ;CHECK: %64 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %63 ;CHECK: OpStore %64 %36 -;CHECK: %66 = OpIAdd %uint %50 %uint_3 -;CHECK: %67 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %66 -;CHECK: OpStore %67 %uint_4 -;CHECK: %70 = OpLoad %v4float %gl_FragCoord -;CHECK: %72 = OpBitcast %v4uint %70 -;CHECK: %73 = OpCompositeExtract %uint %72 0 -;CHECK: %74 = OpIAdd %uint %50 %uint_4 -;CHECK: %75 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %74 -;CHECK: OpStore %75 %73 -;CHECK: %76 = OpCompositeExtract %uint %72 1 -;CHECK: %78 = OpIAdd %uint %50 %uint_5 -;CHECK: %79 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %78 -;CHECK: OpStore %79 %76 +;CHECK: %65 = OpIAdd %uint %50 %uint_3 +;CHECK: %66 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %65 +;CHECK: OpStore %66 %uint_4 +;CHECK: %69 = OpLoad %v4float %gl_FragCoord +;CHECK: %71 = OpBitcast %v4uint %69 +;CHECK: %72 = OpCompositeExtract %uint %71 0 +;CHECK: %73 = OpIAdd %uint %50 %uint_4 +;CHECK: %74 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %73 +;CHECK: OpStore %74 %72 +;CHECK: %75 = OpCompositeExtract %uint %71 1 +;CHECK: %77 = OpIAdd %uint %50 %uint_5 +;CHECK: %78 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %77 +;CHECK: OpStore %78 %75 ;CHECK: %80 = OpIAdd %uint %50 %uint_7 ;CHECK: %81 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %80 ;CHECK: OpStore %81 %37 @@ -9347,7 +9336,7 @@ TEST_F(InstBindlessTest, ImageBufferOOBWrite) { ;CHECK: %uint = OpTypeInt 32 0 ;CHECK: %uint_0 = OpConstant %uint 0 ;CHECK: %bool = OpTypeBool -;CHECK: %uint_7 = OpConstant %uint 7 +;CHECK: %uint_3 = OpConstant %uint 3 ;CHECK: %34 = OpTypeFunction %void %uint %uint %uint %uint %uint ;CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint ;CHECK: %_struct_42 = OpTypeStruct %uint %_runtimearr_uint @@ -9359,11 +9348,11 @@ TEST_F(InstBindlessTest, ImageBufferOOBWrite) { ;CHECK: %uint_1 = OpConstant %uint 1 ;CHECK: %uint_23 = OpConstant %uint 23 ;CHECK: %uint_2 = OpConstant %uint 2 -;CHECK: %uint_3 = OpConstant %uint 3 ;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float ;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: %v4uint = OpTypeVector %uint 4 ;CHECK: %uint_5 = OpConstant %uint 5 +;CHECK: %uint_7 = OpConstant %uint 7 ;CHECK: %uint_8 = OpConstant %uint 8 ;CHECK: %uint_9 = OpConstant %uint 9 ;CHECK: %uint_10 = OpConstant %uint 10 @@ -9391,7 +9380,7 @@ TEST_F(InstBindlessTest, ImageBufferOOBWrite) { ;CHECK: OpImageWrite %32 %14 %18 ;CHECK: OpBranch %29 ;CHECK: %31 = OpLabel -;CHECK: %91 = OpFunctionCall %void %33 %uint_34 %uint_7 %uint_0 %23 %25 +;CHECK: %91 = OpFunctionCall %void %33 %uint_34 %uint_3 %uint_0 %23 %25 ;CHECK: OpBranch %29 ;CHECK: %29 = OpLabel OpReturn @@ -9420,19 +9409,19 @@ TEST_F(InstBindlessTest, ImageBufferOOBWrite) { ;CHECK: %62 = OpIAdd %uint %49 %uint_2 ;CHECK: %63 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %62 ;CHECK: OpStore %63 %35 -;CHECK: %65 = OpIAdd %uint %49 %uint_3 -;CHECK: %66 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %65 -;CHECK: OpStore %66 %uint_4 -;CHECK: %69 = OpLoad %v4float %gl_FragCoord -;CHECK: %71 = OpBitcast %v4uint %69 -;CHECK: %72 = OpCompositeExtract %uint %71 0 -;CHECK: %73 = OpIAdd %uint %49 %uint_4 -;CHECK: %74 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %73 -;CHECK: OpStore %74 %72 -;CHECK: %75 = OpCompositeExtract %uint %71 1 -;CHECK: %77 = OpIAdd %uint %49 %uint_5 -;CHECK: %78 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %77 -;CHECK: OpStore %78 %75 +;CHECK: %64 = OpIAdd %uint %49 %uint_3 +;CHECK: %65 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %64 +;CHECK: OpStore %65 %uint_4 +;CHECK: %68 = OpLoad %v4float %gl_FragCoord +;CHECK: %70 = OpBitcast %v4uint %68 +;CHECK: %71 = OpCompositeExtract %uint %70 0 +;CHECK: %72 = OpIAdd %uint %49 %uint_4 +;CHECK: %73 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %72 +;CHECK: OpStore %73 %71 +;CHECK: %74 = OpCompositeExtract %uint %70 1 +;CHECK: %76 = OpIAdd %uint %49 %uint_5 +;CHECK: %77 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %76 +;CHECK: OpStore %77 %74 ;CHECK: %79 = OpIAdd %uint %49 %uint_7 ;CHECK: %80 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %79 ;CHECK: OpStore %80 %36 @@ -9511,7 +9500,7 @@ TEST_F(InstBindlessTest, TextureBufferOOBFetch) { ;CHECK: %uint = OpTypeInt 32 0 ;CHECK: %uint_0 = OpConstant %uint 0 ;CHECK: %bool = OpTypeBool -;CHECK: %uint_6 = OpConstant %uint 6 +;CHECK: %uint_3 = OpConstant %uint 3 ;CHECK: %35 = OpTypeFunction %void %uint %uint %uint %uint %uint ;CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint ;CHECK: %_struct_43 = OpTypeStruct %uint %_runtimearr_uint @@ -9523,7 +9512,6 @@ TEST_F(InstBindlessTest, TextureBufferOOBFetch) { ;CHECK: %uint_1 = OpConstant %uint 1 ;CHECK: %uint_23 = OpConstant %uint 23 ;CHECK: %uint_2 = OpConstant %uint 2 -;CHECK: %uint_3 = OpConstant %uint 3 ;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float ;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: %v4uint = OpTypeVector %uint 4 @@ -9533,7 +9521,7 @@ TEST_F(InstBindlessTest, TextureBufferOOBFetch) { ;CHECK: %uint_9 = OpConstant %uint 9 ;CHECK: %uint_10 = OpConstant %uint 10 ;CHECK: %uint_32 = OpConstant %uint 32 -;CHECK: %94 = OpConstantNull %v4float +;CHECK: %93 = OpConstantNull %v4float %main = OpFunction %void None %3 %5 = OpLabel ;CHECK: OpBranch %21 @@ -9558,11 +9546,11 @@ TEST_F(InstBindlessTest, TextureBufferOOBFetch) { ;CHECK: %33 = OpImageFetch %v4float %32 %17 ;CHECK: OpBranch %29 ;CHECK: %31 = OpLabel -;CHECK: %93 = OpFunctionCall %void %34 %uint_32 %uint_6 %uint_0 %23 %25 +;CHECK: %92 = OpFunctionCall %void %34 %uint_32 %uint_3 %uint_0 %23 %25 ;CHECK: OpBranch %29 ;CHECK: %29 = OpLabel -;CHECK: %95 = OpPhi %v4float %33 %30 %94 %31 -;CHECK: OpStore %x %95 +;CHECK: %94 = OpPhi %v4float %33 %30 %93 %31 +;CHECK: OpStore %x %94 OpReturn OpFunctionEnd ;CHECK: %34 = OpFunction %void None %35 @@ -9589,31 +9577,31 @@ TEST_F(InstBindlessTest, TextureBufferOOBFetch) { ;CHECK: %63 = OpIAdd %uint %50 %uint_2 ;CHECK: %64 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %63 ;CHECK: OpStore %64 %36 -;CHECK: %66 = OpIAdd %uint %50 %uint_3 -;CHECK: %67 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %66 -;CHECK: OpStore %67 %uint_4 -;CHECK: %70 = OpLoad %v4float %gl_FragCoord -;CHECK: %72 = OpBitcast %v4uint %70 -;CHECK: %73 = OpCompositeExtract %uint %72 0 -;CHECK: %74 = OpIAdd %uint %50 %uint_4 -;CHECK: %75 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %74 -;CHECK: OpStore %75 %73 -;CHECK: %76 = OpCompositeExtract %uint %72 1 -;CHECK: %78 = OpIAdd %uint %50 %uint_5 -;CHECK: %79 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %78 -;CHECK: OpStore %79 %76 -;CHECK: %81 = OpIAdd %uint %50 %uint_7 -;CHECK: %82 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %81 -;CHECK: OpStore %82 %37 -;CHECK: %84 = OpIAdd %uint %50 %uint_8 -;CHECK: %85 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %84 -;CHECK: OpStore %85 %38 -;CHECK: %87 = OpIAdd %uint %50 %uint_9 -;CHECK: %88 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %87 -;CHECK: OpStore %88 %39 -;CHECK: %90 = OpIAdd %uint %50 %uint_10 -;CHECK: %91 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %90 -;CHECK: OpStore %91 %40 +;CHECK: %65 = OpIAdd %uint %50 %uint_3 +;CHECK: %66 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %65 +;CHECK: OpStore %66 %uint_4 +;CHECK: %69 = OpLoad %v4float %gl_FragCoord +;CHECK: %71 = OpBitcast %v4uint %69 +;CHECK: %72 = OpCompositeExtract %uint %71 0 +;CHECK: %73 = OpIAdd %uint %50 %uint_4 +;CHECK: %74 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %73 +;CHECK: OpStore %74 %72 +;CHECK: %75 = OpCompositeExtract %uint %71 1 +;CHECK: %77 = OpIAdd %uint %50 %uint_5 +;CHECK: %78 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %77 +;CHECK: OpStore %78 %75 +;CHECK: %80 = OpIAdd %uint %50 %uint_7 +;CHECK: %81 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %80 +;CHECK: OpStore %81 %37 +;CHECK: %83 = OpIAdd %uint %50 %uint_8 +;CHECK: %84 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %83 +;CHECK: OpStore %84 %38 +;CHECK: %86 = OpIAdd %uint %50 %uint_9 +;CHECK: %87 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %86 +;CHECK: OpStore %87 %39 +;CHECK: %89 = OpIAdd %uint %50 %uint_10 +;CHECK: %90 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %89 +;CHECK: OpStore %90 %40 ;CHECK: OpBranch %54 ;CHECK: %54 = OpLabel ;CHECK: OpReturn @@ -9681,7 +9669,7 @@ TEST_F(InstBindlessTest, SamplerBufferOOBFetch) { ;CHECK: %uint = OpTypeInt 32 0 ;CHECK: %uint_0 = OpConstant %uint 0 ;CHECK: %bool = OpTypeBool -;CHECK: %uint_6 = OpConstant %uint 6 +;CHECK: %uint_3 = OpConstant %uint 3 ;CHECK: %38 = OpTypeFunction %void %uint %uint %uint %uint %uint ;CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint ;CHECK: %_struct_46 = OpTypeStruct %uint %_runtimearr_uint @@ -9693,7 +9681,6 @@ TEST_F(InstBindlessTest, SamplerBufferOOBFetch) { ;CHECK: %uint_1 = OpConstant %uint 1 ;CHECK: %uint_23 = OpConstant %uint 23 ;CHECK: %uint_2 = OpConstant %uint 2 -;CHECK: %uint_3 = OpConstant %uint 3 ;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float ;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: %v4uint = OpTypeVector %uint 4 @@ -9703,7 +9690,7 @@ TEST_F(InstBindlessTest, SamplerBufferOOBFetch) { ;CHECK: %uint_9 = OpConstant %uint 9 ;CHECK: %uint_10 = OpConstant %uint 10 ;CHECK: %uint_34 = OpConstant %uint 34 -;CHECK: %97 = OpConstantNull %v4float +;CHECK: %96 = OpConstantNull %v4float %main = OpFunction %void None %3 %5 = OpLabel ;CHECK: OpBranch %23 @@ -9730,11 +9717,11 @@ TEST_F(InstBindlessTest, SamplerBufferOOBFetch) { ;CHECK: %36 = OpImageFetch %v4float %35 %18 ;CHECK: OpBranch %31 ;CHECK: %33 = OpLabel -;CHECK: %96 = OpFunctionCall %void %37 %uint_34 %uint_6 %uint_0 %25 %27 +;CHECK: %95 = OpFunctionCall %void %37 %uint_34 %uint_3 %uint_0 %25 %27 ;CHECK: OpBranch %31 ;CHECK: %31 = OpLabel -;CHECK: %98 = OpPhi %v4float %36 %32 %97 %33 -;CHECK: OpStore %x %98 +;CHECK: %97 = OpPhi %v4float %36 %32 %96 %33 +;CHECK: OpStore %x %97 OpReturn OpFunctionEnd ;CHECK: %37 = OpFunction %void None %38 @@ -9761,31 +9748,31 @@ TEST_F(InstBindlessTest, SamplerBufferOOBFetch) { ;CHECK: %66 = OpIAdd %uint %53 %uint_2 ;CHECK: %67 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %66 ;CHECK: OpStore %67 %39 -;CHECK: %69 = OpIAdd %uint %53 %uint_3 -;CHECK: %70 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %69 -;CHECK: OpStore %70 %uint_4 -;CHECK: %73 = OpLoad %v4float %gl_FragCoord -;CHECK: %75 = OpBitcast %v4uint %73 -;CHECK: %76 = OpCompositeExtract %uint %75 0 -;CHECK: %77 = OpIAdd %uint %53 %uint_4 -;CHECK: %78 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %77 -;CHECK: OpStore %78 %76 -;CHECK: %79 = OpCompositeExtract %uint %75 1 -;CHECK: %81 = OpIAdd %uint %53 %uint_5 -;CHECK: %82 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %81 -;CHECK: OpStore %82 %79 -;CHECK: %84 = OpIAdd %uint %53 %uint_7 -;CHECK: %85 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %84 -;CHECK: OpStore %85 %40 -;CHECK: %87 = OpIAdd %uint %53 %uint_8 -;CHECK: %88 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %87 -;CHECK: OpStore %88 %41 -;CHECK: %90 = OpIAdd %uint %53 %uint_9 -;CHECK: %91 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %90 -;CHECK: OpStore %91 %42 -;CHECK: %93 = OpIAdd %uint %53 %uint_10 -;CHECK: %94 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %93 -;CHECK: OpStore %94 %43 +;CHECK: %68 = OpIAdd %uint %53 %uint_3 +;CHECK: %69 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %68 +;CHECK: OpStore %69 %uint_4 +;CHECK: %72 = OpLoad %v4float %gl_FragCoord +;CHECK: %74 = OpBitcast %v4uint %72 +;CHECK: %75 = OpCompositeExtract %uint %74 0 +;CHECK: %76 = OpIAdd %uint %53 %uint_4 +;CHECK: %77 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %76 +;CHECK: OpStore %77 %75 +;CHECK: %78 = OpCompositeExtract %uint %74 1 +;CHECK: %80 = OpIAdd %uint %53 %uint_5 +;CHECK: %81 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %80 +;CHECK: OpStore %81 %78 +;CHECK: %83 = OpIAdd %uint %53 %uint_7 +;CHECK: %84 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %83 +;CHECK: OpStore %84 %40 +;CHECK: %86 = OpIAdd %uint %53 %uint_8 +;CHECK: %87 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %86 +;CHECK: OpStore %87 %41 +;CHECK: %89 = OpIAdd %uint %53 %uint_9 +;CHECK: %90 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %89 +;CHECK: OpStore %90 %42 +;CHECK: %92 = OpIAdd %uint %53 %uint_10 +;CHECK: %93 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %92 +;CHECK: OpStore %93 %43 ;CHECK: OpBranch %57 ;CHECK: %57 = OpLabel ;CHECK: OpReturn @@ -9860,7 +9847,7 @@ TEST_F(InstBindlessTest, SamplerBufferConstructorOOBFetch) { ;CHECK: %uint = OpTypeInt 32 0 ;CHECK: %uint_0 = OpConstant %uint 0 ;CHECK: %bool = OpTypeBool -;CHECK: %uint_6 = OpConstant %uint 6 +;CHECK: %uint_3 = OpConstant %uint 3 ;CHECK: %44 = OpTypeFunction %void %uint %uint %uint %uint %uint ;CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint ;CHECK: %_struct_52 = OpTypeStruct %uint %_runtimearr_uint @@ -9872,7 +9859,6 @@ TEST_F(InstBindlessTest, SamplerBufferConstructorOOBFetch) { ;CHECK: %uint_1 = OpConstant %uint 1 ;CHECK: %uint_23 = OpConstant %uint 23 ;CHECK: %uint_2 = OpConstant %uint 2 -;CHECK: %uint_3 = OpConstant %uint 3 ;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float ;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: %v4uint = OpTypeVector %uint 4 @@ -9882,7 +9868,7 @@ TEST_F(InstBindlessTest, SamplerBufferConstructorOOBFetch) { ;CHECK: %uint_9 = OpConstant %uint 9 ;CHECK: %uint_10 = OpConstant %uint 10 ;CHECK: %uint_42 = OpConstant %uint 42 -;CHECK: %103 = OpConstantNull %v4float +;CHECK: %102 = OpConstantNull %v4float %main = OpFunction %void None %3 %5 = OpLabel ;CHECK: OpBranch %28 @@ -9912,11 +9898,11 @@ TEST_F(InstBindlessTest, SamplerBufferConstructorOOBFetch) { ;CHECK: %42 = OpImageFetch %v4float %41 %23 ;CHECK: OpBranch %36 ;CHECK: %38 = OpLabel -;CHECK: %102 = OpFunctionCall %void %43 %uint_42 %uint_6 %uint_0 %30 %32 +;CHECK: %101 = OpFunctionCall %void %43 %uint_42 %uint_3 %uint_0 %30 %32 ;CHECK: OpBranch %36 ;CHECK: %36 = OpLabel -;CHECK: %104 = OpPhi %v4float %42 %37 %103 %38 -;CHECK: OpStore %x %104 +;CHECK: %103 = OpPhi %v4float %42 %37 %102 %38 +;CHECK: OpStore %x %103 OpReturn OpFunctionEnd ;CHECK: %43 = OpFunction %void None %44 @@ -9943,31 +9929,31 @@ TEST_F(InstBindlessTest, SamplerBufferConstructorOOBFetch) { ;CHECK: %72 = OpIAdd %uint %59 %uint_2 ;CHECK: %73 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %72 ;CHECK: OpStore %73 %45 -;CHECK: %75 = OpIAdd %uint %59 %uint_3 -;CHECK: %76 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %75 -;CHECK: OpStore %76 %uint_4 -;CHECK: %79 = OpLoad %v4float %gl_FragCoord -;CHECK: %81 = OpBitcast %v4uint %79 -;CHECK: %82 = OpCompositeExtract %uint %81 0 -;CHECK: %83 = OpIAdd %uint %59 %uint_4 -;CHECK: %84 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %83 -;CHECK: OpStore %84 %82 -;CHECK: %85 = OpCompositeExtract %uint %81 1 -;CHECK: %87 = OpIAdd %uint %59 %uint_5 -;CHECK: %88 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %87 -;CHECK: OpStore %88 %85 -;CHECK: %90 = OpIAdd %uint %59 %uint_7 -;CHECK: %91 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %90 -;CHECK: OpStore %91 %46 -;CHECK: %93 = OpIAdd %uint %59 %uint_8 -;CHECK: %94 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %93 -;CHECK: OpStore %94 %47 -;CHECK: %96 = OpIAdd %uint %59 %uint_9 -;CHECK: %97 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %96 -;CHECK: OpStore %97 %48 -;CHECK: %99 = OpIAdd %uint %59 %uint_10 -;CHECK: %100 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %99 -;CHECK: OpStore %100 %49 +;CHECK: %74 = OpIAdd %uint %59 %uint_3 +;CHECK: %75 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %74 +;CHECK: OpStore %75 %uint_4 +;CHECK: %78 = OpLoad %v4float %gl_FragCoord +;CHECK: %80 = OpBitcast %v4uint %78 +;CHECK: %81 = OpCompositeExtract %uint %80 0 +;CHECK: %82 = OpIAdd %uint %59 %uint_4 +;CHECK: %83 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %82 +;CHECK: OpStore %83 %81 +;CHECK: %84 = OpCompositeExtract %uint %80 1 +;CHECK: %86 = OpIAdd %uint %59 %uint_5 +;CHECK: %87 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %86 +;CHECK: OpStore %87 %84 +;CHECK: %89 = OpIAdd %uint %59 %uint_7 +;CHECK: %90 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %89 +;CHECK: OpStore %90 %46 +;CHECK: %92 = OpIAdd %uint %59 %uint_8 +;CHECK: %93 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %92 +;CHECK: OpStore %93 %47 +;CHECK: %95 = OpIAdd %uint %59 %uint_9 +;CHECK: %96 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %95 +;CHECK: OpStore %96 %48 +;CHECK: %98 = OpIAdd %uint %59 %uint_10 +;CHECK: %99 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %98 +;CHECK: OpStore %99 %49 ;CHECK: OpBranch %63 ;CHECK: %63 = OpLabel ;CHECK: OpReturn -- cgit v1.2.3 From b1507d0d2ba8ed06b53bd4edb5f430b1122dd2ca Mon Sep 17 00:00:00 2001 From: Pierre Moreau Date: Wed, 13 Jan 2021 15:05:40 +0100 Subject: Linker usability improvements (#4084) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * tools/linker: Error out on unrecognized options Fixes #4083. * tools/linker: Use early returns when parsing options This was already the case for some linker options, and other tools were doing so for all of their options. * tools/linker: Rework the usage output * The new formatting for long options taking a value makes it explicit that there is no equal sign between the option name and the value. * The options are sorted by lexicographical order. * Change the option formatting from 90 columns to 80, to match the other tools. * tools/linker: Change the default environment to spv1.5 * tools/linker: Change the default output to spv.out Instead of writing to the standard output when the "-o" option is not specified, the resulting linked SPIR-V binary will be written to "spv.out". One can still have the output sent to the standard output by specifying "-o -". * tools/linker: Update the reported target for --version Running `spirv-link --version` will now report the currently selected environment. * tools/linker: Sort header includes * linker: Improve module-related error messages * Use 1-based indexing of modules; * Say which module could not be built; * Use the correct total number of input modules in the error message when one fails to build. --- source/link/linker.cpp | 5 ++- tools/link/linker.cpp | 99 +++++++++++++++++++++++++++----------------------- 2 files changed, 57 insertions(+), 47 deletions(-) diff --git a/source/link/linker.cpp b/source/link/linker.cpp index da6f0a78..8da4a98d 100644 --- a/source/link/linker.cpp +++ b/source/link/linker.cpp @@ -676,14 +676,15 @@ spv_result_t Link(const Context& context, const uint32_t* const* binaries, if (schema != 0u) { position.index = 4u; return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_BINARY) - << "Schema is non-zero for module " << i << "."; + << "Schema is non-zero for module " << i + 1 << "."; } std::unique_ptr ir_context = BuildModule( c_context->target_env, consumer, binaries[i], binary_sizes[i]); if (ir_context == nullptr) return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_BINARY) - << "Failed to build a module out of " << ir_contexts.size() << "."; + << "Failed to build module " << i + 1 << " out of " << num_binaries + << "."; modules.push_back(ir_context->module()); ir_contexts.push_back(std::move(ir_context)); } diff --git a/tools/link/linker.cpp b/tools/link/linker.cpp index 82d430eb..1956f595 100644 --- a/tools/link/linker.cpp +++ b/tools/link/linker.cpp @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "spirv-tools/linker.hpp" + #include #include #include @@ -19,42 +21,56 @@ #include "source/spirv_target_env.h" #include "source/table.h" #include "spirv-tools/libspirv.hpp" -#include "spirv-tools/linker.hpp" #include "tools/io.h" -void print_usage(char* argv0) { - std::string target_env_list = spvTargetEnvList(27, 95); +namespace { + +const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_5; + +void print_usage(const char* program) { + std::string target_env_list = spvTargetEnvList(16, 80); + // NOTE: Please maintain flags in lexicographical order. printf( R"(%s - Link SPIR-V binary files together. -USAGE: %s [options] [ ...] +USAGE: %s [options] [-o ] ... -The SPIR-V binaries are read from the different . +The SPIR-V binaries are read from the different (s). +The SPIR-V resulting linked binary module is written to the file "out.spv" +unless the -o option is used; if is "-", it is written to the standard +output. NOTE: The linker is a work in progress. -Options: - -h, --help Print this help. - -o Name of the resulting linked SPIR-V binary. - --create-library Link the binaries into a library, keeping all exported symbols. - --allow-partial-linkage Allow partial linkage by accepting imported symbols to be unresolved. - --verify-ids Verify that IDs in the resulting modules are truly unique. - --version Display linker version information - --target-env {%s} - Use validation rules from the specified environment. +Options (in lexicographical order): + --allow-partial-linkage + Allow partial linkage by accepting imported symbols to be + unresolved. + --create-library + Link the binaries into a library, keeping all exported symbols. + -h, --help + Print this help. + --target-env + Set the target environment. Without this flag the target + environment defaults to spv1.5. must be one of + {%s} + --verify-ids + Verify that IDs in the resulting modules are truly unique. + --version + Display linker version information )", - argv0, argv0, target_env_list.c_str()); + program, program, target_env_list.c_str()); } +} // namespace + int main(int argc, char** argv) { std::vector inFiles; const char* outFile = nullptr; - spv_target_env target_env = SPV_ENV_UNIVERSAL_1_0; + spv_target_env target_env = kDefaultEnvironment; spvtools::LinkerOptions options; - bool continue_processing = true; - int return_code = 0; - for (int argi = 1; continue_processing && argi < argc; ++argi) { + for (int argi = 1; argi < argc; ++argi) { const char* cur_arg = argv[argi]; if ('-' == cur_arg[0]) { if (0 == strcmp(cur_arg, "-o")) { @@ -63,55 +79,48 @@ int main(int argc, char** argv) { outFile = argv[++argi]; } else { fprintf(stderr, "error: More than one output file specified\n"); - continue_processing = false; - return_code = 1; + return 1; } } else { fprintf(stderr, "error: Missing argument to %s\n", cur_arg); - continue_processing = false; - return_code = 1; + return 1; } - } else if (0 == strcmp(cur_arg, "--create-library")) { - options.SetCreateLibrary(true); - } else if (0 == strcmp(cur_arg, "--verify-ids")) { - options.SetVerifyIds(true); } else if (0 == strcmp(cur_arg, "--allow-partial-linkage")) { options.SetAllowPartialLinkage(true); - } else if (0 == strcmp(cur_arg, "--version")) { - printf("%s\n", spvSoftwareVersionDetailsString()); - // TODO(dneto): Add OpenCL 2.2 at least. - printf("Targets:\n %s\n %s\n %s\n", - spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_1), - spvTargetEnvDescription(SPV_ENV_VULKAN_1_0), - spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_2)); - continue_processing = false; - return_code = 0; + } else if (0 == strcmp(cur_arg, "--create-library")) { + options.SetCreateLibrary(true); } else if (0 == strcmp(cur_arg, "--help") || 0 == strcmp(cur_arg, "-h")) { print_usage(argv[0]); - continue_processing = false; - return_code = 0; + return 0; } else if (0 == strcmp(cur_arg, "--target-env")) { if (argi + 1 < argc) { const auto env_str = argv[++argi]; if (!spvParseTargetEnv(env_str, &target_env)) { fprintf(stderr, "error: Unrecognized target env: %s\n", env_str); - continue_processing = false; - return_code = 1; + return 1; } } else { fprintf(stderr, "error: Missing argument to --target-env\n"); - continue_processing = false; - return_code = 1; + return 1; } + } else if (0 == strcmp(cur_arg, "--verify-ids")) { + options.SetVerifyIds(true); + } else if (0 == strcmp(cur_arg, "--version")) { + printf("%s\n", spvSoftwareVersionDetailsString()); + printf("Target: %s\n", spvTargetEnvDescription(target_env)); + return 0; + } else { + fprintf(stderr, "error: Unrecognized option: %s\n\n", argv[argi]); + print_usage(argv[0]); + return 1; } } else { inFiles.push_back(cur_arg); } } - // Exit if command line parsing was not successful. - if (!continue_processing) { - return return_code; + if (!outFile) { + outFile = "out.spv"; } if (inFiles.empty()) { -- cgit v1.2.3 From cec658c11603a5411a38f0f86d0ecc04250df4b7 Mon Sep 17 00:00:00 2001 From: Jaebaek Seo Date: Wed, 13 Jan 2021 09:08:28 -0500 Subject: Avoid integrity check failures caused by propagating line instructions (#4096) Propagating the OpLine/OpNoLine to preserve the debug information through transformations results in integrity check failures because of the extra line instructions. This commit lets spirv-opt skip the integrity check when the code contains OpLine or OpNoLine. --- source/opt/ir_loader.cpp | 9 ++-- source/opt/module.h | 14 +++--- source/opt/optimizer.cpp | 6 ++- test/opt/optimizer_test.cpp | 118 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 134 insertions(+), 13 deletions(-) diff --git a/source/opt/ir_loader.cpp b/source/opt/ir_loader.cpp index 70e5144a..e443ebb5 100644 --- a/source/opt/ir_loader.cpp +++ b/source/opt/ir_loader.cpp @@ -41,6 +41,7 @@ bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) { ++inst_index_; const auto opcode = static_cast(inst->opcode); if (IsDebugLineInst(opcode)) { + module()->SetContainsDebugInfo(); last_line_inst_.reset(); dbg_line_info_.push_back( Instruction(module()->context(), *inst, last_dbg_scope_)); @@ -61,12 +62,12 @@ bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) { inlined_at = inst->words[kInlinedAtIndex]; last_dbg_scope_ = DebugScope(inst->words[kLexicalScopeIndex], inlined_at); - module()->SetContainsDebugScope(); + module()->SetContainsDebugInfo(); return true; } if (ext_inst_key == OpenCLDebugInfo100DebugNoScope) { last_dbg_scope_ = DebugScope(kNoDebugScope, kNoInlinedAt); - module()->SetContainsDebugScope(); + module()->SetContainsDebugInfo(); return true; } } else { @@ -78,12 +79,12 @@ bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) { inlined_at = inst->words[kInlinedAtIndex]; last_dbg_scope_ = DebugScope(inst->words[kLexicalScopeIndex], inlined_at); - module()->SetContainsDebugScope(); + module()->SetContainsDebugInfo(); return true; } if (ext_inst_key == DebugInfoDebugNoScope) { last_dbg_scope_ = DebugScope(kNoDebugScope, kNoInlinedAt); - module()->SetContainsDebugScope(); + module()->SetContainsDebugInfo(); return true; } } diff --git a/source/opt/module.h b/source/opt/module.h index 2c96f029..d609b603 100644 --- a/source/opt/module.h +++ b/source/opt/module.h @@ -49,7 +49,7 @@ class Module { using const_inst_iterator = InstructionList::const_iterator; // Creates an empty module with zero'd header. - Module() : header_({}), contains_debug_scope_(false) {} + Module() : header_({}), contains_debug_info_(false) {} // Sets the header to the given |header|. void SetHeader(const ModuleHeader& header) { header_ = header; } @@ -119,9 +119,9 @@ class Module { // Appends a function to this module. inline void AddFunction(std::unique_ptr f); - // Sets |contains_debug_scope_| as true. - inline void SetContainsDebugScope(); - inline bool ContainsDebugScope() { return contains_debug_scope_; } + // Sets |contains_debug_info_| as true. + inline void SetContainsDebugInfo(); + inline bool ContainsDebugInfo() { return contains_debug_info_; } // Returns a vector of pointers to type-declaration instructions in this // module. @@ -301,8 +301,8 @@ class Module { // any instruction. We record them here, so they will not be lost. std::vector trailing_dbg_line_info_; - // This module contains DebugScope or DebugNoScope. - bool contains_debug_scope_; + // This module contains DebugScope/DebugNoScope or OpLine/OpNoLine. + bool contains_debug_info_; }; // Pretty-prints |module| to |str|. Returns |str|. @@ -364,7 +364,7 @@ inline void Module::AddFunction(std::unique_ptr f) { functions_.emplace_back(std::move(f)); } -inline void Module::SetContainsDebugScope() { contains_debug_scope_ = true; } +inline void Module::SetContainsDebugInfo() { contains_debug_info_ = true; } inline Module::inst_iterator Module::capability_begin() { return capabilities_.begin(); diff --git a/source/opt/optimizer.cpp b/source/opt/optimizer.cpp index 8726ff93..c2a21f2c 100644 --- a/source/opt/optimizer.cpp +++ b/source/opt/optimizer.cpp @@ -583,10 +583,12 @@ bool Optimizer::Run(const uint32_t* original_binary, #ifndef NDEBUG // We do not keep the result id of DebugScope in struct DebugScope. // Instead, we assign random ids for them, which results in integrity + // check failures. In addition, propagating the OpLine/OpNoLine to preserve + // the debug information through transformations results in integrity // check failures. We want to skip the integrity check when the module - // contains DebugScope instructions. + // contains DebugScope or OpLine/OpNoLine instructions. if (status == opt::Pass::Status::SuccessWithoutChange && - !context->module()->ContainsDebugScope()) { + !context->module()->ContainsDebugInfo()) { std::vector optimized_binary_with_nop; context->module()->ToBinary(&optimized_binary_with_nop, /* skip_nop = */ false); diff --git a/test/opt/optimizer_test.cpp b/test/opt/optimizer_test.cpp index 945aa782..de79536e 100644 --- a/test/opt/optimizer_test.cpp +++ b/test/opt/optimizer_test.cpp @@ -762,6 +762,124 @@ OpFunctionEnd << "Was expecting the OpNop to have been removed."; } +TEST(Optimizer, AvoidIntegrityCheckForExtraLineInfo) { + // Test that it avoids the integrity check when no optimizations are run and + // OpLines are propagated. + const std::string before = R"(OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%1 = OpString "Test" +%void = OpTypeVoid +%3 = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%_ptr_Function_uint = OpTypePointer Function %uint +%6 = OpFunction %void None %3 +%7 = OpLabel +OpLine %1 10 0 +%8 = OpVariable %_ptr_Function_uint Function +OpLine %1 10 0 +%9 = OpVariable %_ptr_Function_uint Function +OpLine %1 20 0 +OpReturn +OpFunctionEnd +)"; + + const std::string after = R"(OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%1 = OpString "Test" +%void = OpTypeVoid +%3 = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%_ptr_Function_uint = OpTypePointer Function %uint +%6 = OpFunction %void None %3 +%7 = OpLabel +OpLine %1 10 0 +%8 = OpVariable %_ptr_Function_uint Function +%9 = OpVariable %_ptr_Function_uint Function +OpLine %1 20 0 +OpReturn +OpFunctionEnd +)"; + + std::vector binary; + SpirvTools tools(SPV_ENV_VULKAN_1_1); + tools.Assemble(before, &binary); + + Optimizer opt(SPV_ENV_VULKAN_1_1); + + std::vector optimized; + class ValidatorOptions validator_options; + ASSERT_TRUE(opt.Run(binary.data(), binary.size(), &optimized, + validator_options, true)) + << before << "\n"; + + std::string disassembly; + tools.Disassemble(optimized.data(), optimized.size(), &disassembly); + + EXPECT_EQ(after, disassembly) + << "Was expecting the OpLine to have been propagated."; +} + +TEST(Optimizer, AvoidIntegrityCheckForDebugScope) { + // Test that it avoids the integrity check when the code contains DebugScope. + const std::string before = R"(OpCapability Shader +%1 = OpExtInstImport "OpenCL.DebugInfo.100" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +%3 = OpString "simple_vs.hlsl" +OpSource HLSL 600 %3 +OpName %main "main" +%void = OpTypeVoid +%5 = OpTypeFunction %void +%6 = OpExtInst %void %1 DebugSource %3 +%7 = OpExtInst %void %1 DebugCompilationUnit 2 4 %6 HLSL +%main = OpFunction %void None %5 +%14 = OpLabel +%26 = OpExtInst %void %1 DebugScope %7 +OpReturn +%27 = OpExtInst %void %1 DebugNoScope +OpFunctionEnd +)"; + + const std::string after = R"(OpCapability Shader +%1 = OpExtInstImport "OpenCL.DebugInfo.100" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +%3 = OpString "simple_vs.hlsl" +OpSource HLSL 600 %3 +OpName %main "main" +%void = OpTypeVoid +%5 = OpTypeFunction %void +%6 = OpExtInst %void %1 DebugSource %3 +%7 = OpExtInst %void %1 DebugCompilationUnit 2 4 %6 HLSL +%main = OpFunction %void None %5 +%8 = OpLabel +%11 = OpExtInst %void %1 DebugScope %7 +OpReturn +%12 = OpExtInst %void %1 DebugNoScope +OpFunctionEnd +)"; + + std::vector binary; + SpirvTools tools(SPV_ENV_VULKAN_1_1); + tools.Assemble(before, &binary); + + Optimizer opt(SPV_ENV_VULKAN_1_1); + + std::vector optimized; + ASSERT_TRUE(opt.Run(binary.data(), binary.size(), &optimized)) + << before << "\n"; + + std::string disassembly; + tools.Disassemble(optimized.data(), optimized.size(), &disassembly); + + EXPECT_EQ(after, disassembly) + << "Was expecting the result id of DebugScope to have been changed."; +} + } // namespace } // namespace opt } // namespace spvtools -- cgit v1.2.3 From b2cfc5d1ceca52b6a250591598701d632f1980d0 Mon Sep 17 00:00:00 2001 From: sfricke-samsung <46493288+sfricke-samsung@users.noreply.github.com> Date: Thu, 14 Jan 2021 06:41:18 -0800 Subject: spirv-val: Vulkan atomic storage class (#4079) * spirv-val: Vulkan atomic storage class * Add PhysicalStorageBuffer --- source/val/validate_atomics.cpp | 14 +++++++++++++- source/val/validation_state.cpp | 2 ++ test/val/val_atomics_test.cpp | 17 +++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/source/val/validate_atomics.cpp b/source/val/validate_atomics.cpp index 3f1f5617..dd263a79 100644 --- a/source/val/validate_atomics.cpp +++ b/source/val/validate_atomics.cpp @@ -213,7 +213,19 @@ spv_result_t AtomicsPass(ValidationState_t& _, const Instruction* inst) { // Then Shader rules if (_.HasCapability(SpvCapabilityShader)) { - if (storage_class == SpvStorageClassFunction) { + if (spvIsVulkanEnv(_.context()->target_env)) { + if ((storage_class != SpvStorageClassUniform) && + (storage_class != SpvStorageClassStorageBuffer) && + (storage_class != SpvStorageClassWorkgroup) && + (storage_class != SpvStorageClassImage) && + (storage_class != SpvStorageClassPhysicalStorageBuffer)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << _.VkErrorID(4686) << spvOpcodeString(opcode) + << ": Vulkan spec only allows storage classes for atomic to " + "be: Uniform, Workgroup, Image, StorageBuffer, or " + "PhysicalStorageBuffer."; + } + } else if (storage_class == SpvStorageClassFunction) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << spvOpcodeString(opcode) << ": Function storage class forbidden when the Shader " diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index fb1069de..27cf624a 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -1691,6 +1691,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-FPRoundingMode-04675); case 4685: return VUID_WRAP(VUID-StandaloneSpirv-OpGroupNonUniformBallotBitCount-04685); + case 4686: + return VUID_WRAP(VUID-StandaloneSpirv-None-04686); case 4711: return VUID_WRAP(VUID-StandaloneSpirv-OpTypeForwardPointer-04711); default: diff --git a/test/val/val_atomics_test.cpp b/test/val/val_atomics_test.cpp index aca0f3c9..b7735fc2 100644 --- a/test/val/val_atomics_test.cpp +++ b/test/val/val_atomics_test.cpp @@ -421,6 +421,23 @@ OpAtomicStore %f32_var_function %device %relaxed %f32_1 CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-None-04686")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("AtomicStore: Vulkan spec only allows storage classes for " + "atomic to be: Uniform, Workgroup, Image, StorageBuffer, or " + "PhysicalStorageBuffer.")); +} + +TEST_F(ValidateAtomics, AtomicStoreFunctionPointerStorageType) { + const std::string body = R"( +%f32_var_function = OpVariable %f32_ptr_function Function +OpAtomicStore %f32_var_function %device %relaxed %f32_1 +)"; + + CompileSuccessfully(GenerateShaderCode(body)); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("AtomicStore: Function storage class forbidden when " "the Shader capability is declared.")); -- cgit v1.2.3 From 9150cd441f43ab1e896435bcb16addf5bdafe7ab Mon Sep 17 00:00:00 2001 From: Ryan Harrison Date: Thu, 14 Jan 2021 16:45:18 -0500 Subject: Remove WebGPU support (#4108) Leaves SPV_ENV_WEBGPU_0 enum in place, but marked deprecated, so users of the library are not broken by an API enum being removed. Fixes #4101 --- Android.mk | 5 - BUILD.gn | 10 - README.md | 1 - include/spirv-tools/libspirv.h | 2 +- include/spirv-tools/optimizer.hpp | 41 -- source/ext_inst.cpp | 1 - source/libspirv.cpp | 6 +- source/opt/CMakeLists.txt | 9 - .../opt/decompose_initialized_variables_pass.cpp | 112 ---- source/opt/decompose_initialized_variables_pass.h | 57 -- source/opt/generate_webgpu_initializers_pass.cpp | 116 ---- source/opt/generate_webgpu_initializers_pass.h | 62 -- source/opt/legalize_vector_shuffle_pass.cpp | 39 -- source/opt/legalize_vector_shuffle_pass.h | 53 -- source/opt/optimizer.cpp | 58 +- source/opt/passes.h | 5 - source/opt/split_invalid_unreachable_pass.cpp | 95 --- source/opt/split_invalid_unreachable_pass.h | 51 -- source/opt/strip_atomic_counter_memory_pass.cpp | 57 -- source/opt/strip_atomic_counter_memory_pass.h | 51 -- source/spirv_target_env.cpp | 61 +- source/spirv_target_env.h | 8 +- source/table.cpp | 1 - source/val/validate.cpp | 77 +-- source/val/validate_annotation.cpp | 63 -- source/val/validate_builtins.cpp | 154 +---- source/val/validate_capability.cpp | 21 - source/val/validate_cfg.cpp | 121 ---- source/val/validate_composites.cpp | 8 - source/val/validate_extensions.cpp | 26 - source/val/validate_image.cpp | 11 +- source/val/validate_memory.cpp | 53 +- source/val/validate_memory_semantics.cpp | 49 -- source/val/validate_misc.cpp | 4 - source/val/validate_mode_setting.cpp | 22 - source/val/validate_scopes.cpp | 80 --- source/val/validate_type.cpp | 33 +- source/val/validation_state.cpp | 17 - test/fuzzers/BUILD.gn | 46 -- .../fuzzers/spvtools_opt_vulkantowebgpu_fuzzer.cpp | 38 -- .../fuzzers/spvtools_opt_webgputovulkan_fuzzer.cpp | 38 -- test/fuzzers/spvtools_val_webgpu_fuzzer.cpp | 36 -- test/opt/CMakeLists.txt | 5 - test/opt/decompose_initialized_variables_test.cpp | 252 -------- test/opt/generate_webgpu_initializers_test.cpp | 347 ----------- test/opt/legalize_vector_shuffle_test.cpp | 81 --- test/opt/optimizer_test.cpp | 494 +--------------- test/opt/split_invalid_unreachable_test.cpp | 155 ----- test/opt/strip_atomic_counter_memory_test.cpp | 406 ------------- test/target_env_test.cpp | 1 - test/tools/opt/flags.py | 51 +- test/unit_spirv.h | 2 +- test/val/CMakeLists.txt | 1 - test/val/val_atomics_test.cpp | 151 ----- test/val/val_barriers_test.cpp | 238 -------- test/val/val_builtins_test.cpp | 648 ++------------------- test/val/val_capability_test.cpp | 41 -- test/val/val_cfg_test.cpp | 426 +++----------- test/val/val_code_generator.cpp | 65 --- test/val/val_code_generator.h | 1 - test/val/val_data_test.cpp | 172 ------ test/val/val_decoration_test.cpp | 101 ---- test/val/val_id_test.cpp | 58 -- test/val/val_image_test.cpp | 71 --- test/val/val_layout_test.cpp | 51 -- test/val/val_memory_test.cpp | 402 ------------- test/val/val_modes_test.cpp | 51 +- test/val/val_storage_test.cpp | 64 -- test/val/val_validation_state_test.cpp | 78 --- test/val/val_version_test.cpp | 22 +- test/val/val_webgpu_test.cpp | 424 -------------- tools/opt/opt.cpp | 108 ---- tools/val/val.cpp | 5 +- 73 files changed, 205 insertions(+), 6565 deletions(-) delete mode 100644 source/opt/decompose_initialized_variables_pass.cpp delete mode 100644 source/opt/decompose_initialized_variables_pass.h delete mode 100644 source/opt/generate_webgpu_initializers_pass.cpp delete mode 100644 source/opt/generate_webgpu_initializers_pass.h delete mode 100644 source/opt/legalize_vector_shuffle_pass.cpp delete mode 100644 source/opt/legalize_vector_shuffle_pass.h delete mode 100644 source/opt/split_invalid_unreachable_pass.cpp delete mode 100644 source/opt/split_invalid_unreachable_pass.h delete mode 100644 source/opt/strip_atomic_counter_memory_pass.cpp delete mode 100644 source/opt/strip_atomic_counter_memory_pass.h delete mode 100644 test/fuzzers/spvtools_opt_vulkantowebgpu_fuzzer.cpp delete mode 100644 test/fuzzers/spvtools_opt_webgputovulkan_fuzzer.cpp delete mode 100644 test/fuzzers/spvtools_val_webgpu_fuzzer.cpp delete mode 100644 test/opt/decompose_initialized_variables_test.cpp delete mode 100644 test/opt/generate_webgpu_initializers_test.cpp delete mode 100644 test/opt/legalize_vector_shuffle_test.cpp delete mode 100644 test/opt/split_invalid_unreachable_test.cpp delete mode 100644 test/opt/strip_atomic_counter_memory_test.cpp delete mode 100644 test/val/val_webgpu_test.cpp diff --git a/Android.mk b/Android.mk index 0b64ea6d..1000f422 100644 --- a/Android.mk +++ b/Android.mk @@ -93,7 +93,6 @@ SPVTOOLS_OPT_SRC_FILES := \ source/opt/dead_branch_elim_pass.cpp \ source/opt/dead_insert_elim_pass.cpp \ source/opt/dead_variable_elimination.cpp \ - source/opt/decompose_initialized_variables_pass.cpp \ source/opt/decoration_manager.cpp \ source/opt/debug_info_manager.cpp \ source/opt/def_use_manager.cpp \ @@ -112,7 +111,6 @@ SPVTOOLS_OPT_SRC_FILES := \ source/opt/fold_spec_constant_op_and_composite_pass.cpp \ source/opt/freeze_spec_constant_value_pass.cpp \ source/opt/function.cpp \ - source/opt/generate_webgpu_initializers_pass.cpp \ source/opt/graphics_robust_access_pass.cpp \ source/opt/if_conversion.cpp \ source/opt/inline_pass.cpp \ @@ -126,7 +124,6 @@ SPVTOOLS_OPT_SRC_FILES := \ source/opt/instrument_pass.cpp \ source/opt/ir_context.cpp \ source/opt/ir_loader.cpp \ - source/opt/legalize_vector_shuffle_pass.cpp \ source/opt/licm_pass.cpp \ source/opt/local_access_chain_convert_pass.cpp \ source/opt/local_redundancy_elimination.cpp \ @@ -161,10 +158,8 @@ SPVTOOLS_OPT_SRC_FILES := \ source/opt/scalar_replacement_pass.cpp \ source/opt/set_spec_constant_default_value_pass.cpp \ source/opt/simplification_pass.cpp \ - source/opt/split_invalid_unreachable_pass.cpp \ source/opt/ssa_rewrite_pass.cpp \ source/opt/strength_reduction_pass.cpp \ - source/opt/strip_atomic_counter_memory_pass.cpp \ source/opt/strip_debug_info_pass.cpp \ source/opt/strip_reflect_info_pass.cpp \ source/opt/struct_cfg_analysis.cpp \ diff --git a/BUILD.gn b/BUILD.gn index 2387fc6a..845eb29e 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -539,8 +539,6 @@ static_library("spvtools_opt") { "source/opt/dead_insert_elim_pass.h", "source/opt/dead_variable_elimination.cpp", "source/opt/dead_variable_elimination.h", - "source/opt/decompose_initialized_variables_pass.cpp", - "source/opt/decompose_initialized_variables_pass.h", "source/opt/decoration_manager.cpp", "source/opt/decoration_manager.h", "source/opt/debug_info_manager.cpp", @@ -578,8 +576,6 @@ static_library("spvtools_opt") { "source/opt/freeze_spec_constant_value_pass.h", "source/opt/function.cpp", "source/opt/function.h", - "source/opt/generate_webgpu_initializers_pass.cpp", - "source/opt/generate_webgpu_initializers_pass.h", "source/opt/graphics_robust_access_pass.cpp", "source/opt/graphics_robust_access_pass.h", "source/opt/if_conversion.cpp", @@ -608,8 +604,6 @@ static_library("spvtools_opt") { "source/opt/ir_loader.cpp", "source/opt/ir_loader.h", "source/opt/iterator.h", - "source/opt/legalize_vector_shuffle_pass.cpp", - "source/opt/legalize_vector_shuffle_pass.h", "source/opt/licm_pass.cpp", "source/opt/licm_pass.h", "source/opt/local_access_chain_convert_pass.cpp", @@ -680,14 +674,10 @@ static_library("spvtools_opt") { "source/opt/set_spec_constant_default_value_pass.h", "source/opt/simplification_pass.cpp", "source/opt/simplification_pass.h", - "source/opt/split_invalid_unreachable_pass.cpp", - "source/opt/split_invalid_unreachable_pass.h", "source/opt/ssa_rewrite_pass.cpp", "source/opt/ssa_rewrite_pass.h", "source/opt/strength_reduction_pass.cpp", "source/opt/strength_reduction_pass.h", - "source/opt/strip_atomic_counter_memory_pass.cpp", - "source/opt/strip_atomic_counter_memory_pass.h", "source/opt/strip_debug_info_pass.cpp", "source/opt/strip_debug_info_pass.h", "source/opt/strip_reflect_info_pass.cpp", diff --git a/README.md b/README.md index 44f582fb..3637305b 100644 --- a/README.md +++ b/README.md @@ -136,7 +136,6 @@ As of this writing, there are 67 transforms including examples such as: * Loop-invariant code motion * Loop unroll * Other - * Generate WebGPU initializers * Graphics robust access * Upgrade memory model to VulkanKHR diff --git a/include/spirv-tools/libspirv.h b/include/spirv-tools/libspirv.h index a0114c3f..8f412a66 100644 --- a/include/spirv-tools/libspirv.h +++ b/include/spirv-tools/libspirv.h @@ -482,7 +482,7 @@ typedef enum { SPV_ENV_OPENCL_EMBEDDED_2_2, // OpenCL Embedded Profile 2.2 latest revision. SPV_ENV_UNIVERSAL_1_3, // SPIR-V 1.3 latest revision, no other restrictions. SPV_ENV_VULKAN_1_1, // Vulkan 1.1 latest revision. - SPV_ENV_WEBGPU_0, // Work in progress WebGPU 1.0. + SPV_ENV_WEBGPU_0, // DEPRECATED, may be removed in the future. SPV_ENV_UNIVERSAL_1_4, // SPIR-V 1.4 latest revision, no other restrictions. // Vulkan 1.1 with VK_KHR_spirv_1_4, i.e. SPIR-V 1.4 binary. diff --git a/include/spirv-tools/optimizer.hpp b/include/spirv-tools/optimizer.hpp index 27352b25..1683d077 100644 --- a/include/spirv-tools/optimizer.hpp +++ b/include/spirv-tools/optimizer.hpp @@ -68,11 +68,6 @@ class Optimizer { // The instance will have an empty message consumer, which ignores all // messages from the library. Use SetMessageConsumer() to supply a consumer // if messages are of concern. - // - // For collections of passes that are meant to transform the input into - // another execution environment, then the source environment should be - // supplied. e.g. for VulkanToWebGPUPasses the environment should be - // SPV_ENV_VULKAN_1_1 not SPV_ENV_WEBGPU_0. explicit Optimizer(spv_target_env env); // Disables copy/move constructor/assignment operations. @@ -106,16 +101,6 @@ class Optimizer { // from time to time. Optimizer& RegisterSizePasses(); - // Registers passes that have been prescribed for converting from Vulkan to - // WebGPU. This sequence of passes is subject to constant review and will - // change from time to time. - Optimizer& RegisterVulkanToWebGPUPasses(); - - // Registers passes that have been prescribed for converting from WebGPU to - // Vulkan. This sequence of passes is subject to constant review and will - // change from time to time. - Optimizer& RegisterWebGPUToVulkanPasses(); - // Registers passes that attempt to legalize the generated code. // // Note: this recipe is specially designed for legalizing SPIR-V. It should be @@ -238,13 +223,6 @@ class Optimizer { // A null pass does nothing to the SPIR-V module to be optimized. Optimizer::PassToken CreateNullPass(); -// Creates a strip-atomic-counter-memory pass. -// A strip-atomic-counter-memory pass removes all usages of the -// AtomicCounterMemory bit in Memory Semantics bitmasks. This bit is a no-op in -// Vulkan, so isn't needed in that env. And the related capability is not -// allowed in WebGPU, so it is not allowed in that env. -Optimizer::PassToken CreateStripAtomicCounterMemoryPass(); - // Creates a strip-debug-info pass. // A strip-debug-info pass removes all debug instructions (as documented in // Section 3.32.2 of the SPIR-V spec) of the SPIR-V module to be optimized. @@ -802,30 +780,11 @@ Optimizer::PassToken CreateUpgradeMemoryModelPass(); // where an instruction is moved into a more deeply nested construct. Optimizer::PassToken CreateCodeSinkingPass(); -// Create a pass to adds initializers for OpVariable calls that require them -// in WebGPU. Currently this pass naively initializes variables that are -// missing an initializer with a null value. In the future it may initialize -// variables to the first value stored in them, if that is a constant. -Optimizer::PassToken CreateGenerateWebGPUInitializersPass(); - // Create a pass to fix incorrect storage classes. In order to make code // generation simpler, DXC may generate code where the storage classes do not // match up correctly. This pass will fix the errors that it can. Optimizer::PassToken CreateFixStorageClassPass(); -// Create a pass to legalize OpVectorShuffle operands going into WebGPU. WebGPU -// forbids using 0xFFFFFFFF, which indicates an undefined result, so this pass -// converts those literals to 0. -Optimizer::PassToken CreateLegalizeVectorShufflePass(); - -// Create a pass to decompose initialized variables into a seperate variable -// declaration and an initial store. -Optimizer::PassToken CreateDecomposeInitializedVariablesPass(); - -// Create a pass to attempt to split up invalid unreachable merge-blocks and -// continue-targets to legalize for WebGPU. -Optimizer::PassToken CreateSplitInvalidUnreachablePass(); - // Creates a graphics robust access pass. // // This pass injects code to clamp indexed accesses to buffers and internal diff --git a/source/ext_inst.cpp b/source/ext_inst.cpp index 3471ebe0..795cb0f3 100644 --- a/source/ext_inst.cpp +++ b/source/ext_inst.cpp @@ -89,7 +89,6 @@ spv_result_t spvExtInstTableGet(spv_ext_inst_table* pExtInstTable, case SPV_ENV_UNIVERSAL_1_3: case SPV_ENV_VULKAN_1_1: case SPV_ENV_VULKAN_1_1_SPIRV_1_4: - case SPV_ENV_WEBGPU_0: case SPV_ENV_UNIVERSAL_1_4: case SPV_ENV_UNIVERSAL_1_5: case SPV_ENV_VULKAN_1_2: diff --git a/source/libspirv.cpp b/source/libspirv.cpp index a1ed11d3..0bc09350 100644 --- a/source/libspirv.cpp +++ b/source/libspirv.cpp @@ -14,8 +14,8 @@ #include "spirv-tools/libspirv.hpp" +#include #include - #include #include #include @@ -60,7 +60,9 @@ struct SpirvTools::Impl { spv_context context; // C interface context object. }; -SpirvTools::SpirvTools(spv_target_env env) : impl_(new Impl(env)) {} +SpirvTools::SpirvTools(spv_target_env env) : impl_(new Impl(env)) { + assert(env != SPV_ENV_WEBGPU_0); +} SpirvTools::~SpirvTools() {} diff --git a/source/opt/CMakeLists.txt b/source/opt/CMakeLists.txt index f3ac5906..14a6bee7 100644 --- a/source/opt/CMakeLists.txt +++ b/source/opt/CMakeLists.txt @@ -32,7 +32,6 @@ set(SPIRV_TOOLS_OPT_SOURCES dead_branch_elim_pass.h dead_insert_elim_pass.h dead_variable_elimination.h - decompose_initialized_variables_pass.h decoration_manager.h debug_info_manager.h def_use_manager.h @@ -52,7 +51,6 @@ set(SPIRV_TOOLS_OPT_SOURCES fold_spec_constant_op_and_composite_pass.h freeze_spec_constant_value_pass.h function.h - generate_webgpu_initializers_pass.h graphics_robust_access_pass.h if_conversion.h inline_exhaustive_pass.h @@ -103,10 +101,8 @@ set(SPIRV_TOOLS_OPT_SOURCES scalar_replacement_pass.h set_spec_constant_default_value_pass.h simplification_pass.h - split_invalid_unreachable_pass.h ssa_rewrite_pass.h strength_reduction_pass.h - strip_atomic_counter_memory_pass.h strip_debug_info_pass.h strip_reflect_info_pass.h struct_cfg_analysis.h @@ -140,7 +136,6 @@ set(SPIRV_TOOLS_OPT_SOURCES dead_branch_elim_pass.cpp dead_insert_elim_pass.cpp dead_variable_elimination.cpp - decompose_initialized_variables_pass.cpp decoration_manager.cpp debug_info_manager.cpp def_use_manager.cpp @@ -160,7 +155,6 @@ set(SPIRV_TOOLS_OPT_SOURCES freeze_spec_constant_value_pass.cpp function.cpp graphics_robust_access_pass.cpp - generate_webgpu_initializers_pass.cpp if_conversion.cpp inline_exhaustive_pass.cpp inline_opaque_pass.cpp @@ -173,7 +167,6 @@ set(SPIRV_TOOLS_OPT_SOURCES instrument_pass.cpp ir_context.cpp ir_loader.cpp - legalize_vector_shuffle_pass.cpp licm_pass.cpp local_access_chain_convert_pass.cpp local_redundancy_elimination.cpp @@ -208,10 +201,8 @@ set(SPIRV_TOOLS_OPT_SOURCES scalar_replacement_pass.cpp set_spec_constant_default_value_pass.cpp simplification_pass.cpp - split_invalid_unreachable_pass.cpp ssa_rewrite_pass.cpp strength_reduction_pass.cpp - strip_atomic_counter_memory_pass.cpp strip_debug_info_pass.cpp strip_reflect_info_pass.cpp struct_cfg_analysis.cpp diff --git a/source/opt/decompose_initialized_variables_pass.cpp b/source/opt/decompose_initialized_variables_pass.cpp deleted file mode 100644 index 875bf7e8..00000000 --- a/source/opt/decompose_initialized_variables_pass.cpp +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (c) 2019 Google LLC. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/opt/decompose_initialized_variables_pass.h" - -#include "source/opt/ir_context.h" - -namespace spvtools { -namespace opt { - -using inst_iterator = InstructionList::iterator; - -namespace { - -bool HasInitializer(Instruction* inst) { - if (inst->opcode() != SpvOpVariable) return false; - if (inst->NumOperands() < 4) return false; - - return true; -} - -} // namespace - -Pass::Status DecomposeInitializedVariablesPass::Process() { - auto* module = context()->module(); - std::unordered_set changed; - - std::vector> global_stores; - for (auto iter = module->types_values_begin(); - iter != module->types_values_end(); ++iter) { - Instruction* inst = &(*iter); - if (!HasInitializer(inst)) continue; - - auto var_id = inst->result_id(); - auto val_id = inst->GetOperand(3).words[0]; - global_stores.push_back(std::make_tuple(var_id, val_id)); - iter->RemoveOperand(3); - changed.insert(&*iter); - } - - std::unordered_set entry_ids; - for (auto entry = module->entry_points().begin(); - entry != module->entry_points().end(); ++entry) { - entry_ids.insert(entry->GetSingleWordInOperand(1)); - } - - for (auto func = module->begin(); func != module->end(); ++func) { - std::vector function_stores; - auto first_block = func->entry().get(); - inst_iterator insert_point = first_block->begin(); - for (auto iter = first_block->begin(); - iter != first_block->end() && iter->opcode() == SpvOpVariable; - ++iter) { - // For valid SPIRV-V, there is guaranteed to be at least one instruction - // after the OpVariable instructions. - insert_point = (*iter).NextNode(); - Instruction* inst = &(*iter); - if (!HasInitializer(inst)) continue; - - auto var_id = inst->result_id(); - auto val_id = inst->GetOperand(3).words[0]; - Instruction* store_inst = new Instruction( - context(), SpvOpStore, 0, 0, - {{SPV_OPERAND_TYPE_ID, {var_id}}, {SPV_OPERAND_TYPE_ID, {val_id}}}); - function_stores.push_back(store_inst); - iter->RemoveOperand(3); - changed.insert(&*iter); - } - - if (entry_ids.find(func->result_id()) != entry_ids.end()) { - for (auto store_ids : global_stores) { - uint32_t var_id; - uint32_t val_id; - std::tie(var_id, val_id) = store_ids; - auto* store_inst = new Instruction( - context(), SpvOpStore, 0, 0, - {{SPV_OPERAND_TYPE_ID, {var_id}}, {SPV_OPERAND_TYPE_ID, {val_id}}}); - context()->set_instr_block(store_inst, &*first_block); - first_block->AddInstruction(std::unique_ptr(store_inst)); - store_inst->InsertBefore(&*insert_point); - changed.insert(store_inst); - } - } - - for (auto store = function_stores.begin(); store != function_stores.end(); - ++store) { - context()->set_instr_block(*store, first_block); - (*store)->InsertBefore(&*insert_point); - changed.insert(*store); - } - } - - auto* def_use_mgr = get_def_use_mgr(); - for (auto* inst : changed) def_use_mgr->UpdateDefUse(inst); - - return !changed.empty() ? Pass::Status::SuccessWithChange - : Pass::Status::SuccessWithoutChange; -} - -} // namespace opt -} // namespace spvtools diff --git a/source/opt/decompose_initialized_variables_pass.h b/source/opt/decompose_initialized_variables_pass.h deleted file mode 100644 index c0bd35e7..00000000 --- a/source/opt/decompose_initialized_variables_pass.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2019 Google LLC. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_OPT_DECOMPOSE_INITALIZED_VAIRABLES_PASS_H_ -#define SOURCE_OPT_DECOMPOSE_INITALIZED_VAIRABLES_PASS_H_ - -#include "source/opt/ir_context.h" -#include "source/opt/module.h" -#include "source/opt/pass.h" - -namespace spvtools { -namespace opt { - -// Converts variable declartions with initializers into seperate declaration and -// assignment statements. This is done due to known issues with some Vulkan -// implementations' handling of initialized variables. -// -// Only decomposes variables with storage classes that are valid in Vulkan -// execution environments; Output, Private, and Function. -// Currently only Function is implemented. -class DecomposeInitializedVariablesPass : public Pass { - public: - const char* name() const override { - return "decompose-initialized-variables"; - } - Status Process() override; - - IRContext::Analysis GetPreservedAnalyses() override { - return IRContext::kAnalysisInstrToBlockMapping | - IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators | - IRContext::kAnalysisCFG | IRContext::kAnalysisDominatorAnalysis | - IRContext::kAnalysisLoopAnalysis | IRContext::kAnalysisNameMap | - IRContext::kAnalysisScalarEvolution | - IRContext::kAnalysisRegisterPressure | - IRContext::kAnalysisValueNumberTable | - IRContext::kAnalysisStructuredCFG | - IRContext::kAnalysisBuiltinVarId | - IRContext::kAnalysisIdToFuncMapping | IRContext::kAnalysisTypes | - IRContext::kAnalysisDefUse | IRContext::kAnalysisConstants; - } -}; - -} // namespace opt -} // namespace spvtools - -#endif // SOURCE_OPT_DECOMPOSE_INITALIZED_VAIRABLES_PASS_H_ diff --git a/source/opt/generate_webgpu_initializers_pass.cpp b/source/opt/generate_webgpu_initializers_pass.cpp deleted file mode 100644 index eaed3c28..00000000 --- a/source/opt/generate_webgpu_initializers_pass.cpp +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright (c) 2019 Google LLC. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/opt/generate_webgpu_initializers_pass.h" -#include "source/opt/ir_context.h" - -namespace spvtools { -namespace opt { - -using inst_iterator = InstructionList::iterator; - -namespace { - -bool NeedsWebGPUInitializer(Instruction* inst) { - if (inst->opcode() != SpvOpVariable) return false; - - auto storage_class = inst->GetSingleWordOperand(2); - if (storage_class != SpvStorageClassOutput && - storage_class != SpvStorageClassPrivate && - storage_class != SpvStorageClassFunction) { - return false; - } - - if (inst->NumOperands() > 3) return false; - - return true; -} - -} // namespace - -Pass::Status GenerateWebGPUInitializersPass::Process() { - auto* module = context()->module(); - bool changed = false; - - // Handle global/module scoped variables - for (auto iter = module->types_values_begin(); - iter != module->types_values_end(); ++iter) { - Instruction* inst = &(*iter); - - if (inst->opcode() == SpvOpConstantNull) { - null_constant_type_map_[inst->type_id()] = inst; - seen_null_constants_.insert(inst); - continue; - } - - if (!NeedsWebGPUInitializer(inst)) continue; - - changed = true; - - auto* constant_inst = GetNullConstantForVariable(inst); - if (!constant_inst) return Status::Failure; - - if (seen_null_constants_.find(constant_inst) == - seen_null_constants_.end()) { - constant_inst->InsertBefore(inst); - null_constant_type_map_[inst->type_id()] = inst; - seen_null_constants_.insert(inst); - } - AddNullInitializerToVariable(constant_inst, inst); - } - - // Handle local/function scoped variables - for (auto func = module->begin(); func != module->end(); ++func) { - auto block = func->entry().get(); - for (auto iter = block->begin(); - iter != block->end() && iter->opcode() == SpvOpVariable; ++iter) { - Instruction* inst = &(*iter); - if (!NeedsWebGPUInitializer(inst)) continue; - - changed = true; - auto* constant_inst = GetNullConstantForVariable(inst); - if (!constant_inst) return Status::Failure; - - AddNullInitializerToVariable(constant_inst, inst); - } - } - - return changed ? Status::SuccessWithChange : Status::SuccessWithoutChange; -} - -Instruction* GenerateWebGPUInitializersPass::GetNullConstantForVariable( - Instruction* variable_inst) { - auto constant_mgr = context()->get_constant_mgr(); - auto* def_use_mgr = get_def_use_mgr(); - - auto* ptr_inst = def_use_mgr->GetDef(variable_inst->type_id()); - auto type_id = ptr_inst->GetInOperand(1).words[0]; - if (null_constant_type_map_.find(type_id) == null_constant_type_map_.end()) { - auto* constant_type = context()->get_type_mgr()->GetType(type_id); - auto* constant = constant_mgr->GetConstant(constant_type, {}); - return constant_mgr->GetDefiningInstruction(constant, type_id); - } else { - return null_constant_type_map_[type_id]; - } -} - -void GenerateWebGPUInitializersPass::AddNullInitializerToVariable( - Instruction* constant_inst, Instruction* variable_inst) { - auto constant_id = constant_inst->result_id(); - variable_inst->AddOperand(Operand(SPV_OPERAND_TYPE_ID, {constant_id})); - get_def_use_mgr()->AnalyzeInstUse(variable_inst); -} - -} // namespace opt -} // namespace spvtools diff --git a/source/opt/generate_webgpu_initializers_pass.h b/source/opt/generate_webgpu_initializers_pass.h deleted file mode 100644 index f95e84c5..00000000 --- a/source/opt/generate_webgpu_initializers_pass.h +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) 2019 Google LLC. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_OPT_GENERATE_WEBGPU_INITIALIZERS_PASS_H_ -#define SOURCE_OPT_GENERATE_WEBGPU_INITIALIZERS_PASS_H_ - -#include "source/opt/ir_context.h" -#include "source/opt/module.h" -#include "source/opt/pass.h" - -namespace spvtools { -namespace opt { - -// Adds initializers to variables with storage classes Output, Private, and -// Function if they are missing. In the WebGPU environment these storage classes -// require that the variables are initialized. Currently they are initialized to -// NULL, though in the future some of them may be initialized to the first value -// that is stored in them, if that was a constant. -class GenerateWebGPUInitializersPass : public Pass { - public: - const char* name() const override { return "generate-webgpu-initializers"; } - Status Process() override; - - IRContext::Analysis GetPreservedAnalyses() override { - return IRContext::kAnalysisInstrToBlockMapping | - IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators | - IRContext::kAnalysisCFG | IRContext::kAnalysisDominatorAnalysis | - IRContext::kAnalysisLoopAnalysis | IRContext::kAnalysisNameMap | - IRContext::kAnalysisScalarEvolution | - IRContext::kAnalysisRegisterPressure | - IRContext::kAnalysisValueNumberTable | - IRContext::kAnalysisStructuredCFG | - IRContext::kAnalysisBuiltinVarId | - IRContext::kAnalysisIdToFuncMapping | IRContext::kAnalysisTypes | - IRContext::kAnalysisDefUse | IRContext::kAnalysisConstants; - } - - private: - using NullConstantTypeMap = std::unordered_map; - NullConstantTypeMap null_constant_type_map_; - std::unordered_set seen_null_constants_; - - Instruction* GetNullConstantForVariable(Instruction* variable_inst); - void AddNullInitializerToVariable(Instruction* constant_inst, - Instruction* variable_inst); -}; - -} // namespace opt -} // namespace spvtools - -#endif // SOURCE_OPT_GENERATE_WEBGPU_INITIALIZERS_PASS_H_ diff --git a/source/opt/legalize_vector_shuffle_pass.cpp b/source/opt/legalize_vector_shuffle_pass.cpp deleted file mode 100644 index b5d5d599..00000000 --- a/source/opt/legalize_vector_shuffle_pass.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2019 Google LLC. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/opt/legalize_vector_shuffle_pass.h" - -#include "source/opt/ir_context.h" - -namespace spvtools { -namespace opt { - -Pass::Status LegalizeVectorShufflePass::Process() { - bool changed = false; - context()->module()->ForEachInst([&changed](Instruction* inst) { - if (inst->opcode() != SpvOpVectorShuffle) return; - - for (uint32_t idx = 2; idx < inst->NumInOperands(); ++idx) { - auto literal = inst->GetSingleWordInOperand(idx); - if (literal != 0xFFFFFFFF) continue; - changed = true; - inst->SetInOperand(idx, {0}); - } - }); - - return changed ? Status::SuccessWithChange : Status::SuccessWithoutChange; -} - -} // namespace opt -} // namespace spvtools diff --git a/source/opt/legalize_vector_shuffle_pass.h b/source/opt/legalize_vector_shuffle_pass.h deleted file mode 100644 index ca6e1dfb..00000000 --- a/source/opt/legalize_vector_shuffle_pass.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2019 Google LLC. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_OPT_LEGALIZE_VECTOR_SHUFFLE_PASS_H_ -#define SOURCE_OPT_LEGALIZE_VECTOR_SHUFFLE_PASS_H_ - -#include "source/opt/ir_context.h" -#include "source/opt/module.h" -#include "source/opt/pass.h" - -namespace spvtools { -namespace opt { - -// Converts any usages of 0xFFFFFFFF for the literals in OpVectorShuffle to a -// literal 0. This is needed because using OxFFFFFFFF is forbidden by the WebGPU -// spec. 0xFFFFFFFF in the main spec indicates that the result for this -// component has no source, thus is undefined. Since this is undefined -// behaviour we are free to use 0. -class LegalizeVectorShufflePass : public Pass { - public: - const char* name() const override { return "legalize-vector-shuffle"; } - Status Process() override; - - IRContext::Analysis GetPreservedAnalyses() override { - return IRContext::kAnalysisInstrToBlockMapping | - IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators | - IRContext::kAnalysisCFG | IRContext::kAnalysisDominatorAnalysis | - IRContext::kAnalysisLoopAnalysis | IRContext::kAnalysisNameMap | - IRContext::kAnalysisScalarEvolution | - IRContext::kAnalysisRegisterPressure | - IRContext::kAnalysisValueNumberTable | - IRContext::kAnalysisStructuredCFG | - IRContext::kAnalysisBuiltinVarId | - IRContext::kAnalysisIdToFuncMapping | IRContext::kAnalysisTypes | - IRContext::kAnalysisDefUse | IRContext::kAnalysisConstants; - } -}; - -} // namespace opt -} // namespace spvtools - -#endif // SOURCE_OPT_LEGALIZE_VECTOR_SHUFFLE_PASS_H_ diff --git a/source/opt/optimizer.cpp b/source/opt/optimizer.cpp index c2a21f2c..909442cc 100644 --- a/source/opt/optimizer.cpp +++ b/source/opt/optimizer.cpp @@ -62,7 +62,9 @@ struct Optimizer::Impl { opt::PassManager pass_manager; // Internal implementation pass manager. }; -Optimizer::Optimizer(spv_target_env env) : impl_(new Impl(env)) {} +Optimizer::Optimizer(spv_target_env env) : impl_(new Impl(env)) { + assert(env != SPV_ENV_WEBGPU_0); +} Optimizer::~Optimizer() {} @@ -239,23 +241,6 @@ Optimizer& Optimizer::RegisterSizePasses() { .RegisterPass(CreateCFGCleanupPass()); } -Optimizer& Optimizer::RegisterVulkanToWebGPUPasses() { - return RegisterPass(CreateStripAtomicCounterMemoryPass()) - .RegisterPass(CreateGenerateWebGPUInitializersPass()) - .RegisterPass(CreateLegalizeVectorShufflePass()) - .RegisterPass(CreateSplitInvalidUnreachablePass()) - .RegisterPass(CreateEliminateDeadConstantPass()) - .RegisterPass(CreateFlattenDecorationPass()) - .RegisterPass(CreateAggressiveDCEPass()) - .RegisterPass(CreateDeadBranchElimPass()) - .RegisterPass(CreateCompactIdsPass()); -} - -Optimizer& Optimizer::RegisterWebGPUToVulkanPasses() { - return RegisterPass(CreateDecomposeInitializedVariablesPass()) - .RegisterPass(CreateCompactIdsPass()); -} - bool Optimizer::RegisterPassesFromFlags(const std::vector& flags) { for (const auto& flag : flags) { if (!RegisterPassFromFlag(flag)) { @@ -298,9 +283,7 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) { // // Both Pass::name() and Pass::desc() should be static class members so they // can be invoked without creating a pass instance. - if (pass_name == "strip-atomic-counter-memory") { - RegisterPass(CreateStripAtomicCounterMemoryPass()); - } else if (pass_name == "strip-debug") { + if (pass_name == "strip-debug") { RegisterPass(CreateStripDebugInfoPass()); } else if (pass_name == "strip-reflect") { RegisterPass(CreateStripReflectInfoPass()); @@ -505,14 +488,6 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) { RegisterSizePasses(); } else if (pass_name == "legalize-hlsl") { RegisterLegalizationPasses(); - } else if (pass_name == "generate-webgpu-initializers") { - RegisterPass(CreateGenerateWebGPUInitializersPass()); - } else if (pass_name == "legalize-vector-shuffle") { - RegisterPass(CreateLegalizeVectorShufflePass()); - } else if (pass_name == "split-invalid-unreachable") { - RegisterPass(CreateSplitInvalidUnreachablePass()); - } else if (pass_name == "decompose-initialized-variables") { - RegisterPass(CreateDecomposeInitializedVariablesPass()); } else if (pass_name == "graphics-robust-access") { RegisterPass(CreateGraphicsRobustAccessPass()); } else if (pass_name == "wrap-opkill") { @@ -629,11 +604,6 @@ Optimizer::PassToken CreateNullPass() { return MakeUnique(MakeUnique()); } -Optimizer::PassToken CreateStripAtomicCounterMemoryPass() { - return MakeUnique( - MakeUnique()); -} - Optimizer::PassToken CreateStripDebugInfoPass() { return MakeUnique( MakeUnique()); @@ -931,31 +901,11 @@ Optimizer::PassToken CreateCodeSinkingPass() { MakeUnique()); } -Optimizer::PassToken CreateGenerateWebGPUInitializersPass() { - return MakeUnique( - MakeUnique()); -} - Optimizer::PassToken CreateFixStorageClassPass() { return MakeUnique( MakeUnique()); } -Optimizer::PassToken CreateLegalizeVectorShufflePass() { - return MakeUnique( - MakeUnique()); -} - -Optimizer::PassToken CreateDecomposeInitializedVariablesPass() { - return MakeUnique( - MakeUnique()); -} - -Optimizer::PassToken CreateSplitInvalidUnreachablePass() { - return MakeUnique( - MakeUnique()); -} - Optimizer::PassToken CreateGraphicsRobustAccessPass() { return MakeUnique( MakeUnique()); diff --git a/source/opt/passes.h b/source/opt/passes.h index d47cc1ce..1bc94c7e 100644 --- a/source/opt/passes.h +++ b/source/opt/passes.h @@ -30,7 +30,6 @@ #include "source/opt/dead_branch_elim_pass.h" #include "source/opt/dead_insert_elim_pass.h" #include "source/opt/dead_variable_elimination.h" -#include "source/opt/decompose_initialized_variables_pass.h" #include "source/opt/desc_sroa.h" #include "source/opt/eliminate_dead_constant_pass.h" #include "source/opt/eliminate_dead_functions_pass.h" @@ -40,7 +39,6 @@ #include "source/opt/flatten_decoration_pass.h" #include "source/opt/fold_spec_constant_op_and_composite_pass.h" #include "source/opt/freeze_spec_constant_value_pass.h" -#include "source/opt/generate_webgpu_initializers_pass.h" #include "source/opt/graphics_robust_access_pass.h" #include "source/opt/if_conversion.h" #include "source/opt/inline_exhaustive_pass.h" @@ -48,7 +46,6 @@ #include "source/opt/inst_bindless_check_pass.h" #include "source/opt/inst_buff_addr_check_pass.h" #include "source/opt/inst_debug_printf_pass.h" -#include "source/opt/legalize_vector_shuffle_pass.h" #include "source/opt/licm_pass.h" #include "source/opt/local_access_chain_convert_pass.h" #include "source/opt/local_redundancy_elimination.h" @@ -70,10 +67,8 @@ #include "source/opt/scalar_replacement_pass.h" #include "source/opt/set_spec_constant_default_value_pass.h" #include "source/opt/simplification_pass.h" -#include "source/opt/split_invalid_unreachable_pass.h" #include "source/opt/ssa_rewrite_pass.h" #include "source/opt/strength_reduction_pass.h" -#include "source/opt/strip_atomic_counter_memory_pass.h" #include "source/opt/strip_debug_info_pass.h" #include "source/opt/strip_reflect_info_pass.h" #include "source/opt/unify_const_pass.h" diff --git a/source/opt/split_invalid_unreachable_pass.cpp b/source/opt/split_invalid_unreachable_pass.cpp deleted file mode 100644 index 31cfbc33..00000000 --- a/source/opt/split_invalid_unreachable_pass.cpp +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) 2019 Google LLC. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/opt/split_invalid_unreachable_pass.h" - -#include "source/opt/ir_builder.h" -#include "source/opt/ir_context.h" - -namespace spvtools { -namespace opt { - -Pass::Status SplitInvalidUnreachablePass::Process() { - bool changed = false; - std::unordered_set entry_points; - for (auto entry_point : context()->module()->entry_points()) { - entry_points.insert(entry_point.GetSingleWordOperand(1)); - } - - for (auto func = context()->module()->begin(); - func != context()->module()->end(); ++func) { - if (entry_points.find(func->result_id()) == entry_points.end()) continue; - std::unordered_set continue_targets; - std::unordered_set merge_blocks; - std::unordered_set unreachable_blocks; - for (auto block = func->begin(); block != func->end(); ++block) { - unreachable_blocks.insert(&*block); - uint32_t continue_target = block->ContinueBlockIdIfAny(); - if (continue_target != 0) continue_targets.insert(continue_target); - uint32_t merge_block = block->MergeBlockIdIfAny(); - if (merge_block != 0) merge_blocks.insert(merge_block); - } - - cfg()->ForEachBlockInPostOrder( - func->entry().get(), [&unreachable_blocks](BasicBlock* inner_block) { - unreachable_blocks.erase(inner_block); - }); - - for (auto unreachable : unreachable_blocks) { - uint32_t block_id = unreachable->id(); - if (continue_targets.find(block_id) == continue_targets.end() || - merge_blocks.find(block_id) == merge_blocks.end()) { - continue; - } - - std::vector> usages; - context()->get_def_use_mgr()->ForEachUse( - unreachable->GetLabelInst(), - [&usages](Instruction* use, uint32_t idx) { - if ((use->opcode() == SpvOpLoopMerge && idx == 0) || - use->opcode() == SpvOpSelectionMerge) { - usages.push_back(std::make_pair(use, idx)); - } - }); - - for (auto usage : usages) { - Instruction* use; - uint32_t idx; - std::tie(use, idx) = usage; - uint32_t new_id = context()->TakeNextId(); - std::unique_ptr new_label( - new Instruction(context(), SpvOpLabel, 0, new_id, {})); - get_def_use_mgr()->AnalyzeInstDefUse(new_label.get()); - std::unique_ptr new_block( - new BasicBlock(std::move(new_label))); - auto* block_ptr = new_block.get(); - InstructionBuilder builder(context(), new_block.get(), - IRContext::kAnalysisDefUse | - IRContext::kAnalysisInstrToBlockMapping); - builder.AddUnreachable(); - cfg()->RegisterBlock(block_ptr); - (&*func)->InsertBasicBlockBefore(std::move(new_block), unreachable); - use->SetInOperand(0, {new_id}); - get_def_use_mgr()->UpdateDefUse(use); - cfg()->AddEdges(block_ptr); - changed = true; - } - } - } - - return changed ? Status::SuccessWithChange : Status::SuccessWithoutChange; -} - -} // namespace opt -} // namespace spvtools diff --git a/source/opt/split_invalid_unreachable_pass.h b/source/opt/split_invalid_unreachable_pass.h deleted file mode 100644 index a5613448..00000000 --- a/source/opt/split_invalid_unreachable_pass.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2019 Google LLC. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_OPT_SPLIT_INVALID_UNREACHABLE_PASS_H_ -#define SOURCE_OPT_SPLIT_INVALID_UNREACHABLE_PASS_H_ - -#include "source/opt/ir_context.h" -#include "source/opt/module.h" -#include "source/opt/pass.h" - -namespace spvtools { -namespace opt { - -// Attempts to legalize for WebGPU by splitting up invalid unreachable blocks. -// Specifically, looking for cases of unreachable merge-blocks and -// continue-targets that are used more then once, which is illegal in WebGPU. -class SplitInvalidUnreachablePass : public Pass { - public: - const char* name() const override { return "split-invalid-unreachable"; } - Status Process() override; - - IRContext::Analysis GetPreservedAnalyses() override { - return IRContext::kAnalysisInstrToBlockMapping | - IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators | - IRContext::kAnalysisCFG | IRContext::kAnalysisDominatorAnalysis | - IRContext::kAnalysisLoopAnalysis | IRContext::kAnalysisNameMap | - IRContext::kAnalysisScalarEvolution | - IRContext::kAnalysisRegisterPressure | - IRContext::kAnalysisValueNumberTable | - IRContext::kAnalysisStructuredCFG | - IRContext::kAnalysisBuiltinVarId | - IRContext::kAnalysisIdToFuncMapping | IRContext::kAnalysisTypes | - IRContext::kAnalysisDefUse | IRContext::kAnalysisConstants; - } -}; - -} // namespace opt -} // namespace spvtools - -#endif // SOURCE_OPT_SPLIT_INVALID_UNREACHABLE_PASS_H_ diff --git a/source/opt/strip_atomic_counter_memory_pass.cpp b/source/opt/strip_atomic_counter_memory_pass.cpp deleted file mode 100644 index 47714b74..00000000 --- a/source/opt/strip_atomic_counter_memory_pass.cpp +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2019 Google LLC. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/opt/strip_atomic_counter_memory_pass.h" -#include "source/opt/ir_context.h" - -namespace spvtools { -namespace opt { - -Pass::Status StripAtomicCounterMemoryPass::Process() { - bool changed = false; - context()->module()->ForEachInst([this, &changed](Instruction* inst) { - auto indices = spvOpcodeMemorySemanticsOperandIndices(inst->opcode()); - if (indices.empty()) return; - - for (auto idx : indices) { - auto mem_sem_id = inst->GetSingleWordOperand(idx); - const auto& mem_sem_inst = - context()->get_def_use_mgr()->GetDef(mem_sem_id); - // The spec explicitly says that this id must be an OpConstant - auto mem_sem_val = mem_sem_inst->GetSingleWordOperand(2); - if (!(mem_sem_val & SpvMemorySemanticsAtomicCounterMemoryMask)) { - continue; - } - mem_sem_val &= ~SpvMemorySemanticsAtomicCounterMemoryMask; - - analysis::Integer int_type(32, false); - const analysis::Type* uint32_type = - context()->get_type_mgr()->GetRegisteredType(&int_type); - auto* new_const = context()->get_constant_mgr()->GetConstant( - uint32_type, {mem_sem_val}); - auto* new_const_inst = - context()->get_constant_mgr()->GetDefiningInstruction(new_const); - auto new_const_id = new_const_inst->result_id(); - - inst->SetOperand(idx, {new_const_id}); - context()->UpdateDefUse(inst); - changed = true; - } - }); - - return changed ? Status::SuccessWithChange : Status::SuccessWithoutChange; -} - -} // namespace opt -} // namespace spvtools diff --git a/source/opt/strip_atomic_counter_memory_pass.h b/source/opt/strip_atomic_counter_memory_pass.h deleted file mode 100644 index 62e274a1..00000000 --- a/source/opt/strip_atomic_counter_memory_pass.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2019 Google LLC. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_OPT_STRIP_ATOMIC_COUNT_MEMORY_PASS_H_ -#define SOURCE_OPT_STRIP_ATOMIC_COUNT_MEMORY_PASS_H_ - -#include "source/opt/ir_context.h" -#include "source/opt/module.h" -#include "source/opt/pass.h" - -namespace spvtools { -namespace opt { - -// Removes the AtomicCounterMemory bit from the value being passed into memory -// semantics. This bit being set is ignored in Vulkan environments and -// forbidden WebGPU ones. -class StripAtomicCounterMemoryPass : public Pass { - public: - const char* name() const override { return "strip-atomic-counter-memory"; } - Status Process() override; - - IRContext::Analysis GetPreservedAnalyses() override { - return IRContext::kAnalysisInstrToBlockMapping | - IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators | - IRContext::kAnalysisCFG | IRContext::kAnalysisDominatorAnalysis | - IRContext::kAnalysisLoopAnalysis | IRContext::kAnalysisNameMap | - IRContext::kAnalysisScalarEvolution | - IRContext::kAnalysisRegisterPressure | - IRContext::kAnalysisValueNumberTable | - IRContext::kAnalysisStructuredCFG | - IRContext::kAnalysisBuiltinVarId | - IRContext::kAnalysisIdToFuncMapping | IRContext::kAnalysisTypes | - IRContext::kAnalysisDefUse | IRContext::kAnalysisConstants; - } -}; - -} // namespace opt -} // namespace spvtools - -#endif // SOURCE_OPT_STRIP_ATOMIC_COUNT_MEMORY_PASS_H_ diff --git a/source/spirv_target_env.cpp b/source/spirv_target_env.cpp index e2ff99cb..f20ebb4f 100644 --- a/source/spirv_target_env.cpp +++ b/source/spirv_target_env.cpp @@ -14,6 +14,7 @@ #include "source/spirv_target_env.h" +#include #include #include @@ -61,7 +62,8 @@ const char* spvTargetEnvDescription(spv_target_env env) { case SPV_ENV_VULKAN_1_1: return "SPIR-V 1.3 (under Vulkan 1.1 semantics)"; case SPV_ENV_WEBGPU_0: - return "SPIR-V 1.3 (under WIP WebGPU semantics)"; + assert(false); + break; case SPV_ENV_UNIVERSAL_1_4: return "SPIR-V 1.4"; case SPV_ENV_VULKAN_1_1_SPIRV_1_4: @@ -98,8 +100,10 @@ uint32_t spvVersionForTargetEnv(spv_target_env env) { return SPV_SPIRV_VERSION_WORD(1, 2); case SPV_ENV_UNIVERSAL_1_3: case SPV_ENV_VULKAN_1_1: - case SPV_ENV_WEBGPU_0: return SPV_SPIRV_VERSION_WORD(1, 3); + case SPV_ENV_WEBGPU_0: + assert(false); + break; case SPV_ENV_UNIVERSAL_1_4: case SPV_ENV_VULKAN_1_1_SPIRV_1_4: return SPV_SPIRV_VERSION_WORD(1, 4); @@ -134,7 +138,6 @@ static const std::pair spvTargetEnvNameMap[] = { {"opengl4.2", SPV_ENV_OPENGL_4_2}, {"opengl4.3", SPV_ENV_OPENGL_4_3}, {"opengl4.5", SPV_ENV_OPENGL_4_5}, - {"webgpu0", SPV_ENV_WEBGPU_0}, }; bool spvParseTargetEnv(const char* s, spv_target_env* env) { @@ -200,7 +203,6 @@ bool spvIsVulkanEnv(spv_target_env env) { case SPV_ENV_OPENCL_2_2: case SPV_ENV_OPENCL_EMBEDDED_2_2: case SPV_ENV_UNIVERSAL_1_3: - case SPV_ENV_WEBGPU_0: case SPV_ENV_UNIVERSAL_1_4: case SPV_ENV_UNIVERSAL_1_5: return false; @@ -209,6 +211,9 @@ bool spvIsVulkanEnv(spv_target_env env) { case SPV_ENV_VULKAN_1_1_SPIRV_1_4: case SPV_ENV_VULKAN_1_2: return true; + case SPV_ENV_WEBGPU_0: + assert(false); + break; } return false; } @@ -226,7 +231,6 @@ bool spvIsOpenCLEnv(spv_target_env env) { case SPV_ENV_UNIVERSAL_1_2: case SPV_ENV_UNIVERSAL_1_3: case SPV_ENV_VULKAN_1_1: - case SPV_ENV_WEBGPU_0: case SPV_ENV_UNIVERSAL_1_4: case SPV_ENV_VULKAN_1_1_SPIRV_1_4: case SPV_ENV_UNIVERSAL_1_5: @@ -241,38 +245,9 @@ bool spvIsOpenCLEnv(spv_target_env env) { case SPV_ENV_OPENCL_2_1: case SPV_ENV_OPENCL_2_2: return true; - } - return false; -} - -bool spvIsWebGPUEnv(spv_target_env env) { - switch (env) { - case SPV_ENV_UNIVERSAL_1_0: - case SPV_ENV_VULKAN_1_0: - case SPV_ENV_UNIVERSAL_1_1: - case SPV_ENV_OPENGL_4_0: - case SPV_ENV_OPENGL_4_1: - case SPV_ENV_OPENGL_4_2: - case SPV_ENV_OPENGL_4_3: - case SPV_ENV_OPENGL_4_5: - case SPV_ENV_UNIVERSAL_1_2: - case SPV_ENV_UNIVERSAL_1_3: - case SPV_ENV_VULKAN_1_1: - case SPV_ENV_OPENCL_1_2: - case SPV_ENV_OPENCL_EMBEDDED_1_2: - case SPV_ENV_OPENCL_2_0: - case SPV_ENV_OPENCL_EMBEDDED_2_0: - case SPV_ENV_OPENCL_EMBEDDED_2_1: - case SPV_ENV_OPENCL_EMBEDDED_2_2: - case SPV_ENV_OPENCL_2_1: - case SPV_ENV_OPENCL_2_2: - case SPV_ENV_UNIVERSAL_1_4: - case SPV_ENV_VULKAN_1_1_SPIRV_1_4: - case SPV_ENV_UNIVERSAL_1_5: - case SPV_ENV_VULKAN_1_2: - return false; case SPV_ENV_WEBGPU_0: - return true; + assert(false); + break; } return false; } @@ -293,7 +268,6 @@ bool spvIsOpenGLEnv(spv_target_env env) { case SPV_ENV_OPENCL_EMBEDDED_2_2: case SPV_ENV_OPENCL_2_1: case SPV_ENV_OPENCL_2_2: - case SPV_ENV_WEBGPU_0: case SPV_ENV_UNIVERSAL_1_4: case SPV_ENV_VULKAN_1_1_SPIRV_1_4: case SPV_ENV_UNIVERSAL_1_5: @@ -305,14 +279,13 @@ bool spvIsOpenGLEnv(spv_target_env env) { case SPV_ENV_OPENGL_4_3: case SPV_ENV_OPENGL_4_5: return true; + case SPV_ENV_WEBGPU_0: + assert(false); + break; } return false; } -bool spvIsVulkanOrWebGPUEnv(spv_target_env env) { - return spvIsVulkanEnv(env) || spvIsWebGPUEnv(env); -} - std::string spvLogStringForEnv(spv_target_env env) { switch (env) { case SPV_ENV_OPENCL_1_2: @@ -338,9 +311,6 @@ std::string spvLogStringForEnv(spv_target_env env) { case SPV_ENV_VULKAN_1_2: return "Vulkan"; } - case SPV_ENV_WEBGPU_0: { - return "WebGPU"; - } case SPV_ENV_UNIVERSAL_1_0: case SPV_ENV_UNIVERSAL_1_1: case SPV_ENV_UNIVERSAL_1_2: @@ -349,6 +319,9 @@ std::string spvLogStringForEnv(spv_target_env env) { case SPV_ENV_UNIVERSAL_1_5: { return "Universal"; } + case SPV_ENV_WEBGPU_0: + assert(false); + break; } return "Unknown"; } diff --git a/source/spirv_target_env.h b/source/spirv_target_env.h index 1bdedf91..a804d615 100644 --- a/source/spirv_target_env.h +++ b/source/spirv_target_env.h @@ -25,20 +25,14 @@ bool spvIsVulkanEnv(spv_target_env env); // Returns true if |env| is an OPENCL environment, false otherwise. bool spvIsOpenCLEnv(spv_target_env env); -// Returns true if |env| is an WEBGPU environment, false otherwise. -bool spvIsWebGPUEnv(spv_target_env env); - // Returns true if |env| is an OPENGL environment, false otherwise. bool spvIsOpenGLEnv(spv_target_env env); -// Returns true if |env| is a VULKAN or WEBGPU environment, false otherwise. -bool spvIsVulkanOrWebGPUEnv(spv_target_env env); - // Returns the version number for the given SPIR-V target environment. uint32_t spvVersionForTargetEnv(spv_target_env env); // Returns a string to use in logging messages that indicates the class of -// environment, i.e. "Vulkan", "WebGPU", "OpenCL", etc. +// environment, i.e. "Vulkan", "OpenCL", etc. std::string spvLogStringForEnv(spv_target_env env); // Returns a formatted list of all SPIR-V target environment names that diff --git a/source/table.cpp b/source/table.cpp index 8340e8e2..d4a2d7e9 100644 --- a/source/table.cpp +++ b/source/table.cpp @@ -38,7 +38,6 @@ spv_context spvContextCreate(spv_target_env env) { case SPV_ENV_UNIVERSAL_1_3: case SPV_ENV_VULKAN_1_1: case SPV_ENV_VULKAN_1_1_SPIRV_1_4: - case SPV_ENV_WEBGPU_0: case SPV_ENV_UNIVERSAL_1_4: case SPV_ENV_UNIVERSAL_1_5: case SPV_ENV_VULKAN_1_2: diff --git a/source/val/validate.cpp b/source/val/validate.cpp index d6e992b1..a2e116b1 100644 --- a/source/val/validate.cpp +++ b/source/val/validate.cpp @@ -111,57 +111,6 @@ spv_result_t ValidateForwardDecls(ValidationState_t& _) { << id_str.substr(0, id_str.size() - 1); } -std::vector CalculateNamesForEntryPoint(ValidationState_t& _, - const uint32_t id) { - auto id_descriptions = _.entry_point_descriptions(id); - auto id_names = std::vector(); - id_names.reserve((id_descriptions.size())); - - for (auto description : id_descriptions) id_names.push_back(description.name); - - return id_names; -} - -spv_result_t ValidateEntryPointNameUnique(ValidationState_t& _, - const uint32_t id) { - auto id_names = CalculateNamesForEntryPoint(_, id); - const auto names = - std::unordered_set(id_names.begin(), id_names.end()); - - if (id_names.size() != names.size()) { - std::sort(id_names.begin(), id_names.end()); - for (size_t i = 0; i < id_names.size() - 1; i++) { - if (id_names[i] == id_names[i + 1]) { - return _.diag(SPV_ERROR_INVALID_BINARY, _.FindDef(id)) - << "Entry point name \"" << id_names[i] - << "\" is not unique, which is not allow in WebGPU env."; - } - } - } - - for (const auto other_id : _.entry_points()) { - if (other_id == id) continue; - const auto other_id_names = CalculateNamesForEntryPoint(_, other_id); - for (const auto& other_id_name : other_id_names) { - if (names.find(other_id_name) != names.end()) { - return _.diag(SPV_ERROR_INVALID_BINARY, _.FindDef(id)) - << "Entry point name \"" << other_id_name - << "\" is not unique, which is not allow in WebGPU env."; - } - } - } - - return SPV_SUCCESS; -} - -spv_result_t ValidateEntryPointNamesUnique(ValidationState_t& _) { - for (const auto id : _.entry_points()) { - auto result = ValidateEntryPointNameUnique(_, id); - if (result != SPV_SUCCESS) return result; - } - return SPV_SUCCESS; -} - // Entry point validation. Based on 2.16.1 (Universal Validation Rules) of the // SPIRV spec: // * There is at least one OpEntryPoint instruction, unless the Linkage @@ -169,8 +118,7 @@ spv_result_t ValidateEntryPointNamesUnique(ValidationState_t& _) { // * No function can be targeted by both an OpEntryPoint instruction and an // OpFunctionCall instruction. // -// Additionally enforces that entry points for Vulkan and WebGPU should not have -// recursion. And that entry names should be unique for WebGPU. +// Additionally enforces that entry points for Vulkan should not have recursion. spv_result_t ValidateEntryPoints(ValidationState_t& _) { _.ComputeFunctionToEntryPointMapping(); _.ComputeRecursiveEntryPoints(); @@ -189,21 +137,15 @@ spv_result_t ValidateEntryPoints(ValidationState_t& _) { "an OpFunctionCall instruction."; } - // For Vulkan and WebGPU, the static function-call graph for an entry point + // For Vulkan, the static function-call graph for an entry point // must not contain cycles. - if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { + if (spvIsVulkanEnv(_.context()->target_env)) { if (_.recursive_entry_points().find(entry_point) != _.recursive_entry_points().end()) { return _.diag(SPV_ERROR_INVALID_BINARY, _.FindDef(entry_point)) << "Entry points may not have a call graph with cycles."; } } - - // For WebGPU all entry point names must be unique. - if (spvIsWebGPUEnv(_.context()->target_env)) { - const auto result = ValidateEntryPointNamesUnique(_); - if (result != SPV_SUCCESS) return result; - } } return SPV_SUCCESS; @@ -223,12 +165,6 @@ spv_result_t ValidateBinaryUsingContextAndValidationState( << "Invalid SPIR-V magic number."; } - if (spvIsWebGPUEnv(context.target_env) && endian != SPV_ENDIANNESS_LITTLE) { - return DiagnosticStream(position, context.consumer, "", - SPV_ERROR_INVALID_BINARY) - << "WebGPU requires SPIR-V to be little endian."; - } - spv_header_t header; if (spvBinaryHeaderGet(binary.get(), endian, &header)) { return DiagnosticStream(position, context.consumer, "", @@ -321,13 +257,6 @@ spv_result_t ValidateBinaryUsingContextAndValidationState( } const auto called_id = inst->GetOperandAs(2); - if (spvIsWebGPUEnv(context.target_env) && - !vstate->IsFunctionCallDefined(called_id)) { - return vstate->diag(SPV_ERROR_INVALID_LAYOUT, &instruction) - << "For WebGPU, functions need to be defined before being " - "called."; - } - vstate->AddFunctionCallTarget(called_id); } diff --git a/source/val/validate_annotation.cpp b/source/val/validate_annotation.cpp index 8acdb984..85d2b751 100644 --- a/source/val/validate_annotation.cpp +++ b/source/val/validate_annotation.cpp @@ -22,36 +22,6 @@ namespace spvtools { namespace val { namespace { -bool IsValidWebGPUDecoration(uint32_t decoration) { - switch (decoration) { - case SpvDecorationSpecId: - case SpvDecorationBlock: - case SpvDecorationRowMajor: - case SpvDecorationColMajor: - case SpvDecorationArrayStride: - case SpvDecorationMatrixStride: - case SpvDecorationBuiltIn: - case SpvDecorationNoPerspective: - case SpvDecorationFlat: - case SpvDecorationCentroid: - case SpvDecorationRestrict: - case SpvDecorationAliased: - case SpvDecorationNonWritable: - case SpvDecorationNonReadable: - case SpvDecorationUniform: - case SpvDecorationLocation: - case SpvDecorationComponent: - case SpvDecorationIndex: - case SpvDecorationBinding: - case SpvDecorationDescriptorSet: - case SpvDecorationOffset: - case SpvDecorationNoContraction: - return true; - default: - return false; - } -} - std::string LogStringForDecoration(uint32_t decoration) { switch (decoration) { case SpvDecorationRelaxedPrecision: @@ -212,13 +182,6 @@ spv_result_t ValidateDecorate(ValidationState_t& _, const Instruction* inst) { } } - if (spvIsWebGPUEnv(_.context()->target_env) && - !IsValidWebGPUDecoration(decoration)) { - return _.diag(SPV_ERROR_INVALID_ID, inst) - << "OpDecorate decoration '" << LogStringForDecoration(decoration) - << "' is not valid for the WebGPU execution environment."; - } - if (spvIsVulkanEnv(_.context()->target_env)) { if ((decoration == SpvDecorationGLSLShared) || (decoration == SpvDecorationGLSLPacked)) { @@ -271,25 +234,11 @@ spv_result_t ValidateMemberDecorate(ValidationState_t& _, << " members. Largest valid index is " << member_count - 1 << "."; } - const auto decoration = inst->GetOperandAs(2); - if (spvIsWebGPUEnv(_.context()->target_env) && - !IsValidWebGPUDecoration(decoration)) { - return _.diag(SPV_ERROR_INVALID_ID, inst) - << "OpMemberDecorate decoration '" << _.getIdName(decoration) - << "' is not valid for the WebGPU execution environment."; - } - return SPV_SUCCESS; } spv_result_t ValidateDecorationGroup(ValidationState_t& _, const Instruction* inst) { - if (spvIsWebGPUEnv(_.context()->target_env)) { - return _.diag(SPV_ERROR_INVALID_BINARY, inst) - << "OpDecorationGroup is not allowed in the WebGPU execution " - << "environment."; - } - const auto decoration_group_id = inst->GetOperandAs(0); const auto decoration_group = _.FindDef(decoration_group_id); for (auto pair : decoration_group->uses()) { @@ -309,12 +258,6 @@ spv_result_t ValidateDecorationGroup(ValidationState_t& _, spv_result_t ValidateGroupDecorate(ValidationState_t& _, const Instruction* inst) { - if (spvIsWebGPUEnv(_.context()->target_env)) { - return _.diag(SPV_ERROR_INVALID_BINARY, inst) - << "OpGroupDecorate is not allowed in the WebGPU execution " - << "environment."; - } - const auto decoration_group_id = inst->GetOperandAs(0); auto decoration_group = _.FindDef(decoration_group_id); if (!decoration_group || SpvOpDecorationGroup != decoration_group->opcode()) { @@ -337,12 +280,6 @@ spv_result_t ValidateGroupDecorate(ValidationState_t& _, spv_result_t ValidateGroupMemberDecorate(ValidationState_t& _, const Instruction* inst) { - if (spvIsWebGPUEnv(_.context()->target_env)) { - return _.diag(SPV_ERROR_INVALID_BINARY, inst) - << "OpGroupMemberDecorate is not allowed in the WebGPU execution " - << "environment."; - } - const auto decoration_group_id = inst->GetOperandAs(0); const auto decoration_group = _.FindDef(decoration_group_id); if (!decoration_group || SpvOpDecorationGroup != decoration_group->opcode()) { diff --git a/source/val/validate_builtins.cpp b/source/val/validate_builtins.cpp index 4f2a3b11..7fb99089 100644 --- a/source/val/validate_builtins.cpp +++ b/source/val/validate_builtins.cpp @@ -113,28 +113,6 @@ SpvStorageClass GetStorageClass(const Instruction& inst) { return SpvStorageClassMax; } -bool IsBuiltInValidForWebGPU(SpvBuiltIn label) { - switch (label) { - case SpvBuiltInPosition: - case SpvBuiltInVertexIndex: - case SpvBuiltInInstanceIndex: - case SpvBuiltInFrontFacing: - case SpvBuiltInFragCoord: - case SpvBuiltInFragDepth: - case SpvBuiltInNumWorkgroups: - case SpvBuiltInWorkgroupSize: - case SpvBuiltInLocalInvocationId: - case SpvBuiltInGlobalInvocationId: - case SpvBuiltInLocalInvocationIndex: { - return true; - } - default: - break; - } - - return false; -} - typedef enum VUIDError_ { VUIDErrorExecutionModel = 0, VUIDErrorStorageClass = 1, @@ -1260,7 +1238,7 @@ spv_result_t BuiltInsValidator::ValidateClipOrCullDistanceAtReference( spv_result_t BuiltInsValidator::ValidateFragCoordAtDefinition( const Decoration& decoration, const Instruction& inst) { - if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { + if (spvIsVulkanEnv(_.context()->target_env)) { if (spv_result_t error = ValidateF32Vec( decoration, inst, 4, [this, &inst](const std::string& message) -> spv_result_t { @@ -1284,7 +1262,7 @@ spv_result_t BuiltInsValidator::ValidateFragCoordAtReference( const Decoration& decoration, const Instruction& built_in_inst, const Instruction& referenced_inst, const Instruction& referenced_from_inst) { - if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { + if (spvIsVulkanEnv(_.context()->target_env)) { const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); if (storage_class != SpvStorageClassMax && storage_class != SpvStorageClassInput) { @@ -1322,7 +1300,7 @@ spv_result_t BuiltInsValidator::ValidateFragCoordAtReference( spv_result_t BuiltInsValidator::ValidateFragDepthAtDefinition( const Decoration& decoration, const Instruction& inst) { - if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { + if (spvIsVulkanEnv(_.context()->target_env)) { if (spv_result_t error = ValidateF32( decoration, inst, [this, &inst](const std::string& message) -> spv_result_t { @@ -1345,7 +1323,7 @@ spv_result_t BuiltInsValidator::ValidateFragDepthAtReference( const Decoration& decoration, const Instruction& built_in_inst, const Instruction& referenced_inst, const Instruction& referenced_from_inst) { - if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { + if (spvIsVulkanEnv(_.context()->target_env)) { const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); if (storage_class != SpvStorageClassMax && storage_class != SpvStorageClassOutput) { @@ -1398,7 +1376,7 @@ spv_result_t BuiltInsValidator::ValidateFragDepthAtReference( spv_result_t BuiltInsValidator::ValidateFrontFacingAtDefinition( const Decoration& decoration, const Instruction& inst) { - if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { + if (spvIsVulkanEnv(_.context()->target_env)) { if (spv_result_t error = ValidateBool( decoration, inst, [this, &inst](const std::string& message) -> spv_result_t { @@ -1421,7 +1399,7 @@ spv_result_t BuiltInsValidator::ValidateFrontFacingAtReference( const Decoration& decoration, const Instruction& built_in_inst, const Instruction& referenced_inst, const Instruction& referenced_from_inst) { - if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { + if (spvIsVulkanEnv(_.context()->target_env)) { const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); if (storage_class != SpvStorageClassMax && storage_class != SpvStorageClassInput) { @@ -1579,7 +1557,7 @@ spv_result_t BuiltInsValidator::ValidateInvocationIdAtReference( spv_result_t BuiltInsValidator::ValidateInstanceIndexAtDefinition( const Decoration& decoration, const Instruction& inst) { - if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { + if (spvIsVulkanEnv(_.context()->target_env)) { if (spv_result_t error = ValidateI32( decoration, inst, [this, &inst](const std::string& message) -> spv_result_t { @@ -1602,7 +1580,7 @@ spv_result_t BuiltInsValidator::ValidateInstanceIndexAtReference( const Decoration& decoration, const Instruction& built_in_inst, const Instruction& referenced_inst, const Instruction& referenced_from_inst) { - if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { + if (spvIsVulkanEnv(_.context()->target_env)) { const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); if (storage_class != SpvStorageClassMax && storage_class != SpvStorageClassInput) { @@ -1992,46 +1970,6 @@ spv_result_t BuiltInsValidator::ValidatePositionAtReference( } } - if (spvIsWebGPUEnv(_.context()->target_env)) { - const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); - if (storage_class != SpvStorageClassMax && - storage_class != SpvStorageClassOutput) { - return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) - << "WebGPU spec allows BuiltIn Position to be only used for " - "variables with Output storage class. " - << GetReferenceDesc(decoration, built_in_inst, referenced_inst, - referenced_from_inst) - << " " << GetStorageClassDesc(referenced_from_inst); - } - - for (const SpvExecutionModel execution_model : execution_models_) { - switch (execution_model) { - case SpvExecutionModelVertex: { - if (spv_result_t error = ValidateF32Vec( - decoration, built_in_inst, 4, - [this, &referenced_from_inst]( - const std::string& message) -> spv_result_t { - return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) - << "According to the WebGPU spec BuiltIn Position " - "variable needs to be a 4-component 32-bit float " - "vector. " - << message; - })) { - return error; - } - break; - } - default: { - return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) - << "WebGPU spec allows BuiltIn Position to be used only " - "with the Vertex execution model. " - << GetReferenceDesc(decoration, built_in_inst, referenced_inst, - referenced_from_inst, execution_model); - } - } - } - } - if (function_id_ == 0) { // Propagate this rule to all dependant ids in the global scope. id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind( @@ -2547,7 +2485,7 @@ spv_result_t BuiltInsValidator::ValidateTessLevelAtReference( spv_result_t BuiltInsValidator::ValidateVertexIndexAtDefinition( const Decoration& decoration, const Instruction& inst) { - if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { + if (spvIsVulkanEnv(_.context()->target_env)) { if (spv_result_t error = ValidateI32( decoration, inst, [this, &inst](const std::string& message) -> spv_result_t { @@ -2580,51 +2518,14 @@ spv_result_t BuiltInsValidator::ValidateVertexIdAtDefinition( spv_result_t BuiltInsValidator::ValidateLocalInvocationIndexAtDefinition( const Decoration& decoration, const Instruction& inst) { - if (spvIsWebGPUEnv(_.context()->target_env)) { - if (spv_result_t error = ValidateI32( - decoration, inst, - [this, &inst](const std::string& message) -> spv_result_t { - return _.diag(SPV_ERROR_INVALID_DATA, &inst) - << "According to the WebGPU spec BuiltIn " - "LocalInvocationIndex variable needs to be a 32-bit " - "int." - << message; - })) { - return error; - } - } - // Seed at reference checks with this built-in. return ValidateLocalInvocationIndexAtReference(decoration, inst, inst, inst); } spv_result_t BuiltInsValidator::ValidateLocalInvocationIndexAtReference( const Decoration& decoration, const Instruction& built_in_inst, - const Instruction& referenced_inst, + const Instruction&, const Instruction& referenced_from_inst) { - if (spvIsWebGPUEnv(_.context()->target_env)) { - const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); - if (storage_class != SpvStorageClassMax && - storage_class != SpvStorageClassInput) { - return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) - << "WebGPU spec allows BuiltIn LocalInvocationIndex to be only " - "used for variables with Input storage class. " - << GetReferenceDesc(decoration, built_in_inst, referenced_inst, - referenced_from_inst) - << " " << GetStorageClassDesc(referenced_from_inst); - } - - for (const SpvExecutionModel execution_model : execution_models_) { - if (execution_model != SpvExecutionModelGLCompute) { - return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) - << "WebGPU spec allows BuiltIn VertexIndex to be used only " - "with GLCompute execution model. " - << GetReferenceDesc(decoration, built_in_inst, referenced_inst, - referenced_from_inst, execution_model); - } - } - } - if (function_id_ == 0) { // Propagate this rule to all dependant ids in the global scope. id_to_at_reference_checks_[referenced_from_inst.id()].push_back( @@ -2640,7 +2541,7 @@ spv_result_t BuiltInsValidator::ValidateVertexIndexAtReference( const Decoration& decoration, const Instruction& built_in_inst, const Instruction& referenced_inst, const Instruction& referenced_from_inst) { - if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { + if (spvIsVulkanEnv(_.context()->target_env)) { const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); if (storage_class != SpvStorageClassMax && storage_class != SpvStorageClassInput) { @@ -2838,7 +2739,7 @@ spv_result_t BuiltInsValidator::ValidateLayerOrViewportIndexAtReference( spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtDefinition( const Decoration& decoration, const Instruction& inst) { - if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { + if (spvIsVulkanEnv(_.context()->target_env)) { const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]); if (spv_result_t error = ValidateI32Vec( decoration, inst, 3, @@ -2867,7 +2768,7 @@ spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtReference( const Decoration& decoration, const Instruction& built_in_inst, const Instruction& referenced_inst, const Instruction& referenced_from_inst) { - if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { + if (spvIsVulkanEnv(_.context()->target_env)) { const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]); const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); if (storage_class != SpvStorageClassMax && @@ -2887,9 +2788,7 @@ spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtReference( bool has_vulkan_model = execution_model == SpvExecutionModelGLCompute || execution_model == SpvExecutionModelTaskNV || execution_model == SpvExecutionModelMeshNV; - bool has_webgpu_model = execution_model == SpvExecutionModelGLCompute; - if ((spvIsVulkanEnv(_.context()->target_env) && !has_vulkan_model) || - (spvIsWebGPUEnv(_.context()->target_env) && !has_webgpu_model)) { + if (spvIsVulkanEnv(_.context()->target_env) && !has_vulkan_model) { uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel); return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) << _.VkErrorID(vuid) @@ -3086,7 +2985,7 @@ spv_result_t BuiltInsValidator::ValidateI32Vec4InputAtDefinition( spv_result_t BuiltInsValidator::ValidateWorkgroupSizeAtDefinition( const Decoration& decoration, const Instruction& inst) { - if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { + if (spvIsVulkanEnv(_.context()->target_env)) { if (spvIsVulkanEnv(_.context()->target_env) && !spvOpcodeIsConstant(inst.opcode())) { return _.diag(SPV_ERROR_INVALID_DATA, &inst) @@ -3118,7 +3017,7 @@ spv_result_t BuiltInsValidator::ValidateWorkgroupSizeAtReference( const Decoration& decoration, const Instruction& built_in_inst, const Instruction& referenced_inst, const Instruction& referenced_from_inst) { - if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { + if (spvIsVulkanEnv(_.context()->target_env)) { for (const SpvExecutionModel execution_model : execution_models_) { if (execution_model != SpvExecutionModelGLCompute) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) @@ -3768,26 +3667,17 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition( << "BuiltIns can only target variables, structs or constants"; } - if (!spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { - // Early return. All currently implemented rules are based on Vulkan or - // WebGPU spec. + if (!spvIsVulkanEnv(_.context()->target_env)) { + // Early return. All currently implemented rules are based on Vulkan spec. // // TODO: If you are adding validation rules for environments other than - // Vulkan or WebGPU (or general rules which are not environment - // independent), then you need to modify or remove this condition. Consider - // also adding early returns into BuiltIn-specific rules, so that the system - // doesn't spawn new rules which don't do anything. + // Vulkan (or general rules which are not environment independent), then + // you need to modify or remove this condition. Consider also adding early + // returns into BuiltIn-specific rules, so that the system doesn't spawn new + // rules which don't do anything. return SPV_SUCCESS; } - if (spvIsWebGPUEnv(_.context()->target_env) && - !IsBuiltInValidForWebGPU(label)) { - return _.diag(SPV_ERROR_INVALID_DATA, &inst) - << "WebGPU does not allow BuiltIn " - << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]); - } - // If you are adding a new BuiltIn enum, please register it here. // If the newly added enum has validation rules associated with it // consider leaving a TODO and/or creating an issue. diff --git a/source/val/validate_capability.cpp b/source/val/validate_capability.cpp index 4b98bc19..8efd5542 100644 --- a/source/val/validate_capability.cpp +++ b/source/val/validate_capability.cpp @@ -260,19 +260,6 @@ bool IsEnabledByCapabilityOpenCL_2_0(ValidationState_t& _, return false; } -bool IsSupportGuaranteedWebGPU(uint32_t capability) { - switch (capability) { - case SpvCapabilityMatrix: - case SpvCapabilityShader: - case SpvCapabilitySampled1D: - case SpvCapabilityImage1D: - case SpvCapabilityDerivativeControl: - case SpvCapabilityImageQuery: - return true; - } - return false; -} - } // namespace // Validates that capability declarations use operands allowed in the current @@ -365,14 +352,6 @@ spv_result_t CapabilityPass(ValidationState_t& _, const Instruction* inst) { << " Profile specification" << " (or requires extension or capability)"; } - } else if (env == SPV_ENV_WEBGPU_0) { - if (!IsSupportGuaranteedWebGPU(capability) && - !IsEnabledByExtension(_, capability)) { - return _.diag(SPV_ERROR_INVALID_CAPABILITY, inst) - << "Capability " << capability_str() - << " is not allowed by WebGPU specification" - << " (or requires extension)"; - } } return SPV_SUCCESS; diff --git a/source/val/validate_cfg.cpp b/source/val/validate_cfg.cpp index ca2ae1ae..a5f6e6a1 100644 --- a/source/val/validate_cfg.cpp +++ b/source/val/validate_cfg.cpp @@ -820,120 +820,6 @@ spv_result_t StructuredControlFlowChecks( return SPV_SUCCESS; } -spv_result_t PerformWebGPUCfgChecks(ValidationState_t& _, Function* function) { - for (auto& block : function->ordered_blocks()) { - if (block->reachable()) continue; - if (block->is_type(kBlockTypeMerge)) { - // 1. Find the referencing merge and confirm that it is reachable. - BasicBlock* merge_header = function->GetMergeHeader(block); - assert(merge_header != nullptr); - if (!merge_header->reachable()) { - return _.diag(SPV_ERROR_INVALID_CFG, _.FindDef(block->id())) - << "For WebGPU, unreachable merge-blocks must be referenced by " - "a reachable merge instruction."; - } - - // 2. Check that the only instructions are OpLabel and OpUnreachable. - auto* label_inst = block->label(); - auto* terminator_inst = block->terminator(); - assert(label_inst != nullptr); - assert(terminator_inst != nullptr); - - if (terminator_inst->opcode() != SpvOpUnreachable) { - return _.diag(SPV_ERROR_INVALID_CFG, _.FindDef(block->id())) - << "For WebGPU, unreachable merge-blocks must terminate with " - "OpUnreachable."; - } - - auto label_idx = label_inst - &_.ordered_instructions()[0]; - auto terminator_idx = terminator_inst - &_.ordered_instructions()[0]; - if (label_idx + 1 != terminator_idx) { - return _.diag(SPV_ERROR_INVALID_CFG, _.FindDef(block->id())) - << "For WebGPU, unreachable merge-blocks must only contain an " - "OpLabel and OpUnreachable instruction."; - } - - // 3. Use label instruction to confirm there is no uses by branches. - for (auto use : label_inst->uses()) { - const auto* use_inst = use.first; - if (spvOpcodeIsBranch(use_inst->opcode())) { - return _.diag(SPV_ERROR_INVALID_CFG, _.FindDef(block->id())) - << "For WebGPU, unreachable merge-blocks cannot be the target " - "of a branch."; - } - } - } else if (block->is_type(kBlockTypeContinue)) { - // 1. Find referencing loop and confirm that it is reachable. - std::vector continue_headers = - function->GetContinueHeaders(block); - if (continue_headers.empty()) { - return _.diag(SPV_ERROR_INVALID_CFG, _.FindDef(block->id())) - << "For WebGPU, unreachable continue-target must be referenced " - "by a loop instruction."; - } - - std::vector reachable_headers(continue_headers.size()); - auto iter = - std::copy_if(continue_headers.begin(), continue_headers.end(), - reachable_headers.begin(), - [](BasicBlock* header) { return header->reachable(); }); - reachable_headers.resize(std::distance(reachable_headers.begin(), iter)); - - if (reachable_headers.empty()) { - return _.diag(SPV_ERROR_INVALID_CFG, _.FindDef(block->id())) - << "For WebGPU, unreachable continue-target must be referenced " - "by a reachable loop instruction."; - } - - // 2. Check that the only instructions are OpLabel and OpBranch. - auto* label_inst = block->label(); - auto* terminator_inst = block->terminator(); - assert(label_inst != nullptr); - assert(terminator_inst != nullptr); - - if (terminator_inst->opcode() != SpvOpBranch) { - return _.diag(SPV_ERROR_INVALID_CFG, _.FindDef(block->id())) - << "For WebGPU, unreachable continue-target must terminate with " - "OpBranch."; - } - - auto label_idx = label_inst - &_.ordered_instructions()[0]; - auto terminator_idx = terminator_inst - &_.ordered_instructions()[0]; - if (label_idx + 1 != terminator_idx) { - return _.diag(SPV_ERROR_INVALID_CFG, _.FindDef(block->id())) - << "For WebGPU, unreachable continue-target must only contain " - "an OpLabel and an OpBranch instruction."; - } - - // 3. Use label instruction to confirm there is no uses by branches. - for (auto use : label_inst->uses()) { - const auto* use_inst = use.first; - if (spvOpcodeIsBranch(use_inst->opcode())) { - return _.diag(SPV_ERROR_INVALID_CFG, _.FindDef(block->id())) - << "For WebGPU, unreachable continue-target cannot be the " - "target of a branch."; - } - } - - // 4. Confirm that continue-target has a back edge to a reachable loop - // header block. - auto branch_target = terminator_inst->GetOperandAs(0); - for (auto* continue_header : reachable_headers) { - if (branch_target != continue_header->id()) { - return _.diag(SPV_ERROR_INVALID_CFG, _.FindDef(block->id())) - << "For WebGPU, unreachable continue-target must only have a " - "back edge to a single reachable loop instruction."; - } - } - } else { - return _.diag(SPV_ERROR_INVALID_CFG, _.FindDef(block->id())) - << "For WebGPU, all blocks must be reachable, unless they are " - << "degenerate cases of merge-block or continue-target."; - } - } - return SPV_SUCCESS; -} - spv_result_t PerformCfgChecks(ValidationState_t& _) { for (auto& function : _.functions()) { // Check all referenced blocks are defined within a function @@ -1014,13 +900,6 @@ spv_result_t PerformCfgChecks(ValidationState_t& _) { << _.getIdName(idom->id()); } } - - // For WebGPU check that all unreachable blocks are degenerate cases for - // merge-block or continue-target. - if (spvIsWebGPUEnv(_.context()->target_env)) { - spv_result_t result = PerformWebGPUCfgChecks(_, &function); - if (result != SPV_SUCCESS) return result; - } } // If we have structed control flow, check that no block has a control // flow nesting depth larger than the limit. diff --git a/source/val/validate_composites.cpp b/source/val/validate_composites.cpp index d5b978ff..5d6c5e37 100644 --- a/source/val/validate_composites.cpp +++ b/source/val/validate_composites.cpp @@ -535,12 +535,10 @@ spv_result_t ValidateVectorShuffle(ValidationState_t& _, } // All Component literals must either be FFFFFFFF or in [0, N - 1]. - // For WebGPU specifically, Component literals cannot be FFFFFFFF. auto vector1ComponentCount = vector1Type->GetOperandAs(2); auto vector2ComponentCount = vector2Type->GetOperandAs(2); auto N = vector1ComponentCount + vector2ComponentCount; auto firstLiteralIndex = 4; - const auto is_webgpu_env = spvIsWebGPUEnv(_.context()->target_env); for (size_t i = firstLiteralIndex; i < inst->operands().size(); ++i) { auto literal = inst->GetOperandAs(i); if (literal != 0xFFFFFFFF && literal >= N) { @@ -548,12 +546,6 @@ spv_result_t ValidateVectorShuffle(ValidationState_t& _, << "Component index " << literal << " is out of bounds for " << "combined (Vector1 + Vector2) size of " << N << "."; } - - if (is_webgpu_env && literal == 0xFFFFFFFF) { - return _.diag(SPV_ERROR_INVALID_ID, inst) - << "Component literal at operand " << i - firstLiteralIndex - << " cannot be 0xFFFFFFFF in WebGPU execution environment."; - } } if (_.HasCapability(SpvCapabilityShader) && diff --git a/source/val/validate_extensions.cpp b/source/val/validate_extensions.cpp index 17b04460..af6ae2b7 100644 --- a/source/val/validate_extensions.cpp +++ b/source/val/validate_extensions.cpp @@ -685,34 +685,9 @@ bool IsDebugVariableWithIntScalarType(ValidationState_t& _, } // anonymous namespace -spv_result_t ValidateExtension(ValidationState_t& _, const Instruction* inst) { - if (spvIsWebGPUEnv(_.context()->target_env)) { - std::string extension = GetExtensionString(&(inst->c_inst())); - - if (extension != ExtensionToString(kSPV_KHR_vulkan_memory_model)) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "For WebGPU, the only valid parameter to OpExtension is " - << "\"" << ExtensionToString(kSPV_KHR_vulkan_memory_model) - << "\"."; - } - } - - return SPV_SUCCESS; -} - spv_result_t ValidateExtInstImport(ValidationState_t& _, const Instruction* inst) { const auto name_id = 1; - if (spvIsWebGPUEnv(_.context()->target_env)) { - const std::string name(reinterpret_cast( - inst->words().data() + inst->operands()[name_id].offset)); - if (name != "GLSL.std.450") { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "For WebGPU, the only valid parameter to OpExtInstImport is " - "\"GLSL.std.450\"."; - } - } - if (!_.HasExtension(kSPV_KHR_non_semantic_info)) { const std::string name(reinterpret_cast( inst->words().data() + inst->operands()[name_id].offset)); @@ -3149,7 +3124,6 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) { spv_result_t ExtensionPass(ValidationState_t& _, const Instruction* inst) { const SpvOp opcode = inst->opcode(); - if (opcode == SpvOpExtension) return ValidateExtension(_, inst); if (opcode == SpvOpExtInstImport) return ValidateExtInstImport(_, inst); if (opcode == SpvOpExtInst) return ValidateExtInst(_, inst); diff --git a/source/val/validate_image.cpp b/source/val/validate_image.cpp index 9597630b..f5ba5d1a 100644 --- a/source/val/validate_image.cpp +++ b/source/val/validate_image.cpp @@ -821,12 +821,11 @@ spv_result_t ValidateTypeImage(ValidationState_t& _, const Instruction* inst) { << "Invalid Sampled " << info.sampled << " (must be 0, 1 or 2)"; } - if (spvIsVulkanEnv(target_env) || spvIsWebGPUEnv(target_env)) { + if (spvIsVulkanEnv(target_env)) { if (info.sampled == 0) { return _.diag(SPV_ERROR_INVALID_DATA, inst) - << _.VkErrorID(4657) << "Sampled must be 1 or 2 in the " - << (spvIsVulkanEnv(target_env) ? "Vulkan" : "WebGPU") - << " environment."; + << _.VkErrorID(4657) + << "Sampled must be 1 or 2 in the Vulkan environment."; } } @@ -1469,9 +1468,9 @@ spv_result_t ValidateImageRead(ValidationState_t& _, const Instruction* inst) { } const auto target_env = _.context()->target_env; - // Vulkan and WebGPU require the result to be a 4-element int or float + // Vulkan requires the result to be a 4-element int or float // vector. - if (spvIsVulkanEnv(target_env) || spvIsWebGPUEnv(target_env)) { + if (spvIsVulkanEnv(target_env)) { if (_.GetDimension(actual_result_type) != 4) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected " << GetActualResultTypeStr(opcode) diff --git a/source/val/validate_memory.cpp b/source/val/validate_memory.cpp index 34ca301b..45a232da 100644 --- a/source/val/validate_memory.cpp +++ b/source/val/validate_memory.cpp @@ -578,12 +578,12 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { } } - // WebGPU & Vulkan Appendix A: Check that if contains initializer, then + // Vulkan Appendix A: Check that if contains initializer, then // storage class is Output, Private, or Function. if (inst->operands().size() > 3 && storage_class != SpvStorageClassOutput && storage_class != SpvStorageClassPrivate && storage_class != SpvStorageClassFunction) { - if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { + if (spvIsVulkanEnv(_.context()->target_env)) { return _.diag(SPV_ERROR_INVALID_ID, inst) << _.VkErrorID(4651) << "OpVariable, '" << _.getIdName(inst->id()) @@ -597,20 +597,6 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { } } - // WebGPU: All variables with storage class Output, Private, or Function MUST - // have an initializer. - if (spvIsWebGPUEnv(_.context()->target_env) && inst->operands().size() <= 3 && - (storage_class == SpvStorageClassOutput || - storage_class == SpvStorageClassPrivate || - storage_class == SpvStorageClassFunction)) { - return _.diag(SPV_ERROR_INVALID_ID, inst) - << "OpVariable, '" << _.getIdName(inst->id()) - << "', must have an initializer.\n" - << "From WebGPU execution environment spec:\n" - << "All variables in the following storage classes must have an " - << "initializer: Output, Private, or Function"; - } - if (storage_class == SpvStorageClassPhysicalStorageBufferEXT) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "PhysicalStorageBufferEXT must not be used with OpVariable."; @@ -703,41 +689,6 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { } } - // WebGPU specific validation rules for OpTypeRuntimeArray - if (spvIsWebGPUEnv(_.context()->target_env)) { - // OpTypeRuntimeArray should only ever be in an OpTypeStruct, - // so should never appear as a bare variable. - if (value_type && value_type->opcode() == SpvOpTypeRuntimeArray) { - return _.diag(SPV_ERROR_INVALID_ID, inst) - << "OpVariable, '" << _.getIdName(inst->id()) - << "', is attempting to create memory for an illegal type, " - << "OpTypeRuntimeArray.\nFor WebGPU OpTypeRuntimeArray can only " - << "appear as the final member of an OpTypeStruct, thus cannot " - << "be instantiated via OpVariable"; - } - - // If an OpStruct has an OpTypeRuntimeArray somewhere within it, then it - // must have the storage class StorageBuffer and be decorated - // with Block. - if (value_type && value_type->opcode() == SpvOpTypeStruct) { - if (DoesStructContainRTA(_, value_type)) { - if (storage_class == SpvStorageClassStorageBuffer) { - if (!_.HasDecoration(value_id, SpvDecorationBlock)) { - return _.diag(SPV_ERROR_INVALID_ID, inst) - << "For WebGPU, an OpTypeStruct variable containing an " - << "OpTypeRuntimeArray must be decorated with Block if it " - << "has storage class StorageBuffer."; - } - } else { - return _.diag(SPV_ERROR_INVALID_ID, inst) - << "For WebGPU, OpTypeStruct variables containing " - << "OpTypeRuntimeArray must have storage class of " - << "StorageBuffer"; - } - } - } - } - // Cooperative matrix types can only be allocated in Function or Private if ((storage_class != SpvStorageClassFunction && storage_class != SpvStorageClassPrivate) && diff --git a/source/val/validate_memory_semantics.cpp b/source/val/validate_memory_semantics.cpp index 6af720f5..8e47f8a3 100644 --- a/source/val/validate_memory_semantics.cpp +++ b/source/val/validate_memory_semantics.cpp @@ -56,55 +56,6 @@ spv_result_t ValidateMemorySemantics(ValidationState_t& _, return SPV_SUCCESS; } - if (spvIsWebGPUEnv(_.context()->target_env)) { - uint32_t valid_bits; - switch (inst->opcode()) { - case SpvOpControlBarrier: - if (!(value & SpvMemorySemanticsAcquireReleaseMask)) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "For WebGPU, AcquireRelease must be set for Memory " - "Semantics of OpControlBarrier."; - } - - if (!(value & SpvMemorySemanticsWorkgroupMemoryMask)) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "For WebGPU, WorkgroupMemory must be set for Memory " - "Semantics of OpControlBarrier."; - } - - valid_bits = SpvMemorySemanticsAcquireReleaseMask | - SpvMemorySemanticsWorkgroupMemoryMask; - if (value & ~valid_bits) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "For WebGPU only WorkgroupMemory and AcquireRelease may be " - "set for Memory Semantics of OpControlBarrier."; - } - break; - case SpvOpMemoryBarrier: - if (!(value & SpvMemorySemanticsImageMemoryMask)) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "For WebGPU, ImageMemory must be set for Memory Semantics " - "of OpMemoryBarrier."; - } - valid_bits = SpvMemorySemanticsImageMemoryMask; - if (value & ~valid_bits) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "For WebGPU only ImageMemory may be set for Memory " - "Semantics of OpMemoryBarrier."; - } - break; - default: - if (spvOpcodeIsAtomicOp(inst->opcode())) { - if (value != 0) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "For WebGPU Memory no bits may be set for Memory " - "Semantics of OpAtomic* instructions."; - } - } - break; - } - } - const size_t num_memory_order_set_bits = spvtools::utils::CountSetBits( value & (SpvMemorySemanticsAcquireMask | SpvMemorySemanticsReleaseMask | SpvMemorySemanticsAcquireReleaseMask | diff --git a/source/val/validate_misc.cpp b/source/val/validate_misc.cpp index b0bc9219..0c30f3ca 100644 --- a/source/val/validate_misc.cpp +++ b/source/val/validate_misc.cpp @@ -37,10 +37,6 @@ spv_result_t ValidateUndef(ValidationState_t& _, const Instruction* inst) { << "Cannot create undefined values with 8- or 16-bit types"; } - if (spvIsWebGPUEnv(_.context()->target_env)) { - return _.diag(SPV_ERROR_INVALID_BINARY, inst) << "OpUndef is disallowed"; - } - return SPV_SUCCESS; } diff --git a/source/val/validate_mode_setting.cpp b/source/val/validate_mode_setting.cpp index 6facd1de..ab550a92 100644 --- a/source/val/validate_mode_setting.cpp +++ b/source/val/validate_mode_setting.cpp @@ -471,21 +471,6 @@ spv_result_t ValidateExecutionMode(ValidationState_t& _, } } - if (spvIsWebGPUEnv(_.context()->target_env)) { - if (mode != SpvExecutionModeOriginUpperLeft && - mode != SpvExecutionModeDepthReplacing && - mode != SpvExecutionModeDepthGreater && - mode != SpvExecutionModeDepthLess && - mode != SpvExecutionModeDepthUnchanged && - mode != SpvExecutionModeLocalSize && - mode != SpvExecutionModeLocalSizeHint) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Execution mode must be one of OriginUpperLeft, " - "DepthReplacing, DepthGreater, DepthLess, DepthUnchanged, " - "LocalSize, or LocalSizeHint for WebGPU environment."; - } - } - return SPV_SUCCESS; } @@ -500,13 +485,6 @@ spv_result_t ValidateMemoryModel(ValidationState_t& _, "the VulkanKHR memory model is used."; } - if (spvIsWebGPUEnv(_.context()->target_env)) { - if (_.addressing_model() != SpvAddressingModelLogical) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Addressing model must be Logical for WebGPU environment."; - } - } - if (spvIsOpenCLEnv(_.context()->target_env)) { if ((_.addressing_model() != SpvAddressingModelPhysical32) && (_.addressing_model() != SpvAddressingModelPhysical64)) { diff --git a/source/val/validate_scopes.cpp b/source/val/validate_scopes.cpp index 73cd6ca2..636d54c4 100644 --- a/source/val/validate_scopes.cpp +++ b/source/val/validate_scopes.cpp @@ -137,30 +137,6 @@ spv_result_t ValidateExecutionScope(ValidationState_t& _, } } - // WebGPU Specific rules - if (spvIsWebGPUEnv(_.context()->target_env)) { - if (value != SpvScopeWorkgroup) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) - << ": in WebGPU environment Execution Scope is limited to " - << "Workgroup"; - } else { - _.function(inst->function()->id()) - ->RegisterExecutionModelLimitation( - [](SpvExecutionModel model, std::string* message) { - if (model != SpvExecutionModelGLCompute) { - if (message) { - *message = - ": in WebGPU environment, Workgroup Execution Scope is " - "limited to GLCompute execution model"; - } - return false; - } - return true; - }); - } - } - // TODO(atgoo@github.com) Add checks for OpenCL and OpenGL environments. // General SPIRV rules @@ -260,62 +236,6 @@ spv_result_t ValidateMemoryScope(ValidationState_t& _, const Instruction* inst, } } - // WebGPU specific rules - if (spvIsWebGPUEnv(_.context()->target_env)) { - switch (inst->opcode()) { - case SpvOpControlBarrier: - if (value != SpvScopeWorkgroup) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) - << ": in WebGPU environment Memory Scope is limited to " - << "Workgroup for OpControlBarrier"; - } - break; - case SpvOpMemoryBarrier: - if (value != SpvScopeWorkgroup) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) - << ": in WebGPU environment Memory Scope is limited to " - << "Workgroup for OpMemoryBarrier"; - } - break; - default: - if (spvOpcodeIsAtomicOp(inst->opcode())) { - if (value != SpvScopeQueueFamilyKHR) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) - << ": in WebGPU environment Memory Scope is limited to " - << "QueueFamilyKHR for OpAtomic* operations"; - } - } - - if (value != SpvScopeWorkgroup && value != SpvScopeInvocation && - value != SpvScopeQueueFamilyKHR) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) - << ": in WebGPU environment Memory Scope is limited to " - << "Workgroup, Invocation, and QueueFamilyKHR"; - } - break; - } - - if (value == SpvScopeWorkgroup) { - _.function(inst->function()->id()) - ->RegisterExecutionModelLimitation( - [](SpvExecutionModel model, std::string* message) { - if (model != SpvExecutionModelGLCompute) { - if (message) { - *message = - ": in WebGPU environment, Workgroup Memory Scope is " - "limited to GLCompute execution model"; - } - return false; - } - return true; - }); - } - } - // TODO(atgoo@github.com) Add checks for OpenCL and OpenGL environments. return SPV_SUCCESS; diff --git a/source/val/validate_type.cpp b/source/val/validate_type.cpp index 8352301b..6a5ea3c1 100644 --- a/source/val/validate_type.cpp +++ b/source/val/validate_type.cpp @@ -40,21 +40,6 @@ int64_t ConstantLiteralAsInt64(uint32_t width, return static_cast(uint64_t(lo_word) | uint64_t(hi_word) << 32); } -// Returns, as an uint64_t, the literal value from an OpConstant or the -// default value of an OpSpecConstant, assuming it is an integral type. -// For signed integers, relies the rule that literal value is sign extended -// to fill out to word granularity. Assumes that the constant value -// has -int64_t ConstantLiteralAsUint64(uint32_t width, - const std::vector& const_words) { - const uint32_t lo_word = const_words[3]; - if (width <= 32) return lo_word; - assert(width <= 64); - assert(const_words.size() > 4); - const uint32_t hi_word = const_words[4]; // Must exist, per spec. - return (uint64_t(lo_word) | uint64_t(hi_word) << 32); -} - // Validates that type declarations are unique, unless multiple declarations // of the same data type are allowed by the specification. // (see section 2.8 Types and Variables) @@ -240,7 +225,7 @@ spv_result_t ValidateTypeArray(ValidationState_t& _, const Instruction* inst) { << "' is a void type."; } - if (spvIsVulkanOrWebGPUEnv(_.context()->target_env) && + if (spvIsVulkanEnv(_.context()->target_env) && element_type->opcode() == SpvOpTypeRuntimeArray) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "OpTypeArray Element Type '" << _.getIdName(element_type_id) @@ -279,18 +264,6 @@ spv_result_t ValidateTypeArray(ValidationState_t& _, const Instruction* inst) { << "OpTypeArray Length '" << _.getIdName(length_id) << "' default value must be at least 1: found " << ivalue; } - if (spvIsWebGPUEnv(_.context()->target_env)) { - // WebGPU has maximum integer width of 32 bits, and max array size - // is one more than the max signed integer representation. - const uint64_t max_permitted = (uint64_t(1) << 31); - const uint64_t uvalue = ConstantLiteralAsUint64(width, length->words()); - if (uvalue > max_permitted) { - return _.diag(SPV_ERROR_INVALID_ID, inst) - << "OpTypeArray Length '" << _.getIdName(length_id) - << "' size exceeds max value " << max_permitted - << " permitted by WebGPU: got " << uvalue; - } - } } break; case SpvOpConstantNull: return _.diag(SPV_ERROR_INVALID_ID, inst) @@ -322,7 +295,7 @@ spv_result_t ValidateTypeRuntimeArray(ValidationState_t& _, << _.getIdName(element_id) << "' is a void type."; } - if (spvIsVulkanOrWebGPUEnv(_.context()->target_env) && + if (spvIsVulkanEnv(_.context()->target_env) && element_type->opcode() == SpvOpTypeRuntimeArray) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "OpTypeRuntimeArray Element Type '" @@ -394,7 +367,7 @@ spv_result_t ValidateTypeStruct(ValidationState_t& _, const Instruction* inst) { << "."; } - if (spvIsVulkanOrWebGPUEnv(_.context()->target_env) && + if (spvIsVulkanEnv(_.context()->target_env) && member_type->opcode() == SpvOpTypeRuntimeArray) { const bool is_last_member = member_type_index == inst->operands().size() - 1; diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index 27cf624a..967fd9f3 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -1240,23 +1240,6 @@ bool ValidationState_t::ContainsLimitedUseIntOrFloatType(uint32_t id) const { bool ValidationState_t::IsValidStorageClass( SpvStorageClass storage_class) const { - if (spvIsWebGPUEnv(context()->target_env)) { - switch (storage_class) { - case SpvStorageClassUniformConstant: - case SpvStorageClassUniform: - case SpvStorageClassStorageBuffer: - case SpvStorageClassInput: - case SpvStorageClassOutput: - case SpvStorageClassImage: - case SpvStorageClassWorkgroup: - case SpvStorageClassPrivate: - case SpvStorageClassFunction: - return true; - default: - return false; - } - } - if (spvIsVulkanEnv(context()->target_env)) { switch (storage_class) { case SpvStorageClassUniformConstant: diff --git a/test/fuzzers/BUILD.gn b/test/fuzzers/BUILD.gn index be1258a4..ec09b2b0 100644 --- a/test/fuzzers/BUILD.gn +++ b/test/fuzzers/BUILD.gn @@ -39,10 +39,7 @@ if (!build_with_chromium || use_fuzzing_engine) { ":spvtools_opt_legalization_fuzzer", ":spvtools_opt_performance_fuzzer", ":spvtools_opt_size_fuzzer", - ":spvtools_opt_webgputovulkan_fuzzer", - ":spvtools_opt_vulkantowebgpu_fuzzer", ":spvtools_val_fuzzer", - ":spvtools_val_webgpu_fuzzer", ] } } @@ -104,31 +101,12 @@ spvtools_fuzzer("spvtools_opt_size_fuzzer_src") { ] } - -spvtools_fuzzer("spvtools_opt_webgputovulkan_fuzzer_src") { - sources = [ - "spvtools_opt_webgputovulkan_fuzzer.cpp", - ] -} - -spvtools_fuzzer("spvtools_opt_vulkantowebgpu_fuzzer_src") { - sources = [ - "spvtools_opt_vulkantowebgpu_fuzzer.cpp", - ] -} - spvtools_fuzzer("spvtools_val_fuzzer_src") { sources = [ "spvtools_val_fuzzer.cpp", ] } -spvtools_fuzzer("spvtools_val_webgpu_fuzzer_src") { - sources = [ - "spvtools_val_webgpu_fuzzer.cpp", - ] -} - if (!build_with_chromium || use_fuzzing_engine) { fuzzer_test("spvtools_as_fuzzer") { sources = [] @@ -181,22 +159,6 @@ if (!build_with_chromium || use_fuzzing_engine) { seed_corpus = "corpora/spv" } - fuzzer_test("spvtools_opt_webgputovulkan_fuzzer") { - sources = [] - deps = [ - ":spvtools_opt_webgputovulkan_fuzzer_src", - ] - seed_corpus = "corpora/spv" - } - - fuzzer_test("spvtools_opt_vulkantowebgpu_fuzzer") { - sources = [] - deps = [ - ":spvtools_opt_vulkantowebgpu_fuzzer_src", - ] - seed_corpus = "corpora/spv" - } - fuzzer_test("spvtools_val_fuzzer") { sources = [] deps = [ @@ -204,12 +166,4 @@ if (!build_with_chromium || use_fuzzing_engine) { ] seed_corpus = "corpora/spv" } - - fuzzer_test("spvtools_val_webgpu_fuzzer") { - sources = [] - deps = [ - ":spvtools_val_webgpu_fuzzer_src", - ] - seed_corpus = "corpora/spv" - } } diff --git a/test/fuzzers/spvtools_opt_vulkantowebgpu_fuzzer.cpp b/test/fuzzers/spvtools_opt_vulkantowebgpu_fuzzer.cpp deleted file mode 100644 index 9371c0df..00000000 --- a/test/fuzzers/spvtools_opt_vulkantowebgpu_fuzzer.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2019 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include - -#include "spirv-tools/optimizer.hpp" - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - spvtools::Optimizer optimizer(SPV_ENV_VULKAN_1_1); - optimizer.SetMessageConsumer([](spv_message_level_t, const char*, - const spv_position_t&, const char*) {}); - - std::vector input; - input.resize(size >> 2); - - size_t count = 0; - for (size_t i = 0; (i + 3) < size; i += 4) { - input[count++] = data[i] | (data[i + 1] << 8) | (data[i + 2] << 16) | - (data[i + 3]) << 24; - } - - optimizer.RegisterVulkanToWebGPUPasses(); - optimizer.Run(input.data(), input.size(), &input); - - return 0; -} diff --git a/test/fuzzers/spvtools_opt_webgputovulkan_fuzzer.cpp b/test/fuzzers/spvtools_opt_webgputovulkan_fuzzer.cpp deleted file mode 100644 index 78ddbb75..00000000 --- a/test/fuzzers/spvtools_opt_webgputovulkan_fuzzer.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2019 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include - -#include "spirv-tools/optimizer.hpp" - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - spvtools::Optimizer optimizer(SPV_ENV_WEBGPU_0); - optimizer.SetMessageConsumer([](spv_message_level_t, const char*, - const spv_position_t&, const char*) {}); - - std::vector input; - input.resize(size >> 2); - - size_t count = 0; - for (size_t i = 0; (i + 3) < size; i += 4) { - input[count++] = data[i] | (data[i + 1] << 8) | (data[i + 2] << 16) | - (data[i + 3]) << 24; - } - - optimizer.RegisterWebGPUToVulkanPasses(); - optimizer.Run(input.data(), input.size(), &input); - - return 0; -} diff --git a/test/fuzzers/spvtools_val_webgpu_fuzzer.cpp b/test/fuzzers/spvtools_val_webgpu_fuzzer.cpp deleted file mode 100644 index bed6e1a2..00000000 --- a/test/fuzzers/spvtools_val_webgpu_fuzzer.cpp +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2019 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include - -#include "spirv-tools/libspirv.hpp" - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - spvtools::SpirvTools tools(SPV_ENV_WEBGPU_0); - tools.SetMessageConsumer([](spv_message_level_t, const char*, - const spv_position_t&, const char*) {}); - - std::vector input; - input.resize(size >> 2); - - size_t count = 0; - for (size_t i = 0; (i + 3) < size; i += 4) { - input[count++] = data[i] | (data[i + 1] << 8) | (data[i + 2] << 16) | - (data[i + 3]) << 24; - } - - tools.Validate(input); - return 0; -} diff --git a/test/opt/CMakeLists.txt b/test/opt/CMakeLists.txt index 34269587..79cb3fc4 100644 --- a/test/opt/CMakeLists.txt +++ b/test/opt/CMakeLists.txt @@ -34,7 +34,6 @@ add_spvtools_unittest(TARGET opt dead_insert_elim_test.cpp dead_variable_elim_test.cpp debug_info_manager_test.cpp - decompose_initialized_variables_test.cpp decoration_manager_test.cpp def_use_test.cpp desc_sroa_test.cpp @@ -48,7 +47,6 @@ add_spvtools_unittest(TARGET opt fold_test.cpp freeze_spec_const_test.cpp function_test.cpp - generate_webgpu_initializers_test.cpp graphics_robust_access_test.cpp if_conversion_test.cpp inline_opaque_test.cpp @@ -63,7 +61,6 @@ add_spvtools_unittest(TARGET opt ir_context_test.cpp ir_loader_test.cpp iterator_test.cpp - legalize_vector_shuffle_test.cpp line_debug_info_test.cpp local_access_chain_convert_test.cpp local_redundancy_elimination_test.cpp @@ -88,9 +85,7 @@ add_spvtools_unittest(TARGET opt scalar_replacement_test.cpp set_spec_const_default_value_test.cpp simplification_test.cpp - split_invalid_unreachable_test.cpp strength_reduction_test.cpp - strip_atomic_counter_memory_test.cpp strip_debug_info_test.cpp strip_reflect_info_test.cpp struct_cfg_analysis_test.cpp diff --git a/test/opt/decompose_initialized_variables_test.cpp b/test/opt/decompose_initialized_variables_test.cpp deleted file mode 100644 index 06ba59a5..00000000 --- a/test/opt/decompose_initialized_variables_test.cpp +++ /dev/null @@ -1,252 +0,0 @@ -// Copyright (c) 2019 Google LLC. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include "test/opt/pass_fixture.h" -#include "test/opt/pass_utils.h" - -namespace spvtools { -namespace opt { -namespace { - -using DecomposeInitializedVariablesTest = PassTest<::testing::Test>; - -std::string single_entry_header = R"(OpCapability Shader -OpCapability VulkanMemoryModel -OpExtension "SPV_KHR_vulkan_memory_model" -OpMemoryModel Logical Vulkan -OpEntryPoint Vertex %1 "shader" -%uint = OpTypeInt 32 0 -%uint_1 = OpConstant %uint 1 -%4 = OpConstantNull %uint -%void = OpTypeVoid -%6 = OpTypeFunction %void -)"; - -std::string GetFunctionTest(std::string body) { - auto result = single_entry_header; - result += "%_ptr_Function_uint = OpTypePointer Function %uint\n"; - result += "%1 = OpFunction %void None %6\n"; - result += "%8 = OpLabel\n"; - result += body + "\n"; - result += "OpReturn\n"; - result += "OpFunctionEnd\n"; - return result; -} - -TEST_F(DecomposeInitializedVariablesTest, FunctionChanged) { - std::string input = "%9 = OpVariable %_ptr_Function_uint Function %uint_1"; - std::string expected = R"(%9 = OpVariable %_ptr_Function_uint Function -OpStore %9 %uint_1)"; - - SinglePassRunAndCheck( - GetFunctionTest(input), GetFunctionTest(expected), - /* skip_nop = */ false); -} - -TEST_F(DecomposeInitializedVariablesTest, FunctionUnchanged) { - std::string input = "%9 = OpVariable %_ptr_Function_uint Function"; - - SinglePassRunAndCheck( - GetFunctionTest(input), GetFunctionTest(input), /* skip_nop = */ false); -} - -TEST_F(DecomposeInitializedVariablesTest, FunctionMultipleVariables) { - std::string input = R"(%9 = OpVariable %_ptr_Function_uint Function %uint_1 -%10 = OpVariable %_ptr_Function_uint Function %4)"; - std::string expected = R"(%9 = OpVariable %_ptr_Function_uint Function -%10 = OpVariable %_ptr_Function_uint Function -OpStore %9 %uint_1 -OpStore %10 %4)"; - - SinglePassRunAndCheck( - GetFunctionTest(input), GetFunctionTest(expected), - /* skip_nop = */ false); -} - -std::string GetGlobalTest(std::string storage_class, bool initialized, - bool decomposed) { - auto result = single_entry_header; - - result += "%_ptr_" + storage_class + "_uint = OpTypePointer " + - storage_class + " %uint\n"; - if (initialized) { - result += "%8 = OpVariable %_ptr_" + storage_class + "_uint " + - storage_class + " %4\n"; - } else { - result += "%8 = OpVariable %_ptr_" + storage_class + "_uint " + - storage_class + "\n"; - } - result += R"(%1 = OpFunction %void None %9 -%9 = OpLabel -)"; - if (decomposed) result += "OpStore %8 %4\n"; - result += R"(OpReturn -OpFunctionEnd -)"; - return result; -} - -TEST_F(DecomposeInitializedVariablesTest, PrivateChanged) { - std::string input = GetGlobalTest("Private", true, false); - std::string expected = GetGlobalTest("Private", false, true); - SinglePassRunAndCheck( - input, expected, /* skip_nop = */ false); -} - -TEST_F(DecomposeInitializedVariablesTest, PrivateUnchanged) { - std::string input = GetGlobalTest("Private", false, false); - SinglePassRunAndCheck( - input, input, /* skip_nop = */ false); -} - -TEST_F(DecomposeInitializedVariablesTest, OutputChanged) { - std::string input = GetGlobalTest("Output", true, false); - std::string expected = GetGlobalTest("Output", false, true); - SinglePassRunAndCheck( - input, expected, /* skip_nop = */ false); -} - -TEST_F(DecomposeInitializedVariablesTest, OutputUnchanged) { - std::string input = GetGlobalTest("Output", false, false); - SinglePassRunAndCheck( - input, input, /* skip_nop = */ false); -} - -std::string multiple_entry_header = R"(OpCapability Shader -OpCapability VulkanMemoryModel -OpExtension "SPV_KHR_vulkan_memory_model" -OpMemoryModel Logical Vulkan -OpEntryPoint Vertex %1 "vertex" -OpEntryPoint Fragment %2 "fragment" -%uint = OpTypeInt 32 0 -%4 = OpConstantNull %uint -%void = OpTypeVoid -%6 = OpTypeFunction %void -)"; - -std::string GetGlobalMultipleEntryTest(std::string storage_class, - bool initialized, bool decomposed) { - auto result = multiple_entry_header; - result += "%_ptr_" + storage_class + "_uint = OpTypePointer " + - storage_class + " %uint\n"; - if (initialized) { - result += "%8 = OpVariable %_ptr_" + storage_class + "_uint " + - storage_class + " %4\n"; - } else { - result += "%8 = OpVariable %_ptr_" + storage_class + "_uint " + - storage_class + "\n"; - } - result += R"(%1 = OpFunction %void None %9 -%9 = OpLabel -)"; - if (decomposed) result += "OpStore %8 %4\n"; - result += R"(OpReturn -OpFunctionEnd -%2 = OpFunction %void None %10 -%10 = OpLabel -)"; - if (decomposed) result += "OpStore %8 %4\n"; - result += R"(OpReturn -OpFunctionEnd -)"; - - return result; -} - -TEST_F(DecomposeInitializedVariablesTest, PrivateMultipleEntryChanged) { - std::string input = GetGlobalMultipleEntryTest("Private", true, false); - std::string expected = GetGlobalMultipleEntryTest("Private", false, true); - SinglePassRunAndCheck( - input, expected, /* skip_nop = */ false); -} - -TEST_F(DecomposeInitializedVariablesTest, PrivateMultipleEntryUnchanged) { - std::string input = GetGlobalMultipleEntryTest("Private", false, false); - SinglePassRunAndCheck( - input, input, /* skip_nop = */ false); -} - -TEST_F(DecomposeInitializedVariablesTest, OutputMultipleEntryChanged) { - std::string input = GetGlobalMultipleEntryTest("Output", true, false); - std::string expected = GetGlobalMultipleEntryTest("Output", false, true); - SinglePassRunAndCheck( - input, expected, /* skip_nop = */ false); -} - -TEST_F(DecomposeInitializedVariablesTest, OutputMultipleEntryUnchanged) { - std::string input = GetGlobalMultipleEntryTest("Output", false, false); - SinglePassRunAndCheck( - input, input, /* skip_nop = */ false); -} - -std::string GetGlobalWithNonEntryPointTest(std::string storage_class, - bool initialized, bool decomposed) { - auto result = single_entry_header; - result += "%_ptr_" + storage_class + "_uint = OpTypePointer " + - storage_class + " %uint\n"; - if (initialized) { - result += "%8 = OpVariable %_ptr_" + storage_class + "_uint " + - storage_class + " %4\n"; - } else { - result += "%8 = OpVariable %_ptr_" + storage_class + "_uint " + - storage_class + "\n"; - } - result += R"(%1 = OpFunction %void None %9 -%9 = OpLabel -)"; - if (decomposed) result += "OpStore %8 %4\n"; - result += R"(OpReturn -OpFunctionEnd -%10 = OpFunction %void None %11 -%11 = OpLabel -OpReturn -OpFunctionEnd -)"; - - return result; -} - -TEST_F(DecomposeInitializedVariablesTest, PrivateWithNonEntryPointChanged) { - std::string input = GetGlobalWithNonEntryPointTest("Private", true, false); - std::string expected = GetGlobalWithNonEntryPointTest("Private", false, true); - SinglePassRunAndCheck( - input, expected, /* skip_nop = */ false); -} - -TEST_F(DecomposeInitializedVariablesTest, PrivateWithNonEntryPointUnchanged) { - std::string input = GetGlobalWithNonEntryPointTest("Private", false, false); - // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndCheck( - input, input, /* skip_nop = */ false); -} - -TEST_F(DecomposeInitializedVariablesTest, OutputWithNonEntryPointChanged) { - std::string input = GetGlobalWithNonEntryPointTest("Output", true, false); - std::string expected = GetGlobalWithNonEntryPointTest("Output", false, true); - SinglePassRunAndCheck( - input, expected, /* skip_nop = */ false); -} - -TEST_F(DecomposeInitializedVariablesTest, OutputWithNonEntryPointUnchanged) { - std::string input = GetGlobalWithNonEntryPointTest("Output", false, false); - // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndCheck( - input, input, /* skip_nop = */ false); -} - -} // namespace -} // namespace opt -} // namespace spvtools diff --git a/test/opt/generate_webgpu_initializers_test.cpp b/test/opt/generate_webgpu_initializers_test.cpp deleted file mode 100644 index 4aab2ce2..00000000 --- a/test/opt/generate_webgpu_initializers_test.cpp +++ /dev/null @@ -1,347 +0,0 @@ -// Copyright (c) 2019 Google LLC. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include "test/opt/pass_fixture.h" -#include "test/opt/pass_utils.h" - -namespace spvtools { -namespace opt { -namespace { - -typedef std::tuple GenerateWebGPUInitializersParam; - -using GlobalVariableTest = - PassTest<::testing::TestWithParam>; -using LocalVariableTest = - PassTest<::testing::TestWithParam>; - -using GenerateWebGPUInitializersTest = PassTest<::testing::Test>; - -void operator+=(std::vector& lhs, const char* rhs) { - lhs.push_back(rhs); -} - -void operator+=(std::vector& lhs, - const std::vector& rhs) { - lhs.reserve(lhs.size() + rhs.size()); - for (auto* c : rhs) lhs.push_back(c); -} - -std::string GetGlobalVariableTestString(std::string ptr_str, - std::string var_str, - std::string const_str = "") { - std::vector result = { - // clang-format off - "OpCapability Shader", - "OpCapability VulkanMemoryModel", - "OpExtension \"SPV_KHR_vulkan_memory_model\"", - "OpMemoryModel Logical Vulkan", - "OpEntryPoint Vertex %1 \"shader\"", - "%uint = OpTypeInt 32 0", - ptr_str.c_str()}; - // clang-format on - - if (!const_str.empty()) result += const_str.c_str(); - - result += { - // clang-format off - var_str.c_str(), - "%uint_0 = OpConstant %uint 0", - "%void = OpTypeVoid", - "%7 = OpTypeFunction %void", - "%1 = OpFunction %void None %7", - "%8 = OpLabel", - "OpStore %4 %uint_0", - "OpReturn", - "OpFunctionEnd" - // clang-format on - }; - return JoinAllInsts(result); -} - -std::string GetPointerString(std::string storage_type) { - std::string result = "%_ptr_"; - result += storage_type + "_uint = OpTypePointer "; - result += storage_type + " %uint"; - return result; -} - -std::string GetGlobalVariableString(std::string storage_type, - bool initialized) { - std::string result = "%4 = OpVariable %_ptr_"; - result += storage_type + "_uint "; - result += storage_type; - if (initialized) result += " %9"; - return result; -} - -std::string GetUninitializedGlobalVariableTestString(std::string storage_type) { - return GetGlobalVariableTestString( - GetPointerString(storage_type), - GetGlobalVariableString(storage_type, false)); -} - -std::string GetNullConstantString() { return "%9 = OpConstantNull %uint"; } - -std::string GetInitializedGlobalVariableTestString(std::string storage_type) { - return GetGlobalVariableTestString( - GetPointerString(storage_type), - GetGlobalVariableString(storage_type, true), GetNullConstantString()); -} - -TEST_P(GlobalVariableTest, Check) { - std::string storage_class = std::get<0>(GetParam()); - bool changed = std::get<1>(GetParam()); - std::string input = GetUninitializedGlobalVariableTestString(storage_class); - std::string expected = - changed ? GetInitializedGlobalVariableTestString(storage_class) : input; - - SinglePassRunAndCheck(input, expected, - /* skip_nop = */ false); -} - -// clang-format off -INSTANTIATE_TEST_SUITE_P( - GenerateWebGPUInitializers, GlobalVariableTest, - ::testing::ValuesIn(std::vector({ - std::make_tuple("Private", true), - std::make_tuple("Output", true), - std::make_tuple("Function", true), - std::make_tuple("UniformConstant", false), - std::make_tuple("Input", false), - std::make_tuple("Uniform", false), - std::make_tuple("Workgroup", false) - }))); -// clang-format on - -std::string GetLocalVariableTestString(std::string ptr_str, std::string var_str, - std::string const_str = "") { - std::vector result = { - // clang-format off - "OpCapability Shader", - "OpCapability VulkanMemoryModel", - "OpExtension \"SPV_KHR_vulkan_memory_model\"", - "OpMemoryModel Logical Vulkan", - "OpEntryPoint Vertex %1 \"shader\"", - "%uint = OpTypeInt 32 0", - ptr_str.c_str(), - "%uint_0 = OpConstant %uint 0", - "%void = OpTypeVoid", - "%6 = OpTypeFunction %void"}; - // clang-format on - - if (!const_str.empty()) result += const_str.c_str(); - - result += { - // clang-format off - "%1 = OpFunction %void None %6", - "%7 = OpLabel", - var_str.c_str(), - "OpStore %8 %uint_0" - // clang-format on - }; - return JoinAllInsts(result); -} - -std::string GetLocalVariableString(std::string storage_type, bool initialized) { - std::string result = "%8 = OpVariable %_ptr_"; - result += storage_type + "_uint "; - result += storage_type; - if (initialized) result += " %9"; - return result; -} - -std::string GetUninitializedLocalVariableTestString(std::string storage_type) { - return GetLocalVariableTestString( - GetPointerString(storage_type), - GetLocalVariableString(storage_type, false)); -} - -std::string GetInitializedLocalVariableTestString(std::string storage_type) { - return GetLocalVariableTestString(GetPointerString(storage_type), - GetLocalVariableString(storage_type, true), - GetNullConstantString()); -} - -TEST_P(LocalVariableTest, Check) { - std::string storage_class = std::get<0>(GetParam()); - bool changed = std::get<1>(GetParam()); - - std::string input = GetUninitializedLocalVariableTestString(storage_class); - std::string expected = - changed ? GetInitializedLocalVariableTestString(storage_class) : input; - - SinglePassRunAndCheck(input, expected, - /* skip_nop = */ false); -} - -// clang-format off -INSTANTIATE_TEST_SUITE_P( - GenerateWebGPUInitializers, LocalVariableTest, - ::testing::ValuesIn(std::vector({ - std::make_tuple("Private", true), - std::make_tuple("Output", true), - std::make_tuple("Function", true), - std::make_tuple("UniformConstant", false), - std::make_tuple("Input", false), - std::make_tuple("Uniform", false), - std::make_tuple("Workgroup", false) - }))); -// clang-format on - -TEST_F(GenerateWebGPUInitializersTest, AlreadyInitializedUnchanged) { - std::vector spirv = { - // clang-format off - "OpCapability Shader", - "OpCapability VulkanMemoryModel", - "OpExtension \"SPV_KHR_vulkan_memory_model\"", - "OpMemoryModel Logical Vulkan", - "OpEntryPoint Vertex %1 \"shader\"", - "%uint = OpTypeInt 32 0", - "%_ptr_Private_uint = OpTypePointer Private %uint", - "%uint_0 = OpConstant %uint 0", - "%5 = OpVariable %_ptr_Private_uint Private %uint_0", - "%void = OpTypeVoid", - "%7 = OpTypeFunction %void", - "%1 = OpFunction %void None %7", - "%8 = OpLabel", - "OpReturn", - "OpFunctionEnd" - // clang-format on - }; - std::string str = JoinAllInsts(spirv); - - SinglePassRunAndCheck(str, str, - /* skip_nop = */ false); -} - -TEST_F(GenerateWebGPUInitializersTest, AmbigiousArrays) { - std::vector input_spirv = { - // clang-format off - "OpCapability Shader", - "OpCapability VulkanMemoryModel", - "OpExtension \"SPV_KHR_vulkan_memory_model\"", - "OpMemoryModel Logical Vulkan", - "OpEntryPoint Vertex %1 \"shader\"", - "%uint = OpTypeInt 32 0", - "%uint_2 = OpConstant %uint 2", - "%_arr_uint_uint_2 = OpTypeArray %uint %uint_2", - "%_arr_uint_uint_2_0 = OpTypeArray %uint %uint_2", - "%_ptr_Private__arr_uint_uint_2 = OpTypePointer Private %_arr_uint_uint_2", -"%_ptr_Private__arr_uint_uint_2_0 = OpTypePointer Private %_arr_uint_uint_2_0", - "%8 = OpConstantNull %_arr_uint_uint_2_0", - "%9 = OpVariable %_ptr_Private__arr_uint_uint_2 Private", - "%10 = OpVariable %_ptr_Private__arr_uint_uint_2_0 Private %8", - "%void = OpTypeVoid", - "%12 = OpTypeFunction %void", - "%1 = OpFunction %void None %12", - "%13 = OpLabel", - "OpReturn", - "OpFunctionEnd" - // clang-format on - }; - std::string input_str = JoinAllInsts(input_spirv); - - std::vector expected_spirv = { - // clang-format off - "OpCapability Shader", - "OpCapability VulkanMemoryModel", - "OpExtension \"SPV_KHR_vulkan_memory_model\"", - "OpMemoryModel Logical Vulkan", - "OpEntryPoint Vertex %1 \"shader\"", - "%uint = OpTypeInt 32 0", - "%uint_2 = OpConstant %uint 2", - "%_arr_uint_uint_2 = OpTypeArray %uint %uint_2", - "%_arr_uint_uint_2_0 = OpTypeArray %uint %uint_2", - "%_ptr_Private__arr_uint_uint_2 = OpTypePointer Private %_arr_uint_uint_2", -"%_ptr_Private__arr_uint_uint_2_0 = OpTypePointer Private %_arr_uint_uint_2_0", - "%8 = OpConstantNull %_arr_uint_uint_2_0", - "%14 = OpConstantNull %_arr_uint_uint_2", - "%9 = OpVariable %_ptr_Private__arr_uint_uint_2 Private %14", - "%10 = OpVariable %_ptr_Private__arr_uint_uint_2_0 Private %8", - "%void = OpTypeVoid", - "%12 = OpTypeFunction %void", - "%1 = OpFunction %void None %12", - "%13 = OpLabel", - "OpReturn", - "OpFunctionEnd" - // clang-format on - }; - std::string expected_str = JoinAllInsts(expected_spirv); - - SinglePassRunAndCheck(input_str, expected_str, - /* skip_nop = */ false); -} - -TEST_F(GenerateWebGPUInitializersTest, AmbigiousStructs) { - std::vector input_spirv = { - // clang-format off - "OpCapability Shader", - "OpCapability VulkanMemoryModel", - "OpExtension \"SPV_KHR_vulkan_memory_model\"", - "OpMemoryModel Logical Vulkan", - "OpEntryPoint Vertex %1 \"shader\"", - "%uint = OpTypeInt 32 0", - "%_struct_3 = OpTypeStruct %uint", - "%_struct_4 = OpTypeStruct %uint", -"%_ptr_Private__struct_3 = OpTypePointer Private %_struct_3", -"%_ptr_Private__struct_4 = OpTypePointer Private %_struct_4", - "%7 = OpConstantNull %_struct_3", - "%8 = OpVariable %_ptr_Private__struct_3 Private %7", - "%9 = OpVariable %_ptr_Private__struct_4 Private", - "%void = OpTypeVoid", - "%11 = OpTypeFunction %void", - "%1 = OpFunction %void None %11", - "%12 = OpLabel", - "OpReturn", - "OpFunctionEnd" - // clang-format on - }; - std::string input_str = JoinAllInsts(input_spirv); - - std::vector expected_spirv = { - // clang-format off - "OpCapability Shader", - "OpCapability VulkanMemoryModel", - "OpExtension \"SPV_KHR_vulkan_memory_model\"", - "OpMemoryModel Logical Vulkan", - "OpEntryPoint Vertex %1 \"shader\"", - "%uint = OpTypeInt 32 0", - "%_struct_3 = OpTypeStruct %uint", - "%_struct_4 = OpTypeStruct %uint", -"%_ptr_Private__struct_3 = OpTypePointer Private %_struct_3", -"%_ptr_Private__struct_4 = OpTypePointer Private %_struct_4", - "%7 = OpConstantNull %_struct_3", - "%8 = OpVariable %_ptr_Private__struct_3 Private %7", - "%13 = OpConstantNull %_struct_4", - "%9 = OpVariable %_ptr_Private__struct_4 Private %13", - "%void = OpTypeVoid", - "%11 = OpTypeFunction %void", - "%1 = OpFunction %void None %11", - "%12 = OpLabel", - "OpReturn", - "OpFunctionEnd" - // clang-format on - }; - std::string expected_str = JoinAllInsts(expected_spirv); - - SinglePassRunAndCheck(input_str, expected_str, - /* skip_nop = */ false); -} - -} // namespace -} // namespace opt -} // namespace spvtools diff --git a/test/opt/legalize_vector_shuffle_test.cpp b/test/opt/legalize_vector_shuffle_test.cpp deleted file mode 100644 index 07d96eb3..00000000 --- a/test/opt/legalize_vector_shuffle_test.cpp +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) 2019 Google LLC. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include "test/opt/pass_fixture.h" -#include "test/opt/pass_utils.h" - -namespace spvtools { -namespace opt { -namespace { - -using LegalizeVectorShuffleTest = PassTest<::testing::Test>; - -void operator+=(std::vector& lhs, const char* rhs) { - lhs.push_back(rhs); -} - -void operator+=(std::vector& lhs, - const std::vector rhs) { - for (auto elem : rhs) lhs.push_back(elem); -} - -std::vector header = { - "OpCapability Shader", - "OpCapability VulkanMemoryModel", - "OpExtension \"SPV_KHR_vulkan_memory_model\"", - "OpMemoryModel Logical Vulkan", - "OpEntryPoint Vertex %1 \"shader\"", - "%uint = OpTypeInt 32 0", - "%v3uint = OpTypeVector %uint 3"}; - -std::string GetTestString(const char* shuffle) { - std::vector result = header; - result += {"%_ptr_Function_v3uint = OpTypePointer Function %v3uint", - "%void = OpTypeVoid", - "%6 = OpTypeFunction %void", - "%1 = OpFunction %void None %6", - "%7 = OpLabel", - "%8 = OpVariable %_ptr_Function_v3uint Function", - "%9 = OpLoad %v3uint %8", - "%10 = OpLoad %v3uint %8"}; - result += shuffle; - result += {"OpReturn", "OpFunctionEnd"}; - return JoinAllInsts(result); -} - -TEST_F(LegalizeVectorShuffleTest, Changed) { - std::string input = - GetTestString("%11 = OpVectorShuffle %v3uint %9 %10 2 1 0xFFFFFFFF"); - std::string expected = - GetTestString("%11 = OpVectorShuffle %v3uint %9 %10 2 1 0"); - - SinglePassRunAndCheck(input, expected, - /* skip_nop = */ false); -} - -TEST_F(LegalizeVectorShuffleTest, FunctionUnchanged) { - std::string input = - GetTestString("%11 = OpVectorShuffle %v3uint %9 %10 2 1 0"); - std::string expected = - GetTestString("%11 = OpVectorShuffle %v3uint %9 %10 2 1 0"); - - SinglePassRunAndCheck(input, expected, - /* skip_nop = */ false); -} - -} // namespace -} // namespace opt -} // namespace spvtools diff --git a/test/opt/optimizer_test.cpp b/test/opt/optimizer_test.cpp index de79536e..a51638a1 100644 --- a/test/opt/optimizer_test.cpp +++ b/test/opt/optimizer_test.cpp @@ -221,498 +221,6 @@ TEST(Optimizer, CanRegisterPassesFromFlags) { EXPECT_EQ(msg_level, SPV_MSG_ERROR); } -TEST(Optimizer, VulkanToWebGPUSetsCorrectPasses) { - Optimizer opt(SPV_ENV_VULKAN_1_1); - opt.RegisterVulkanToWebGPUPasses(); - std::vector pass_names = opt.GetPassNames(); - - std::vector registered_passes; - for (auto name = pass_names.begin(); name != pass_names.end(); ++name) - registered_passes.push_back(*name); - - std::vector expected_passes = {"eliminate-dead-branches", - "eliminate-dead-code-aggressive", - "eliminate-dead-const", - "flatten-decorations", - "strip-atomic-counter-memory", - "generate-webgpu-initializers", - "legalize-vector-shuffle", - "split-invalid-unreachable", - "compact-ids"}; - std::sort(registered_passes.begin(), registered_passes.end()); - std::sort(expected_passes.begin(), expected_passes.end()); - - ASSERT_EQ(registered_passes.size(), expected_passes.size()); - for (size_t i = 0; i < registered_passes.size(); i++) - EXPECT_EQ(registered_passes[i], expected_passes[i]); -} - -struct VulkanToWebGPUPassCase { - // Input SPIR-V - std::string input; - // Expected result SPIR-V - std::string expected; - // Specific pass under test, used for logging messages. - std::string pass; -}; - -using VulkanToWebGPUPassTest = - PassTest<::testing::TestWithParam>; - -TEST_P(VulkanToWebGPUPassTest, Ran) { - std::vector binary; - { - SpirvTools tools(SPV_ENV_VULKAN_1_1); - tools.Assemble(GetParam().input, &binary); - } - - Optimizer opt(SPV_ENV_VULKAN_1_1); - opt.RegisterVulkanToWebGPUPasses(); - - std::vector optimized; - class ValidatorOptions validator_options; - ASSERT_TRUE(opt.Run(binary.data(), binary.size(), &optimized, - validator_options, true)) - << GetParam().input << "\n"; - std::string disassembly; - { - SpirvTools tools(SPV_ENV_WEBGPU_0); - tools.Disassemble(optimized.data(), optimized.size(), &disassembly); - } - - EXPECT_EQ(GetParam().expected, disassembly) - << "Was expecting pass '" << GetParam().pass << "' to have been run.\n"; -} - -INSTANTIATE_TEST_SUITE_P( - Optimizer, VulkanToWebGPUPassTest, - ::testing::ValuesIn(std::vector{ - // FlattenDecorations - {// input - "OpCapability Shader\n" - "OpCapability VulkanMemoryModel\n" - "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" - "OpMemoryModel Logical Vulkan\n" - "OpEntryPoint Fragment %main \"main\" %hue %saturation %value\n" - "OpExecutionMode %main OriginUpperLeft\n" - "OpDecorate %group Flat\n" - "OpDecorate %group NoPerspective\n" - "%group = OpDecorationGroup\n" - "%void = OpTypeVoid\n" - "%void_fn = OpTypeFunction %void\n" - "%float = OpTypeFloat 32\n" - "%_ptr_Input_float = OpTypePointer Input %float\n" - "%hue = OpVariable %_ptr_Input_float Input\n" - "%saturation = OpVariable %_ptr_Input_float Input\n" - "%value = OpVariable %_ptr_Input_float Input\n" - "%main = OpFunction %void None %void_fn\n" - "%entry = OpLabel\n" - "OpReturn\n" - "OpFunctionEnd\n", - // expected - "OpCapability Shader\n" - "OpCapability VulkanMemoryModel\n" - "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" - "OpMemoryModel Logical Vulkan\n" - "OpEntryPoint Fragment %1 \"main\" %2 %3 %4\n" - "OpExecutionMode %1 OriginUpperLeft\n" - "%void = OpTypeVoid\n" - "%6 = OpTypeFunction %void\n" - "%float = OpTypeFloat 32\n" - "%_ptr_Input_float = OpTypePointer Input %float\n" - "%2 = OpVariable %_ptr_Input_float Input\n" - "%3 = OpVariable %_ptr_Input_float Input\n" - "%4 = OpVariable %_ptr_Input_float Input\n" - "%1 = OpFunction %void None %6\n" - "%9 = OpLabel\n" - "OpReturn\n" - "OpFunctionEnd\n", - // pass - "flatten-decorations"}, - // Eliminate Dead Constants - {// input - "OpCapability Shader\n" - "OpCapability VulkanMemoryModel\n" - "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" - "OpMemoryModel Logical Vulkan\n" - "OpEntryPoint Vertex %func \"shader\"\n" - "%u32 = OpTypeInt 32 0\n" - "%u32_ptr = OpTypePointer Workgroup %u32\n" - "%u32_var = OpVariable %u32_ptr Workgroup\n" - "%u32_1 = OpConstant %u32 1\n" - "%cross_device = OpConstant %u32 0\n" - "%relaxed = OpConstant %u32 0\n" - "%acquire_release_atomic_counter_workgroup = OpConstant %u32 1288\n" - "%void = OpTypeVoid\n" - "%void_f = OpTypeFunction %void\n" - "%func = OpFunction %void None %void_f\n" - "%label = OpLabel\n" - "OpReturn\n" - "OpFunctionEnd\n", - // expected - "OpCapability Shader\n" - "OpCapability VulkanMemoryModel\n" - "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" - "OpMemoryModel Logical Vulkan\n" - "OpEntryPoint Vertex %1 \"shader\"\n" - "%uint = OpTypeInt 32 0\n" - "%_ptr_Workgroup_uint = OpTypePointer Workgroup %uint\n" - "%4 = OpVariable %_ptr_Workgroup_uint Workgroup\n" - "%void = OpTypeVoid\n" - "%6 = OpTypeFunction %void\n" - "%1 = OpFunction %void None %6\n" - "%7 = OpLabel\n" - "OpReturn\n" - "OpFunctionEnd\n", - "eliminate-dead-const"}, - // Strip Atomic Counter Memory - {// input - "OpCapability Shader\n" - "OpCapability VulkanMemoryModel\n" - "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" - "OpMemoryModel Logical Vulkan\n" - "OpEntryPoint Vertex %func \"shader\"\n" - "%u32 = OpTypeInt 32 0\n" - "%u32_ptr = OpTypePointer Workgroup %u32\n" - "%u32_var = OpVariable %u32_ptr Workgroup\n" - "%u32_0 = OpConstant %u32 0\n" - "%u32_1 = OpConstant %u32 1\n" - "%cross_device = OpConstant %u32 0\n" - "%acquire_release_atomic_counter_workgroup = OpConstant %u32 1288\n" - "%void = OpTypeVoid\n" - "%void_f = OpTypeFunction %void\n" - "%func = OpFunction %void None %void_f\n" - "%label = OpLabel\n" - " OpAtomicStore %u32_var %cross_device " - "%acquire_release_atomic_counter_workgroup %u32_1\n" - "%val1 = OpAtomicIIncrement %u32 %u32_var %cross_device " - "%acquire_release_atomic_counter_workgroup\n" - "%val2 = OpAtomicCompareExchange %u32 %u32_var %cross_device " - "%acquire_release_atomic_counter_workgroup " - "%acquire_release_atomic_counter_workgroup %u32_0 %u32_0\n" - "OpReturn\n" - "OpFunctionEnd\n", - // expected - "OpCapability Shader\n" - "OpCapability VulkanMemoryModel\n" - "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" - "OpMemoryModel Logical Vulkan\n" - "OpEntryPoint Vertex %1 \"shader\"\n" - "%uint = OpTypeInt 32 0\n" - "%_ptr_Workgroup_uint = OpTypePointer Workgroup %uint\n" - "%4 = OpVariable %_ptr_Workgroup_uint Workgroup\n" - "%uint_0 = OpConstant %uint 0\n" - "%uint_1 = OpConstant %uint 1\n" - "%uint_0_0 = OpConstant %uint 0\n" - "%void = OpTypeVoid\n" - "%9 = OpTypeFunction %void\n" - "%uint_264 = OpConstant %uint 264\n" - "%1 = OpFunction %void None %9\n" - "%11 = OpLabel\n" - "OpAtomicStore %4 %uint_0_0 %uint_264 %uint_1\n" - "%12 = OpAtomicIIncrement %uint %4 %uint_0_0 %uint_264\n" - "%13 = OpAtomicCompareExchange %uint %4 %uint_0_0 %uint_264 %uint_264 " - "%uint_0 %uint_0\n" - "OpReturn\n" - "OpFunctionEnd\n", - // pass - "strip-atomic-counter-memory"}, - // Generate WebGPU Initializers - {// input - "OpCapability Shader\n" - "OpCapability VulkanMemoryModel\n" - "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" - "OpMemoryModel Logical Vulkan\n" - "OpEntryPoint Vertex %func \"shader\"\n" - "%u32 = OpTypeInt 32 0\n" - "%u32_ptr = OpTypePointer Private %u32\n" - "%u32_var = OpVariable %u32_ptr Private\n" - "%u32_0 = OpConstant %u32 0\n" - "%void = OpTypeVoid\n" - "%void_f = OpTypeFunction %void\n" - "%func = OpFunction %void None %void_f\n" - "%label = OpLabel\n" - "OpStore %u32_var %u32_0\n" - "OpReturn\n" - "OpFunctionEnd\n", - // expected - "OpCapability Shader\n" - "OpCapability VulkanMemoryModel\n" - "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" - "OpMemoryModel Logical Vulkan\n" - "OpEntryPoint Vertex %1 \"shader\"\n" - "%uint = OpTypeInt 32 0\n" - "%_ptr_Private_uint = OpTypePointer Private %uint\n" - "%4 = OpConstantNull %uint\n" - "%5 = OpVariable %_ptr_Private_uint Private %4\n" - "%uint_0 = OpConstant %uint 0\n" - "%void = OpTypeVoid\n" - "%8 = OpTypeFunction %void\n" - "%1 = OpFunction %void None %8\n" - "%9 = OpLabel\n" - "OpStore %5 %uint_0\n" - "OpReturn\n" - "OpFunctionEnd\n", - // pass - "generate-webgpu-initializers"}, - // Legalize Vector Shuffle - {// input - "OpCapability Shader\n" - "OpCapability VulkanMemoryModel\n" - "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" - "OpMemoryModel Logical Vulkan\n" - "OpEntryPoint Vertex %1 \"shader\"\n" - "%uint = OpTypeInt 32 0\n" - "%v3uint = OpTypeVector %uint 3\n" - "%_ptr_Function_v3uint = OpTypePointer Function %v3uint\n" - "%void = OpTypeVoid\n" - "%6 = OpTypeFunction %void\n" - "%1 = OpFunction %void None %6\n" - "%7 = OpLabel\n" - "%8 = OpVariable %_ptr_Function_v3uint Function\n" - "%9 = OpLoad %v3uint %8\n" - "%10 = OpLoad %v3uint %8\n" - "%11 = OpVectorShuffle %v3uint %9 %10 2 1 0xFFFFFFFF\n" - "OpReturn\n" - "OpFunctionEnd\n", - // expected - "OpCapability Shader\n" - "OpCapability VulkanMemoryModel\n" - "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" - "OpMemoryModel Logical Vulkan\n" - "OpEntryPoint Vertex %1 \"shader\"\n" - "%uint = OpTypeInt 32 0\n" - "%v3uint = OpTypeVector %uint 3\n" - "%_ptr_Function_v3uint = OpTypePointer Function %v3uint\n" - "%void = OpTypeVoid\n" - "%6 = OpTypeFunction %void\n" - "%7 = OpConstantNull %v3uint\n" - "%1 = OpFunction %void None %6\n" - "%8 = OpLabel\n" - "%9 = OpVariable %_ptr_Function_v3uint Function %7\n" - "%10 = OpLoad %v3uint %9\n" - "%11 = OpLoad %v3uint %9\n" - "%12 = OpVectorShuffle %v3uint %10 %11 2 1 0\n" - "OpReturn\n" - "OpFunctionEnd\n", - // pass - "legalize-vector-shuffle"}, - // Split Invalid Unreachable - {// input - "OpCapability Shader\n" - "OpCapability VulkanMemoryModel\n" - "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" - "OpMemoryModel Logical Vulkan\n" - "OpEntryPoint Vertex %1 \"shader\"\n" - "%uint = OpTypeInt 32 0\n" - "%uint_1 = OpConstant %uint 1\n" - "%uint_2 = OpConstant %uint 2\n" - "%void = OpTypeVoid\n" - "%bool = OpTypeBool\n" - "%7 = OpTypeFunction %void\n" - "%1 = OpFunction %void None %7\n" - "%8 = OpLabel\n" - "OpBranch %9\n" - "%9 = OpLabel\n" - "OpLoopMerge %10 %11 None\n" - "OpBranch %12\n" - "%12 = OpLabel\n" - "%13 = OpSLessThan %bool %uint_1 %uint_2\n" - "OpSelectionMerge %11 None\n" - "OpBranchConditional %13 %14 %15\n" - "%14 = OpLabel\n" - "OpReturn\n" - "%15 = OpLabel\n" - "OpReturn\n" - "%10 = OpLabel\n" - "OpUnreachable\n" - "%11 = OpLabel\n" - "OpBranch %9\n" - "OpFunctionEnd\n", - // expected - "OpCapability Shader\n" - "OpCapability VulkanMemoryModel\n" - "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" - "OpMemoryModel Logical Vulkan\n" - "OpEntryPoint Vertex %1 \"shader\"\n" - "%uint = OpTypeInt 32 0\n" - "%uint_1 = OpConstant %uint 1\n" - "%uint_2 = OpConstant %uint 2\n" - "%void = OpTypeVoid\n" - "%bool = OpTypeBool\n" - "%7 = OpTypeFunction %void\n" - "%1 = OpFunction %void None %7\n" - "%8 = OpLabel\n" - "OpBranch %9\n" - "%9 = OpLabel\n" - "OpLoopMerge %10 %11 None\n" - "OpBranch %12\n" - "%12 = OpLabel\n" - "%13 = OpSLessThan %bool %uint_1 %uint_2\n" - "OpSelectionMerge %14 None\n" - "OpBranchConditional %13 %15 %16\n" - "%15 = OpLabel\n" - "OpReturn\n" - "%16 = OpLabel\n" - "OpReturn\n" - "%10 = OpLabel\n" - "OpUnreachable\n" - "%14 = OpLabel\n" - "OpUnreachable\n" - "%11 = OpLabel\n" - "OpBranch %9\n" - "OpFunctionEnd\n", - // pass - "split-invalid-unreachable"}, - // Compact IDs - {// input - "OpCapability Shader\n" - "OpCapability VulkanMemoryModel\n" - "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" - "OpMemoryModel Logical Vulkan\n" - "OpEntryPoint Vertex %1000 \"shader\"\n" - "%10 = OpTypeVoid\n" - "%100 = OpTypeFunction %10\n" - "%1000 = OpFunction %10 None %100\n" - "%10000 = OpLabel\n" - "OpReturn\n" - "OpFunctionEnd\n", - // expected - "OpCapability Shader\n" - "OpCapability VulkanMemoryModel\n" - "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" - "OpMemoryModel Logical Vulkan\n" - "OpEntryPoint Vertex %1 \"shader\"\n" - "%void = OpTypeVoid\n" - "%3 = OpTypeFunction %void\n" - "%1 = OpFunction %void None %3\n" - "%4 = OpLabel\n" - "OpReturn\n" - "OpFunctionEnd\n", - // pass - "compact-ids"}})); - -TEST(Optimizer, WebGPUToVulkanSetsCorrectPasses) { - Optimizer opt(SPV_ENV_WEBGPU_0); - opt.RegisterWebGPUToVulkanPasses(); - std::vector pass_names = opt.GetPassNames(); - - std::vector registered_passes; - for (auto name = pass_names.begin(); name != pass_names.end(); ++name) - registered_passes.push_back(*name); - - std::vector expected_passes = {"decompose-initialized-variables", - "compact-ids"}; - std::sort(registered_passes.begin(), registered_passes.end()); - std::sort(expected_passes.begin(), expected_passes.end()); - - ASSERT_EQ(registered_passes.size(), expected_passes.size()); - for (size_t i = 0; i < registered_passes.size(); i++) - EXPECT_EQ(registered_passes[i], expected_passes[i]); -} - -struct WebGPUToVulkanPassCase { - // Input SPIR-V - std::string input; - // Expected result SPIR-V - std::string expected; - // Specific pass under test, used for logging messages. - std::string pass; -}; - -using WebGPUToVulkanPassTest = - PassTest<::testing::TestWithParam>; - -TEST_P(WebGPUToVulkanPassTest, Ran) { - std::vector binary; - { - SpirvTools tools(SPV_ENV_WEBGPU_0); - tools.Assemble(GetParam().input, &binary); - } - - Optimizer opt(SPV_ENV_WEBGPU_0); - opt.RegisterWebGPUToVulkanPasses(); - - std::vector optimized; - class ValidatorOptions validator_options; - ASSERT_TRUE(opt.Run(binary.data(), binary.size(), &optimized, - validator_options, true)); - std::string disassembly; - { - SpirvTools tools(SPV_ENV_VULKAN_1_1); - tools.Disassemble(optimized.data(), optimized.size(), &disassembly); - } - - EXPECT_EQ(GetParam().expected, disassembly) - << "Was expecting pass '" << GetParam().pass << "' to have been run.\n"; -} - -INSTANTIATE_TEST_SUITE_P( - Optimizer, WebGPUToVulkanPassTest, - ::testing::ValuesIn(std::vector{ - // Decompose Initialized Variables - {// input - "OpCapability Shader\n" - "OpCapability VulkanMemoryModel\n" - "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" - "OpMemoryModel Logical Vulkan\n" - "OpEntryPoint Vertex %1 \"shader\"\n" - "%uint = OpTypeInt 32 0\n" - "%_ptr_Function_uint = OpTypePointer Function %uint\n" - "%4 = OpConstantNull %uint\n" - "%void = OpTypeVoid\n" - "%6 = OpTypeFunction %void\n" - "%1 = OpFunction %void None %6\n" - "%7 = OpLabel\n" - "%8 = OpVariable %_ptr_Function_uint Function %4\n" - "OpReturn\n" - "OpFunctionEnd\n", - // expected - "OpCapability Shader\n" - "OpCapability VulkanMemoryModel\n" - "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" - "OpMemoryModel Logical Vulkan\n" - "OpEntryPoint Vertex %1 \"shader\"\n" - "%uint = OpTypeInt 32 0\n" - "%_ptr_Function_uint = OpTypePointer Function %uint\n" - "%4 = OpConstantNull %uint\n" - "%void = OpTypeVoid\n" - "%6 = OpTypeFunction %void\n" - "%1 = OpFunction %void None %6\n" - "%7 = OpLabel\n" - "%8 = OpVariable %_ptr_Function_uint Function\n" - "OpStore %8 %4\n" - "OpReturn\n" - "OpFunctionEnd\n", - // pass - "decompose-initialized-variables"}, - // Compact IDs - {// input - "OpCapability Shader\n" - "OpCapability VulkanMemoryModel\n" - "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" - "OpMemoryModel Logical Vulkan\n" - "OpEntryPoint Vertex %1000 \"shader\"\n" - "%10 = OpTypeVoid\n" - "%100 = OpTypeFunction %10\n" - "%1000 = OpFunction %10 None %100\n" - "%10000 = OpLabel\n" - "OpReturn\n" - "OpFunctionEnd\n", - // expected - "OpCapability Shader\n" - "OpCapability VulkanMemoryModel\n" - "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" - "OpMemoryModel Logical Vulkan\n" - "OpEntryPoint Vertex %1 \"shader\"\n" - "%void = OpTypeVoid\n" - "%3 = OpTypeFunction %void\n" - "%1 = OpFunction %void None %3\n" - "%4 = OpLabel\n" - "OpReturn\n" - "OpFunctionEnd\n", - // pass - "compact-ids"}})); TEST(Optimizer, RemoveNop) { // Test that OpNops are removed even if no optimizations are run. @@ -754,7 +262,7 @@ OpFunctionEnd << before << "\n"; std::string disassembly; { - SpirvTools tools(SPV_ENV_WEBGPU_0); + SpirvTools tools(SPV_ENV_VULKAN_1_1); tools.Disassemble(optimized.data(), optimized.size(), &disassembly); } diff --git a/test/opt/split_invalid_unreachable_test.cpp b/test/opt/split_invalid_unreachable_test.cpp deleted file mode 100644 index 520af015..00000000 --- a/test/opt/split_invalid_unreachable_test.cpp +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright (c) 2019 Google LLC. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include "test/opt/pass_fixture.h" -#include "test/opt/pass_utils.h" - -namespace spvtools { -namespace opt { -namespace { - -using SplitInvalidUnreachableTest = PassTest<::testing::Test>; - -std::string spirv_header = R"(OpCapability Shader -OpCapability VulkanMemoryModel -OpExtension "SPV_KHR_vulkan_memory_model" -OpMemoryModel Logical Vulkan -OpEntryPoint Vertex %1 "shader" -%uint = OpTypeInt 32 0 -%uint_1 = OpConstant %uint 1 -%uint_2 = OpConstant %uint 2 -%void = OpTypeVoid -%bool = OpTypeBool -%7 = OpTypeFunction %void -)"; - -std::string function_head = R"(%1 = OpFunction %void None %7 -%8 = OpLabel -OpBranch %9 -)"; - -std::string function_tail = "OpFunctionEnd\n"; - -std::string GetLoopMergeBlock(std::string block_id, std::string merge_id, - std::string continue_id, std::string body_id) { - std::string result; - result += block_id + " = OpLabel\n"; - result += "OpLoopMerge " + merge_id + " " + continue_id + " None\n"; - result += "OpBranch " + body_id + "\n"; - return result; -} - -std::string GetSelectionMergeBlock(std::string block_id, - std::string condition_id, - std::string merge_id, std::string true_id, - std::string false_id) { - std::string result; - result += block_id + " = OpLabel\n"; - result += condition_id + " = OpSLessThan %bool %uint_1 %uint_2\n"; - result += "OpSelectionMerge " + merge_id + " None\n"; - result += "OpBranchConditional " + condition_id + " " + true_id + " " + - false_id + "\n"; - - return result; -} - -std::string GetReturnBlock(std::string block_id) { - std::string result; - result += block_id + " = OpLabel\n"; - result += "OpReturn\n"; - return result; -} - -std::string GetUnreachableBlock(std::string block_id) { - std::string result; - result += block_id + " = OpLabel\n"; - result += "OpUnreachable\n"; - return result; -} - -std::string GetBranchBlock(std::string block_id, std::string target_id) { - std::string result; - result += block_id + " = OpLabel\n"; - result += "OpBranch " + target_id + "\n"; - return result; -} - -TEST_F(SplitInvalidUnreachableTest, NoInvalidBlocks) { - std::string input = spirv_header + function_head; - input += GetLoopMergeBlock("%9", "%10", "%11", "%12"); - input += GetSelectionMergeBlock("%12", "%13", "%14", "%15", "%16"); - input += GetReturnBlock("%15"); - input += GetReturnBlock("%16"); - input += GetUnreachableBlock("%10"); - input += GetBranchBlock("%11", "%9"); - input += GetUnreachableBlock("%14"); - input += function_tail; - - SinglePassRunAndCheck(input, input, - /* skip_nop = */ false); -} - -TEST_F(SplitInvalidUnreachableTest, SelectionInLoop) { - std::string input = spirv_header + function_head; - input += GetLoopMergeBlock("%9", "%10", "%11", "%12"); - input += GetSelectionMergeBlock("%12", "%13", "%11", "%15", "%16"); - input += GetReturnBlock("%15"); - input += GetReturnBlock("%16"); - input += GetUnreachableBlock("%10"); - input += GetBranchBlock("%11", "%9"); - input += function_tail; - - std::string expected = spirv_header + function_head; - expected += GetLoopMergeBlock("%9", "%10", "%11", "%12"); - expected += GetSelectionMergeBlock("%12", "%13", "%16", "%14", "%15"); - expected += GetReturnBlock("%14"); - expected += GetReturnBlock("%15"); - expected += GetUnreachableBlock("%10"); - expected += GetUnreachableBlock("%16"); - expected += GetBranchBlock("%11", "%9"); - expected += function_tail; - - SinglePassRunAndCheck(input, expected, - /* skip_nop = */ false); -} - -TEST_F(SplitInvalidUnreachableTest, LoopInSelection) { - std::string input = spirv_header + function_head; - input += GetSelectionMergeBlock("%9", "%10", "%11", "%12", "%13"); - input += GetLoopMergeBlock("%12", "%14", "%11", "%15"); - input += GetReturnBlock("%13"); - input += GetUnreachableBlock("%14"); - input += GetBranchBlock("%11", "%12"); - input += GetReturnBlock("%15"); - input += function_tail; - - std::string expected = spirv_header + function_head; - expected += GetSelectionMergeBlock("%9", "%10", "%16", "%12", "%13"); - expected += GetLoopMergeBlock("%12", "%14", "%11", "%15"); - expected += GetReturnBlock("%13"); - expected += GetUnreachableBlock("%14"); - expected += GetUnreachableBlock("%16"); - expected += GetBranchBlock("%11", "%12"); - expected += GetReturnBlock("%15"); - expected += function_tail; - - SinglePassRunAndCheck(input, expected, - /* skip_nop = */ false); -} - -} // namespace -} // namespace opt -} // namespace spvtools diff --git a/test/opt/strip_atomic_counter_memory_test.cpp b/test/opt/strip_atomic_counter_memory_test.cpp deleted file mode 100644 index 90daa59c..00000000 --- a/test/opt/strip_atomic_counter_memory_test.cpp +++ /dev/null @@ -1,406 +0,0 @@ -// Copyright (c) 2019 Google LLC. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include "test/opt/pass_fixture.h" -#include "test/opt/pass_utils.h" - -namespace spvtools { -namespace opt { -namespace { - -typedef std::tuple StripAtomicCounterMemoryParam; - -using MemorySemanticsModified = - PassTest<::testing::TestWithParam>; -using NonMemorySemanticsUnmodifiedTest = PassTest<::testing::Test>; - -void operator+=(std::vector& lhs, const char* rhs) { - lhs.push_back(rhs); -} - -std::string GetConstDecl(std::string val) { - std::string decl; - decl += "%uint_" + val + " = OpConstant %uint " + val; - return decl; -} - -std::string GetUnchangedString(std::string(generate_inst)(std::string), - std::string val) { - std::string decl = GetConstDecl(val); - std::string inst = generate_inst(val); - - std::vector result = { - // clang-format off - "OpCapability Shader", - "OpCapability VulkanMemoryModel", - "OpExtension \"SPV_KHR_vulkan_memory_model\"", - "OpMemoryModel Logical Vulkan", - "OpEntryPoint Vertex %1 \"shader\"", - "%uint = OpTypeInt 32 0", -"%_ptr_Workgroup_uint = OpTypePointer Workgroup %uint", - "%4 = OpVariable %_ptr_Workgroup_uint Workgroup", - "%uint_0 = OpConstant %uint 0", - "%uint_1 = OpConstant %uint 1", - "%void = OpTypeVoid", - "%8 = OpTypeFunction %void", - decl.c_str(), - "%1 = OpFunction %void None %8", - "%10 = OpLabel", - inst.c_str(), - "OpReturn", - "OpFunctionEnd" - // clang-format on - }; - return JoinAllInsts(result); -} - -std::string GetChangedString(std::string(generate_inst)(std::string), - std::string orig, std::string changed) { - std::string orig_decl = GetConstDecl(orig); - std::string changed_decl = GetConstDecl(changed); - std::string inst = generate_inst(changed); - - std::vector result = { - // clang-format off - "OpCapability Shader", - "OpCapability VulkanMemoryModel", - "OpExtension \"SPV_KHR_vulkan_memory_model\"", - "OpMemoryModel Logical Vulkan", - "OpEntryPoint Vertex %1 \"shader\"", - "%uint = OpTypeInt 32 0", -"%_ptr_Workgroup_uint = OpTypePointer Workgroup %uint", - "%4 = OpVariable %_ptr_Workgroup_uint Workgroup", - "%uint_0 = OpConstant %uint 0", - "%uint_1 = OpConstant %uint 1", - "%void = OpTypeVoid", - "%8 = OpTypeFunction %void", - orig_decl.c_str() }; - // clang-format on - if (changed != "0") result += changed_decl.c_str(); - result += "%1 = OpFunction %void None %8"; - result += "%10 = OpLabel"; - result += inst.c_str(); - result += "OpReturn"; - result += "OpFunctionEnd"; - return JoinAllInsts(result); -} - -std::tuple GetInputAndExpected( - std::string(generate_inst)(std::string), - StripAtomicCounterMemoryParam param) { - std::string orig = std::get<0>(param); - std::string changed = std::get<1>(param); - std::string input = GetUnchangedString(generate_inst, orig); - std::string expected = orig == changed - ? GetUnchangedString(generate_inst, changed) - : GetChangedString(generate_inst, orig, changed); - return std::make_tuple(input, expected); -} - -std::string GetOpControlBarrierInst(std::string val) { - return "OpControlBarrier %uint_1 %uint_1 %uint_" + val; -} - -TEST_P(MemorySemanticsModified, OpControlBarrier) { - std::string input, expected; - std::tie(input, expected) = - GetInputAndExpected(GetOpControlBarrierInst, GetParam()); - SinglePassRunAndCheck(input, expected, - /* skip_nop = */ false); -} - -std::string GetOpMemoryBarrierInst(std::string val) { - return "OpMemoryBarrier %uint_1 %uint_" + val; -} - -TEST_P(MemorySemanticsModified, OpMemoryBarrier) { - std::string input, expected; - std::tie(input, expected) = - GetInputAndExpected(GetOpMemoryBarrierInst, GetParam()); - SinglePassRunAndCheck(input, expected, - /* skip_nop = */ false); -} - -std::string GetOpAtomicLoadInst(std::string val) { - return "%11 = OpAtomicLoad %uint %4 %uint_1 %uint_" + val; -} - -TEST_P(MemorySemanticsModified, OpAtomicLoad) { - std::string input, expected; - std::tie(input, expected) = - GetInputAndExpected(GetOpAtomicLoadInst, GetParam()); - SinglePassRunAndCheck(input, expected, - /* skip_nop = */ false); -} - -std::string GetOpAtomicStoreInst(std::string val) { - return "OpAtomicStore %4 %uint_1 %uint_" + val + " %uint_1"; -} - -TEST_P(MemorySemanticsModified, OpAtomicStore) { - std::string input, expected; - std::tie(input, expected) = - GetInputAndExpected(GetOpAtomicStoreInst, GetParam()); - SinglePassRunAndCheck(input, expected, - /* skip_nop = */ false); -} - -std::string GetOpAtomicExchangeInst(std::string val) { - return "%11 = OpAtomicExchange %uint %4 %uint_1 %uint_" + val + " %uint_0"; -} - -TEST_P(MemorySemanticsModified, OpAtomicExchange) { - std::string input, expected; - std::tie(input, expected) = - GetInputAndExpected(GetOpAtomicExchangeInst, GetParam()); - SinglePassRunAndCheck(input, expected, - /* skip_nop = */ false); -} - -std::string GetOpAtomicCompareExchangeInst(std::string val) { - return "%11 = OpAtomicCompareExchange %uint %4 %uint_1 %uint_" + val + - " %uint_" + val + " %uint_0 %uint_0"; -} - -TEST_P(MemorySemanticsModified, OpAtomicCompareExchange) { - std::string input, expected; - std::tie(input, expected) = - GetInputAndExpected(GetOpAtomicCompareExchangeInst, GetParam()); - SinglePassRunAndCheck(input, expected, - /* skip_nop = */ false); -} - -std::string GetOpAtomicCompareExchangeWeakInst(std::string val) { - return "%11 = OpAtomicCompareExchangeWeak %uint %4 %uint_1 %uint_" + val + - " %uint_" + val + " %uint_0 %uint_0"; -} - -TEST_P(MemorySemanticsModified, OpAtomicCompareExchangeWeak) { - std::string input, expected; - std::tie(input, expected) = - GetInputAndExpected(GetOpAtomicCompareExchangeWeakInst, GetParam()); - SinglePassRunAndCheck(input, expected, - /* skip_nop = */ false); -} - -std::string GetOpAtomicIIncrementInst(std::string val) { - return "%11 = OpAtomicIIncrement %uint %4 %uint_1 %uint_" + val; -} - -TEST_P(MemorySemanticsModified, OpAtomicIIncrement) { - std::string input, expected; - std::tie(input, expected) = - GetInputAndExpected(GetOpAtomicIIncrementInst, GetParam()); - SinglePassRunAndCheck(input, expected, - /* skip_nop = */ false); -} - -std::string GetOpAtomicIDecrementInst(std::string val) { - return "%11 = OpAtomicIDecrement %uint %4 %uint_1 %uint_" + val; -} - -TEST_P(MemorySemanticsModified, OpAtomicIDecrement) { - std::string input, expected; - std::tie(input, expected) = - GetInputAndExpected(GetOpAtomicIDecrementInst, GetParam()); - SinglePassRunAndCheck(input, expected, - /* skip_nop = */ false); -} - -std::string GetOpAtomicIAddInst(std::string val) { - return "%11 = OpAtomicIAdd %uint %4 %uint_1 %uint_" + val + " %uint_1"; -} - -TEST_P(MemorySemanticsModified, OpAtomicIAdd) { - std::string input, expected; - std::tie(input, expected) = - GetInputAndExpected(GetOpAtomicIAddInst, GetParam()); - SinglePassRunAndCheck(input, expected, - /* skip_nop = */ false); -} - -std::string GetOpAtomicISubInst(std::string val) { - return "%11 = OpAtomicISub %uint %4 %uint_1 %uint_" + val + " %uint_1"; -} - -TEST_P(MemorySemanticsModified, OpAtomicISub) { - std::string input, expected; - std::tie(input, expected) = - GetInputAndExpected(GetOpAtomicISubInst, GetParam()); - SinglePassRunAndCheck(input, expected, - /* skip_nop = */ false); -} - -std::string GetOpAtomicSMinInst(std::string val) { - return "%11 = OpAtomicSMin %uint %4 %uint_1 %uint_" + val + " %uint_1"; -} - -TEST_P(MemorySemanticsModified, OpAtomicSMin) { - std::string input, expected; - std::tie(input, expected) = - GetInputAndExpected(GetOpAtomicSMinInst, GetParam()); - SinglePassRunAndCheck(input, expected, - /* skip_nop = */ false); -} - -std::string GetOpAtomicUMinInst(std::string val) { - return "%11 = OpAtomicUMin %uint %4 %uint_1 %uint_" + val + " %uint_1"; -} - -TEST_P(MemorySemanticsModified, OpAtomicUMin) { - std::string input, expected; - std::tie(input, expected) = - GetInputAndExpected(GetOpAtomicUMinInst, GetParam()); - SinglePassRunAndCheck(input, expected, - /* skip_nop = */ false); -} - -std::string GetOpAtomicSMaxInst(std::string val) { - return "%11 = OpAtomicSMax %uint %4 %uint_1 %uint_" + val + " %uint_1"; -} - -TEST_P(MemorySemanticsModified, OpAtomicSMax) { - std::string input, expected; - std::tie(input, expected) = - GetInputAndExpected(GetOpAtomicSMaxInst, GetParam()); - SinglePassRunAndCheck(input, expected, - /* skip_nop = */ false); -} - -std::string GetOpAtomicUMaxInst(std::string val) { - return "%11 = OpAtomicUMax %uint %4 %uint_1 %uint_" + val + " %uint_1"; -} - -TEST_P(MemorySemanticsModified, OpAtomicUMax) { - std::string input, expected; - std::tie(input, expected) = - GetInputAndExpected(GetOpAtomicUMaxInst, GetParam()); - SinglePassRunAndCheck(input, expected, - /* skip_nop = */ false); -} - -std::string GetOpAtomicAndInst(std::string val) { - return "%11 = OpAtomicAnd %uint %4 %uint_1 %uint_" + val + " %uint_1"; -} - -TEST_P(MemorySemanticsModified, OpAtomicAnd) { - std::string input, expected; - std::tie(input, expected) = - GetInputAndExpected(GetOpAtomicAndInst, GetParam()); - SinglePassRunAndCheck(input, expected, - /* skip_nop = */ false); -} - -std::string GetOpAtomicOrInst(std::string val) { - return "%11 = OpAtomicOr %uint %4 %uint_1 %uint_" + val + " %uint_1"; -} - -TEST_P(MemorySemanticsModified, OpAtomicOr) { - std::string input, expected; - std::tie(input, expected) = - GetInputAndExpected(GetOpAtomicOrInst, GetParam()); - SinglePassRunAndCheck(input, expected, - /* skip_nop = */ false); -} - -std::string GetOpAtomicXorInst(std::string val) { - return "%11 = OpAtomicXor %uint %4 %uint_1 %uint_" + val + " %uint_1"; -} - -TEST_P(MemorySemanticsModified, OpAtomicXor) { - std::string input, expected; - std::tie(input, expected) = - GetInputAndExpected(GetOpAtomicXorInst, GetParam()); - SinglePassRunAndCheck(input, expected, - /* skip_nop = */ false); -} - -std::string GetOpAtomicFlagTestAndSetInst(std::string val) { - return "%11 = OpAtomicFlagTestAndSet %uint %4 %uint_1 %uint_" + val; -} - -TEST_P(MemorySemanticsModified, OpAtomicFlagTestAndSet) { - std::string input, expected; - std::tie(input, expected) = - GetInputAndExpected(GetOpAtomicFlagTestAndSetInst, GetParam()); - SinglePassRunAndCheck(input, expected, - /* skip_nop = */ false); -} - -std::string GetOpAtomicFlagClearInst(std::string val) { - return "OpAtomicFlagClear %4 %uint_1 %uint_" + val; -} - -TEST_P(MemorySemanticsModified, OpAtomicFlagClear) { - std::string input, expected; - std::tie(input, expected) = - GetInputAndExpected(GetOpAtomicFlagClearInst, GetParam()); - SinglePassRunAndCheck(input, expected, - /* skip_nop = */ false); -} - -std::string GetOpMemoryNamedBarrierInst(std::string val) { - return "OpMemoryNamedBarrier %4 %uint_1 %uint_" + val; -} - -TEST_P(MemorySemanticsModified, OpMemoryNamedBarrier) { - std::string input, expected; - std::tie(input, expected) = - GetInputAndExpected(GetOpMemoryNamedBarrierInst, GetParam()); - SinglePassRunAndCheck(input, expected, - /* skip_nop = */ false); -} - -// clang-format off -INSTANTIATE_TEST_SUITE_P( - StripAtomicCounterMemoryTest, MemorySemanticsModified, - ::testing::ValuesIn(std::vector({ - std::make_tuple("1024", "0"), - std::make_tuple("5", "5"), - std::make_tuple("1288", "264"), - std::make_tuple("264", "264") - }))); -// clang-format on - -std::string GetNoMemorySemanticsPresentInst(std::string val) { - return "%11 = OpVariable %_ptr_Workgroup_uint Workgroup %uint_" + val; -} - -TEST_F(NonMemorySemanticsUnmodifiedTest, NoMemorySemanticsPresent) { - std::string input, expected; - StripAtomicCounterMemoryParam param = std::make_tuple("1288", "1288"); - std::tie(input, expected) = - GetInputAndExpected(GetNoMemorySemanticsPresentInst, param); - SinglePassRunAndCheck(input, expected, - /* skip_nop = */ false); -} - -std::string GetMemorySemanticsPresentInst(std::string val) { - return "%11 = OpAtomicIAdd %uint %4 %uint_1 %uint_" + val + " %uint_1288"; -} - -TEST_F(NonMemorySemanticsUnmodifiedTest, MemorySemanticsPresent) { - std::string input, expected; - StripAtomicCounterMemoryParam param = std::make_tuple("1288", "264"); - std::tie(input, expected) = - GetInputAndExpected(GetMemorySemanticsPresentInst, param); - SinglePassRunAndCheck(input, expected, - /* skip_nop = */ false); -} - -} // namespace -} // namespace opt -} // namespace spvtools diff --git a/test/target_env_test.cpp b/test/target_env_test.cpp index 9c86e2da..4acb8ff2 100644 --- a/test/target_env_test.cpp +++ b/test/target_env_test.cpp @@ -95,7 +95,6 @@ INSTANTIATE_TEST_SUITE_P( {"opencl2.0embedded", true, SPV_ENV_OPENCL_EMBEDDED_2_0}, {"opencl2.1embedded", true, SPV_ENV_OPENCL_EMBEDDED_2_1}, {"opencl2.2embedded", true, SPV_ENV_OPENCL_EMBEDDED_2_2}, - {"webgpu0", true, SPV_ENV_WEBGPU_0}, {"opencl2.3", false, SPV_ENV_UNIVERSAL_1_0}, {"opencl3.0", false, SPV_ENV_UNIVERSAL_1_0}, {"vulkan1.9", false, SPV_ENV_UNIVERSAL_1_0}, diff --git a/test/tools/opt/flags.py b/test/tools/opt/flags.py index f8117d9d..c79f6807 100644 --- a/test/tools/opt/flags.py +++ b/test/tools/opt/flags.py @@ -73,10 +73,7 @@ class TestValidPassFlags(expect.ValidObjectFile1_5, '--remove-duplicates', '--replace-invalid-opcode', '--ssa-rewrite', '--scalar-replacement', '--scalar-replacement=42', '--strength-reduction', '--strip-debug', '--strip-reflect', '--vector-dce', '--workaround-1209', - '--unify-const', '--legalize-vector-shuffle', - '--split-invalid-unreachable', '--generate-webgpu-initializers', - '--decompose-initialized-variables', '--graphics-robust-access', - '--wrap-opkill', '--amd-ext-to-khr' + '--unify-const', '--graphics-robust-access', '--wrap-opkill', '--amd-ext-to-khr' ] expected_passes = [ 'wrap-opkill', @@ -124,10 +121,6 @@ class TestValidPassFlags(expect.ValidObjectFile1_5, 'vector-dce', 'workaround-1209', 'unify-const', - 'legalize-vector-shuffle', - 'split-invalid-unreachable', - 'generate-webgpu-initializers', - 'decompose-initialized-variables', 'graphics-robust-access', 'wrap-opkill', 'amd-ext-to-khr' @@ -362,45 +355,3 @@ class TestLoopPeelingThresholdArgsInvalidNumber(expect.ErrorMessageSubstr): spirv_args = ['--loop-peeling-threshold=a10f'] expected_error_substr = 'must have a positive integer argument' - -@inside_spirv_testsuite('SpirvOptFlags') -class TestWebGPUToVulkanThenVulkanToWebGPUIsInvalid(expect.ReturnCodeIsNonZero, expect.ErrorMessageSubstr): - """Tests Vulkan->WebGPU flag cannot be used after WebGPU->Vulkan flag.""" - - spirv_args = ['--webgpu-to-vulkan', '--vulkan-to-webgpu'] - expected_error_substr = 'Cannot use both' - -@inside_spirv_testsuite('SpirvOptFlags') -class TestVulkanToWebGPUThenWebGPUToVulkanIsInvalid(expect.ReturnCodeIsNonZero, expect.ErrorMessageSubstr): - """Tests WebGPU->Vulkan flag cannot be used after Vulkan->WebGPU flag.""" - - spirv_args = ['--vulkan-to-webgpu', '--webgpu-to-vulkan'] - expected_error_substr = 'Cannot use both' - -@inside_spirv_testsuite('SpirvOptFlags') -class TestTargetEnvThenVulkanToWebGPUIsInvalid(expect.ReturnCodeIsNonZero, expect.ErrorMessageSubstr): - """Tests Vulkan->WebGPU flag cannot be used after target env flag.""" - - spirv_args = ['--target-env=opengl4.0', '--vulkan-to-webgpu'] - expected_error_substr = 'defines the target environment' - -@inside_spirv_testsuite('SpirvOptFlags') -class TestVulkanToWebGPUThenTargetEnvIsInvalid(expect.ReturnCodeIsNonZero, expect.ErrorMessageSubstr): - """Tests target env flag cannot be used after Vulkan->WebGPU flag.""" - - spirv_args = ['--vulkan-to-webgpu', '--target-env=opengl4.0'] - expected_error_substr = 'defines the target environment' - -@inside_spirv_testsuite('SpirvOptFlags') -class TestTargetEnvThenWebGPUToVulkanIsInvalid(expect.ReturnCodeIsNonZero, expect.ErrorMessageSubstr): - """Tests WebGPU->Vulkan flag cannot be used after target env flag.""" - - spirv_args = ['--target-env=opengl4.0', '--webgpu-to-vulkan'] - expected_error_substr = 'defines the target environment' - -@inside_spirv_testsuite('SpirvOptFlags') -class TestWebGPUToVulkanThenTargetEnvIsInvalid(expect.ReturnCodeIsNonZero, expect.ErrorMessageSubstr): - """Tests target env flag cannot be used after WebGPU->Vulkan flag.""" - - spirv_args = ['--webgpu-to-vulkan', '--target-env=opengl4.0'] - expected_error_substr = 'defines the target environment' diff --git a/test/unit_spirv.h b/test/unit_spirv.h index 32646620..f0a2958d 100644 --- a/test/unit_spirv.h +++ b/test/unit_spirv.h @@ -195,7 +195,7 @@ inline std::vector AllTargetEnvironments() { SPV_ENV_OPENGL_4_1, SPV_ENV_OPENGL_4_2, SPV_ENV_OPENGL_4_3, SPV_ENV_OPENGL_4_5, SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_3, - SPV_ENV_VULKAN_1_1, SPV_ENV_WEBGPU_0, + SPV_ENV_VULKAN_1_1, }; } diff --git a/test/val/CMakeLists.txt b/test/val/CMakeLists.txt index 153a9167..b17d1cb1 100644 --- a/test/val/CMakeLists.txt +++ b/test/val/CMakeLists.txt @@ -89,7 +89,6 @@ add_spvtools_unittest(TARGET val_stuvw val_type_unique_test.cpp val_validation_state_test.cpp val_version_test.cpp - val_webgpu_test.cpp ${VAL_TEST_COMMON_SRCS} LIBS ${SPIRV_TOOLS_FULL_VISIBILITY} PCH_FILE pch_test_val diff --git a/test/val/val_atomics_test.cpp b/test/val/val_atomics_test.cpp index b7735fc2..8a79e456 100644 --- a/test/val/val_atomics_test.cpp +++ b/test/val/val_atomics_test.cpp @@ -113,23 +113,6 @@ std::string GenerateShaderCode( memory_model); } -std::string GenerateWebGPUShaderCode( - const std::string& body, - const std::string& capabilities_and_extensions = "") { - const std::string vulkan_memory_capability = R"( -OpCapability VulkanMemoryModelDeviceScopeKHR -OpCapability VulkanMemoryModelKHR -)"; - const std::string vulkan_memory_extension = R"( -OpExtension "SPV_KHR_vulkan_memory_model" -)"; - return GenerateShaderCodeImpl(body, - vulkan_memory_capability + - capabilities_and_extensions + - vulkan_memory_extension, - "", "VulkanKHR"); -} - std::string GenerateKernelCode( const std::string& body, const std::string& capabilities_and_extensions = "") { @@ -518,39 +501,6 @@ TEST_F(ValidateAtomics, AtomicLoadVulkanInt64) { "AtomicLoad: 64-bit atomics require the Int64Atomics capability")); } -TEST_F(ValidateAtomics, AtomicLoadWebGPUSuccess) { - const std::string body = R"( -%val1 = OpAtomicLoad %u32 %u32_var %queuefamily %relaxed -)"; - - CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); -} - -TEST_F(ValidateAtomics, AtomicLoadWebGPUNonQueueFamilyFailure) { - const std::string body = R"( -%val3 = OpAtomicLoad %u32 %u32_var %invocation %relaxed -)"; - - CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Memory Scope is limited to QueueFamilyKHR for " - "OpAtomic* operations")); -} - -TEST_F(ValidateAtomics, AtomicLoadWebGPUNonRelaxedFailure) { - const std::string body = R"( -%val1 = OpAtomicLoad %u32 %u32_var %queuefamily %acquire -)"; - - CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("no bits may be set for Memory Semantics of OpAtomic* " - "instructions")); -} - TEST_F(ValidateAtomics, VK_KHR_shader_atomic_int64Success) { const std::string body = R"( %val1 = OpAtomicUMin %u64 %u64_var %device %relaxed %u64_1 @@ -727,38 +677,6 @@ OpAtomicStore %u32_var %device %sequentially_consistent %u32_1 "Acquire, AcquireRelease and SequentiallyConsistent")); } -TEST_F(ValidateAtomics, AtomicStoreWebGPUSuccess) { - const std::string body = R"( -OpAtomicStore %u32_var %queuefamily %relaxed %u32_1 -)"; - - CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); -} -TEST_F(ValidateAtomics, AtomicStoreWebGPUNonQueueFamilyFailure) { - const std::string body = R"( -OpAtomicStore %u32_var %workgroup %relaxed %u32_1 -)"; - - CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Memory Scope is limited to QueueFamilyKHR for " - "OpAtomic* operations")); -} - -TEST_F(ValidateAtomics, AtomicStoreWebGPUNonRelaxedFailure) { - const std::string body = R"( -OpAtomicStore %u32_var %queuefamily %release %u32_1 -)"; - - CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("no bits may be set for Memory Semantics of OpAtomic* " - "instructions")); -} - TEST_F(ValidateAtomics, AtomicStoreWrongPointerType) { const std::string body = R"( OpAtomicStore %f32_1 %device %relaxed %f32_1 @@ -2049,75 +1967,6 @@ OpExtension "SPV_KHR_vulkan_memory_model" EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); } -TEST_F(ValidateAtomics, WebGPUCrossDeviceMemoryScopeBad) { - const std::string body = R"( -%val1 = OpAtomicLoad %u32 %u32_var %cross_device %relaxed -)"; - - CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); - EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("in WebGPU environment Memory Scope is limited to " - "QueueFamilyKHR for OpAtomic* operations")); -} - -TEST_F(ValidateAtomics, WebGPUDeviceMemoryScopeBad) { - const std::string body = R"( -%val1 = OpAtomicLoad %u32 %u32_var %device %relaxed -)"; - - CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); - EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("in WebGPU environment Memory Scope is limited to " - "QueueFamilyKHR for OpAtomic* operations")); -} - -TEST_F(ValidateAtomics, WebGPUWorkgroupMemoryScopeBad) { - const std::string body = R"( -%val1 = OpAtomicLoad %u32 %u32_var %workgroup %relaxed -)"; - - CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); - EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("in WebGPU environment Memory Scope is limited to " - "QueueFamilyKHR for OpAtomic* operations")); -} - -TEST_F(ValidateAtomics, WebGPUSubgroupMemoryScopeBad) { - const std::string body = R"( -%val1 = OpAtomicLoad %u32 %u32_var %subgroup %relaxed -)"; - - CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); - EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("in WebGPU environment Memory Scope is limited to " - "QueueFamilyKHR for OpAtomic* operations")); -} - -TEST_F(ValidateAtomics, WebGPUInvocationMemoryScopeBad) { - const std::string body = R"( -%val1 = OpAtomicLoad %u32 %u32_var %invocation %relaxed -)"; - - CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); - EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("in WebGPU environment Memory Scope is limited to " - "QueueFamilyKHR for OpAtomic* operations")); -} - -TEST_F(ValidateAtomics, WebGPUQueueFamilyMemoryScopeGood) { - const std::string body = R"( -%val1 = OpAtomicLoad %u32 %u32_var %queuefamily %relaxed -)"; - - CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); - EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); -} - TEST_F(ValidateAtomics, CompareExchangeWeakV13ValV14Good) { const std::string body = R"( %val1 = OpAtomicCompareExchangeWeak %u32 %u32_var %device %relaxed %relaxed %u32_0 %u32_0 diff --git a/test/val/val_barriers_test.cpp b/test/val/val_barriers_test.cpp index d7ddb46b..579ec69d 100644 --- a/test/val/val_barriers_test.cpp +++ b/test/val/val_barriers_test.cpp @@ -121,42 +121,6 @@ OpCapability Int64 execution_model, memory_model); } -std::string GenerateWebGPUComputeShaderCode( - const std::string& body, - const std::string& capabilities_and_extensions = "", - const std::string& execution_model = "GLCompute") { - const std::string vulkan_memory_capability = R"( -OpCapability VulkanMemoryModelKHR -)"; - const std::string vulkan_memory_extension = R"( -OpExtension "SPV_KHR_vulkan_memory_model" -)"; - const std::string memory_model = "OpMemoryModel Logical VulkanKHR"; - return GenerateShaderCodeImpl(body, - vulkan_memory_capability + - capabilities_and_extensions + - vulkan_memory_extension, - "", execution_model, memory_model); -} - -std::string GenerateWebGPUVertexShaderCode( - const std::string& body, - const std::string& capabilities_and_extensions = "", - const std::string& execution_model = "Vertex") { - const std::string vulkan_memory_capability = R"( -OpCapability VulkanMemoryModelKHR -)"; - const std::string vulkan_memory_extension = R"( -OpExtension "SPV_KHR_vulkan_memory_model" -)"; - const std::string memory_model = "OpMemoryModel Logical VulkanKHR"; - return GenerateShaderCodeImpl(body, - vulkan_memory_capability + - capabilities_and_extensions + - vulkan_memory_extension, - "", execution_model, memory_model); -} - std::string GenerateKernelCode( const std::string& body, const std::string& capabilities_and_extensions = "") { @@ -271,64 +235,6 @@ OpControlBarrier %workgroup %workgroup %acquire_release_uniform_workgroup ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0)); } -TEST_F(ValidateBarriers, OpControlBarrierWebGPUAcquireReleaseSuccess) { - const std::string body = R"( -OpControlBarrier %workgroup %workgroup %acquire_release_workgroup -)"; - - CompileSuccessfully(GenerateWebGPUComputeShaderCode(body), SPV_ENV_WEBGPU_0); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); -} - -TEST_F(ValidateBarriers, OpControlBarrierWebGPURelaxedFailure) { - const std::string body = R"( -OpControlBarrier %workgroup %workgroup %workgroup -)"; - - CompileSuccessfully(GenerateWebGPUComputeShaderCode(body), SPV_ENV_WEBGPU_0); - EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("For WebGPU, AcquireRelease must be set for Memory " - "Semantics of OpControlBarrier")); -} - -TEST_F(ValidateBarriers, OpControlBarrierWebGPUMissingWorkgroupFailure) { - const std::string body = R"( -OpControlBarrier %workgroup %workgroup %acquire_release -)"; - - CompileSuccessfully(GenerateWebGPUComputeShaderCode(body), SPV_ENV_WEBGPU_0); - EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("For WebGPU, WorkgroupMemory must be set for Memory " - "Semantics")); -} - -TEST_F(ValidateBarriers, OpControlBarrierWebGPUUniformFailure) { - const std::string body = R"( -OpControlBarrier %workgroup %workgroup %acquire_release_uniform_workgroup -)"; - - CompileSuccessfully(GenerateWebGPUComputeShaderCode(body), SPV_ENV_WEBGPU_0); - EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("For WebGPU only WorkgroupMemory and AcquireRelease may be set " - "for Memory Semantics of OpControlBarrier.")); -} - -TEST_F(ValidateBarriers, OpControlBarrierWebGPUReleaseFailure) { - const std::string body = R"( -OpControlBarrier %workgroup %workgroup %release_uniform_workgroup -)"; - - CompileSuccessfully(GenerateWebGPUComputeShaderCode(body), SPV_ENV_WEBGPU_0); - EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("For WebGPU, AcquireRelease must be set for Memory " - "Semantics of OpControlBarrier")); -} - TEST_F(ValidateBarriers, OpControlBarrierExecutionModelFragmentSpirv12) { const std::string body = R"( OpControlBarrier %device %device %none @@ -435,44 +341,6 @@ OpControlBarrier %device %workgroup %none "is limited to Workgroup and Subgroup")); } -TEST_F(ValidateBarriers, OpControlBarrierWebGPUExecutionScopeDeviceBad) { - const std::string body = R"( -OpControlBarrier %device %workgroup %none -)"; - - CompileSuccessfully(GenerateWebGPUComputeShaderCode(body), SPV_ENV_WEBGPU_0); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("ControlBarrier: in WebGPU environment Execution Scope " - "is limited to Workgroup")); -} - -TEST_F(ValidateBarriers, OpControlBarrierWebGPUExecutionScopeSubgroupBad) { - const std::string body = R"( -OpControlBarrier %subgroup %workgroup %none -)"; - - CompileSuccessfully(GenerateWebGPUComputeShaderCode(body), SPV_ENV_WEBGPU_0); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("ControlBarrier: in WebGPU environment Execution Scope " - "is limited to Workgroup")); -} - -TEST_F(ValidateBarriers, - OpControlBarrierWebGPUExecutionScopeWorkgroupNonComputeBad) { - const std::string body = R"( -OpControlBarrier %workgroup %workgroup %acquire_release_workgroup -)"; - - CompileSuccessfully(GenerateWebGPUVertexShaderCode(body), SPV_ENV_WEBGPU_0); - ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr( - "Workgroup Execution Scope is limited to GLCompute execution model")); -} - TEST_F(ValidateBarriers, OpControlBarrierVulkanMemoryScopeSubgroup) { const std::string body = R"( OpControlBarrier %subgroup %subgroup %none @@ -507,18 +375,6 @@ OpControlBarrier %subgroup %cross_device %none "cannot be CrossDevice")); } -TEST_F(ValidateBarriers, OpControlBarrierWebGPUMemoryScopeNonWorkgroup) { - const std::string body = R"( -OpControlBarrier %workgroup %subgroup %acquire_release_workgroup -)"; - - CompileSuccessfully(GenerateWebGPUComputeShaderCode(body), SPV_ENV_WEBGPU_0); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("ControlBarrier: in WebGPU environment Memory Scope is " - "limited to Workgroup for OpControlBarrier")); -} - TEST_F(ValidateBarriers, OpControlBarrierAcquireAndRelease) { const std::string body = R"( OpControlBarrier %device %device %acquire_and_release_uniform @@ -738,100 +594,6 @@ OpMemoryBarrier %workgroup %acquire_release_uniform_workgroup ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0)); } -TEST_F(ValidateBarriers, OpMemoryBarrierWebGPUImageMemorySuccess) { - const std::string body = R"( -OpMemoryBarrier %workgroup %image_memory -)"; - - CompileSuccessfully(GenerateWebGPUComputeShaderCode(body), SPV_ENV_WEBGPU_0); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); -} - -TEST_F(ValidateBarriers, OpMemoryBarrierWebGPUDeviceFailure) { - const std::string body = R"( -OpMemoryBarrier %subgroup %image_memory -)"; - - CompileSuccessfully(GenerateWebGPUComputeShaderCode(body), SPV_ENV_WEBGPU_0); - EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("in WebGPU environment Memory Scope is limited to " - "Workgroup for OpMemoryBarrier")); -} - -TEST_F(ValidateBarriers, OpMemoryBarrierWebGPUAcquireReleaseFailure) { - const std::string body = R"( -OpMemoryBarrier %workgroup %acquire_release_uniform_workgroup -)"; - - CompileSuccessfully(GenerateWebGPUComputeShaderCode(body), SPV_ENV_WEBGPU_0); - EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("ImageMemory must be set for Memory Semantics of " - "OpMemoryBarrier")); -} - -TEST_F(ValidateBarriers, OpMemoryBarrierWebGPURelaxedFailure) { - const std::string body = R"( -OpMemoryBarrier %workgroup %uniform_workgroup -)"; - - CompileSuccessfully(GenerateWebGPUComputeShaderCode(body), SPV_ENV_WEBGPU_0); - EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("ImageMemory must be set for Memory Semantics of " - "OpMemoryBarrier")); -} - -TEST_F(ValidateBarriers, OpMemoryBarrierWebGPUAcquireFailure) { - const std::string body = R"( -OpMemoryBarrier %workgroup %acquire_uniform_workgroup -)"; - - CompileSuccessfully(GenerateWebGPUComputeShaderCode(body), SPV_ENV_WEBGPU_0); - EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("ImageMemory must be set for Memory Semantics of " - "OpMemoryBarrier")); -} - -TEST_F(ValidateBarriers, OpMemoryBarrierWebGPUReleaseFailure) { - const std::string body = R"( -OpMemoryBarrier %workgroup %release_uniform_workgroup -)"; - - CompileSuccessfully(GenerateWebGPUComputeShaderCode(body), SPV_ENV_WEBGPU_0); - EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("ImageMemory must be set for Memory Semantics of " - "OpMemoryBarrier")); -} - -TEST_F(ValidateBarriers, OpMemoryBarrierWebGPUUniformFailure) { - const std::string body = R"( -OpMemoryBarrier %workgroup %uniform_image_memory -)"; - - CompileSuccessfully(GenerateWebGPUComputeShaderCode(body), SPV_ENV_WEBGPU_0); - EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("only ImageMemory may be set for Memory Semantics of " - "OpMemoryBarrier")); -} - -TEST_F(ValidateBarriers, OpMemoryBarrierWebGPUWorkgroupNonComputeFailure) { - const std::string body = R"( -OpMemoryBarrier %workgroup %image_memory -)"; - - CompileSuccessfully(GenerateWebGPUVertexShaderCode(body), SPV_ENV_WEBGPU_0); - EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr( - "Workgroup Memory Scope is limited to GLCompute execution model")); -} - TEST_F(ValidateBarriers, OpMemoryBarrierFloatMemoryScope) { const std::string body = R"( OpMemoryBarrier %f32_1 %acquire_release_uniform_workgroup diff --git a/test/val/val_builtins_test.cpp b/test/val/val_builtins_test.cpp index 7d12aaca..66e73be6 100644 --- a/test/val/val_builtins_test.cpp +++ b/test/val/val_builtins_test.cpp @@ -60,13 +60,8 @@ using ValidateVulkanSubgroupBuiltIns = using ValidateVulkanCombineBuiltInExecutionModelDataTypeResult = spvtest::ValidateBase>; -using ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult = - spvtest::ValidateBase>; using ValidateVulkanCombineBuiltInArrayedVariable = spvtest::ValidateBase< std::tuple>; -using ValidateWebGPUCombineBuiltInArrayedVariable = spvtest::ValidateBase< - std::tuple>; using ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult = spvtest::ValidateBase< std::tuple>; -bool InitializerRequired(spv_target_env env, const char* const storage_class) { - return spvIsWebGPUEnv(env) && (strncmp(storage_class, "Output", 6) == 0 || - strncmp(storage_class, "Private", 7) == 0 || - strncmp(storage_class, "Function", 8) == 0); +bool InitializerRequired(const char* const storage_class) { + return (strncmp(storage_class, "Output", 6) == 0 || + strncmp(storage_class, "Private", 7) == 0 || + strncmp(storage_class, "Function", 8) == 0); } -CodeGenerator GetInMainCodeGenerator(spv_target_env env, - const char* const built_in, +CodeGenerator GetInMainCodeGenerator(const char* const built_in, const char* const execution_model, const char* const storage_class, const char* const capabilities, const char* const extensions, const char* const data_type) { - CodeGenerator generator = - spvIsWebGPUEnv(env) ? CodeGenerator::GetWebGPUShaderCodeGenerator() - : CodeGenerator::GetDefaultShaderCodeGenerator(); + CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator(); if (capabilities) { generator.capabilities_ += capabilities; @@ -108,13 +100,13 @@ CodeGenerator GetInMainCodeGenerator(spv_target_env env, std::ostringstream after_types; after_types << "%built_in_type = OpTypeStruct " << data_type << "\n"; - if (InitializerRequired(env, storage_class)) { + if (InitializerRequired(storage_class)) { after_types << "%built_in_null = OpConstantNull %built_in_type\n"; } after_types << "%built_in_ptr = OpTypePointer " << storage_class << " %built_in_type\n"; after_types << "%built_in_var = OpVariable %built_in_ptr " << storage_class; - if (InitializerRequired(env, storage_class)) { + if (InitializerRequired(storage_class)) { after_types << " %built_in_null"; } after_types << "\n"; @@ -167,9 +159,8 @@ TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, InMain) { const char* const vuid = std::get<4>(GetParam()); const TestResult& test_result = std::get<5>(GetParam()); - CodeGenerator generator = - GetInMainCodeGenerator(SPV_ENV_VULKAN_1_0, built_in, execution_model, - storage_class, NULL, NULL, data_type); + CodeGenerator generator = GetInMainCodeGenerator( + built_in, execution_model, storage_class, NULL, NULL, data_type); CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); ASSERT_EQ(test_result.validation_result, @@ -185,28 +176,6 @@ TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, InMain) { } } -TEST_P(ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, InMain) { - const char* const built_in = std::get<0>(GetParam()); - const char* const execution_model = std::get<1>(GetParam()); - const char* const storage_class = std::get<2>(GetParam()); - const char* const data_type = std::get<3>(GetParam()); - const TestResult& test_result = std::get<4>(GetParam()); - - CodeGenerator generator = - GetInMainCodeGenerator(SPV_ENV_WEBGPU_0, built_in, execution_model, - storage_class, NULL, NULL, data_type); - - CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0); - ASSERT_EQ(test_result.validation_result, - ValidateInstructions(SPV_ENV_WEBGPU_0)); - if (test_result.error_str) { - EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str)); - } - if (test_result.error_str2) { - EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str2)); - } -} - TEST_P( ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, InMain) { @@ -219,9 +188,9 @@ TEST_P( const char* const vuid = std::get<6>(GetParam()); const TestResult& test_result = std::get<7>(GetParam()); - CodeGenerator generator = GetInMainCodeGenerator( - SPV_ENV_VULKAN_1_0, built_in, execution_model, storage_class, - capabilities, extensions, data_type); + CodeGenerator generator = + GetInMainCodeGenerator(built_in, execution_model, storage_class, + capabilities, extensions, data_type); CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); ASSERT_EQ(test_result.validation_result, @@ -251,7 +220,7 @@ TEST_P( const TestResult& test_result = std::get<8>(GetParam()); CodeGenerator generator = - GetInMainCodeGenerator(env, built_in, execution_model, storage_class, + GetInMainCodeGenerator(built_in, execution_model, storage_class, capabilities, extensions, data_type); CompileSuccessfully(generator.Build(), env); @@ -267,16 +236,13 @@ TEST_P( } } -CodeGenerator GetInFunctionCodeGenerator(spv_target_env env, - const char* const built_in, +CodeGenerator GetInFunctionCodeGenerator(const char* const built_in, const char* const execution_model, const char* const storage_class, const char* const capabilities, const char* const extensions, const char* const data_type) { - CodeGenerator generator = - spvIsWebGPUEnv(env) ? CodeGenerator::GetWebGPUShaderCodeGenerator() - : CodeGenerator::GetDefaultShaderCodeGenerator(); + CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator(); if (capabilities) { generator.capabilities_ += capabilities; @@ -291,13 +257,13 @@ CodeGenerator GetInFunctionCodeGenerator(spv_target_env env, std::ostringstream after_types; after_types << "%built_in_type = OpTypeStruct " << data_type << "\n"; - if (InitializerRequired(env, storage_class)) { + if (InitializerRequired(storage_class)) { after_types << "%built_in_null = OpConstantNull %built_in_type\n"; } after_types << "%built_in_ptr = OpTypePointer " << storage_class << " %built_in_type\n"; after_types << "%built_in_var = OpVariable %built_in_ptr " << storage_class; - if (InitializerRequired(env, storage_class)) { + if (InitializerRequired(storage_class)) { after_types << " %built_in_null"; } after_types << "\n"; @@ -346,11 +312,7 @@ OpReturn OpFunctionEnd )"; - if (spvIsWebGPUEnv(env)) { - generator.after_types_ += function_body; - } else { - generator.add_at_the_end_ = function_body; - } + generator.add_at_the_end_ = function_body; generator.entry_points_.push_back(std::move(entry_point)); @@ -365,9 +327,8 @@ TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, InFunction) { const char* const vuid = std::get<4>(GetParam()); const TestResult& test_result = std::get<5>(GetParam()); - CodeGenerator generator = - GetInFunctionCodeGenerator(SPV_ENV_VULKAN_1_0, built_in, execution_model, - storage_class, NULL, NULL, data_type); + CodeGenerator generator = GetInFunctionCodeGenerator( + built_in, execution_model, storage_class, NULL, NULL, data_type); CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); ASSERT_EQ(test_result.validation_result, @@ -383,28 +344,6 @@ TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, InFunction) { } } -TEST_P(ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, InFunction) { - const char* const built_in = std::get<0>(GetParam()); - const char* const execution_model = std::get<1>(GetParam()); - const char* const storage_class = std::get<2>(GetParam()); - const char* const data_type = std::get<3>(GetParam()); - const TestResult& test_result = std::get<4>(GetParam()); - - CodeGenerator generator = - GetInFunctionCodeGenerator(SPV_ENV_WEBGPU_0, built_in, execution_model, - storage_class, NULL, NULL, data_type); - - CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0); - ASSERT_EQ(test_result.validation_result, - ValidateInstructions(SPV_ENV_WEBGPU_0)); - if (test_result.error_str) { - EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str)); - } - if (test_result.error_str2) { - EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str2)); - } -} - TEST_P( ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, InFunction) { @@ -417,9 +356,9 @@ TEST_P( const char* const vuid = std::get<6>(GetParam()); const TestResult& test_result = std::get<7>(GetParam()); - CodeGenerator generator = GetInFunctionCodeGenerator( - SPV_ENV_VULKAN_1_0, built_in, execution_model, storage_class, - capabilities, extensions, data_type); + CodeGenerator generator = + GetInFunctionCodeGenerator(built_in, execution_model, storage_class, + capabilities, extensions, data_type); CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); ASSERT_EQ(test_result.validation_result, @@ -435,16 +374,13 @@ TEST_P( } } -CodeGenerator GetVariableCodeGenerator(spv_target_env env, - const char* const built_in, +CodeGenerator GetVariableCodeGenerator(const char* const built_in, const char* const execution_model, const char* const storage_class, const char* const capabilities, const char* const extensions, const char* const data_type) { - CodeGenerator generator = - spvIsWebGPUEnv(env) ? CodeGenerator::GetWebGPUShaderCodeGenerator() - : CodeGenerator::GetDefaultShaderCodeGenerator(); + CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator(); if (capabilities) { generator.capabilities_ += capabilities; @@ -458,13 +394,13 @@ CodeGenerator GetVariableCodeGenerator(spv_target_env env, generator.before_types_ += "\n"; std::ostringstream after_types; - if (InitializerRequired(env, storage_class)) { + if (InitializerRequired(storage_class)) { after_types << "%built_in_null = OpConstantNull " << data_type << "\n"; } after_types << "%built_in_ptr = OpTypePointer " << storage_class << " " << data_type << "\n"; after_types << "%built_in_var = OpVariable %built_in_ptr " << storage_class; - if (InitializerRequired(env, storage_class)) { + if (InitializerRequired(storage_class)) { after_types << " %built_in_null"; } after_types << "\n"; @@ -516,9 +452,8 @@ TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Variable) { const char* const vuid = std::get<4>(GetParam()); const TestResult& test_result = std::get<5>(GetParam()); - CodeGenerator generator = - GetVariableCodeGenerator(SPV_ENV_VULKAN_1_0, built_in, execution_model, - storage_class, NULL, NULL, data_type); + CodeGenerator generator = GetVariableCodeGenerator( + built_in, execution_model, storage_class, NULL, NULL, data_type); CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); ASSERT_EQ(test_result.validation_result, @@ -534,28 +469,6 @@ TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Variable) { } } -TEST_P(ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, Variable) { - const char* const built_in = std::get<0>(GetParam()); - const char* const execution_model = std::get<1>(GetParam()); - const char* const storage_class = std::get<2>(GetParam()); - const char* const data_type = std::get<3>(GetParam()); - const TestResult& test_result = std::get<4>(GetParam()); - - CodeGenerator generator = - GetVariableCodeGenerator(SPV_ENV_WEBGPU_0, built_in, execution_model, - storage_class, NULL, NULL, data_type); - - CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0); - ASSERT_EQ(test_result.validation_result, - ValidateInstructions(SPV_ENV_WEBGPU_0)); - if (test_result.error_str) { - EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str)); - } - if (test_result.error_str2) { - EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str2)); - } -} - TEST_P( ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, Variable) { @@ -568,9 +481,9 @@ TEST_P( const char* const vuid = std::get<6>(GetParam()); const TestResult& test_result = std::get<7>(GetParam()); - CodeGenerator generator = GetVariableCodeGenerator( - SPV_ENV_VULKAN_1_0, built_in, execution_model, storage_class, - capabilities, extensions, data_type); + CodeGenerator generator = + GetVariableCodeGenerator(built_in, execution_model, storage_class, + capabilities, extensions, data_type); CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); ASSERT_EQ(test_result.validation_result, @@ -706,11 +619,6 @@ INSTANTIATE_TEST_SUITE_P( Combine(Values("FragCoord"), Values("Fragment"), Values("Input"), Values("%f32vec4"), Values(nullptr), Values(TestResult()))); -INSTANTIATE_TEST_SUITE_P( - FragCoordSuccess, ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, - Combine(Values("FragCoord"), Values("Fragment"), Values("Input"), - Values("%f32vec4"), Values(TestResult()))); - INSTANTIATE_TEST_SUITE_P( FragCoordNotFragment, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, @@ -723,15 +631,6 @@ INSTANTIATE_TEST_SUITE_P( Values(TestResult(SPV_ERROR_INVALID_DATA, "to be used only with Fragment execution model")))); -INSTANTIATE_TEST_SUITE_P( - FragCoordNotFragment, - ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, - Combine( - Values("FragCoord"), Values("Vertex", "GLCompute"), Values("Input"), - Values("%f32vec4"), - Values(TestResult(SPV_ERROR_INVALID_DATA, - "to be used only with Fragment execution model")))); - INSTANTIATE_TEST_SUITE_P( FragCoordNotInput, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("FragCoord"), Values("Fragment"), Values("Output"), @@ -741,15 +640,6 @@ INSTANTIATE_TEST_SUITE_P( "to be only used for variables with Input storage class", "uses storage class Output")))); -INSTANTIATE_TEST_SUITE_P( - FragCoordNotInput, ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, - Combine(Values("FragCoord"), Values("Fragment"), Values("Output"), - Values("%f32vec4"), - Values(TestResult( - SPV_ERROR_INVALID_DATA, - "to be only used for variables with Input storage class", - "uses storage class Output")))); - INSTANTIATE_TEST_SUITE_P( FragCoordNotFloatVector, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, @@ -760,15 +650,6 @@ INSTANTIATE_TEST_SUITE_P( "needs to be a 4-component 32-bit float vector", "is not a float vector")))); -INSTANTIATE_TEST_SUITE_P( - FragCoordNotFloatVector, - ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, - Combine(Values("FragCoord"), Values("Fragment"), Values("Input"), - Values("%f32arr4", "%u32vec4"), - Values(TestResult(SPV_ERROR_INVALID_DATA, - "needs to be a 4-component 32-bit float vector", - "is not a float vector")))); - INSTANTIATE_TEST_SUITE_P( FragCoordNotFloatVec4, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, @@ -778,15 +659,6 @@ INSTANTIATE_TEST_SUITE_P( "needs to be a 4-component 32-bit float vector", "has 3 components")))); -INSTANTIATE_TEST_SUITE_P( - FragCoordNotFloatVec4, - ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, - Combine(Values("FragCoord"), Values("Fragment"), Values("Input"), - Values("%f32vec3"), - Values(TestResult(SPV_ERROR_INVALID_DATA, - "needs to be a 4-component 32-bit float vector", - "has 3 components")))); - INSTANTIATE_TEST_SUITE_P( FragCoordNotF32Vec4, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, @@ -801,11 +673,6 @@ INSTANTIATE_TEST_SUITE_P( Combine(Values("FragDepth"), Values("Fragment"), Values("Output"), Values("%f32"), Values(nullptr), Values(TestResult()))); -INSTANTIATE_TEST_SUITE_P( - FragDepthSuccess, ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, - Combine(Values("FragDepth"), Values("Fragment"), Values("Output"), - Values("%f32"), Values(TestResult()))); - INSTANTIATE_TEST_SUITE_P( FragDepthNotFragment, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, @@ -818,15 +685,6 @@ INSTANTIATE_TEST_SUITE_P( Values(TestResult(SPV_ERROR_INVALID_DATA, "to be used only with Fragment execution model")))); -INSTANTIATE_TEST_SUITE_P( - FragDepthNotFragment, - ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, - Combine( - Values("FragDepth"), Values("Vertex", "GLCompute"), Values("Output"), - Values("%f32"), - Values(TestResult(SPV_ERROR_INVALID_DATA, - "to be used only with Fragment execution model")))); - INSTANTIATE_TEST_SUITE_P( FragDepthNotOutput, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, @@ -837,16 +695,6 @@ INSTANTIATE_TEST_SUITE_P( "to be only used for variables with Output storage class", "uses storage class Input")))); -INSTANTIATE_TEST_SUITE_P( - FragDepthNotOutput, - ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, - Combine(Values("FragDepth"), Values("Fragment"), Values("Input"), - Values("%f32"), - Values(TestResult( - SPV_ERROR_INVALID_DATA, - "to be only used for variables with Output storage class", - "uses storage class Input")))); - INSTANTIATE_TEST_SUITE_P( FragDepthNotFloatScalar, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, @@ -857,15 +705,6 @@ INSTANTIATE_TEST_SUITE_P( "needs to be a 32-bit float scalar", "is not a float scalar")))); -INSTANTIATE_TEST_SUITE_P( - FragDepthNotFloatScalar, - ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, - Combine(Values("FragDepth"), Values("Fragment"), Values("Output"), - Values("%f32vec4", "%u32"), - Values(TestResult(SPV_ERROR_INVALID_DATA, - "needs to be a 32-bit float scalar", - "is not a float scalar")))); - INSTANTIATE_TEST_SUITE_P( FragDepthNotF32, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("FragDepth"), Values("Fragment"), Values("Output"), @@ -881,12 +720,6 @@ INSTANTIATE_TEST_SUITE_P( Values("Input"), Values("%bool"), Values(nullptr), Values(TestResult()))); -INSTANTIATE_TEST_SUITE_P( - FrontFacingSuccess, - ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, - Combine(Values("FrontFacing"), Values("Fragment"), Values("Input"), - Values("%bool"), Values(TestResult()))); - INSTANTIATE_TEST_SUITE_P( FrontFacingAndHelperInvocationNotFragment, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, @@ -900,15 +733,6 @@ INSTANTIATE_TEST_SUITE_P( Values(TestResult(SPV_ERROR_INVALID_DATA, "to be used only with Fragment execution model")))); -INSTANTIATE_TEST_SUITE_P( - FrontFacingNotFragment, - ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, - Combine( - Values("FrontFacing"), Values("Vertex", "GLCompute"), Values("Input"), - Values("%bool"), - Values(TestResult(SPV_ERROR_INVALID_DATA, - "to be used only with Fragment execution model")))); - INSTANTIATE_TEST_SUITE_P( FrontFacingAndHelperInvocationNotInput, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, @@ -921,16 +745,6 @@ INSTANTIATE_TEST_SUITE_P( "to be only used for variables with Input storage class", "uses storage class Output")))); -INSTANTIATE_TEST_SUITE_P( - FrontFacingNotInput, - ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, - Combine(Values("FrontFacing"), Values("Fragment"), Values("Output"), - Values("%bool"), - Values(TestResult( - SPV_ERROR_INVALID_DATA, - "to be only used for variables with Input storage class", - "uses storage class Output")))); - INSTANTIATE_TEST_SUITE_P( FrontFacingAndHelperInvocationNotBool, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, @@ -942,15 +756,6 @@ INSTANTIATE_TEST_SUITE_P( "needs to be a bool scalar", "is not a bool scalar")))); -INSTANTIATE_TEST_SUITE_P( - FrontFacingNotBool, - ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, - Combine(Values("FrontFacing"), Values("Fragment"), Values("Input"), - Values("%f32", "%u32"), - Values(TestResult(SPV_ERROR_INVALID_DATA, - "needs to be a bool scalar", - "is not a bool scalar")))); - INSTANTIATE_TEST_SUITE_P( ComputeShaderInputInt32Vec3Success, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, @@ -959,13 +764,6 @@ INSTANTIATE_TEST_SUITE_P( Values("GLCompute"), Values("Input"), Values("%u32vec3"), Values(nullptr), Values(TestResult()))); -INSTANTIATE_TEST_SUITE_P( - ComputeShaderInputInt32Vec3Success, - ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, - Combine(Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups"), - Values("GLCompute"), Values("Input"), Values("%u32vec3"), - Values(TestResult()))); - INSTANTIATE_TEST_SUITE_P( ComputeShaderInputInt32Vec3NotGLCompute, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, @@ -982,15 +780,6 @@ INSTANTIATE_TEST_SUITE_P( Values(TestResult(SPV_ERROR_INVALID_DATA, "to be used only with GLCompute execution model")))); -INSTANTIATE_TEST_SUITE_P( - ComputeShaderInputInt32Vec3NotGLCompute, - ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, - Combine( - Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups"), - Values("Vertex", "Fragment"), Values("Input"), Values("%u32vec3"), - Values(TestResult(SPV_ERROR_INVALID_DATA, - "to be used only with GLCompute execution model")))); - INSTANTIATE_TEST_SUITE_P( ComputeShaderInputInt32Vec3NotInput, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, @@ -1006,16 +795,6 @@ INSTANTIATE_TEST_SUITE_P( "to be only used for variables with Input storage class", "uses storage class Output")))); -INSTANTIATE_TEST_SUITE_P( - ComputeShaderInputInt32Vec3NotInput, - ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, - Combine(Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups"), - Values("GLCompute"), Values("Output"), Values("%u32vec3"), - Values(TestResult( - SPV_ERROR_INVALID_DATA, - "to be only used for variables with Input storage class", - "uses storage class Output")))); - INSTANTIATE_TEST_SUITE_P( ComputeShaderInputInt32Vec3NotIntVector, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, @@ -1031,16 +810,6 @@ INSTANTIATE_TEST_SUITE_P( "needs to be a 3-component 32-bit int vector", "is not an int vector")))); -INSTANTIATE_TEST_SUITE_P( - ComputeShaderInputInt32Vec3NotIntVector, - ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, - Combine(Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups"), - Values("GLCompute"), Values("Input"), - Values("%u32arr3", "%f32vec3"), - Values(TestResult(SPV_ERROR_INVALID_DATA, - "needs to be a 3-component 32-bit int vector", - "is not an int vector")))); - INSTANTIATE_TEST_SUITE_P( ComputeShaderInputInt32Vec3NotIntVec3, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, @@ -1055,15 +824,6 @@ INSTANTIATE_TEST_SUITE_P( "needs to be a 3-component 32-bit int vector", "has 4 components")))); -INSTANTIATE_TEST_SUITE_P( - ComputeShaderInputInt32Vec3NotIntVec3, - ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, - Combine(Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups"), - Values("GLCompute"), Values("Input"), Values("%u32vec4"), - Values(TestResult(SPV_ERROR_INVALID_DATA, - "needs to be a 3-component 32-bit int vector", - "has 4 components")))); - INSTANTIATE_TEST_SUITE_P( ComputeShaderInputInt32Vec3NotInt32Vec, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, @@ -1133,12 +893,6 @@ INSTANTIATE_TEST_SUITE_P( Combine(Values("InstanceIndex"), Values("Vertex"), Values("Input"), Values("%u32"), Values(nullptr), Values(TestResult()))); -INSTANTIATE_TEST_SUITE_P( - InstanceIndexSuccess, - ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, - Combine(Values("InstanceIndex"), Values("Vertex"), Values("Input"), - Values("%u32"), Values(TestResult()))); - INSTANTIATE_TEST_SUITE_P( InstanceIndexInvalidExecutionModel, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, @@ -1150,14 +904,6 @@ INSTANTIATE_TEST_SUITE_P( Values(TestResult(SPV_ERROR_INVALID_DATA, "to be used only with Vertex execution model")))); -INSTANTIATE_TEST_SUITE_P( - InstanceIndexInvalidExecutionModel, - ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, - Combine(Values("InstanceIndex"), Values("Fragment", "GLCompute"), - Values("Input"), Values("%u32"), - Values(TestResult(SPV_ERROR_INVALID_DATA, - "to be used only with Vertex execution model")))); - INSTANTIATE_TEST_SUITE_P( InstanceIndexNotInput, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, @@ -1168,16 +914,6 @@ INSTANTIATE_TEST_SUITE_P( "to be only used for variables with Input storage class", "uses storage class Output")))); -INSTANTIATE_TEST_SUITE_P( - InstanceIndexNotInput, - ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, - Combine(Values("InstanceIndex"), Values("Vertex"), Values("Output"), - Values("%u32"), - Values(TestResult( - SPV_ERROR_INVALID_DATA, - "to be only used for variables with Input storage class", - "uses storage class Output")))); - INSTANTIATE_TEST_SUITE_P( InstanceIndexNotIntScalar, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, @@ -1188,15 +924,6 @@ INSTANTIATE_TEST_SUITE_P( "needs to be a 32-bit int scalar", "is not an int scalar")))); -INSTANTIATE_TEST_SUITE_P( - InstanceIndexNotIntScalar, - ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, - Combine(Values("InstanceIndex"), Values("Vertex"), Values("Input"), - Values("%f32", "%u32vec3"), - Values(TestResult(SPV_ERROR_INVALID_DATA, - "needs to be a 32-bit int scalar", - "is not an int scalar")))); - INSTANTIATE_TEST_SUITE_P( InstanceIndexNotInt32, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, @@ -1488,21 +1215,6 @@ INSTANTIATE_TEST_SUITE_P( Values("Output"), Values("%f32vec4"), Values(nullptr), Values(TestResult()))); -INSTANTIATE_TEST_SUITE_P( - PositionOutputSuccess, - ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, - Combine(Values("Position"), Values("Vertex"), Values("Output"), - Values("%f32vec4"), Values(TestResult()))); - -INSTANTIATE_TEST_SUITE_P( - PositionOutputFailure, - ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, - Combine(Values("Position"), Values("Fragment", "GLCompute"), - Values("Output"), Values("%f32vec4"), - Values(TestResult(SPV_ERROR_INVALID_DATA, - "WebGPU spec allows BuiltIn Position to be used " - "only with the Vertex execution model.")))); - INSTANTIATE_TEST_SUITE_P( PositionInputSuccess, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, @@ -1511,16 +1223,6 @@ INSTANTIATE_TEST_SUITE_P( Values("Input"), Values("%f32vec4"), Values(nullptr), Values(TestResult()))); -INSTANTIATE_TEST_SUITE_P( - PositionInputFailure, - ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, - Combine( - Values("Position"), Values("Vertex", "Fragment", "GLCompute"), - Values("Input"), Values("%f32vec4"), - Values(TestResult(SPV_ERROR_INVALID_DATA, - "WebGPU spec allows BuiltIn Position to be only used " - "for variables with Output storage class")))); - INSTANTIATE_TEST_SUITE_P( PositionInvalidStorageClass, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, @@ -1566,15 +1268,6 @@ INSTANTIATE_TEST_SUITE_P( "needs to be a 4-component 32-bit float vector", "is not a float vector")))); -INSTANTIATE_TEST_SUITE_P( - PositionNotFloatVector, - ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, - Combine( - Values("Position"), Values("Vertex"), Values("Output"), - Values("%f32arr4", "%u32vec4"), - Values(TestResult(SPV_ERROR_INVALID_DATA, - "needs to be a 4-component 32-bit float vector")))); - INSTANTIATE_TEST_SUITE_P( PositionNotFloatVec4, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, @@ -1584,15 +1277,6 @@ INSTANTIATE_TEST_SUITE_P( "needs to be a 4-component 32-bit float vector", "has 3 components")))); -INSTANTIATE_TEST_SUITE_P( - PositionNotFloatVec4, - ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, - Combine( - Values("Position"), Values("Vertex"), Values("Output"), - Values("%f32vec3"), - Values(TestResult(SPV_ERROR_INVALID_DATA, - "needs to be a 4-component 32-bit float vector")))); - INSTANTIATE_TEST_SUITE_P( PositionNotF32Vec4, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, @@ -2067,12 +1751,6 @@ INSTANTIATE_TEST_SUITE_P( Combine(Values("VertexIndex"), Values("Vertex"), Values("Input"), Values("%u32"), Values(nullptr), Values(TestResult()))); -INSTANTIATE_TEST_SUITE_P( - VertexIndexSuccess, - ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, - Combine(Values("VertexIndex"), Values("Vertex"), Values("Input"), - Values("%u32"), Values(TestResult()))); - INSTANTIATE_TEST_SUITE_P( VertexIndexInvalidExecutionModel, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, @@ -2084,14 +1762,6 @@ INSTANTIATE_TEST_SUITE_P( Values(TestResult(SPV_ERROR_INVALID_DATA, "to be used only with Vertex execution model")))); -INSTANTIATE_TEST_SUITE_P( - VertexIndexInvalidExecutionModel, - ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, - Combine(Values("VertexIndex"), Values("Fragment", "GLCompute"), - Values("Input"), Values("%u32"), - Values(TestResult(SPV_ERROR_INVALID_DATA, - "to be used only with Vertex execution model")))); - INSTANTIATE_TEST_SUITE_P( VertexIndexNotInput, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, @@ -2102,16 +1772,6 @@ INSTANTIATE_TEST_SUITE_P( "Vulkan spec allows BuiltIn VertexIndex to be only " "used for variables with Input storage class")))); -INSTANTIATE_TEST_SUITE_P( - VertexIndexNotInput, - ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, - Combine( - Values("VertexIndex"), Values("Vertex"), Values("Output"), - Values("%u32"), - Values(TestResult(SPV_ERROR_INVALID_DATA, - "WebGPU spec allows BuiltIn VertexIndex to be only " - "used for variables with Input storage class")))); - INSTANTIATE_TEST_SUITE_P( VertexIndexNotIntScalar, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, @@ -2122,15 +1782,6 @@ INSTANTIATE_TEST_SUITE_P( "needs to be a 32-bit int scalar", "is not an int scalar")))); -INSTANTIATE_TEST_SUITE_P( - VertexIndexNotIntScalar, - ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, - Combine(Values("VertexIndex"), Values("Vertex"), Values("Input"), - Values("%f32", "%u32vec3"), - Values(TestResult(SPV_ERROR_INVALID_DATA, - "needs to be a 32-bit int scalar", - "is not an int scalar")))); - INSTANTIATE_TEST_SUITE_P( VertexIndexNotInt32, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, @@ -2140,50 +1791,6 @@ INSTANTIATE_TEST_SUITE_P( "needs to be a 32-bit int scalar", "has bit width 64")))); -INSTANTIATE_TEST_SUITE_P( - LocalInvocationIndexSuccess, - ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, - Combine(Values("LocalInvocationIndex"), Values("GLCompute"), - Values("Input"), Values("%u32"), Values(TestResult()))); - -INSTANTIATE_TEST_SUITE_P( - LocalInvocationIndexInvalidExecutionModel, - ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, - Combine( - Values("LocalInvocationIndex"), Values("Fragment", "Vertex"), - Values("Input"), Values("%u32"), - Values(TestResult(SPV_ERROR_INVALID_DATA, - "to be used only with GLCompute execution model")))); - -INSTANTIATE_TEST_SUITE_P( - LocalInvocationIndexNotInput, - ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, - Combine( - Values("LocalInvocationIndex"), Values("GLCompute"), Values("Output"), - Values("%u32"), - Values(TestResult(SPV_ERROR_INVALID_DATA, - "WebGPU spec allows BuiltIn LocalInvocationIndex to " - "be only used for variables with Input storage " - "class")))); - -INSTANTIATE_TEST_SUITE_P( - LocalInvocationIndexNotIntScalar, - ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, - Combine(Values("LocalInvocationIndex"), Values("GLCompute"), - Values("Input"), Values("%f32", "%u32vec3"), - Values(TestResult(SPV_ERROR_INVALID_DATA, - "needs to be a 32-bit int", "is not an int")))); - -INSTANTIATE_TEST_SUITE_P( - AllowListRejection, - ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, - Combine(Values("PointSize", "ClipDistance", "CullDistance", "VertexId", - "InstanceId", "PointCoord", "SampleMask", "HelperInvocation", - "WorkgroupId"), - Values("Vertex"), Values("Input"), Values("%u32"), - Values(TestResult(SPV_ERROR_INVALID_DATA, - "WebGPU does not allow BuiltIn")))); - INSTANTIATE_TEST_SUITE_P( BaseInstanceOrVertexSuccess, ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, @@ -2936,14 +2543,11 @@ INSTANTIATE_TEST_SUITE_P( Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 3-component 32-bit int vector")))); -CodeGenerator GetArrayedVariableCodeGenerator(spv_target_env env, - const char* const built_in, +CodeGenerator GetArrayedVariableCodeGenerator(const char* const built_in, const char* const execution_model, const char* const storage_class, const char* const data_type) { - CodeGenerator generator = - spvIsWebGPUEnv(env) ? CodeGenerator::GetWebGPUShaderCodeGenerator() - : CodeGenerator::GetDefaultShaderCodeGenerator(); + CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator(); generator.before_types_ = "OpDecorate %built_in_var BuiltIn "; generator.before_types_ += built_in; @@ -2951,14 +2555,14 @@ CodeGenerator GetArrayedVariableCodeGenerator(spv_target_env env, std::ostringstream after_types; after_types << "%built_in_array = OpTypeArray " << data_type << " %u32_3\n"; - if (InitializerRequired(env, storage_class)) { + if (InitializerRequired(storage_class)) { after_types << "%built_in_array_null = OpConstantNull %built_in_array\n"; } after_types << "%built_in_ptr = OpTypePointer " << storage_class << " %built_in_array\n"; after_types << "%built_in_var = OpVariable %built_in_ptr " << storage_class; - if (InitializerRequired(env, storage_class)) { + if (InitializerRequired(storage_class)) { after_types << " %built_in_array_null"; } after_types << "\n"; @@ -3007,7 +2611,7 @@ TEST_P(ValidateVulkanCombineBuiltInArrayedVariable, Variable) { const TestResult& test_result = std::get<4>(GetParam()); CodeGenerator generator = GetArrayedVariableCodeGenerator( - SPV_ENV_VULKAN_1_0, built_in, execution_model, storage_class, data_type); + built_in, execution_model, storage_class, data_type); CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); ASSERT_EQ(test_result.validation_result, @@ -3020,27 +2624,6 @@ TEST_P(ValidateVulkanCombineBuiltInArrayedVariable, Variable) { } } -TEST_P(ValidateWebGPUCombineBuiltInArrayedVariable, Variable) { - const char* const built_in = std::get<0>(GetParam()); - const char* const execution_model = std::get<1>(GetParam()); - const char* const storage_class = std::get<2>(GetParam()); - const char* const data_type = std::get<3>(GetParam()); - const TestResult& test_result = std::get<4>(GetParam()); - - CodeGenerator generator = GetArrayedVariableCodeGenerator( - SPV_ENV_WEBGPU_0, built_in, execution_model, storage_class, data_type); - - CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0); - ASSERT_EQ(test_result.validation_result, - ValidateInstructions(SPV_ENV_WEBGPU_0)); - if (test_result.error_str) { - EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str)); - } - if (test_result.error_str2) { - EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str2)); - } -} - INSTANTIATE_TEST_SUITE_P(PointSizeArrayedF32TessControl, ValidateVulkanCombineBuiltInArrayedVariable, Combine(Values("PointSize"), @@ -3086,14 +2669,6 @@ INSTANTIATE_TEST_SUITE_P( "needs to be a 4-component 32-bit float vector", "is not a float vector")))); -INSTANTIATE_TEST_SUITE_P( - PositionArrayedF32Vec4Vertex, ValidateWebGPUCombineBuiltInArrayedVariable, - Combine(Values("Position"), Values("Vertex"), Values("Output"), - Values("%f32vec4"), - Values(TestResult(SPV_ERROR_INVALID_DATA, - "needs to be a 4-component 32-bit float vector", - "is not a float vector")))); - INSTANTIATE_TEST_SUITE_P( ClipAndCullDistanceOutputSuccess, ValidateVulkanCombineBuiltInArrayedVariable, @@ -3197,10 +2772,8 @@ INSTANTIATE_TEST_SUITE_P( "needs to be a 32-bit int scalar", "has bit width 64")))); -CodeGenerator GetWorkgroupSizeSuccessGenerator(spv_target_env env) { - CodeGenerator generator = - env == SPV_ENV_WEBGPU_0 ? CodeGenerator::GetWebGPUShaderCodeGenerator() - : CodeGenerator::GetDefaultShaderCodeGenerator(); +CodeGenerator GetWorkgroupSizeSuccessGenerator() { + CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator(); generator.before_types_ = R"( OpDecorate %workgroup_size BuiltIn WorkgroupSize @@ -3222,22 +2795,13 @@ OpDecorate %workgroup_size BuiltIn WorkgroupSize } TEST_F(ValidateBuiltIns, VulkanWorkgroupSizeSuccess) { - CodeGenerator generator = - GetWorkgroupSizeSuccessGenerator(SPV_ENV_VULKAN_1_0); + CodeGenerator generator = GetWorkgroupSizeSuccessGenerator(); CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0)); } -TEST_F(ValidateBuiltIns, WebGPUWorkgroupSizeSuccess) { - CodeGenerator generator = GetWorkgroupSizeSuccessGenerator(SPV_ENV_WEBGPU_0); - CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); -} - -CodeGenerator GetWorkgroupSizeFragmentGenerator(spv_target_env env) { - CodeGenerator generator = - env == SPV_ENV_WEBGPU_0 ? CodeGenerator::GetWebGPUShaderCodeGenerator() - : CodeGenerator::GetDefaultShaderCodeGenerator(); +CodeGenerator GetWorkgroupSizeFragmentGenerator() { + CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator(); generator.before_types_ = R"( OpDecorate %workgroup_size BuiltIn WorkgroupSize @@ -3260,8 +2824,7 @@ OpDecorate %workgroup_size BuiltIn WorkgroupSize } TEST_F(ValidateBuiltIns, VulkanWorkgroupSizeFragment) { - CodeGenerator generator = - GetWorkgroupSizeFragmentGenerator(SPV_ENV_VULKAN_1_0); + CodeGenerator generator = GetWorkgroupSizeFragmentGenerator(); CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); @@ -3277,20 +2840,6 @@ TEST_F(ValidateBuiltIns, VulkanWorkgroupSizeFragment) { "VUID-WorkgroupSize-WorkgroupSize-04427")); } -TEST_F(ValidateBuiltIns, WebGPUWorkgroupSizeFragment) { - CodeGenerator generator = GetWorkgroupSizeFragmentGenerator(SPV_ENV_WEBGPU_0); - - CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("WebGPU spec allows BuiltIn WorkgroupSize to be used " - "only with GLCompute execution model")); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("is referencing ID <2> (OpConstantComposite) which is " - "decorated with BuiltIn WorkgroupSize in function <1> " - "called with execution model Fragment")); -} - TEST_F(ValidateBuiltIns, WorkgroupSizeNotConstant) { CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator(); generator.before_types_ = R"( @@ -3316,10 +2865,8 @@ OpDecorate %copy BuiltIn WorkgroupSize HasSubstr("BuiltIns can only target variables, structs or constants")); } -CodeGenerator GetWorkgroupSizeNotVectorGenerator(spv_target_env env) { - CodeGenerator generator = - env == SPV_ENV_WEBGPU_0 ? CodeGenerator::GetWebGPUShaderCodeGenerator() - : CodeGenerator::GetDefaultShaderCodeGenerator(); +CodeGenerator GetWorkgroupSizeNotVectorGenerator() { + CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator(); generator.before_types_ = R"( OpDecorate %workgroup_size BuiltIn WorkgroupSize @@ -3341,8 +2888,7 @@ OpDecorate %workgroup_size BuiltIn WorkgroupSize } TEST_F(ValidateBuiltIns, VulkanWorkgroupSizeNotVector) { - CodeGenerator generator = - GetWorkgroupSizeNotVectorGenerator(SPV_ENV_VULKAN_1_0); + CodeGenerator generator = GetWorkgroupSizeNotVectorGenerator(); CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); @@ -3354,22 +2900,8 @@ TEST_F(ValidateBuiltIns, VulkanWorkgroupSizeNotVector) { AnyVUID("VUID-WorkgroupSize-WorkgroupSize-04427")); } -TEST_F(ValidateBuiltIns, WebGPUWorkgroupSizeNotVector) { - CodeGenerator generator = - GetWorkgroupSizeNotVectorGenerator(SPV_ENV_WEBGPU_0); - - CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("According to the WebGPU spec BuiltIn WorkgroupSize " - "variable needs to be a 3-component 32-bit int vector. " - "ID <2> (OpConstant) is not an int vector.")); -} - -CodeGenerator GetWorkgroupSizeNotIntVectorGenerator(spv_target_env env) { - CodeGenerator generator = - env == SPV_ENV_WEBGPU_0 ? CodeGenerator::GetWebGPUShaderCodeGenerator() - : CodeGenerator::GetDefaultShaderCodeGenerator(); +CodeGenerator GetWorkgroupSizeNotIntVectorGenerator() { + CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator(); generator.before_types_ = R"( OpDecorate %workgroup_size BuiltIn WorkgroupSize @@ -3391,8 +2923,7 @@ OpDecorate %workgroup_size BuiltIn WorkgroupSize } TEST_F(ValidateBuiltIns, VulkanWorkgroupSizeNotIntVector) { - CodeGenerator generator = - GetWorkgroupSizeNotIntVectorGenerator(SPV_ENV_VULKAN_1_0); + CodeGenerator generator = GetWorkgroupSizeNotIntVectorGenerator(); CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); @@ -3404,22 +2935,8 @@ TEST_F(ValidateBuiltIns, VulkanWorkgroupSizeNotIntVector) { AnyVUID("VUID-WorkgroupSize-WorkgroupSize-04427")); } -TEST_F(ValidateBuiltIns, WebGPUWorkgroupSizeNotIntVector) { - CodeGenerator generator = - GetWorkgroupSizeNotIntVectorGenerator(SPV_ENV_WEBGPU_0); - - CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("According to the WebGPU spec BuiltIn WorkgroupSize " - "variable needs to be a 3-component 32-bit int vector. " - "ID <2> (OpConstantComposite) is not an int vector.")); -} - -CodeGenerator GetWorkgroupSizeNotVec3Generator(spv_target_env env) { - CodeGenerator generator = - env == SPV_ENV_WEBGPU_0 ? CodeGenerator::GetWebGPUShaderCodeGenerator() - : CodeGenerator::GetDefaultShaderCodeGenerator(); +CodeGenerator GetWorkgroupSizeNotVec3Generator() { + CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator(); generator.before_types_ = R"( OpDecorate %workgroup_size BuiltIn WorkgroupSize @@ -3441,8 +2958,7 @@ OpDecorate %workgroup_size BuiltIn WorkgroupSize } TEST_F(ValidateBuiltIns, VulkanWorkgroupSizeNotVec3) { - CodeGenerator generator = - GetWorkgroupSizeNotVec3Generator(SPV_ENV_VULKAN_1_0); + CodeGenerator generator = GetWorkgroupSizeNotVec3Generator(); CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); @@ -3454,17 +2970,6 @@ TEST_F(ValidateBuiltIns, VulkanWorkgroupSizeNotVec3) { AnyVUID("VUID-WorkgroupSize-WorkgroupSize-04427")); } -TEST_F(ValidateBuiltIns, WebGPUWorkgroupSizeNotVec3) { - CodeGenerator generator = GetWorkgroupSizeNotVec3Generator(SPV_ENV_WEBGPU_0); - - CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("According to the WebGPU spec BuiltIn WorkgroupSize " - "variable needs to be a 3-component 32-bit int vector. " - "ID <2> (OpConstantComposite) has 2 components.")); -} - TEST_F(ValidateBuiltIns, WorkgroupSizeNotInt32Vec) { CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator(); generator.before_types_ = R"( @@ -3742,10 +3247,8 @@ OpFunctionEnd HasSubstr("called with execution model Fragment")); } -CodeGenerator GetNoDepthReplacingGenerator(spv_target_env env) { - CodeGenerator generator = - spvIsWebGPUEnv(env) ? CodeGenerator::GetWebGPUShaderCodeGenerator() - : CodeGenerator::GetDefaultShaderCodeGenerator(); +CodeGenerator GetNoDepthReplacingGenerator() { + CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator(); generator.before_types_ = R"( OpMemberDecorate %output_type 0 BuiltIn FragDepth @@ -3778,17 +3281,13 @@ OpReturn OpFunctionEnd )"; - if (spvIsWebGPUEnv(env)) { - generator.after_types_ += function_body; - } else { generator.add_at_the_end_ = function_body; - } return generator; } TEST_F(ValidateBuiltIns, VulkanFragmentFragDepthNoDepthReplacing) { - CodeGenerator generator = GetNoDepthReplacingGenerator(SPV_ENV_VULKAN_1_0); + CodeGenerator generator = GetNoDepthReplacingGenerator(); CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); @@ -3799,21 +3298,8 @@ TEST_F(ValidateBuiltIns, VulkanFragmentFragDepthNoDepthReplacing) { HasSubstr("VUID-FragDepth-FragDepth-04216")); } -TEST_F(ValidateBuiltIns, WebGPUFragmentFragDepthNoDepthReplacing) { - CodeGenerator generator = GetNoDepthReplacingGenerator(SPV_ENV_WEBGPU_0); - - CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("WebGPU spec requires DepthReplacing execution mode to " - "be declared when using BuiltIn FragDepth")); -} - -CodeGenerator GetOneMainHasDepthReplacingOtherHasntGenerator( - spv_target_env env) { - CodeGenerator generator = - spvIsWebGPUEnv(env) ? CodeGenerator::GetWebGPUShaderCodeGenerator() - : CodeGenerator::GetDefaultShaderCodeGenerator(); +CodeGenerator GetOneMainHasDepthReplacingOtherHasntGenerator() { + CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator(); generator.before_types_ = R"( OpMemberDecorate %output_type 0 BuiltIn FragDepth @@ -3857,19 +3343,14 @@ OpReturn OpFunctionEnd )"; - if (spvIsWebGPUEnv(env)) { - generator.after_types_ += function_body; - } else { generator.add_at_the_end_ = function_body; - } return generator; } TEST_F(ValidateBuiltIns, VulkanFragmentFragDepthOneMainHasDepthReplacingOtherHasnt) { - CodeGenerator generator = - GetOneMainHasDepthReplacingOtherHasntGenerator(SPV_ENV_VULKAN_1_0); + CodeGenerator generator = GetOneMainHasDepthReplacingOtherHasntGenerator(); CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); @@ -3880,17 +3361,6 @@ TEST_F(ValidateBuiltIns, HasSubstr("VUID-FragDepth-FragDepth-04216")); } -TEST_F(ValidateBuiltIns, - WebGPUFragmentFragDepthOneMainHasDepthReplacingOtherHasnt) { - CodeGenerator generator = - GetOneMainHasDepthReplacingOtherHasntGenerator(SPV_ENV_WEBGPU_0); - - CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("WebGPU spec requires DepthReplacing execution mode to " - "be declared when using BuiltIn FragDepth")); -} TEST_F(ValidateBuiltIns, AllowInstanceIdWithIntersectionShader) { CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator(); diff --git a/test/val/val_capability_test.cpp b/test/val/val_capability_test.cpp index 9705cb8f..82f8d381 100644 --- a/test/val/val_capability_test.cpp +++ b/test/val/val_capability_test.cpp @@ -116,8 +116,6 @@ using ValidateCapabilityOpenGL40 = spvtest::ValidateBase; using ValidateCapabilityVulkan11 = spvtest::ValidateBase; // Always assembles using Vulkan 1.2. using ValidateCapabilityVulkan12 = spvtest::ValidateBase; -// Always assembles using WebGPU. -using ValidateCapabilityWebGPU = spvtest::ValidateBase; TEST_F(ValidateCapability, Default) { const char str[] = R"( @@ -588,18 +586,6 @@ const std::vector& AllVulkan12Capabilities() { return *r; } -const std::vector& AllWebGPUCapabilities() { - static const auto r = new std::vector{ - "", - "Shader", - "Matrix", - "Sampled1D", - "Image1D", - "ImageQuery", - "DerivativeControl"}; - return *r; -} - const std::vector& MatrixDependencies() { static const auto r = new std::vector{ "Matrix", @@ -790,12 +776,6 @@ const char kGLSL450MemoryModel[] = \ " OpCapability Shader" " OpMemoryModel Logical GLSL450 "; -const char kVulkanMemoryModel[] = \ - " OpCapability Shader" - " OpCapability VulkanMemoryModelKHR" - " OpExtension \"SPV_KHR_vulkan_memory_model\"" - " OpMemoryModel Logical VulkanKHR "; - const char kVoidFVoid[] = \ " %void = OpTypeVoid" " %void_f = OpTypeFunction %void" @@ -1814,16 +1794,6 @@ std::make_pair(std::string(kGLSL450MemoryModel) + AllSpirV10Capabilities()) ))); -INSTANTIATE_TEST_SUITE_P(Capabilities, ValidateCapabilityWebGPU, - Combine( - // All capabilities to try. - ValuesIn(AllCapabilities()), - Values( -std::make_pair(std::string(kVulkanMemoryModel) + - "OpEntryPoint Vertex %func \"shader\" \n" + std::string(kVoidFVoid), - AllWebGPUCapabilities()) -))); - INSTANTIATE_TEST_SUITE_P(Capabilities, ValidateCapabilityVulkan11, Combine( // All capabilities to try. @@ -2047,17 +2017,6 @@ TEST_P(ValidateCapabilityOpenGL40, Capability) { } } -TEST_P(ValidateCapabilityWebGPU, Capability) { - const std::string capability = Capability(GetParam()); - if (Exists(capability, SPV_ENV_WEBGPU_0)) { - const std::string test_code = MakeAssembly(GetParam()); - CompileSuccessfully(test_code, SPV_ENV_WEBGPU_0); - ASSERT_EQ(ExpectedResult(GetParam()), - ValidateInstructions(SPV_ENV_WEBGPU_0)) - << test_code; - } -} - TEST_F(ValidateCapability, SemanticsIdIsAnIdNotALiteral) { // From https://github.com/KhronosGroup/SPIRV-Tools/issues/248 // The validator was interpreting the memory semantics ID number diff --git a/test/val/val_cfg_test.cpp b/test/val/val_cfg_test.cpp index 7a268ebb..9698fb1c 100644 --- a/test/val/val_cfg_test.cpp +++ b/test/val/val_cfg_test.cpp @@ -168,15 +168,6 @@ const std::string& GetDefaultHeader(SpvCapability cap) { return (cap == SpvCapabilityShader) ? shader_header : kernel_header; } -const std::string& GetWebGPUHeader() { - static const std::string header = - "OpCapability Shader\n" - "OpCapability VulkanMemoryModelKHR\n" - "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" - "OpMemoryModel Logical VulkanKHR\n"; - return header; -} - const std::string& types_consts() { static const std::string types = "%voidt = OpTypeVoid\n" @@ -714,10 +705,8 @@ TEST_P(ValidateCFG, HeaderDoesntStrictlyDominateMergeBad) { } } -std::string GetUnreachableMergeNoMergeInst(SpvCapability cap, - spv_target_env env) { - std::string header = - spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap); +std::string GetUnreachableMergeNoMergeInst(SpvCapability cap) { + std::string header = GetDefaultHeader(cap); Block entry("entry"); Block branch("branch", SpvOpBranchConditional); Block t("t", SpvOpReturn); @@ -725,17 +714,11 @@ std::string GetUnreachableMergeNoMergeInst(SpvCapability cap, Block merge("merge", SpvOpReturn); entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); - if (!spvIsWebGPUEnv(env) && cap == SpvCapabilityShader) + if (cap == SpvCapabilityShader) branch.AppendBody("OpSelectionMerge %merge None\n"); std::string str = header; - if (spvIsWebGPUEnv(env)) { - str += - "OpEntryPoint Fragment %func \"func\"\n" - "OpExecutionMode %func OriginUpperLeft\n"; - } - if (!spvIsWebGPUEnv(env)) - str += nameOps("branch", "merge", std::make_pair("func", "Main")); + str += nameOps("branch", "merge", std::make_pair("func", "Main")); str += types_consts() + "%func = OpFunction %voidt None %funct\n"; str += entry >> branch; str += branch >> std::vector({t, f}); @@ -748,23 +731,12 @@ std::string GetUnreachableMergeNoMergeInst(SpvCapability cap, } TEST_P(ValidateCFG, UnreachableMergeNoMergeInst) { - CompileSuccessfully( - GetUnreachableMergeNoMergeInst(GetParam(), SPV_ENV_UNIVERSAL_1_0)); + CompileSuccessfully(GetUnreachableMergeNoMergeInst(GetParam())); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } -TEST_F(ValidateCFG, WebGPUUnreachableMergeNoMergeInst) { - CompileSuccessfully( - GetUnreachableMergeNoMergeInst(SpvCapabilityShader, SPV_ENV_WEBGPU_0)); - ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("For WebGPU, all blocks must be reachable")); -} - -std::string GetUnreachableMergeTerminatedBy(SpvCapability cap, - spv_target_env env, SpvOp op) { - std::string header = - spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap); +std::string GetUnreachableMergeTerminatedBy(SpvCapability cap, SpvOp op) { + std::string header = GetDefaultHeader(cap); Block entry("entry"); Block branch("branch", SpvOpBranchConditional); @@ -774,16 +746,10 @@ std::string GetUnreachableMergeTerminatedBy(SpvCapability cap, entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); std::string str = header; - if (spvIsWebGPUEnv(env)) { - str += - "OpEntryPoint Fragment %func \"func\"\n" - "OpExecutionMode %func OriginUpperLeft\n"; - } if (cap == SpvCapabilityShader) branch.AppendBody("OpSelectionMerge %merge None\n"); - if (!spvIsWebGPUEnv(env)) - str += nameOps("branch", "merge", std::make_pair("func", "Main")); + str += nameOps("branch", "merge", std::make_pair("func", "Main")); str += types_consts(); str += "%func = OpFunction %voidt None %funct\n"; str += entry >> branch; @@ -797,49 +763,24 @@ std::string GetUnreachableMergeTerminatedBy(SpvCapability cap, } TEST_P(ValidateCFG, UnreachableMergeTerminatedByOpUnreachable) { - CompileSuccessfully(GetUnreachableMergeTerminatedBy( - GetParam(), SPV_ENV_UNIVERSAL_1_0, SpvOpUnreachable)); + CompileSuccessfully( + GetUnreachableMergeTerminatedBy(GetParam(), SpvOpUnreachable)); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_F(ValidateCFG, UnreachableMergeTerminatedByOpKill) { - CompileSuccessfully(GetUnreachableMergeTerminatedBy( - SpvCapabilityShader, SPV_ENV_UNIVERSAL_1_0, SpvOpKill)); + CompileSuccessfully( + GetUnreachableMergeTerminatedBy(SpvCapabilityShader, SpvOpKill)); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_P(ValidateCFG, UnreachableMergeTerminatedByOpReturn) { - CompileSuccessfully(GetUnreachableMergeTerminatedBy( - GetParam(), SPV_ENV_UNIVERSAL_1_0, SpvOpReturn)); + CompileSuccessfully(GetUnreachableMergeTerminatedBy(GetParam(), SpvOpReturn)); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } -TEST_F(ValidateCFG, WebGPUUnreachableMergeTerminatedByOpUnreachable) { - CompileSuccessfully(GetUnreachableMergeTerminatedBy( - SpvCapabilityShader, SPV_ENV_WEBGPU_0, SpvOpUnreachable)); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); -} - -TEST_F(ValidateCFG, WebGPUUnreachableMergeTerminatedByOpKill) { - CompileSuccessfully(GetUnreachableMergeTerminatedBy( - SpvCapabilityShader, SPV_ENV_WEBGPU_0, SpvOpKill)); - ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("must terminate with OpUnreachable")); -} - -TEST_P(ValidateCFG, WebGPUUnreachableMergeTerminatedByOpReturn) { - CompileSuccessfully(GetUnreachableMergeTerminatedBy( - SpvCapabilityShader, SPV_ENV_WEBGPU_0, SpvOpReturn)); - ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("must terminate with OpUnreachable")); -} - -std::string GetUnreachableContinueTerminatedBy(SpvCapability cap, - spv_target_env env, SpvOp op) { - std::string header = - spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap); +std::string GetUnreachableContinueTerminatedBy(SpvCapability cap, SpvOp op) { + std::string header = GetDefaultHeader(cap); Block entry("entry"); Block branch("branch", SpvOpBranch); @@ -849,16 +790,10 @@ std::string GetUnreachableContinueTerminatedBy(SpvCapability cap, if (op == SpvOpBranch) target >> branch; std::string str = header; - if (spvIsWebGPUEnv(env)) { - str += - "OpEntryPoint Fragment %func \"func\"\n" - "OpExecutionMode %func OriginUpperLeft\n"; - } if (cap == SpvCapabilityShader) branch.AppendBody("OpLoopMerge %merge %target None\n"); - if (!spvIsWebGPUEnv(env)) - str += nameOps("branch", "merge", "target", std::make_pair("func", "Main")); + str += nameOps("branch", "merge", "target", std::make_pair("func", "Main")); str += types_consts(); str += "%func = OpFunction %voidt None %funct\n"; str += entry >> branch; @@ -871,8 +806,8 @@ std::string GetUnreachableContinueTerminatedBy(SpvCapability cap, } TEST_P(ValidateCFG, UnreachableContinueTerminatedBySpvOpUnreachable) { - CompileSuccessfully(GetUnreachableContinueTerminatedBy( - GetParam(), SPV_ENV_UNIVERSAL_1_0, SpvOpUnreachable)); + CompileSuccessfully( + GetUnreachableContinueTerminatedBy(GetParam(), SpvOpUnreachable)); if (GetParam() == SpvCapabilityShader) { ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), @@ -883,16 +818,16 @@ TEST_P(ValidateCFG, UnreachableContinueTerminatedBySpvOpUnreachable) { } TEST_F(ValidateCFG, UnreachableContinueTerminatedBySpvOpKill) { - CompileSuccessfully(GetUnreachableContinueTerminatedBy( - SpvCapabilityShader, SPV_ENV_UNIVERSAL_1_0, SpvOpKill)); + CompileSuccessfully( + GetUnreachableContinueTerminatedBy(SpvCapabilityShader, SpvOpKill)); ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("targeted by 0 back-edge blocks")); } TEST_P(ValidateCFG, UnreachableContinueTerminatedBySpvOpReturn) { - CompileSuccessfully(GetUnreachableContinueTerminatedBy( - GetParam(), SPV_ENV_UNIVERSAL_1_0, SpvOpReturn)); + CompileSuccessfully( + GetUnreachableContinueTerminatedBy(GetParam(), SpvOpReturn)); if (GetParam() == SpvCapabilityShader) { ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), @@ -903,48 +838,13 @@ TEST_P(ValidateCFG, UnreachableContinueTerminatedBySpvOpReturn) { } TEST_P(ValidateCFG, UnreachableContinueTerminatedBySpvOpBranch) { - CompileSuccessfully(GetUnreachableContinueTerminatedBy( - GetParam(), SPV_ENV_UNIVERSAL_1_0, SpvOpBranch)); + CompileSuccessfully( + GetUnreachableContinueTerminatedBy(GetParam(), SpvOpBranch)); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } -TEST_F(ValidateCFG, WebGPUUnreachableContinueTerminatedBySpvOpUnreachable) { - CompileSuccessfully(GetUnreachableContinueTerminatedBy( - SpvCapabilityShader, SPV_ENV_WEBGPU_0, SpvOpUnreachable)); - ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("For WebGPU, unreachable continue-target must " - "terminate with OpBranch.\n %12 = OpLabel\n")); -} - -TEST_F(ValidateCFG, WebGPUUnreachableContinueTerminatedBySpvOpKill) { - CompileSuccessfully(GetUnreachableContinueTerminatedBy( - SpvCapabilityShader, SPV_ENV_WEBGPU_0, SpvOpKill)); - ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("For WebGPU, unreachable continue-target must " - "terminate with OpBranch.\n %12 = OpLabel\n")); -} - -TEST_F(ValidateCFG, WebGPUUnreachableContinueTerminatedBySpvOpReturn) { - CompileSuccessfully(GetUnreachableContinueTerminatedBy( - SpvCapabilityShader, SPV_ENV_WEBGPU_0, SpvOpReturn)); - ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("For WebGPU, unreachable continue-target must " - "terminate with OpBranch.\n %12 = OpLabel\n")); -} - -TEST_F(ValidateCFG, WebGPUUnreachableContinueTerminatedBySpvOpBranch) { - CompileSuccessfully(GetUnreachableContinueTerminatedBy( - SpvCapabilityShader, SPV_ENV_WEBGPU_0, SpvOpBranch)); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); -} - -std::string GetUnreachableMergeUnreachableMergeInst(SpvCapability cap, - spv_target_env env) { - std::string header = - spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap); +std::string GetUnreachableMergeUnreachableMergeInst(SpvCapability cap) { + std::string header = GetDefaultHeader(cap); Block body("body", SpvOpReturn); Block entry("entry"); @@ -955,16 +855,10 @@ std::string GetUnreachableMergeUnreachableMergeInst(SpvCapability cap, entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); std::string str = header; - if (spvIsWebGPUEnv(env)) { - str += - "OpEntryPoint Fragment %func \"func\"\n" - "OpExecutionMode %func OriginUpperLeft\n"; - } if (cap == SpvCapabilityShader) branch.AppendBody("OpSelectionMerge %merge None\n"); - if (!spvIsWebGPUEnv(env)) - str += nameOps("branch", "merge", std::make_pair("func", "Main")); + str += nameOps("branch", "merge", std::make_pair("func", "Main")); str += types_consts(); str += "%func = OpFunction %voidt None %funct\n"; str += body; @@ -979,23 +873,12 @@ std::string GetUnreachableMergeUnreachableMergeInst(SpvCapability cap, } TEST_P(ValidateCFG, UnreachableMergeUnreachableMergeInst) { - CompileSuccessfully(GetUnreachableMergeUnreachableMergeInst( - GetParam(), SPV_ENV_UNIVERSAL_1_0)); + CompileSuccessfully(GetUnreachableMergeUnreachableMergeInst(GetParam())); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } -TEST_F(ValidateCFG, WebGPUUnreachableMergeUnreachableMergeInst) { - CompileSuccessfully(GetUnreachableMergeUnreachableMergeInst( - SpvCapabilityShader, SPV_ENV_WEBGPU_0)); - ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("must be referenced by a reachable merge instruction")); -} - -std::string GetUnreachableContinueUnreachableLoopInst(SpvCapability cap, - spv_target_env env) { - std::string header = - spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap); +std::string GetUnreachableContinueUnreachableLoopInst(SpvCapability cap) { + std::string header = GetDefaultHeader(cap); Block body("body", SpvOpReturn); Block entry("entry"); @@ -1006,16 +889,10 @@ std::string GetUnreachableContinueUnreachableLoopInst(SpvCapability cap, target >> branch; std::string str = header; - if (spvIsWebGPUEnv(env)) { - str += - "OpEntryPoint Fragment %func \"func\"\n" - "OpExecutionMode %func OriginUpperLeft\n"; - } if (cap == SpvCapabilityShader) branch.AppendBody("OpLoopMerge %merge %target None\n"); - if (!spvIsWebGPUEnv(env)) - str += nameOps("branch", "merge", "target", std::make_pair("func", "Main")); + str += nameOps("branch", "merge", "target", std::make_pair("func", "Main")); str += types_consts(); str += "%func = OpFunction %voidt None %funct\n"; str += body; @@ -1029,8 +906,7 @@ std::string GetUnreachableContinueUnreachableLoopInst(SpvCapability cap, } TEST_P(ValidateCFG, UnreachableContinueUnreachableLoopInst) { - CompileSuccessfully(GetUnreachableContinueUnreachableLoopInst( - GetParam(), SPV_ENV_UNIVERSAL_1_0)); + CompileSuccessfully(GetUnreachableContinueUnreachableLoopInst(GetParam())); if (GetParam() == SpvCapabilityShader) { // Shader causes additional structured CFG checks that cause a failure. ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); @@ -1043,18 +919,8 @@ TEST_P(ValidateCFG, UnreachableContinueUnreachableLoopInst) { } } -TEST_F(ValidateCFG, WebGPUUnreachableContinueUnreachableLoopInst) { - CompileSuccessfully(GetUnreachableContinueUnreachableLoopInst( - SpvCapabilityShader, SPV_ENV_WEBGPU_0)); - ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("must be referenced by a reachable loop instruction")); -} - -std::string GetUnreachableMergeWithComplexBody(SpvCapability cap, - spv_target_env env) { - std::string header = - spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap); +std::string GetUnreachableMergeWithComplexBody(SpvCapability cap) { + std::string header = GetDefaultHeader(cap); Block entry("entry"); Block branch("branch", SpvOpBranchConditional); @@ -1062,23 +928,15 @@ std::string GetUnreachableMergeWithComplexBody(SpvCapability cap, Block f("f", SpvOpReturn); Block merge("merge", SpvOpUnreachable); - entry.AppendBody(spvIsWebGPUEnv(env) - ? "%placeholder = OpVariable %intptrt Function %two\n" - : "%placeholder = OpVariable %intptrt Function\n"); + entry.AppendBody("%placeholder = OpVariable %intptrt Function\n"); entry.AppendBody("%cond = OpSLessThan %boolt %one %two\n"); merge.AppendBody("OpStore %placeholder %one\n"); std::string str = header; - if (spvIsWebGPUEnv(env)) { - str += - "OpEntryPoint Fragment %func \"func\"\n" - "OpExecutionMode %func OriginUpperLeft\n"; - } if (cap == SpvCapabilityShader) branch.AppendBody("OpSelectionMerge %merge None\n"); - if (!spvIsWebGPUEnv(env)) - str += nameOps("branch", "merge", std::make_pair("func", "Main")); + str += nameOps("branch", "merge", std::make_pair("func", "Main")); str += types_consts(); str += "%intptrt = OpTypePointer Function %intt\n"; str += "%func = OpFunction %voidt None %funct\n"; @@ -1093,24 +951,12 @@ std::string GetUnreachableMergeWithComplexBody(SpvCapability cap, } TEST_P(ValidateCFG, UnreachableMergeWithComplexBody) { - CompileSuccessfully( - GetUnreachableMergeWithComplexBody(GetParam(), SPV_ENV_UNIVERSAL_1_0)); + CompileSuccessfully(GetUnreachableMergeWithComplexBody(GetParam())); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } -TEST_F(ValidateCFG, WebGPUUnreachableMergeWithComplexBody) { - CompileSuccessfully(GetUnreachableMergeWithComplexBody(SpvCapabilityShader, - SPV_ENV_WEBGPU_0)); - ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("must only contain an OpLabel and OpUnreachable instruction")); -} - -std::string GetUnreachableContinueWithComplexBody(SpvCapability cap, - spv_target_env env) { - std::string header = - spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap); +std::string GetUnreachableContinueWithComplexBody(SpvCapability cap) { + std::string header = GetDefaultHeader(cap); Block entry("entry"); Block branch("branch", SpvOpBranch); @@ -1119,22 +965,14 @@ std::string GetUnreachableContinueWithComplexBody(SpvCapability cap, target >> branch; - entry.AppendBody(spvIsWebGPUEnv(env) - ? "%placeholder = OpVariable %intptrt Function %two\n" - : "%placeholder = OpVariable %intptrt Function\n"); + entry.AppendBody("%placeholder = OpVariable %intptrt Function\n"); target.AppendBody("OpStore %placeholder %one\n"); std::string str = header; - if (spvIsWebGPUEnv(env)) { - str += - "OpEntryPoint Fragment %func \"func\"\n" - "OpExecutionMode %func OriginUpperLeft\n"; - } if (cap == SpvCapabilityShader) branch.AppendBody("OpLoopMerge %merge %target None\n"); - if (!spvIsWebGPUEnv(env)) - str += nameOps("branch", "merge", "target", std::make_pair("func", "Main")); + str += nameOps("branch", "merge", "target", std::make_pair("func", "Main")); str += types_consts(); str += "%intptrt = OpTypePointer Function %intt\n"; str += "%func = OpFunction %voidt None %funct\n"; @@ -1148,24 +986,12 @@ std::string GetUnreachableContinueWithComplexBody(SpvCapability cap, } TEST_P(ValidateCFG, UnreachableContinueWithComplexBody) { - CompileSuccessfully( - GetUnreachableContinueWithComplexBody(GetParam(), SPV_ENV_UNIVERSAL_1_0)); + CompileSuccessfully(GetUnreachableContinueWithComplexBody(GetParam())); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } -TEST_F(ValidateCFG, WebGPUUnreachableContinueWithComplexBody) { - CompileSuccessfully(GetUnreachableContinueWithComplexBody(SpvCapabilityShader, - SPV_ENV_WEBGPU_0)); - ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("must only contain an OpLabel and an OpBranch instruction")); -} - -std::string GetUnreachableMergeWithBranchUse(SpvCapability cap, - spv_target_env env) { - std::string header = - spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap); +std::string GetUnreachableMergeWithBranchUse(SpvCapability cap) { + std::string header = GetDefaultHeader(cap); Block entry("entry"); Block branch("branch", SpvOpBranchConditional); @@ -1176,16 +1002,10 @@ std::string GetUnreachableMergeWithBranchUse(SpvCapability cap, entry.AppendBody("%cond = OpSLessThan %boolt %one %two\n"); std::string str = header; - if (spvIsWebGPUEnv(env)) { - str += - "OpEntryPoint Fragment %func \"func\"\n" - "OpExecutionMode %func OriginUpperLeft\n"; - } if (cap == SpvCapabilityShader) branch.AppendBody("OpSelectionMerge %merge None\n"); - if (!spvIsWebGPUEnv(env)) - str += nameOps("branch", "merge", std::make_pair("func", "Main")); + str += nameOps("branch", "merge", std::make_pair("func", "Main")); str += types_consts(); str += "%func = OpFunction %voidt None %funct\n"; str += entry >> branch; @@ -1199,15 +1019,12 @@ std::string GetUnreachableMergeWithBranchUse(SpvCapability cap, } TEST_P(ValidateCFG, UnreachableMergeWithBranchUse) { - CompileSuccessfully( - GetUnreachableMergeWithBranchUse(GetParam(), SPV_ENV_UNIVERSAL_1_0)); + CompileSuccessfully(GetUnreachableMergeWithBranchUse(GetParam())); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); } -std::string GetUnreachableMergeWithMultipleUses(SpvCapability cap, - spv_target_env env) { - std::string header = - spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap); +std::string GetUnreachableMergeWithMultipleUses(SpvCapability cap) { + std::string header = GetDefaultHeader(cap); Block entry("entry"); Block branch("branch", SpvOpBranchConditional); @@ -1219,18 +1036,12 @@ std::string GetUnreachableMergeWithMultipleUses(SpvCapability cap, entry.AppendBody("%cond = OpSLessThan %boolt %one %two\n"); std::string str = header; - if (spvIsWebGPUEnv(env)) { - str += - "OpEntryPoint Fragment %func \"func\"\n" - "OpExecutionMode %func OriginUpperLeft\n"; - } if (cap == SpvCapabilityShader) { branch.AppendBody("OpSelectionMerge %merge None\n"); duplicate.AppendBody("OpSelectionMerge %merge None\n"); } - if (!spvIsWebGPUEnv(env)) - str += nameOps("branch", "merge", std::make_pair("func", "Main")); + str += nameOps("branch", "merge", std::make_pair("func", "Main")); str += types_consts(); str += "%func = OpFunction %voidt None %funct\n"; str += entry >> branch; @@ -1245,8 +1056,7 @@ std::string GetUnreachableMergeWithMultipleUses(SpvCapability cap, } TEST_P(ValidateCFG, UnreachableMergeWithMultipleUses) { - CompileSuccessfully( - GetUnreachableMergeWithMultipleUses(GetParam(), SPV_ENV_UNIVERSAL_1_0)); + CompileSuccessfully(GetUnreachableMergeWithMultipleUses(GetParam())); if (GetParam() == SpvCapabilityShader) { ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), @@ -1256,18 +1066,8 @@ TEST_P(ValidateCFG, UnreachableMergeWithMultipleUses) { } } -TEST_F(ValidateCFG, WebGPUUnreachableMergeWithMultipleUses) { - CompileSuccessfully(GetUnreachableMergeWithMultipleUses(SpvCapabilityShader, - SPV_ENV_WEBGPU_0)); - ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("is already a merge block for another header")); -} - -std::string GetUnreachableContinueWithBranchUse(SpvCapability cap, - spv_target_env env) { - std::string header = - spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap); +std::string GetUnreachableContinueWithBranchUse(SpvCapability cap) { + std::string header = GetDefaultHeader(cap); Block entry("entry"); Block foo("foo", SpvOpBranch); @@ -1278,21 +1078,13 @@ std::string GetUnreachableContinueWithBranchUse(SpvCapability cap, foo >> target; target >> branch; - entry.AppendBody(spvIsWebGPUEnv(env) - ? "%placeholder = OpVariable %intptrt Function %two\n" - : "%placeholder = OpVariable %intptrt Function\n"); + entry.AppendBody("%placeholder = OpVariable %intptrt Function\n"); std::string str = header; - if (spvIsWebGPUEnv(env)) { - str += - "OpEntryPoint Fragment %func \"func\"\n" - "OpExecutionMode %func OriginUpperLeft\n"; - } if (cap == SpvCapabilityShader) branch.AppendBody("OpLoopMerge %merge %target None\n"); - if (!spvIsWebGPUEnv(env)) - str += nameOps("branch", "merge", "target", std::make_pair("func", "Main")); + str += nameOps("branch", "merge", "target", std::make_pair("func", "Main")); str += types_consts(); str += "%intptrt = OpTypePointer Function %intt\n"; str += "%func = OpFunction %voidt None %funct\n"; @@ -1307,23 +1099,12 @@ std::string GetUnreachableContinueWithBranchUse(SpvCapability cap, } TEST_P(ValidateCFG, UnreachableContinueWithBranchUse) { - CompileSuccessfully( - GetUnreachableContinueWithBranchUse(GetParam(), SPV_ENV_UNIVERSAL_1_0)); + CompileSuccessfully(GetUnreachableContinueWithBranchUse(GetParam())); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } -TEST_F(ValidateCFG, WebGPUUnreachableContinueWithBranchUse) { - CompileSuccessfully(GetUnreachableContinueWithBranchUse(SpvCapabilityShader, - SPV_ENV_WEBGPU_0)); - ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("cannot be the target of a branch.")); -} - -std::string GetReachableMergeAndContinue(SpvCapability cap, - spv_target_env env) { - std::string header = - spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap); +std::string GetReachableMergeAndContinue(SpvCapability cap) { + std::string header = GetDefaultHeader(cap); Block entry("entry"); Block branch("branch", SpvOpBranch); @@ -1339,20 +1120,13 @@ std::string GetReachableMergeAndContinue(SpvCapability cap, f >> target; std::string str = header; - if (spvIsWebGPUEnv(env)) { - str += - "OpEntryPoint Fragment %func \"func\"\n" - "OpExecutionMode %func OriginUpperLeft\n"; - } if (cap == SpvCapabilityShader) { branch.AppendBody("OpLoopMerge %merge %target None\n"); body.AppendBody("OpSelectionMerge %f None\n"); } - if (!spvIsWebGPUEnv(env)) - str += nameOps("branch", "merge", "target", "body", "t", "f", - std::make_pair("func", "Main")); - + str += nameOps("branch", "merge", "target", "body", "t", "f", + std::make_pair("func", "Main")); str += types_consts(); str += "%func = OpFunction %voidt None %funct\n"; str += entry >> branch; @@ -1368,21 +1142,12 @@ std::string GetReachableMergeAndContinue(SpvCapability cap, } TEST_P(ValidateCFG, ReachableMergeAndContinue) { - CompileSuccessfully( - GetReachableMergeAndContinue(GetParam(), SPV_ENV_UNIVERSAL_1_0)); + CompileSuccessfully(GetReachableMergeAndContinue(GetParam())); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } -TEST_F(ValidateCFG, WebGPUReachableMergeAndContinue) { - CompileSuccessfully( - GetReachableMergeAndContinue(SpvCapabilityShader, SPV_ENV_WEBGPU_0)); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); -} - -std::string GetUnreachableMergeAndContinue(SpvCapability cap, - spv_target_env env) { - std::string header = - spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap); +std::string GetUnreachableMergeAndContinue(SpvCapability cap) { + std::string header = GetDefaultHeader(cap); Block entry("entry"); Block branch("branch", SpvOpBranch); @@ -1396,20 +1161,13 @@ std::string GetUnreachableMergeAndContinue(SpvCapability cap, body.SetBody("%cond = OpSLessThan %boolt %one %two\n"); std::string str = header; - if (spvIsWebGPUEnv(env)) { - str += - "OpEntryPoint Fragment %func \"func\"\n" - "OpExecutionMode %func OriginUpperLeft\n"; - } if (cap == SpvCapabilityShader) { branch.AppendBody("OpLoopMerge %merge %target None\n"); body.AppendBody("OpSelectionMerge %target None\n"); } - if (!spvIsWebGPUEnv(env)) - str += nameOps("branch", "merge", "target", "body", "t", "f", - std::make_pair("func", "Main")); - + str += nameOps("branch", "merge", "target", "body", "t", "f", + std::make_pair("func", "Main")); str += types_consts(); str += "%func = OpFunction %voidt None %funct\n"; str += entry >> branch; @@ -1425,36 +1183,19 @@ std::string GetUnreachableMergeAndContinue(SpvCapability cap, } TEST_P(ValidateCFG, UnreachableMergeAndContinue) { - CompileSuccessfully( - GetUnreachableMergeAndContinue(GetParam(), SPV_ENV_UNIVERSAL_1_0)); + CompileSuccessfully(GetUnreachableMergeAndContinue(GetParam())); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } -TEST_F(ValidateCFG, WebGPUUnreachableMergeAndContinue) { - CompileSuccessfully( - GetUnreachableMergeAndContinue(SpvCapabilityShader, SPV_ENV_WEBGPU_0)); - ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("unreachable merge-blocks must terminate with OpUnreachable")); -} - -std::string GetUnreachableBlock(SpvCapability cap, spv_target_env env) { - std::string header = - spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap); +std::string GetUnreachableBlock(SpvCapability cap) { + std::string header = GetDefaultHeader(cap); Block entry("entry"); Block unreachable("unreachable"); Block exit("exit", SpvOpReturn); std::string str = header; - if (spvIsWebGPUEnv(env)) { - str += - "OpEntryPoint Fragment %func \"func\"\n" - "OpExecutionMode %func OriginUpperLeft\n"; - } - if (!spvIsWebGPUEnv(env)) - str += nameOps("unreachable", "exit", std::make_pair("func", "Main")); + str += nameOps("unreachable", "exit", std::make_pair("func", "Main")); str += types_consts(); str += "%func = OpFunction %voidt None %funct\n"; str += entry >> exit; @@ -1466,20 +1207,12 @@ std::string GetUnreachableBlock(SpvCapability cap, spv_target_env env) { } TEST_P(ValidateCFG, UnreachableBlock) { - CompileSuccessfully(GetUnreachableBlock(GetParam(), SPV_ENV_UNIVERSAL_1_0)); + CompileSuccessfully(GetUnreachableBlock(GetParam())); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } -TEST_F(ValidateCFG, WebGPUUnreachableBlock) { - CompileSuccessfully( - GetUnreachableBlock(SpvCapabilityShader, SPV_ENV_WEBGPU_0)); - ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), HasSubstr("all blocks must be reachable")); -} - -std::string GetUnreachableBranch(SpvCapability cap, spv_target_env env) { - std::string header = - spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap); +std::string GetUnreachableBranch(SpvCapability cap) { + std::string header = GetDefaultHeader(cap); Block entry("entry"); Block unreachable("unreachable", SpvOpBranchConditional); @@ -1493,13 +1226,7 @@ std::string GetUnreachableBranch(SpvCapability cap, spv_target_env env) { unreachable.AppendBody("OpSelectionMerge %merge None\n"); std::string str = header; - if (spvIsWebGPUEnv(env)) { - str += - "OpEntryPoint Fragment %func \"func\"\n" - "OpExecutionMode %func OriginUpperLeft\n"; - } - if (!spvIsWebGPUEnv(env)) - str += nameOps("unreachable", "exit", std::make_pair("func", "Main")); + str += nameOps("unreachable", "exit", std::make_pair("func", "Main")); str += types_consts(); str += "%func = OpFunction %voidt None %funct\n"; @@ -1516,17 +1243,10 @@ std::string GetUnreachableBranch(SpvCapability cap, spv_target_env env) { } TEST_P(ValidateCFG, UnreachableBranch) { - CompileSuccessfully(GetUnreachableBranch(GetParam(), SPV_ENV_UNIVERSAL_1_0)); + CompileSuccessfully(GetUnreachableBranch(GetParam())); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } -TEST_F(ValidateCFG, WebGPUUnreachableBranch) { - CompileSuccessfully( - GetUnreachableBranch(SpvCapabilityShader, SPV_ENV_WEBGPU_0)); - ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), HasSubstr("all blocks must be reachable")); -} - TEST_P(ValidateCFG, EmptyFunction) { std::string str = GetDefaultHeader(GetParam()) + std::string(types_consts()) + R"(%func = OpFunction %voidt None %funct diff --git a/test/val/val_code_generator.cpp b/test/val/val_code_generator.cpp index 96971f9b..f151f51a 100644 --- a/test/val/val_code_generator.cpp +++ b/test/val/val_code_generator.cpp @@ -32,13 +32,6 @@ OpCapability SampleRateShading )"; } -std::string GetWebGPUShaderCapabilities() { - return R"( -OpCapability Shader -OpCapability VulkanMemoryModelKHR -)"; -} - std::string GetDefaultShaderTypes() { return R"( %void = OpTypeVoid @@ -127,55 +120,6 @@ std::string GetDefaultShaderTypes() { )"; } -std::string GetWebGPUShaderTypes() { - return R"( -%void = OpTypeVoid -%func = OpTypeFunction %void -%bool = OpTypeBool -%f32 = OpTypeFloat 32 -%u32 = OpTypeInt 32 0 -%f32vec2 = OpTypeVector %f32 2 -%f32vec3 = OpTypeVector %f32 3 -%f32vec4 = OpTypeVector %f32 4 -%u32vec2 = OpTypeVector %u32 2 -%u32vec3 = OpTypeVector %u32 3 -%u32vec4 = OpTypeVector %u32 4 - -%f32_0 = OpConstant %f32 0 -%f32_1 = OpConstant %f32 1 -%f32_2 = OpConstant %f32 2 -%f32_3 = OpConstant %f32 3 -%f32_4 = OpConstant %f32 4 -%f32_h = OpConstant %f32 0.5 -%f32vec2_01 = OpConstantComposite %f32vec2 %f32_0 %f32_1 -%f32vec2_12 = OpConstantComposite %f32vec2 %f32_1 %f32_2 -%f32vec3_012 = OpConstantComposite %f32vec3 %f32_0 %f32_1 %f32_2 -%f32vec3_123 = OpConstantComposite %f32vec3 %f32_1 %f32_2 %f32_3 -%f32vec4_0123 = OpConstantComposite %f32vec4 %f32_0 %f32_1 %f32_2 %f32_3 -%f32vec4_1234 = OpConstantComposite %f32vec4 %f32_1 %f32_2 %f32_3 %f32_4 - -%u32_0 = OpConstant %u32 0 -%u32_1 = OpConstant %u32 1 -%u32_2 = OpConstant %u32 2 -%u32_3 = OpConstant %u32 3 -%u32_4 = OpConstant %u32 4 - -%u32vec2_01 = OpConstantComposite %u32vec2 %u32_0 %u32_1 -%u32vec2_12 = OpConstantComposite %u32vec2 %u32_1 %u32_2 -%u32vec4_0123 = OpConstantComposite %u32vec4 %u32_0 %u32_1 %u32_2 %u32_3 - -%u32arr2 = OpTypeArray %u32 %u32_2 -%u32arr3 = OpTypeArray %u32 %u32_3 -%u32arr4 = OpTypeArray %u32 %u32_4 -%f32arr2 = OpTypeArray %f32 %u32_2 -%f32arr3 = OpTypeArray %f32 %u32_3 -%f32arr4 = OpTypeArray %f32 %u32_4 - -%f32vec3arr3 = OpTypeArray %f32vec3 %u32_3 -%f32vec4arr3 = OpTypeArray %f32vec4 %u32_3 -)"; -} - } // namespace CodeGenerator CodeGenerator::GetDefaultShaderCodeGenerator() { @@ -186,15 +130,6 @@ CodeGenerator CodeGenerator::GetDefaultShaderCodeGenerator() { return generator; } -CodeGenerator CodeGenerator::GetWebGPUShaderCodeGenerator() { - CodeGenerator generator; - generator.capabilities_ = GetWebGPUShaderCapabilities(); - generator.memory_model_ = "OpMemoryModel Logical VulkanKHR\n"; - generator.extensions_ = "OpExtension \"SPV_KHR_vulkan_memory_model\"\n"; - generator.types_ = GetWebGPUShaderTypes(); - return generator; -} - std::string CodeGenerator::Build() const { std::ostringstream ss; diff --git a/test/val/val_code_generator.h b/test/val/val_code_generator.h index e580ddff..c69deeec 100644 --- a/test/val/val_code_generator.h +++ b/test/val/val_code_generator.h @@ -31,7 +31,6 @@ struct EntryPoint { class CodeGenerator { public: static CodeGenerator GetDefaultShaderCodeGenerator(); - static CodeGenerator GetWebGPUShaderCodeGenerator(); std::string Build() const; diff --git a/test/val/val_data_test.cpp b/test/val/val_data_test.cpp index 99a9aa09..1d4c0e04 100644 --- a/test/val/val_data_test.cpp +++ b/test/val/val_data_test.cpp @@ -36,24 +36,6 @@ std::string HeaderWith(std::string cap) { cap + " OpMemoryModel Logical GLSL450 "; } -std::string WebGPUHeaderWith(std::string cap) { - return R"( -OpCapability Shader -OpCapability )" + - cap + R"( -OpCapability VulkanMemoryModelKHR -OpExtension "SPV_KHR_vulkan_memory_model" -OpMemoryModel Logical VulkanKHR -)"; -} - -std::string webgpu_header = R"( -OpCapability Shader -OpCapability VulkanMemoryModelKHR -OpExtension "SPV_KHR_vulkan_memory_model" -OpMemoryModel Logical VulkanKHR -)"; - std::string header = R"( OpCapability Shader OpCapability Linkage @@ -267,18 +249,6 @@ TEST_F(ValidateData, int8_with_storage_push_constant_8_good) { EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()) << getDiagnosticString(); } -TEST_F(ValidateData, webgpu_int8_bad) { - std::string str = WebGPUHeaderWith("Int8") + "%2 = OpTypeInt 8 0"; - CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0); - ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY, - ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("Capability Int8 is not allowed by WebGPU specification (or " - "requires extension)\n" - " OpCapability Int8\n")); -} - TEST_F(ValidateData, int16_good) { std::string str = header_with_int16 + "%2 = OpTypeInt 16 1"; CompileSuccessfully(str.c_str()); @@ -338,34 +308,6 @@ TEST_F(ValidateData, int16_bad) { EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_int16_cap_error)); } -TEST_F(ValidateData, webgpu_int16_bad) { - std::string str = WebGPUHeaderWith("Int16") + "%2 = OpTypeInt 16 1"; - CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0); - ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY, - ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("Capability Int16 is not allowed by WebGPU specification (or " - "requires extension)\n" - " OpCapability Int16\n")); -} - -TEST_F(ValidateData, webgpu_int32_good) { - std::string str = webgpu_header + R"( - OpEntryPoint Fragment %func "func" - OpExecutionMode %func OriginUpperLeft -%uint_t = OpTypeInt 32 0 - %void = OpTypeVoid -%func_t = OpTypeFunction %void - %func = OpFunction %void None %func_t - %1 = OpLabel - OpReturn - OpFunctionEnd -)"; - CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); -} - TEST_F(ValidateData, int64_good) { std::string str = header_with_int64 + "%2 = OpTypeInt 64 1"; CompileSuccessfully(str.c_str()); @@ -379,18 +321,6 @@ TEST_F(ValidateData, int64_bad) { EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_int64_cap_error)); } -TEST_F(ValidateData, webgpu_int64_bad) { - std::string str = WebGPUHeaderWith("Int64") + "%2 = OpTypeInt 64 1"; - CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0); - ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY, - ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("Capability Int64 is not allowed by WebGPU specification (or " - "requires extension)\n" - " OpCapability Int64\n")); -} - // Number of bits in an integer may be only one of: {8,16,32,64} TEST_F(ValidateData, int_invalid_num_bits) { std::string str = header + "%2 = OpTypeInt 48 1"; @@ -418,34 +348,6 @@ TEST_F(ValidateData, float16_bad) { EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_float16_cap_error)); } -TEST_F(ValidateData, webgpu_float16_bad) { - std::string str = WebGPUHeaderWith("Float16") + "%2 = OpTypeFloat 16"; - CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0); - ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY, - ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("Capability Float16 is not allowed by WebGPU specification (or " - "requires extension)\n" - " OpCapability Float16\n")); -} - -TEST_F(ValidateData, webgpu_float32_good) { - std::string str = webgpu_header + R"( - OpEntryPoint Fragment %func "func" - OpExecutionMode %func OriginUpperLeft -%float_t = OpTypeFloat 32 - %void = OpTypeVoid - %func_t = OpTypeFunction %void - %func = OpFunction %void None %func_t - %1 = OpLabel - OpReturn - OpFunctionEnd -)"; - CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); -} - TEST_F(ValidateData, float64_good) { std::string str = header_with_float64 + "%2 = OpTypeFloat 64"; CompileSuccessfully(str.c_str()); @@ -459,18 +361,6 @@ TEST_F(ValidateData, float64_bad) { EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_float64_cap_error)); } -TEST_F(ValidateData, webgpu_float64_bad) { - std::string str = WebGPUHeaderWith("Float64") + "%2 = OpTypeFloat 64"; - CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0); - ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY, - ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("Capability Float64 is not allowed by WebGPU specification (or " - "requires extension)\n" - " OpCapability Float64\n")); -} - // Number of bits in a float may be only one of: {16,32,64} TEST_F(ValidateData, float_invalid_num_bits) { std::string str = header + "%2 = OpTypeFloat 48"; @@ -882,68 +772,6 @@ TEST_F(ValidateData, vulkan_RTA_not_at_end_of_struct) { "OpTypeStruct %_runtimearr_uint %uint\n")); } -TEST_F(ValidateData, webgpu_RTA_array_at_end_of_struct) { - std::string str = R"( - OpCapability Shader - OpCapability VulkanMemoryModelKHR - OpExtension "SPV_KHR_vulkan_memory_model" - OpMemoryModel Logical VulkanKHR - OpEntryPoint Fragment %func "func" - OpExecutionMode %func OriginUpperLeft - OpDecorate %array_t ArrayStride 4 - OpMemberDecorate %struct_t 0 Offset 0 - OpMemberDecorate %struct_t 1 Offset 4 - OpDecorate %struct_t Block - %uint_t = OpTypeInt 32 0 - %array_t = OpTypeRuntimeArray %uint_t - %struct_t = OpTypeStruct %uint_t %array_t -%struct_ptr = OpTypePointer StorageBuffer %struct_t - %2 = OpVariable %struct_ptr StorageBuffer - %void = OpTypeVoid - %func_t = OpTypeFunction %void - %func = OpFunction %void None %func_t - %1 = OpLabel - OpReturn - OpFunctionEnd -)"; - - CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); -} - -TEST_F(ValidateData, webgpu_RTA_not_at_end_of_struct) { - std::string str = R"( - OpCapability Shader - OpCapability VulkanMemoryModelKHR - OpExtension "SPV_KHR_vulkan_memory_model" - OpMemoryModel Logical VulkanKHR - OpEntryPoint Fragment %func "func" - OpExecutionMode %func OriginUpperLeft - OpDecorate %array_t ArrayStride 4 - OpMemberDecorate %struct_t 0 Offset 0 - OpMemberDecorate %struct_t 1 Offset 4 - OpDecorate %struct_t Block - %uint_t = OpTypeInt 32 0 - %array_t = OpTypeRuntimeArray %uint_t - %struct_t = OpTypeStruct %array_t %uint_t -%struct_ptr = OpTypePointer StorageBuffer %struct_t - %2 = OpVariable %struct_ptr StorageBuffer - %void = OpTypeVoid - %func_t = OpTypeFunction %void - %func = OpFunction %void None %func_t - %1 = OpLabel - OpReturn - OpFunctionEnd -)"; - - CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0); - ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("In WebGPU, OpTypeRuntimeArray must only be used for " - "the last member of an OpTypeStruct\n %_struct_3 = " - "OpTypeStruct %_runtimearr_uint %uint\n")); -} - TEST_F(ValidateData, TypeForwardReference) { std::string test = R"( OpCapability Shader diff --git a/test/val/val_decoration_test.cpp b/test/val/val_decoration_test.cpp index 1b68503d..8fe1aa6c 100644 --- a/test/val/val_decoration_test.cpp +++ b/test/val/val_decoration_test.cpp @@ -42,8 +42,6 @@ struct TestResult { }; using ValidateDecorations = spvtest::ValidateBase; -using ValidateWebGPUCombineDecorationResult = - spvtest::ValidateBase>; using ValidateVulkanCombineDecorationResult = spvtest::ValidateBase>; @@ -165,44 +163,6 @@ TEST_F(ValidateDecorations, ValidateGroupDecorateRegistration) { EXPECT_THAT(vstate_->id_decorations(4), Eq(expected_decorations)); } -TEST_F(ValidateDecorations, WebGPUOpDecorationGroupBad) { - std::string spirv = R"( - OpCapability Shader - OpCapability VulkanMemoryModelKHR - OpExtension "SPV_KHR_vulkan_memory_model" - OpMemoryModel Logical VulkanKHR - OpDecorate %1 DescriptorSet 0 - OpDecorate %1 NonWritable - OpDecorate %1 Restrict - %1 = OpDecorationGroup - OpGroupDecorate %1 %2 %3 - OpGroupDecorate %1 %4 - %float = OpTypeFloat 32 -%_runtimearr_float = OpTypeRuntimeArray %float - %_struct_9 = OpTypeStruct %_runtimearr_float -%_ptr_Uniform__struct_9 = OpTypePointer Uniform %_struct_9 - %2 = OpVariable %_ptr_Uniform__struct_9 Uniform - %_struct_10 = OpTypeStruct %_runtimearr_float -%_ptr_Uniform__struct_10 = OpTypePointer Uniform %_struct_10 - %3 = OpVariable %_ptr_Uniform__struct_10 Uniform - %_struct_11 = OpTypeStruct %_runtimearr_float -%_ptr_Uniform__struct_11 = OpTypePointer Uniform %_struct_11 - %4 = OpVariable %_ptr_Uniform__struct_11 Uniform - )"; - CompileSuccessfully(spirv); - EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpDecorationGroup is not allowed in the WebGPU " - "execution environment.\n %1 = OpDecorationGroup\n")); -} - -// For WebGPU, OpGroupDecorate does not have a test case, because it requires -// being preceded by OpDecorationGroup, which will cause a validation error. - -// For WebGPU, OpGroupMemberDecorate does not have a test case, because it -// requires being preceded by OpDecorationGroup, which will cause a validation -// error. - TEST_F(ValidateDecorations, ValidateGroupMemberDecorateRegistration) { std::string spirv = R"( OpCapability Shader @@ -6390,67 +6350,6 @@ TEST_F(ValidateDecorations, NonWritableRuntimeArrayGood) { EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); } -TEST_P(ValidateWebGPUCombineDecorationResult, Decorate) { - const char* const decoration = std::get<0>(GetParam()); - const TestResult& test_result = std::get<1>(GetParam()); - - CodeGenerator generator = CodeGenerator::GetWebGPUShaderCodeGenerator(); - generator.before_types_ = "OpDecorate %u32 "; - generator.before_types_ += decoration; - generator.before_types_ += "\n"; - - EntryPoint entry_point; - entry_point.name = "main"; - entry_point.execution_model = "Vertex"; - generator.entry_points_.push_back(std::move(entry_point)); - - CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0); - ASSERT_EQ(test_result.validation_result, - ValidateInstructions(SPV_ENV_WEBGPU_0)); - if (test_result.error_str != "") { - EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str)); - } -} - -TEST_P(ValidateWebGPUCombineDecorationResult, DecorateMember) { - const char* const decoration = std::get<0>(GetParam()); - const TestResult& test_result = std::get<1>(GetParam()); - - CodeGenerator generator = CodeGenerator::GetWebGPUShaderCodeGenerator(); - generator.before_types_ = "OpMemberDecorate %struct_type 0 "; - generator.before_types_ += decoration; - generator.before_types_ += "\n"; - - generator.after_types_ = "%struct_type = OpTypeStruct %u32\n"; - - EntryPoint entry_point; - entry_point.name = "main"; - entry_point.execution_model = "Vertex"; - generator.entry_points_.push_back(std::move(entry_point)); - - CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0); - ASSERT_EQ(test_result.validation_result, - ValidateInstructions(SPV_ENV_WEBGPU_0)); - if (!test_result.error_str.empty()) { - EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str)); - } -} - -INSTANTIATE_TEST_SUITE_P( - DecorationCapabilityFailure, ValidateWebGPUCombineDecorationResult, - Combine(Values("CPacked", "Patch", "Sample", "Constant", - "SaturatedConversion", "NonUniformEXT"), - Values(TestResult(SPV_ERROR_INVALID_CAPABILITY, - "requires one of these capabilities")))); - -INSTANTIATE_TEST_SUITE_P( - DecorationAllowListFailure, ValidateWebGPUCombineDecorationResult, - Combine(Values("RelaxedPrecision", "BufferBlock", "GLSLShared", - "GLSLPacked", "Invariant", "Volatile", "Coherent"), - Values(TestResult( - SPV_ERROR_INVALID_ID, - "is not valid for the WebGPU execution environment.")))); - TEST_P(ValidateVulkanCombineDecorationResult, Decorate) { const char* const decoration = std::get<0>(GetParam()); const char* const vuid = std::get<1>(GetParam()); diff --git a/test/val/val_id_test.cpp b/test/val/val_id_test.cpp index ad8ebfc6..c65d1715 100644 --- a/test/val/val_id_test.cpp +++ b/test/val/val_id_test.cpp @@ -954,31 +954,6 @@ TEST_P(OpTypeArrayLengthTest, LengthPositiveHugeEnding1InVulkan) { } } -TEST_P(OpTypeArrayLengthTest, LengthPositiveHugeEnding0InWebGPU) { - env_ = SPV_ENV_WEBGPU_0; - const int width = GetParam(); - // WebGPU only has 32 bit integers. - if (width != 32) return; - const int max_int_width = 32; - const auto module = CompileSuccessfully(MakeArrayLength( - big_num_ending_0(width), kUnsigned, width, max_int_width, true)); - EXPECT_EQ(SPV_SUCCESS, Val(module)); -} - -TEST_P(OpTypeArrayLengthTest, LengthPositiveHugeEnding1InWebGPU) { - env_ = SPV_ENV_WEBGPU_0; - const int width = GetParam(); - // WebGPU only has 32 bit integers. - if (width != 32) return; - const int max_int_width = 32; - const auto module = CompileSuccessfully(MakeArrayLength( - big_num_ending_1(width), kUnsigned, width, max_int_width, true)); - EXPECT_EQ(SPV_ERROR_INVALID_ID, - Val(module, - "OpTypeArray Length '3\\[%.*\\]' size exceeds max value " - "2147483648 permitted by WebGPU: got 2147483649")); -} - // The only valid widths for integers are 8, 16, 32, and 64. // Since the Int8 capability requires the Kernel capability, and the Kernel // capability prohibits usage of signed integers, we can skip 8-bit integers @@ -4731,39 +4706,6 @@ TEST_F(ValidateIdWithMessage, OpVectorShuffleLiterals) { "size of 5.")); } -TEST_F(ValidateIdWithMessage, WebGPUOpVectorShuffle0xFFFFFFFFLiteralBad) { - std::string spirv = R"( - OpCapability Shader - OpCapability VulkanMemoryModelKHR - OpExtension "SPV_KHR_vulkan_memory_model" - OpMemoryModel Logical VulkanKHR -%float = OpTypeFloat 32 -%vec2 = OpTypeVector %float 2 -%vec3 = OpTypeVector %float 3 -%vec4 = OpTypeVector %float 4 -%ptr_vec2 = OpTypePointer Function %vec2 -%ptr_vec3 = OpTypePointer Function %vec3 -%float_1 = OpConstant %float 1 -%float_2 = OpConstant %float 2 -%1 = OpConstantComposite %vec2 %float_2 %float_1 -%2 = OpConstantComposite %vec3 %float_1 %float_2 %float_2 -%3 = OpTypeFunction %vec4 -%4 = OpFunction %vec4 None %3 -%5 = OpLabel -%var = OpVariable %ptr_vec2 Function %1 -%var2 = OpVariable %ptr_vec3 Function %2 -%6 = OpLoad %vec2 %var -%7 = OpLoad %vec3 %var2 -%8 = OpVectorShuffle %vec4 %6 %7 4 3 1 0xffffffff - OpReturnValue %8 - OpFunctionEnd)"; - CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0); - EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Component literal at operand 3 cannot be 0xFFFFFFFF in" - " WebGPU execution environment.")); -} - // TODO: OpCompositeConstruct // TODO: OpCompositeExtract // TODO: OpCompositeInsert diff --git a/test/val/val_image_test.cpp b/test/val/val_image_test.cpp index dc093213..bcee6231 100644 --- a/test/val/val_image_test.cpp +++ b/test/val/val_image_test.cpp @@ -454,26 +454,6 @@ std::string TrivialMain() { )"; } -std::string GetWebGPUShaderHeader() { - return R"( - OpCapability Shader - OpMemoryModel Logical GLSL450 - OpEntryPoint GLCompute %main "main" - OpExecutionMode %main LocalSize 1 1 1 - %void = OpTypeVoid - %func = OpTypeFunction %void - %f32 = OpTypeFloat 32 - %u32 = OpTypeInt 32 0 - %f32vec2 = OpTypeVector %f32 2 - %f32vec3 = OpTypeVector %f32 3 - %f32vec4 = OpTypeVector %f32 4 - %u32vec2 = OpTypeVector %u32 2 - %u32vec3 = OpTypeVector %u32 3 - %u32vec4 = OpTypeVector %u32 4 - %u32vec2null = OpConstantNull %u32vec2 - )"; -} - std::string GetShaderHeader(const std::string& capabilities_and_extensions = "", bool include_entry_point = true) { std::ostringstream ss; @@ -833,37 +813,6 @@ TEST_F(ValidateImage, TypeImage_Vulkan_Sampled0_Invalid) { HasSubstr("Sampled must be 1 or 2 in the Vulkan environment.")); } -TEST_F(ValidateImage, TypeImage_WebGPU_Sampled1_OK) { - const std::string code = GetWebGPUShaderHeader() + R"( -%img_type = OpTypeImage %f32 2D 0 0 0 1 Unknown -)" + TrivialMain(); - - CompileSuccessfully(code.c_str()); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), Eq("")); -} - -TEST_F(ValidateImage, TypeImage_WebGPU_Sampled2_OK) { - const std::string code = GetWebGPUShaderHeader() + R"( -%img_type = OpTypeImage %f32 2D 0 0 0 2 Rgba32f -)" + TrivialMain(); - - CompileSuccessfully(code.c_str()); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), Eq("")); -} - -TEST_F(ValidateImage, TypeImage_WebGPU_Sampled0_Invalid) { - const std::string code = GetWebGPUShaderHeader() + R"( -%img_type = OpTypeImage %f32 2D 0 0 0 0 Unknown -)" + TrivialMain(); - - CompileSuccessfully(code.c_str()); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Sampled must be 1 or 2 in the WebGPU environment.")); -} - TEST_F(ValidateImage, TypeImageWrongFormatForSubpassData) { const std::string code = GetShaderHeader("OpCapability InputAttachment\n", false) + @@ -3322,26 +3271,6 @@ TEST_F(ValidateImage, ReadWrongNumComponentsResultType_Vulkan) { HasSubstr("Expected Result Type to have 4 components")); } -TEST_F(ValidateImage, ReadWrongNumComponentsResultType_WebGPU) { - const std::string code = GetWebGPUShaderHeader() + R"( -%img_type = OpTypeImage %f32 2D 0 0 0 2 Unknown -%ptr_type = OpTypePointer UniformConstant %img_type -%var = OpVariable %ptr_type UniformConstant -%main = OpFunction %void None %func -%entry = OpLabel -%img = OpLoad %img_type %var -%res1 = OpImageRead %u32vec3 %img %u32vec2null -OpReturn -OpFunctionEnd -)"; - - CompileSuccessfully(code.c_str()); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)) - << getDiagnosticString(); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Expected Result Type to have 4 components")); -} - TEST_F(ValidateImage, ReadNotImage) { const std::string body = R"( %sampler = OpLoad %type_sampler %uniform_sampler diff --git a/test/val/val_layout_test.cpp b/test/val/val_layout_test.cpp index 43fa0469..d34c97f9 100644 --- a/test/val/val_layout_test.cpp +++ b/test/val/val_layout_test.cpp @@ -667,57 +667,6 @@ TEST_F(ValidateLayout, ModuleProcessedInvalidInBasicBlock) { HasSubstr("ModuleProcessed cannot appear in a function declaration")); } -TEST_F(ValidateLayout, WebGPUCallerBeforeCalleeBad) { - char str[] = R"( - OpCapability Shader - OpCapability VulkanMemoryModelKHR - OpExtension "SPV_KHR_vulkan_memory_model" - OpMemoryModel Logical VulkanKHR - OpEntryPoint GLCompute %main "main" -%void = OpTypeVoid -%voidfn = OpTypeFunction %void -%main = OpFunction %void None %voidfn -%1 = OpLabel -%2 = OpFunctionCall %void %callee - OpReturn - OpFunctionEnd -%callee = OpFunction %void None %voidfn -%3 = OpLabel - OpReturn - OpFunctionEnd -)"; - - CompileSuccessfully(str, SPV_ENV_WEBGPU_0); - ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("For WebGPU, functions need to be defined before being " - "called.\n %5 = OpFunctionCall %void %6\n")); -} - -TEST_F(ValidateLayout, WebGPUCalleeBeforeCallerGood) { - char str[] = R"( - OpCapability Shader - OpCapability VulkanMemoryModelKHR - OpExtension "SPV_KHR_vulkan_memory_model" - OpMemoryModel Logical VulkanKHR - OpEntryPoint GLCompute %main "main" -%void = OpTypeVoid -%voidfn = OpTypeFunction %void -%callee = OpFunction %void None %voidfn -%3 = OpLabel - OpReturn - OpFunctionEnd -%main = OpFunction %void None %voidfn -%1 = OpLabel -%2 = OpFunctionCall %void %callee - OpReturn - OpFunctionEnd -)"; - - CompileSuccessfully(str, SPV_ENV_WEBGPU_0); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); -} - // TODO(umar): Test optional instructions } // namespace diff --git a/test/val/val_memory_test.cpp b/test/val/val_memory_test.cpp index 6d6b8983..8142f859 100644 --- a/test/val/val_memory_test.cpp +++ b/test/val/val_memory_test.cpp @@ -362,192 +362,6 @@ OpFunctionEnd EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); } -TEST_F(ValidateMemory, WebGPUInitializerWithOutputStorageClassesGood) { - std::string spirv = R"( -OpCapability Shader -OpCapability VulkanMemoryModelKHR -OpExtension "SPV_KHR_vulkan_memory_model" -OpMemoryModel Logical VulkanKHR -OpEntryPoint Fragment %func "func" -OpExecutionMode %func OriginUpperLeft -%float = OpTypeFloat 32 -%float_ptr = OpTypePointer Output %float -%init_val = OpConstant %float 1.0 -%1 = OpVariable %float_ptr Output %init_val -%void = OpTypeVoid -%functy = OpTypeFunction %void -%func = OpFunction %void None %functy -%2 = OpLabel -OpReturn -OpFunctionEnd -)"; - CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0); - EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); -} - -TEST_F(ValidateMemory, WebGPUInitializerWithFunctionStorageClassesGood) { - std::string spirv = R"( -OpCapability Shader -OpCapability VulkanMemoryModelKHR -OpExtension "SPV_KHR_vulkan_memory_model" -OpMemoryModel Logical VulkanKHR -OpEntryPoint Fragment %func "func" -OpExecutionMode %func OriginUpperLeft -%float = OpTypeFloat 32 -%float_ptr = OpTypePointer Function %float -%init_val = OpConstant %float 1.0 -%void = OpTypeVoid -%functy = OpTypeFunction %void -%func = OpFunction %void None %functy -%1 = OpLabel -%2 = OpVariable %float_ptr Function %init_val -OpReturn -OpFunctionEnd -)"; - CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0); - EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); -} - -TEST_F(ValidateMemory, WebGPUInitializerWithPrivateStorageClassesGood) { - std::string spirv = R"( -OpCapability Shader -OpCapability VulkanMemoryModelKHR -OpExtension "SPV_KHR_vulkan_memory_model" -OpMemoryModel Logical VulkanKHR -OpEntryPoint Fragment %func "func" -OpExecutionMode %func OriginUpperLeft -%float = OpTypeFloat 32 -%float_ptr = OpTypePointer Private %float -%init_val = OpConstant %float 1.0 -%1 = OpVariable %float_ptr Private %init_val -%void = OpTypeVoid -%functy = OpTypeFunction %void -%func = OpFunction %void None %functy -%2 = OpLabel -OpReturn -OpFunctionEnd -)"; - CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0); - EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); -} - -TEST_F(ValidateMemory, WebGPUInitializerWithDisallowedStorageClassesBad) { - std::string spirv = R"( -OpCapability Shader -OpCapability VulkanMemoryModelKHR -OpExtension "SPV_KHR_vulkan_memory_model" -OpMemoryModel Logical VulkanKHR -OpEntryPoint Fragment %func "func" -OpExecutionMode %func OriginUpperLeft -%float = OpTypeFloat 32 -%float_ptr = OpTypePointer Uniform %float -%init_val = OpConstant %float 1.0 -%1 = OpVariable %float_ptr Uniform %init_val -%void = OpTypeVoid -%functy = OpTypeFunction %void -%func = OpFunction %void None %functy -%2 = OpLabel -OpReturn -OpFunctionEnd -)"; - CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0); - EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("OpVariable, '5[%5]', has a disallowed initializer & " - "storage class combination.\nFrom WebGPU spec:\nVariable " - "declarations that include initializers must have one of the " - "following storage classes: Output, Private, or Function\n %5 " - "= OpVariable %_ptr_Uniform_float Uniform %float_1\n")); -} - -TEST_F(ValidateMemory, WebGPUOutputStorageClassWithoutInitializerBad) { - std::string spirv = R"( -OpCapability Shader -OpCapability VulkanMemoryModelKHR -OpExtension "SPV_KHR_vulkan_memory_model" -OpMemoryModel Logical VulkanKHR -OpEntryPoint Fragment %func "func" -OpExecutionMode %func OriginUpperLeft -%float = OpTypeFloat 32 -%float_ptr = OpTypePointer Output %float -%1 = OpVariable %float_ptr Output -%void = OpTypeVoid -%functy = OpTypeFunction %void -%func = OpFunction %void None %functy -%2 = OpLabel -OpReturn -OpFunctionEnd -)"; - CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0); - EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("OpVariable, '4[%4]', must have an initializer.\n" - "From WebGPU execution environment spec:\n" - "All variables in the following storage classes must have an " - "initializer: Output, Private, or Function\n" - " %4 = OpVariable %_ptr_Output_float Output\n")); -} - -TEST_F(ValidateMemory, WebGPUFunctionStorageClassWithoutInitializerBad) { - std::string spirv = R"( -OpCapability Shader -OpCapability VulkanMemoryModelKHR -OpExtension "SPV_KHR_vulkan_memory_model" -OpMemoryModel Logical VulkanKHR -OpEntryPoint Fragment %func "func" -OpExecutionMode %func OriginUpperLeft -%float = OpTypeFloat 32 -%float_ptr = OpTypePointer Function %float -%void = OpTypeVoid -%functy = OpTypeFunction %void -%func = OpFunction %void None %functy -%1 = OpLabel -%2 = OpVariable %float_ptr Function -OpReturn -OpFunctionEnd -)"; - CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0); - EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("OpVariable, '7[%7]', must have an initializer.\n" - "From WebGPU execution environment spec:\n" - "All variables in the following storage classes must have an " - "initializer: Output, Private, or Function\n" - " %7 = OpVariable %_ptr_Function_float Function\n")); -} - -TEST_F(ValidateMemory, WebGPUPrivateStorageClassWithoutInitializerBad) { - std::string spirv = R"( -OpCapability Shader -OpCapability VulkanMemoryModelKHR -OpExtension "SPV_KHR_vulkan_memory_model" -OpMemoryModel Logical VulkanKHR -OpEntryPoint Fragment %func "func" -OpExecutionMode %func OriginUpperLeft -%float = OpTypeFloat 32 -%float_ptr = OpTypePointer Private %float -%1 = OpVariable %float_ptr Private -%void = OpTypeVoid -%functy = OpTypeFunction %void -%func = OpFunction %void None %functy -%2 = OpLabel -OpReturn -OpFunctionEnd -)"; - CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0); - EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("OpVariable, '4[%4]', must have an initializer.\n" - "From WebGPU execution environment spec:\n" - "All variables in the following storage classes must have an " - "initializer: Output, Private, or Function\n" - " %4 = OpVariable %_ptr_Private_float Private\n")); -} - TEST_F(ValidateMemory, VulkanInitializerWithOutputStorageClassesGood) { std::string spirv = R"( OpCapability Shader @@ -2282,38 +2096,6 @@ OpFunctionEnd "%_ptr_UniformConstant__runtimearr_2 UniformConstant\n")); } -TEST_F(ValidateMemory, WebGPURTAOutsideOfStructBad) { - std::string spirv = R"( -OpCapability Shader -OpCapability VulkanMemoryModelKHR -OpExtension "SPV_KHR_vulkan_memory_model" -OpMemoryModel Logical VulkanKHR -OpEntryPoint Fragment %func "func" -OpExecutionMode %func OriginUpperLeft -%sampler_t = OpTypeSampler -%array_t = OpTypeRuntimeArray %sampler_t -%array_ptr = OpTypePointer UniformConstant %array_t -%2 = OpVariable %array_ptr UniformConstant -%void = OpTypeVoid -%func_t = OpTypeFunction %void -%func = OpFunction %void None %func_t -%1 = OpLabel -OpReturn -OpFunctionEnd -)"; - - CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0); - EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr( - "OpVariable, '5[%5]', is attempting to create memory for an " - "illegal type, OpTypeRuntimeArray.\nFor WebGPU OpTypeRuntimeArray " - "can only appear as the final member of an OpTypeStruct, thus cannot " - "be instantiated via OpVariable\n %5 = OpVariable " - "%_ptr_UniformConstant__runtimearr_2 UniformConstant\n")); -} - TEST_F(ValidateMemory, VulkanRTAOutsideOfStructWithRuntimeDescriptorArrayGood) { std::string spirv = R"( OpCapability Shader @@ -2403,34 +2185,6 @@ OpFunctionEnd EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1)); } -TEST_F(ValidateMemory, WebGPURTAInsideStorageBufferStructGood) { - std::string spirv = R"( -OpCapability Shader -OpCapability VulkanMemoryModelKHR -OpExtension "SPV_KHR_vulkan_memory_model" -OpMemoryModel Logical VulkanKHR -OpEntryPoint Fragment %func "func" -OpExecutionMode %func OriginUpperLeft -OpDecorate %array_t ArrayStride 4 -OpMemberDecorate %struct_t 0 Offset 0 -OpDecorate %struct_t Block -%uint_t = OpTypeInt 32 0 -%array_t = OpTypeRuntimeArray %uint_t -%struct_t = OpTypeStruct %array_t -%struct_ptr = OpTypePointer StorageBuffer %struct_t -%2 = OpVariable %struct_ptr StorageBuffer -%void = OpTypeVoid -%func_t = OpTypeFunction %void -%func = OpFunction %void None %func_t -%1 = OpLabel -OpReturn -OpFunctionEnd -)"; - - CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0); - EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); -} - TEST_F(ValidateMemory, VulkanRTAInsideWrongStorageClassStructBad) { std::string spirv = R"( OpCapability Shader @@ -2460,36 +2214,6 @@ OpFunctionEnd "OpVariable %_ptr_Workgroup__struct_4 Workgroup\n")); } -TEST_F(ValidateMemory, WebGPURTAInsideWrongStorageClassStructBad) { - std::string spirv = R"( -OpCapability Shader -OpCapability VulkanMemoryModelKHR -OpExtension "SPV_KHR_vulkan_memory_model" -OpMemoryModel Logical VulkanKHR -OpEntryPoint Fragment %func "func" -OpExecutionMode %func OriginUpperLeft -%uint_t = OpTypeInt 32 0 -%array_t = OpTypeRuntimeArray %uint_t -%struct_t = OpTypeStruct %array_t -%struct_ptr = OpTypePointer Workgroup %struct_t -%2 = OpVariable %struct_ptr Workgroup -%void = OpTypeVoid -%func_t = OpTypeFunction %void -%func = OpFunction %void None %func_t -%1 = OpLabel -OpReturn -OpFunctionEnd -)"; - - CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0); - EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("For WebGPU, OpTypeStruct variables containing " - "OpTypeRuntimeArray must have storage class of StorageBuffer\n " - " %6 = OpVariable %_ptr_Workgroup__struct_4 Workgroup\n")); -} - TEST_F(ValidateMemory, VulkanRTAInsideStorageBufferStructWithoutBlockBad) { std::string spirv = R"( OpCapability Shader @@ -2518,36 +2242,6 @@ OpFunctionEnd "%_ptr_StorageBuffer__struct_4 StorageBuffer\n")); } -TEST_F(ValidateMemory, WebGPURTAInsideStorageBufferStructWithoutBlockBad) { - std::string spirv = R"( -OpCapability Shader -OpCapability VulkanMemoryModelKHR -OpExtension "SPV_KHR_vulkan_memory_model" -OpMemoryModel Logical VulkanKHR -OpEntryPoint Fragment %func "func" -OpExecutionMode %func OriginUpperLeft -%uint_t = OpTypeInt 32 0 -%array_t = OpTypeRuntimeArray %uint_t -%struct_t = OpTypeStruct %array_t -%struct_ptr = OpTypePointer StorageBuffer %struct_t -%2 = OpVariable %struct_ptr StorageBuffer -%void = OpTypeVoid -%func_t = OpTypeFunction %void -%func = OpFunction %void None %func_t -%1 = OpLabel -OpReturn -OpFunctionEnd -)"; - - CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0); - EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("For WebGPU, an OpTypeStruct variable containing an " - "OpTypeRuntimeArray must be decorated with Block if it " - "has storage class StorageBuffer.\n %6 = OpVariable " - "%_ptr_StorageBuffer__struct_4 StorageBuffer\n")); -} - TEST_F(ValidateMemory, VulkanRTAInsideUniformStructGood) { std::string spirv = R"( OpCapability Shader @@ -2574,39 +2268,6 @@ OpFunctionEnd EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1)); } -TEST_F(ValidateMemory, WebGPURTAInsideUniformStructBad) { - std::string spirv = R"( -OpCapability Shader -OpCapability VulkanMemoryModelKHR -OpExtension "SPV_KHR_vulkan_memory_model" -OpMemoryModel Logical VulkanKHR -OpEntryPoint Fragment %func "func" -OpExecutionMode %func OriginUpperLeft -OpDecorate %array_t ArrayStride 4 -OpMemberDecorate %struct_t 0 Offset 0 -OpDecorate %struct_t Block -%uint_t = OpTypeInt 32 0 -%array_t = OpTypeRuntimeArray %uint_t -%struct_t = OpTypeStruct %array_t -%struct_ptr = OpTypePointer Uniform %struct_t -%2 = OpVariable %struct_ptr Uniform -%void = OpTypeVoid -%func_t = OpTypeFunction %void -%func = OpFunction %void None %func_t -%1 = OpLabel -OpReturn -OpFunctionEnd -)"; - - CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0); - EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("For WebGPU, OpTypeStruct variables containing " - "OpTypeRuntimeArray must have storage class of StorageBuffer\n " - " %6 = OpVariable %_ptr_Uniform__struct_3 Uniform\n")); -} - TEST_F(ValidateMemory, VulkanRTAInsideUniformStructWithoutBufferBlockBad) { std::string spirv = R"( OpCapability Shader @@ -2664,37 +2325,6 @@ OpFunctionEnd "OpTypeRuntimeArray %_runtimearr_2\n")); } -TEST_F(ValidateMemory, WebGPURTAInsideRTABad) { - std::string spirv = R"( -OpCapability Shader -OpCapability VulkanMemoryModelKHR -OpExtension "SPV_KHR_vulkan_memory_model" -OpMemoryModel Logical VulkanKHR -OpEntryPoint Fragment %func "func" -OpExecutionMode %func OriginUpperLeft -%sampler_t = OpTypeSampler -%inner_array_t = OpTypeRuntimeArray %sampler_t -%array_t = OpTypeRuntimeArray %inner_array_t -%array_ptr = OpTypePointer UniformConstant %array_t -%2 = OpVariable %array_ptr UniformConstant -%void = OpTypeVoid -%func_t = OpTypeFunction %void -%func = OpFunction %void None %func_t -%1 = OpLabel -OpReturn -OpFunctionEnd -)"; - - CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0); - EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr( - "OpTypeRuntimeArray Element Type '3[%_runtimearr_2]' is not " - "valid in WebGPU environments.\n %_runtimearr__runtimearr_2 = " - "OpTypeRuntimeArray %_runtimearr_2\n")); -} - TEST_F(ValidateMemory, VulkanRTAInsideRTAWithRuntimeDescriptorArrayBad) { std::string spirv = R"( OpCapability RuntimeDescriptorArrayEXT @@ -2855,38 +2485,6 @@ OpFunctionEnd "OpTypeArray %_runtimearr_4 %uint_1\n")); } -TEST_F(ValidateMemory, WebGPURTAInsideArrayBad) { - std::string spirv = R"( -OpCapability Shader -OpCapability VulkanMemoryModelKHR -OpExtension "SPV_KHR_vulkan_memory_model" -OpMemoryModel Logical VulkanKHR -OpEntryPoint Fragment %func "func" -OpExecutionMode %func OriginUpperLeft -%uint_t = OpTypeInt 32 0 -%dim = OpConstant %uint_t 1 -%sampler_t = OpTypeSampler -%inner_array_t = OpTypeRuntimeArray %sampler_t -%array_t = OpTypeArray %inner_array_t %dim -%array_ptr = OpTypePointer UniformConstant %array_t -%2 = OpVariable %array_ptr UniformConstant -%void = OpTypeVoid -%func_t = OpTypeFunction %void -%func = OpFunction %void None %func_t -%1 = OpLabel -OpReturn -OpFunctionEnd -)"; - - CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0); - EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("OpTypeArray Element Type '5[%_runtimearr_4]' is not " - "valid in WebGPU environments.\n %_arr__runtimearr_4_uint_1 = " - "OpTypeArray %_runtimearr_4 %uint_1\n")); -} - TEST_F(ValidateMemory, VulkanRTAInsideArrayWithRuntimeDescriptorArrayBad) { std::string spirv = R"( OpCapability RuntimeDescriptorArrayEXT diff --git a/test/val/val_modes_test.cpp b/test/val/val_modes_test.cpp index 7980c937..7b231594 100644 --- a/test/val/val_modes_test.cpp +++ b/test/val/val_modes_test.cpp @@ -535,24 +535,16 @@ TEST_P(ValidateModeExecution, ExecutionMode) { std::ostringstream sstr; sstr << "OpCapability Shader\n"; - if (!spvIsWebGPUEnv(env)) { - sstr << "OpCapability Geometry\n"; - sstr << "OpCapability Tessellation\n"; - sstr << "OpCapability TransformFeedback\n"; - } - if (!spvIsVulkanOrWebGPUEnv(env)) { + sstr << "OpCapability Geometry\n"; + sstr << "OpCapability Tessellation\n"; + sstr << "OpCapability TransformFeedback\n"; + if (!spvIsVulkanEnv(env)) { sstr << "OpCapability Kernel\n"; if (env == SPV_ENV_UNIVERSAL_1_3) { sstr << "OpCapability SubgroupDispatch\n"; } } - if (spvIsWebGPUEnv(env)) { - sstr << "OpCapability VulkanMemoryModelKHR\n"; - sstr << "OpExtension \"SPV_KHR_vulkan_memory_model\"\n"; - sstr << "OpMemoryModel Logical VulkanKHR\n"; - } else { - sstr << "OpMemoryModel Logical GLSL450\n"; - } + sstr << "OpMemoryModel Logical GLSL450\n"; sstr << "OpEntryPoint " << model << " %main \"main\"\n"; if (mode.find("LocalSizeId") == 0 || mode.find("LocalSizeHintId") == 0 || mode.find("SubgroupsPerWorkgroupId") == 0) { @@ -718,39 +710,6 @@ INSTANTIATE_TEST_SUITE_P( "SubgroupsPerWorkgroup 1", "SubgroupsPerWorkgroupId %int1"), Values(SPV_ENV_UNIVERSAL_1_3))); -INSTANTIATE_TEST_SUITE_P(ValidateModeGLComputeWebGPUAllowListGood, - ValidateModeExecution, - Combine(Values(SPV_SUCCESS), Values(""), - Values("GLCompute"), Values("LocalSize 1 1 1"), - Values(SPV_ENV_WEBGPU_0))); - -INSTANTIATE_TEST_SUITE_P( - ValidateModeGLComputeWebGPUAllowListBad, ValidateModeExecution, - Combine(Values(SPV_ERROR_INVALID_DATA), - Values("Execution mode must be one of OriginUpperLeft, " - "DepthReplacing, DepthGreater, DepthLess, DepthUnchanged, " - "LocalSize, or LocalSizeHint for WebGPU environment"), - Values("GLCompute"), Values("LocalSizeId %int1 %int1 %int1"), - Values(SPV_ENV_WEBGPU_0))); - -INSTANTIATE_TEST_SUITE_P( - ValidateModeFragmentWebGPUAllowListGood, ValidateModeExecution, - Combine(Values(SPV_SUCCESS), Values(""), Values("Fragment"), - Values("OriginUpperLeft", "DepthReplacing", "DepthGreater", - "DepthLess", "DepthUnchanged"), - Values(SPV_ENV_WEBGPU_0))); - -INSTANTIATE_TEST_SUITE_P( - ValidateModeFragmentWebGPUAllowListBad, ValidateModeExecution, - Combine(Values(SPV_ERROR_INVALID_DATA), - Values("Execution mode must be one of OriginUpperLeft, " - "DepthReplacing, DepthGreater, DepthLess, DepthUnchanged, " - "LocalSize, or LocalSizeHint for WebGPU environment"), - Values("Fragment"), - Values("PixelCenterInteger", "OriginLowerLeft", - "EarlyFragmentTests"), - Values(SPV_ENV_WEBGPU_0))); - TEST_F(ValidateModeExecution, MeshNVLocalSize) { const std::string spirv = R"( OpCapability Shader diff --git a/test/val/val_storage_test.cpp b/test/val/val_storage_test.cpp index fe37a93c..e6f98bff 100644 --- a/test/val/val_storage_test.cpp +++ b/test/val/val_storage_test.cpp @@ -250,70 +250,6 @@ TEST_F(ValidateStorage, RelaxedLogicalPointerFunctionParamBad) { HasSubstr("OpFunctionCall Argument '")); } -std::string GetVarDeclStr(const std::string& storage_class) { - if (storage_class != "Output" && storage_class != "Private" && - storage_class != "Function") { - return "%var = OpVariable %ptrt " + storage_class + "\n"; - } else { - return "%var = OpVariable %ptrt " + storage_class + " %null\n"; - } -} - -TEST_P(ValidateStorageClass, WebGPU) { - std::string storage_class = std::get<0>(GetParam()); - bool is_local = std::get<1>(GetParam()); - bool is_valid = std::get<2>(GetParam()); - std::string error = std::get<3>(GetParam()); - - std::string str = R"( - OpCapability Shader - OpCapability VulkanMemoryModelKHR - OpExtension "SPV_KHR_vulkan_memory_model" - OpMemoryModel Logical VulkanKHR - OpEntryPoint Fragment %func "func" - OpExecutionMode %func OriginUpperLeft -%intt = OpTypeInt 32 1 -%voidt = OpTypeVoid -%vfunct = OpTypeFunction %voidt -%null = OpConstantNull %intt -)"; - str += "%ptrt = OpTypePointer " + storage_class + " %intt\n"; - if (!is_local) str += GetVarDeclStr(storage_class); - str += R"( -%func = OpFunction %voidt None %vfunct -%funcl = OpLabel -)"; - if (is_local) str += GetVarDeclStr(storage_class); - str += R"( -OpReturn -OpFunctionEnd -)"; - - CompileSuccessfully(str, SPV_ENV_WEBGPU_0); - if (is_valid) { - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); - } else { - ASSERT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), HasSubstr(error)); - } -} - -INSTANTIATE_TEST_SUITE_P( - StorageClass, ValidateStorageClass, - Values(std::make_tuple("UniformConstant", false, true, ""), - std::make_tuple("Uniform", false, true, ""), - std::make_tuple("StorageBuffer", false, true, ""), - std::make_tuple("Input", false, true, ""), - std::make_tuple("Output", false, true, ""), - std::make_tuple("Image", false, true, ""), - std::make_tuple("Workgroup", false, true, ""), - std::make_tuple("Private", false, true, ""), - std::make_tuple("Function", true, true, ""), - std::make_tuple("CrossWorkgroup", false, false, - "Invalid storage class for target environment"), - std::make_tuple("PushConstant", false, false, - "Invalid storage class for target environment"))); - } // namespace } // namespace val } // namespace spvtools diff --git a/test/val/val_validation_state_test.cpp b/test/val/val_validation_state_test.cpp index 45815790..7a38d3a1 100644 --- a/test/val/val_validation_state_test.cpp +++ b/test/val/val_validation_state_test.cpp @@ -245,12 +245,6 @@ TEST_F(ValidationStateTest, CheckVulkanNonRecursiveBodyGood) { ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1)); } -TEST_F(ValidationStateTest, CheckWebGPUNonRecursiveBodyGood) { - std::string spirv = std::string(kVulkanMemoryHeader) + kNonRecursiveBody; - CompileSuccessfully(spirv, SPV_ENV_WEBGPU_0); - EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(SPV_ENV_WEBGPU_0)); -} - TEST_F(ValidationStateTest, CheckDirectlyRecursiveBodyGood) { std::string spirv = std::string(kHeader) + kDirectlyRecursiveBody; CompileSuccessfully(spirv); @@ -267,16 +261,6 @@ TEST_F(ValidationStateTest, CheckVulkanDirectlyRecursiveBodyBad) { " %1 = OpFunction %void Pure|Const %3\n")); } -TEST_F(ValidationStateTest, CheckWebGPUDirectlyRecursiveBodyBad) { - std::string spirv = std::string(kVulkanMemoryHeader) + kDirectlyRecursiveBody; - CompileSuccessfully(spirv, SPV_ENV_WEBGPU_0); - EXPECT_EQ(SPV_ERROR_INVALID_BINARY, - ValidateAndRetrieveValidationState(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Entry points may not have a call graph with cycles.\n " - " %1 = OpFunction %void Pure|Const %3\n")); -} - TEST_F(ValidationStateTest, CheckIndirectlyRecursiveBodyGood) { std::string spirv = std::string(kHeader) + kIndirectlyRecursiveBody; CompileSuccessfully(spirv); @@ -294,68 +278,6 @@ TEST_F(ValidationStateTest, CheckVulkanIndirectlyRecursiveBodyBad) { " %1 = OpFunction %void Pure|Const %3\n")); } -// Indirectly recursive functions are caught by the function definition layout -// rules, because they cause a situation where there are 2 functions that have -// to be before each other, and layout is checked earlier. -TEST_F(ValidationStateTest, CheckWebGPUIndirectlyRecursiveBodyBad) { - std::string spirv = - std::string(kVulkanMemoryHeader) + kIndirectlyRecursiveBody; - CompileSuccessfully(spirv, SPV_ENV_WEBGPU_0); - EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, - ValidateAndRetrieveValidationState(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("For WebGPU, functions need to be defined before being " - "called.\n %10 = OpFunctionCall %_struct_5 %11\n")); -} - -TEST_F(ValidationStateTest, - CheckWebGPUDuplicateEntryNamesDifferentFunctionsBad) { - std::string spirv = std::string(kVulkanMemoryHeader) + R"( -OpEntryPoint Fragment %func_1 "main" -OpEntryPoint Vertex %func_2 "main" -OpExecutionMode %func_1 OriginUpperLeft -%void = OpTypeVoid -%void_f = OpTypeFunction %void -%func_1 = OpFunction %void None %void_f -%label_1 = OpLabel - OpReturn - OpFunctionEnd -%func_2 = OpFunction %void None %void_f -%label_2 = OpLabel - OpReturn - OpFunctionEnd -)"; - - CompileSuccessfully(spirv, SPV_ENV_WEBGPU_0); - EXPECT_EQ(SPV_ERROR_INVALID_BINARY, - ValidateAndRetrieveValidationState(SPV_ENV_WEBGPU_0)); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("Entry point name \"main\" is not unique, which is not allow " - "in WebGPU env.\n %1 = OpFunction %void None %4\n")); -} - -TEST_F(ValidationStateTest, CheckWebGPUDuplicateEntryNamesSameFunctionBad) { - std::string spirv = std::string(kVulkanMemoryHeader) + R"( -OpEntryPoint GLCompute %func_1 "main" -OpEntryPoint Vertex %func_1 "main" -%void = OpTypeVoid -%void_f = OpTypeFunction %void -%func_1 = OpFunction %void None %void_f -%label_1 = OpLabel - OpReturn - OpFunctionEnd -)"; - - CompileSuccessfully(spirv, SPV_ENV_WEBGPU_0); - EXPECT_EQ(SPV_ERROR_INVALID_BINARY, - ValidateAndRetrieveValidationState(SPV_ENV_WEBGPU_0)); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("Entry point name \"main\" is not unique, which is not allow " - "in WebGPU env.\n %1 = OpFunction %void None %3\n")); -} - } // namespace } // namespace val } // namespace spvtools diff --git a/test/val/val_version_test.cpp b/test/val/val_version_test.cpp index 2b9542a1..98565ddb 100644 --- a/test/val/val_version_test.cpp +++ b/test/val/val_version_test.cpp @@ -40,21 +40,6 @@ OpReturn OpFunctionEnd )"; -const std::string webgpu_spirv = R"( -OpCapability Shader -OpCapability VulkanMemoryModelKHR -OpExtension "SPV_KHR_vulkan_memory_model" -OpMemoryModel Logical VulkanKHR -OpEntryPoint Fragment %func "func" -OpExecutionMode %func OriginUpperLeft -%void = OpTypeVoid -%functy = OpTypeFunction %void -%func = OpFunction %void None %functy -%1 = OpLabel -OpReturn -OpFunctionEnd -)"; - const std::string opencl_spirv = R"( OpCapability Addresses OpCapability Kernel @@ -85,7 +70,6 @@ std::string version(spv_target_env env) { return "1.2"; case SPV_ENV_UNIVERSAL_1_3: case SPV_ENV_VULKAN_1_1: - case SPV_ENV_WEBGPU_0: return "1.3"; case SPV_ENV_UNIVERSAL_1_4: case SPV_ENV_VULKAN_1_1_SPIRV_1_4: @@ -126,7 +110,6 @@ INSTANTIATE_TEST_SUITE_P(Universal, ValidateVersion, std::make_tuple(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_OPENGL_4_2, vulkan_spirv, true), std::make_tuple(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_OPENGL_4_3, vulkan_spirv, true), std::make_tuple(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_OPENGL_4_5, vulkan_spirv, true), - std::make_tuple(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_WEBGPU_0, webgpu_spirv, true), std::make_tuple(SPV_ENV_UNIVERSAL_1_1, SPV_ENV_UNIVERSAL_1_0, vulkan_spirv, false), std::make_tuple(SPV_ENV_UNIVERSAL_1_1, SPV_ENV_UNIVERSAL_1_1, vulkan_spirv, true), @@ -139,7 +122,6 @@ INSTANTIATE_TEST_SUITE_P(Universal, ValidateVersion, std::make_tuple(SPV_ENV_UNIVERSAL_1_1, SPV_ENV_OPENGL_4_2, vulkan_spirv, false), std::make_tuple(SPV_ENV_UNIVERSAL_1_1, SPV_ENV_OPENGL_4_3, vulkan_spirv, false), std::make_tuple(SPV_ENV_UNIVERSAL_1_1, SPV_ENV_OPENGL_4_5, vulkan_spirv, false), - std::make_tuple(SPV_ENV_UNIVERSAL_1_1, SPV_ENV_WEBGPU_0, webgpu_spirv, true), std::make_tuple(SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_0, vulkan_spirv, false), std::make_tuple(SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_1, vulkan_spirv, false), @@ -152,7 +134,6 @@ INSTANTIATE_TEST_SUITE_P(Universal, ValidateVersion, std::make_tuple(SPV_ENV_UNIVERSAL_1_2, SPV_ENV_OPENGL_4_2, vulkan_spirv, false), std::make_tuple(SPV_ENV_UNIVERSAL_1_2, SPV_ENV_OPENGL_4_3, vulkan_spirv, false), std::make_tuple(SPV_ENV_UNIVERSAL_1_2, SPV_ENV_OPENGL_4_5, vulkan_spirv, false), - std::make_tuple(SPV_ENV_UNIVERSAL_1_2, SPV_ENV_WEBGPU_0, webgpu_spirv, true), std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_UNIVERSAL_1_0, vulkan_spirv, false), std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_UNIVERSAL_1_1, vulkan_spirv, false), @@ -164,8 +145,7 @@ INSTANTIATE_TEST_SUITE_P(Universal, ValidateVersion, std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_OPENGL_4_1, vulkan_spirv, false), std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_OPENGL_4_2, vulkan_spirv, false), std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_OPENGL_4_3, vulkan_spirv, false), - std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_OPENGL_4_5, vulkan_spirv, false), - std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_WEBGPU_0, webgpu_spirv, true) + std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_OPENGL_4_5, vulkan_spirv, false) ) ); diff --git a/test/val/val_webgpu_test.cpp b/test/val/val_webgpu_test.cpp deleted file mode 100644 index 62fa6a7a..00000000 --- a/test/val/val_webgpu_test.cpp +++ /dev/null @@ -1,424 +0,0 @@ -// Copyright (c) 2018 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Validation tests for WebGPU env specific checks - -#include - -#include "gmock/gmock.h" -#include "test/val/val_fixtures.h" - -namespace spvtools { -namespace val { -namespace { - -using testing::HasSubstr; - -using ValidateWebGPU = spvtest::ValidateBase; - -TEST_F(ValidateWebGPU, OpUndefIsDisallowed) { - std::string spirv = R"( - OpCapability Shader - OpCapability VulkanMemoryModelKHR - OpExtension "SPV_KHR_vulkan_memory_model" - OpMemoryModel Logical VulkanKHR - OpEntryPoint Vertex %func "shader" -%float = OpTypeFloat 32 -%1 = OpUndef %float -%void = OpTypeVoid -%void_f = OpTypeFunction %void -%func = OpFunction %void None %void_f -%label = OpLabel - OpReturn - OpFunctionEnd -)"; - - CompileSuccessfully(spirv); - - // Control case: OpUndef is allowed in SPIR-V 1.3 - EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); - - // Control case: OpUndef is disallowed in the WebGPU env - EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), HasSubstr("OpUndef is disallowed")); -} - -TEST_F(ValidateWebGPU, OpNameIsAllowed) { - std::string spirv = R"( - OpCapability Shader - OpCapability VulkanMemoryModelKHR - OpExtension "SPV_KHR_vulkan_memory_model" - OpMemoryModel Logical VulkanKHR - OpEntryPoint Vertex %func "shader" - OpName %1 "foo" - %1 = OpTypeFloat 32 - %void = OpTypeVoid - %void_f = OpTypeFunction %void - %func = OpFunction %void None %void_f - %label = OpLabel - OpReturn - OpFunctionEnd -)"; - - CompileSuccessfully(spirv); - EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); -} - -TEST_F(ValidateWebGPU, OpMemberNameIsAllowed) { - std::string spirv = R"( - OpCapability Shader - OpCapability VulkanMemoryModelKHR - OpExtension "SPV_KHR_vulkan_memory_model" - OpMemoryModel Logical VulkanKHR - OpEntryPoint Vertex %func "shader" - OpMemberName %2 0 "foo" - %1 = OpTypeFloat 32 - %2 = OpTypeStruct %1 - %void = OpTypeVoid - %void_f = OpTypeFunction %void - %func = OpFunction %void None %void_f - %label = OpLabel - OpReturn - OpFunctionEnd - -)"; - - CompileSuccessfully(spirv); - EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); -} - -TEST_F(ValidateWebGPU, OpSourceIsAllowed) { - std::string spirv = R"( - OpCapability Shader - OpCapability VulkanMemoryModelKHR - OpExtension "SPV_KHR_vulkan_memory_model" - OpMemoryModel Logical VulkanKHR - OpEntryPoint Vertex %func "shader" - OpSource GLSL 450 - %void = OpTypeVoid - %void_f = OpTypeFunction %void - %func = OpFunction %void None %void_f - %label = OpLabel - OpReturn - OpFunctionEnd -)"; - - CompileSuccessfully(spirv); - EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); -} - -TEST_F(ValidateWebGPU, OpSourceContinuedIsAllowed) { - std::string spirv = R"( - OpCapability Shader - OpCapability VulkanMemoryModelKHR - OpExtension "SPV_KHR_vulkan_memory_model" - OpMemoryModel Logical VulkanKHR - OpEntryPoint Vertex %func "shader" - OpSource GLSL 450 - OpSourceContinued "I am a happy shader! Yay! ;" - %void = OpTypeVoid - %void_f = OpTypeFunction %void - %func = OpFunction %void None %void_f - %label = OpLabel - OpReturn - OpFunctionEnd -)"; - - CompileSuccessfully(spirv); - EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); -} - -TEST_F(ValidateWebGPU, OpSourceExtensionIsAllowed) { - std::string spirv = R"( - OpCapability Shader - OpCapability VulkanMemoryModelKHR - OpExtension "SPV_KHR_vulkan_memory_model" - OpMemoryModel Logical VulkanKHR - OpEntryPoint Vertex %func "shader" - OpSourceExtension "bar" - %void = OpTypeVoid - %void_f = OpTypeFunction %void - %func = OpFunction %void None %void_f - %label = OpLabel - OpReturn - OpFunctionEnd -)"; - - CompileSuccessfully(spirv); - EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); -} - -TEST_F(ValidateWebGPU, OpStringIsAllowed) { - std::string spirv = R"( - OpCapability Shader - OpCapability VulkanMemoryModelKHR - OpExtension "SPV_KHR_vulkan_memory_model" - OpMemoryModel Logical VulkanKHR - OpEntryPoint Vertex %func "shader" - %1 = OpString "foo" - %void = OpTypeVoid - %void_f = OpTypeFunction %void - %func = OpFunction %void None %void_f - %label = OpLabel - OpReturn - OpFunctionEnd -)"; - - CompileSuccessfully(spirv); - EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); -} - -TEST_F(ValidateWebGPU, OpLineIsAllowed) { - std::string spirv = R"( - OpCapability Shader - OpCapability VulkanMemoryModelKHR - OpExtension "SPV_KHR_vulkan_memory_model" - OpMemoryModel Logical VulkanKHR - OpEntryPoint Vertex %func "shader" - %1 = OpString "minimal.vert" - OpLine %1 1 1 - %void = OpTypeVoid - %void_f = OpTypeFunction %void - %func = OpFunction %void None %void_f - %label = OpLabel - OpReturn - OpFunctionEnd -)"; - - CompileSuccessfully(spirv); - EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); -} - -TEST_F(ValidateWebGPU, OpNoLineIsAllowed) { - std::string spirv = R"( - OpCapability Shader - OpCapability VulkanMemoryModelKHR - OpExtension "SPV_KHR_vulkan_memory_model" - OpMemoryModel Logical VulkanKHR - OpEntryPoint Vertex %func "shader" - OpNoLine - %void = OpTypeVoid - %void_f = OpTypeFunction %void - %func = OpFunction %void None %void_f - %label = OpLabel - OpReturn - OpFunctionEnd -)"; - - CompileSuccessfully(spirv); - EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); -} - -TEST_F(ValidateWebGPU, LogicalAddressingVulkanKHRMemoryGood) { - std::string spirv = R"( - OpCapability Shader - OpCapability VulkanMemoryModelKHR - OpExtension "SPV_KHR_vulkan_memory_model" - OpMemoryModel Logical VulkanKHR - OpEntryPoint Vertex %func "shader" -%void = OpTypeVoid -%void_f = OpTypeFunction %void -%func = OpFunction %void None %void_f -%label = OpLabel - OpReturn - OpFunctionEnd -)"; - - CompileSuccessfully(spirv); - EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); -} - -TEST_F(ValidateWebGPU, LogicalAddressingGLSL450MemoryGood) { - std::string spirv = R"( - OpCapability Shader - OpMemoryModel Logical GLSL450 - OpEntryPoint Vertex %func "shader" -%void = OpTypeVoid -%void_f = OpTypeFunction %void -%func = OpFunction %void None %void_f -%label = OpLabel - OpReturn - OpFunctionEnd -)"; - - CompileSuccessfully(spirv); - EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); -} - -TEST_F(ValidateWebGPU, LogicalAddressingSimpleMemoryGood) { - std::string spirv = R"( - OpCapability Shader - OpMemoryModel Logical Simple - OpEntryPoint Vertex %func "shader" -%void = OpTypeVoid -%void_f = OpTypeFunction %void -%func = OpFunction %void None %void_f -%label = OpLabel - OpReturn - OpFunctionEnd -)"; - - CompileSuccessfully(spirv); - EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); -} - -TEST_F(ValidateWebGPU, KernelIsBad) { - std::string spirv = R"( - OpCapability Kernel - OpMemoryModel Logical Simple - OpNoLine -)"; - - CompileSuccessfully(spirv); - - EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, - ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Capability Kernel is not allowed by WebGPU " - "specification (or requires extension)")); -} - -TEST_F(ValidateWebGPU, OpenCLMemoryModelBad) { - std::string spirv = R"( - OpCapability Shader - OpMemoryModel Logical OpenCL - OpNoLine -)"; - - CompileSuccessfully(spirv); - - EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, - ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Operand 2 of MemoryModel requires one of these " - "capabilities: Kernel")); -} - -TEST_F(ValidateWebGPU, AllowListedExtendedInstructionsImportGood) { - std::string spirv = R"( - OpCapability Shader - OpCapability VulkanMemoryModelKHR - OpExtension "SPV_KHR_vulkan_memory_model" -%1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical VulkanKHR - OpEntryPoint Vertex %func "shader" -%void = OpTypeVoid -%void_f = OpTypeFunction %void -%func = OpFunction %void None %void_f -%label = OpLabel - OpReturn - OpFunctionEnd -)"; - - CompileSuccessfully(spirv); - - EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); -} - -TEST_F(ValidateWebGPU, NonAllowListedExtendedInstructionsImportBad) { - std::string spirv = R"( - OpCapability Shader - OpCapability VulkanMemoryModelKHR - OpExtension "SPV_KHR_vulkan_memory_model" -%1 = OpExtInstImport "OpenCL.std" - OpMemoryModel Logical VulkanKHR -)"; - - CompileSuccessfully(spirv); - - EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("For WebGPU, the only valid parameter to " - "OpExtInstImport is \"GLSL.std.450\".\n %1 = " - "OpExtInstImport \"OpenCL.std\"\n")); -} - -TEST_F(ValidateWebGPU, NonVulkanKHRMemoryModelExtensionBad) { - std::string spirv = R"( - OpCapability Shader - OpCapability VulkanMemoryModelKHR - OpExtension "SPV_KHR_8bit_storage" - OpExtension "SPV_KHR_vulkan_memory_model" - OpMemoryModel Logical VulkanKHR -)"; - - CompileSuccessfully(spirv); - - EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("For WebGPU, the only valid parameter to OpExtension " - "is \"SPV_KHR_vulkan_memory_model\".\n OpExtension " - "\"SPV_KHR_8bit_storage\"\n")); -} - -spv_binary GenerateTrivialBinary(bool need_little_endian) { - // Smallest possible valid WebGPU SPIR-V binary in little endian. Contains all - // the required boilerplate and a trivial entry point function. - static const uint8_t binary_bytes[] = { - // clang-format off - 0x03, 0x02, 0x23, 0x07, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0xE1, 0x14, 0x00, 0x00, - 0x0A, 0x00, 0x08, 0x00, 0x53, 0x50, 0x56, 0x5F, 0x4B, 0x48, 0x52, 0x5F, - 0x76, 0x75, 0x6C, 0x6B, 0x61, 0x6E, 0x5F, 0x6D, 0x65, 0x6D, 0x6F, 0x72, - 0x79, 0x5F, 0x6D, 0x6F, 0x64, 0x65, 0x6C, 0x00, 0x0E, 0x00, 0x03, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x05, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x73, 0x68, 0x61, 0x64, - 0x65, 0x72, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, - 0x04, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00 - // clang-format on - }; - static const size_t word_count = sizeof(binary_bytes) / sizeof(uint32_t); - std::unique_ptr result(new spv_binary_t); - if (!result) return nullptr; - - result->wordCount = word_count; - result->code = new uint32_t[word_count]; - if (!result->code) return nullptr; - - if (need_little_endian) { - memcpy(result->code, binary_bytes, sizeof(binary_bytes)); - } else { - uint8_t* code_bytes = reinterpret_cast(result->code); - for (size_t word = 0; word < word_count; ++word) { - code_bytes[4 * word] = binary_bytes[4 * word + 3]; - code_bytes[4 * word + 1] = binary_bytes[4 * word + 2]; - code_bytes[4 * word + 2] = binary_bytes[4 * word + 1]; - code_bytes[4 * word + 3] = binary_bytes[4 * word]; - } - } - - return result.release(); -} - -TEST_F(ValidateWebGPU, LittleEndianGood) { - DestroyBinary(); - binary_ = GenerateTrivialBinary(true); - EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); -} - -TEST_F(ValidateWebGPU, BigEndianBad) { - DestroyBinary(); - binary_ = GenerateTrivialBinary(false); - EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions(SPV_ENV_WEBGPU_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("WebGPU requires SPIR-V to be little endian.")); -} - -} // namespace -} // namespace val -} // namespace spvtools diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp index 66f92286..e7e58998 100644 --- a/tools/opt/opt.cpp +++ b/tools/opt/opt.cpp @@ -79,18 +79,6 @@ std::string GetSizePasses() { return GetListOfPassesAsString(optimizer); } -std::string GetVulkanToWebGPUPasses() { - spvtools::Optimizer optimizer(SPV_ENV_VULKAN_1_1); - optimizer.RegisterVulkanToWebGPUPasses(); - return GetListOfPassesAsString(optimizer); -} - -std::string GetWebGPUToVulkanPasses() { - spvtools::Optimizer optimizer(SPV_ENV_WEBGPU_0); - optimizer.RegisterWebGPUToVulkanPasses(); - return GetListOfPassesAsString(optimizer); -} - void PrintUsage(const char* program) { std::string target_env_list = spvTargetEnvList(16, 80); // NOTE: Please maintain flags in lexicographical order. @@ -239,10 +227,6 @@ Options (in lexicographical order):)", values, providing guarantees that satisfy Vulkan's robustBufferAccess rules.)"); printf(R"( - --generate-webgpu-initializers - Adds initial values to OpVariable instructions that are missing - them, due to their storage type requiring them for WebGPU.)"); - printf(R"( --if-conversion Convert if-then-else like assignments into OpSelect.)"); printf(R"( @@ -261,11 +245,6 @@ Options (in lexicographical order):)", option --relax-logical-pointer to the validator.)", GetLegalizationPasses().c_str()); printf(R"( - --legalize-vector-shuffle - Converts any usages of 0xFFFFFFFF for the literals in - OpVectorShuffle to a literal 0. This is done since 0xFFFFFFFF is - forbidden in WebGPU.)"); - printf(R"( --local-redundancy-elimination Looks for instructions in the same basic block that compute the same value, and deletes the redundant ones.)"); @@ -463,13 +442,6 @@ Options (in lexicographical order):)", Forwards this option to the validator. See the validator help for details.)"); printf(R"( - --split-invalid-unreachable - Attempts to legalize for WebGPU cases where an unreachable - merge-block is also a continue-target by splitting it into two - separate blocks. There exist legal, for Vulkan, instances of this - pattern that cannot be converted into legal WebGPU, so this - conversion may not succeed.)"); - printf(R"( --skip-validation Will not validate the SPIR-V before optimizing. If the SPIR-V is invalid, the optimizer may fail or generate incorrect code. @@ -513,34 +485,6 @@ Options (in lexicographical order):)", removes them from the vector. Note this would still leave around lots of dead code that a pass of ADCE will be able to remove.)"); printf(R"( - --vulkan-to-webgpu - Turns on the prescribed passes for converting from Vulkan to - WebGPU and sets the target environment to webgpu0. Other passes - may be turned on via additional flags, but such combinations are - not tested. - Using --target-env with this flag is not allowed. - - This flag is the equivalent of passing in --target-env=webgpu0 - and specifying the following optimization code names: - %s - - NOTE: This flag is a WIP and its behaviour is subject to change.)", - GetVulkanToWebGPUPasses().c_str()); - printf(R"( - --webgpu-to-vulkan - Turns on the prescribed passes for converting from WebGPU to - Vulkan and sets the target environment to vulkan1.1. Other passes - may be turned on via additional flags, but such combinations are - not tested. - Using --target-env with this flag is not allowed. - - This flag is the equivalent of passing in --target-env=vulkan1.1 - and specifying the following optimization code names: - %s - - NOTE: This flag is a WIP and its behaviour is subject to change.)", - GetWebGPUToVulkanPasses().c_str()); - printf(R"( --workaround-1209 Rewrites instructions for which there are known driver bugs to avoid triggering those bugs. @@ -714,9 +658,6 @@ OptStatus ParseFlags(int argc, const char** argv, spvtools::ValidatorOptions* validator_options, spvtools::OptimizerOptions* optimizer_options) { std::vector pass_flags; - bool target_env_set = false; - bool vulkan_to_webgpu_set = false; - bool webgpu_to_vulkan_set = false; for (int argi = 1; argi < argc; ++argi) { const char* cur_arg = argv[argi]; if ('-' == cur_arg[0]) { @@ -781,19 +722,6 @@ OptStatus ParseFlags(int argc, const char** argv, max_id_bound); } else if (0 == strncmp(cur_arg, "--target-env=", sizeof("--target-env=") - 1)) { - target_env_set = true; - if (vulkan_to_webgpu_set) { - spvtools::Error(opt_diagnostic, nullptr, {}, - "--vulkan-to-webgpu defines the target environment, " - "so --target-env cannot be set at the same time"); - return {OPT_STOP, 1}; - } - if (webgpu_to_vulkan_set) { - spvtools::Error(opt_diagnostic, nullptr, {}, - "--webgpu-to-vulkan defines the target environment, " - "so --target-env cannot be set at the same time"); - return {OPT_STOP, 1}; - } const auto split_flag = spvtools::utils::SplitFlagArgs(cur_arg); const auto target_env_str = split_flag.second.c_str(); spv_target_env target_env; @@ -803,42 +731,6 @@ OptStatus ParseFlags(int argc, const char** argv, return {OPT_STOP, 1}; } optimizer->SetTargetEnv(target_env); - } else if (0 == strcmp(cur_arg, "--vulkan-to-webgpu")) { - vulkan_to_webgpu_set = true; - if (target_env_set) { - spvtools::Error(opt_diagnostic, nullptr, {}, - "--vulkan-to-webgpu defines the target environment, " - "so --target-env cannot be set at the same time"); - return {OPT_STOP, 1}; - } - if (webgpu_to_vulkan_set) { - spvtools::Error(opt_diagnostic, nullptr, {}, - "Cannot use both --webgpu-to-vulkan and " - "--vulkan-to-webgpu at the same time, invoke twice " - "if you are wanting to go to and from"); - return {OPT_STOP, 1}; - } - - optimizer->SetTargetEnv(SPV_ENV_VULKAN_1_1); - optimizer->RegisterVulkanToWebGPUPasses(); - } else if (0 == strcmp(cur_arg, "--webgpu-to-vulkan")) { - webgpu_to_vulkan_set = true; - if (target_env_set) { - spvtools::Error(opt_diagnostic, nullptr, {}, - "--webgpu-to-vulkan defines the target environment, " - "so --target-env cannot be set at the same time"); - return {OPT_STOP, 1}; - } - if (vulkan_to_webgpu_set) { - spvtools::Error(opt_diagnostic, nullptr, {}, - "Cannot use both --webgpu-to-vulkan and " - "--vulkan-to-webgpu at the same time, invoke twice " - "if you are wanting to go to and from"); - return {OPT_STOP, 1}; - } - - optimizer->SetTargetEnv(SPV_ENV_WEBGPU_0); - optimizer->RegisterWebGPUToVulkanPasses(); } else if (0 == strcmp(cur_arg, "--validate-after-all")) { optimizer->SetValidateAfterAll(true); } else if (0 == strcmp(cur_arg, "--before-hlsl-legalization")) { diff --git a/tools/val/val.cpp b/tools/val/val.cpp index 19b8c776..da63245a 100644 --- a/tools/val/val.cpp +++ b/tools/val/val.cpp @@ -108,7 +108,7 @@ int main(int argc, char** argv) { printf("%s\n", spvSoftwareVersionDetailsString()); printf( "Targets:\n %s\n %s\n %s\n %s\n %s\n %s\n %s\n %s\n %s\n " - "%s\n %s\n", + "%s\n", spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_0), spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_1), spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_2), @@ -118,8 +118,7 @@ int main(int argc, char** argv) { spvTargetEnvDescription(SPV_ENV_OPENCL_2_2), spvTargetEnvDescription(SPV_ENV_VULKAN_1_0), spvTargetEnvDescription(SPV_ENV_VULKAN_1_1), - spvTargetEnvDescription(SPV_ENV_VULKAN_1_1_SPIRV_1_4), - spvTargetEnvDescription(SPV_ENV_WEBGPU_0)); + spvTargetEnvDescription(SPV_ENV_VULKAN_1_1_SPIRV_1_4)); continue_processing = false; return_code = 0; } else if (0 == strcmp(cur_arg, "--help") || 0 == strcmp(cur_arg, "-h")) { -- cgit v1.2.3 From ee39b5db5f1d51bbdb0422d529d1e99615627bcf Mon Sep 17 00:00:00 2001 From: sfricke-samsung <46493288+sfricke-samsung@users.noreply.github.com> Date: Fri, 15 Jan 2021 06:35:17 -0800 Subject: spirv-val: Add Vulkan Addressing Model check (#4107) --- source/val/validate_mode_setting.cpp | 9 +++++++++ source/val/validation_state.cpp | 2 ++ 2 files changed, 11 insertions(+) diff --git a/source/val/validate_mode_setting.cpp b/source/val/validate_mode_setting.cpp index ab550a92..c816b75c 100644 --- a/source/val/validate_mode_setting.cpp +++ b/source/val/validate_mode_setting.cpp @@ -498,6 +498,15 @@ spv_result_t ValidateMemoryModel(ValidationState_t& _, } } + if (spvIsVulkanEnv(_.context()->target_env)) { + if ((_.addressing_model() != SpvAddressingModelLogical) && + (_.addressing_model() != SpvAddressingModelPhysicalStorageBuffer64)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << _.VkErrorID(4635) + << "Addressing model must be Logical or PhysicalStorageBuffer64 " + << "in the Vulkan environment."; + } + } return SPV_SUCCESS; } diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index 967fd9f3..367506e4 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -1650,6 +1650,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-ShadingRateKHR-ShadingRateKHR-04492); case 4633: return VUID_WRAP(VUID-StandaloneSpirv-None-04633); + case 4635: + return VUID_WRAP(VUID-StandaloneSpirv-None-04635); case 4642: return VUID_WRAP(VUID-StandaloneSpirv-None-04642); case 4649: -- cgit v1.2.3 From 8383bd5d6f26c51d9b6b0b1fd1a001be07aedd8d Mon Sep 17 00:00:00 2001 From: Ben Clayton Date: Mon, 18 Jan 2021 18:36:26 +0000 Subject: Migrate all Kokoro build scripts over to use the docker VM image (#4114) * Work around GCC-9 warning treated as error ``` ../source/opt/instruction.h:101:23: error: '*((void*)& operand +32)' may be used uninitialized in this function [-Werror=maybe-uninitialized] 101 | uint64_t result = uint64_t(words[0]); ``` * Migrate all Kokoro build scripts over to use the docker VM image Required updating the NDK SDK and build scripts, as well as the check_copyright for handling 2021. --- android_test/jni/Application.mk | 2 +- kokoro/android/build.sh | 32 +---- kokoro/linux-clang-asan/build.sh | 2 +- kokoro/linux-clang-debug/build.sh | 2 +- kokoro/linux-clang-release-bazel/build.sh | 23 +--- kokoro/linux-clang-release/build.sh | 2 +- kokoro/linux-gcc-debug/build.sh | 2 +- kokoro/linux-gcc-release/build.sh | 2 +- kokoro/ndk-build/build.sh | 37 +----- kokoro/scripts/linux/build-docker.sh | 196 ++++++++++++++++++++++++++++++ kokoro/scripts/linux/build.sh | 113 +++++------------ kokoro/shaderc-smoketest/build.sh | 53 +------- source/opt/instruction.h | 10 +- utils/check_copyright.py | 2 +- 14 files changed, 249 insertions(+), 229 deletions(-) mode change 100644 => 100755 kokoro/android/build.sh mode change 100644 => 100755 kokoro/linux-clang-asan/build.sh mode change 100644 => 100755 kokoro/linux-clang-debug/build.sh mode change 100644 => 100755 kokoro/linux-clang-release-bazel/build.sh mode change 100644 => 100755 kokoro/linux-clang-release/build.sh mode change 100644 => 100755 kokoro/linux-gcc-debug/build.sh mode change 100644 => 100755 kokoro/linux-gcc-release/build.sh mode change 100644 => 100755 kokoro/ndk-build/build.sh create mode 100755 kokoro/scripts/linux/build-docker.sh mode change 100644 => 100755 kokoro/shaderc-smoketest/build.sh diff --git a/android_test/jni/Application.mk b/android_test/jni/Application.mk index d7ccd349..4e664659 100644 --- a/android_test/jni/Application.mk +++ b/android_test/jni/Application.mk @@ -1,5 +1,5 @@ APP_ABI := all APP_BUILD_SCRIPT := Android.mk -APP_STL := gnustl_static +APP_STL := c++_static APP_PLATFORM := android-9 NDK_TOOLCHAIN_VERSION := 4.9 diff --git a/kokoro/android/build.sh b/kokoro/android/build.sh old mode 100644 new mode 100755 index c05c139a..22c9117a --- a/kokoro/android/build.sh +++ b/kokoro/android/build.sh @@ -20,33 +20,5 @@ set -e # Display commands being run. set -x -BUILD_ROOT=$PWD -SRC=$PWD/github/SPIRV-Tools -TARGET_ARCH="armeabi-v7a with NEON" -export ANDROID_NDK=/opt/android-ndk-r15c - -# Get NINJA. -wget -q https://github.com/ninja-build/ninja/releases/download/v1.8.2/ninja-linux.zip -unzip -q ninja-linux.zip -export PATH="$PWD:$PATH" -git clone --depth=1 https://github.com/taka-no-me/android-cmake.git android-cmake -export TOOLCHAIN_PATH=$PWD/android-cmake/android.toolchain.cmake - - -cd $SRC -git clone --depth=1 https://github.com/KhronosGroup/SPIRV-Headers external/spirv-headers -git clone https://github.com/google/googletest external/googletest -cd external && cd googletest && git reset --hard 1fb1bb23bb8418dc73a5a9a82bbed31dc610fec7 && cd .. && cd .. -git clone --depth=1 https://github.com/google/effcee external/effcee -git clone --depth=1 https://github.com/google/re2 external/re2 - -mkdir build && cd $SRC/build - -# Invoke the build. -BUILD_SHA=${KOKORO_GITHUB_COMMIT:-$KOKORO_GITHUB_PULL_REQUEST_COMMIT} -echo $(date): Starting build... -cmake -DPYTHON_EXECUTABLE:FILEPATH=/usr/bin/python3 -DCMAKE_BUILD_TYPE=Release -DANDROID_NATIVE_API_LEVEL=android-14 -DANDROID_ABI="armeabi-v7a with NEON" -DSPIRV_SKIP_TESTS=ON -DCMAKE_TOOLCHAIN_FILE=$TOOLCHAIN_PATH -GNinja -DANDROID_NDK=$ANDROID_NDK .. - -echo $(date): Build everything... -ninja -echo $(date): Build completed. +SCRIPT_DIR=`dirname "$BASH_SOURCE"` +source $SCRIPT_DIR/../scripts/linux/build.sh ASAN clang cmake-android-ndk diff --git a/kokoro/linux-clang-asan/build.sh b/kokoro/linux-clang-asan/build.sh old mode 100644 new mode 100755 index 8f86e6ec..5cca362d --- a/kokoro/linux-clang-asan/build.sh +++ b/kokoro/linux-clang-asan/build.sh @@ -21,4 +21,4 @@ set -e set -x SCRIPT_DIR=`dirname "$BASH_SOURCE"` -source $SCRIPT_DIR/../scripts/linux/build.sh ASAN clang +source $SCRIPT_DIR/../scripts/linux/build.sh ASAN clang cmake diff --git a/kokoro/linux-clang-debug/build.sh b/kokoro/linux-clang-debug/build.sh old mode 100644 new mode 100755 index 11b2968a..785a6e3b --- a/kokoro/linux-clang-debug/build.sh +++ b/kokoro/linux-clang-debug/build.sh @@ -21,4 +21,4 @@ set -e set -x SCRIPT_DIR=`dirname "$BASH_SOURCE"` -source $SCRIPT_DIR/../scripts/linux/build.sh DEBUG clang +source $SCRIPT_DIR/../scripts/linux/build.sh DEBUG clang cmake diff --git a/kokoro/linux-clang-release-bazel/build.sh b/kokoro/linux-clang-release-bazel/build.sh old mode 100644 new mode 100755 index 05a9bbb4..238ef52b --- a/kokoro/linux-clang-release-bazel/build.sh +++ b/kokoro/linux-clang-release-bazel/build.sh @@ -20,24 +20,5 @@ set -e # Display commands being run. set -x -CC=clang -CXX=clang++ -SRC=$PWD/github/SPIRV-Tools - -cd $SRC -git clone --depth=1 https://github.com/KhronosGroup/SPIRV-Headers external/spirv-headers -git clone https://github.com/google/googletest external/googletest -cd external && cd googletest && git reset --hard 1fb1bb23bb8418dc73a5a9a82bbed31dc610fec7 && cd .. && cd .. -git clone --depth=1 https://github.com/google/effcee external/effcee -git clone --depth=1 https://github.com/google/re2 external/re2 - -gsutil cp gs://bazel/0.29.1/release/bazel-0.29.1-linux-x86_64 . -chmod +x bazel-0.29.1-linux-x86_64 - -echo $(date): Build everything... -./bazel-0.29.1-linux-x86_64 build :all -echo $(date): Build completed. - -echo $(date): Starting bazel test... -./bazel-0.29.1-linux-x86_64 test :all -echo $(date): Bazel test completed. +SCRIPT_DIR=`dirname "$BASH_SOURCE"` +source $SCRIPT_DIR/../scripts/linux/build.sh RELEASE clang bazel diff --git a/kokoro/linux-clang-release/build.sh b/kokoro/linux-clang-release/build.sh old mode 100644 new mode 100755 index 47643317..6a9e0136 --- a/kokoro/linux-clang-release/build.sh +++ b/kokoro/linux-clang-release/build.sh @@ -21,4 +21,4 @@ set -e set -x SCRIPT_DIR=`dirname "$BASH_SOURCE"` -source $SCRIPT_DIR/../scripts/linux/build.sh RELEASE clang +source $SCRIPT_DIR/../scripts/linux/build.sh RELEASE clang cmake diff --git a/kokoro/linux-gcc-debug/build.sh b/kokoro/linux-gcc-debug/build.sh old mode 100644 new mode 100755 index 3ef1e251..c60447e3 --- a/kokoro/linux-gcc-debug/build.sh +++ b/kokoro/linux-gcc-debug/build.sh @@ -21,4 +21,4 @@ set -e set -x SCRIPT_DIR=`dirname "$BASH_SOURCE"` -source $SCRIPT_DIR/../scripts/linux/build.sh DEBUG gcc +source $SCRIPT_DIR/../scripts/linux/build.sh DEBUG gcc cmake diff --git a/kokoro/linux-gcc-release/build.sh b/kokoro/linux-gcc-release/build.sh old mode 100644 new mode 100755 index 3e97d8d3..441ab728 --- a/kokoro/linux-gcc-release/build.sh +++ b/kokoro/linux-gcc-release/build.sh @@ -21,4 +21,4 @@ set -e set -x SCRIPT_DIR=`dirname "$BASH_SOURCE"` -source $SCRIPT_DIR/../scripts/linux/build.sh RELEASE gcc +source $SCRIPT_DIR/../scripts/linux/build.sh RELEASE gcc cmake diff --git a/kokoro/ndk-build/build.sh b/kokoro/ndk-build/build.sh old mode 100644 new mode 100755 index f1f167d8..89c55659 --- a/kokoro/ndk-build/build.sh +++ b/kokoro/ndk-build/build.sh @@ -20,38 +20,5 @@ set -e # Display commands being run. set -x -BUILD_ROOT=$PWD -SRC=$PWD/github/SPIRV-Tools - -# Get NINJA. -wget -q https://github.com/ninja-build/ninja/releases/download/v1.8.2/ninja-linux.zip -unzip -q ninja-linux.zip -export PATH="$PWD:$PATH" - -# NDK Path -export ANDROID_NDK=/opt/android-ndk-r15c - -# Get the dependencies. -cd $SRC -git clone --depth=1 https://github.com/KhronosGroup/SPIRV-Headers external/spirv-headers -git clone https://github.com/google/googletest external/googletest -cd external && cd googletest && git reset --hard 1fb1bb23bb8418dc73a5a9a82bbed31dc610fec7 && cd .. && cd .. -git clone --depth=1 https://github.com/google/effcee external/effcee -git clone --depth=1 https://github.com/google/re2 external/re2 - -mkdir build && cd $SRC/build -mkdir libs -mkdir app - -# Invoke the build. -BUILD_SHA=${KOKORO_GITHUB_COMMIT:-$KOKORO_GITHUB_PULL_REQUEST_COMMIT} -echo $(date): Starting ndk-build ... -$ANDROID_NDK/ndk-build \ - -C $SRC/android_test \ - NDK_PROJECT_PATH=. \ - NDK_LIBS_OUT=./libs \ - NDK_APP_OUT=./app \ - -j8 - -echo $(date): ndk-build completed. - +SCRIPT_DIR=`dirname "$BASH_SOURCE"` +source $SCRIPT_DIR/../scripts/linux/build.sh ASAN clang android-ndk-build diff --git a/kokoro/scripts/linux/build-docker.sh b/kokoro/scripts/linux/build-docker.sh new file mode 100755 index 00000000..ba216987 --- /dev/null +++ b/kokoro/scripts/linux/build-docker.sh @@ -0,0 +1,196 @@ +#!/bin/bash +# Copyright (c) 2018 Google LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Linux Build Script. + +# Fail on any error. +set -e +# Display commands being run. +set -x + +. /bin/using.sh # Declare the bash `using` function for configuring toolchains. + +if [ $COMPILER = "clang" ]; then + using clang-10.0.0 +elif [ $COMPILER = "gcc" ]; then + using gcc-9 +fi + +cd $ROOT_DIR + +function clone_if_missing() { + url=$1 + dir=$2 + if [[ ! -d "$dir" ]]; then + git clone ${@:3} "$url" "$dir" + fi +} + +function clean_dir() { + dir=$1 + if [[ -d "$dir" ]]; then + rm -fr "$dir" + fi + mkdir "$dir" +} + +clone_if_missing https://github.com/KhronosGroup/SPIRV-Headers external/spirv-headers --depth=1 +clone_if_missing https://github.com/google/googletest external/googletest +pushd external/googletest; git reset --hard 1fb1bb23bb8418dc73a5a9a82bbed31dc610fec7; popd +clone_if_missing https://github.com/google/effcee external/effcee --depth=1 +clone_if_missing https://github.com/google/re2 external/re2 --depth=1 +clone_if_missing https://github.com/protocolbuffers/protobuf external/protobuf --branch v3.13.0 + +if [ $TOOL = "cmake" ]; then + using cmake-3.17.2 + using ninja-1.10.0 + + # Possible configurations are: + # ASAN, COVERAGE, RELEASE, DEBUG, DEBUG_EXCEPTION, RELEASE_MINGW + BUILD_TYPE="Debug" + if [ $CONFIG = "RELEASE" ] || [ $CONFIG = "RELEASE_MINGW" ]; then + BUILD_TYPE="RelWithDebInfo" + fi + + SKIP_TESTS="False" + ADDITIONAL_CMAKE_FLAGS="" + if [ $CONFIG = "ASAN" ]; then + ADDITIONAL_CMAKE_FLAGS="-DSPIRV_USE_SANITIZER=address,bounds,null" + [ $COMPILER = "clang" ] || { echo "$CONFIG requires clang"; exit 1; } + elif [ $CONFIG = "COVERAGE" ]; then + ADDITIONAL_CMAKE_FLAGS="-DENABLE_CODE_COVERAGE=ON" + SKIP_TESTS="True" + elif [ $CONFIG = "DEBUG_EXCEPTION" ]; then + ADDITIONAL_CMAKE_FLAGS="-DDISABLE_EXCEPTIONS=ON -DDISABLE_RTTI=ON" + elif [ $CONFIG = "RELEASE_MINGW" ]; then + ADDITIONAL_CMAKE_FLAGS="-Dgtest_disable_pthreads=ON -DCMAKE_TOOLCHAIN_FILE=$SRC/cmake/linux-mingw-toolchain.cmake" + SKIP_TESTS="True" + fi + + clean_dir "$ROOT_DIR/build" + cd "$ROOT_DIR/build" + + # Invoke the build. + BUILD_SHA=${KOKORO_GITHUB_COMMIT:-$KOKORO_GITHUB_PULL_REQUEST_COMMIT} + echo $(date): Starting build... + cmake -DPYTHON_EXECUTABLE:FILEPATH=/usr/bin/python3 -GNinja -DCMAKE_INSTALL_PREFIX=$KOKORO_ARTIFACTS_DIR/install -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DRE2_BUILD_TESTING=OFF -DSPIRV_BUILD_FUZZER=ON $ADDITIONAL_CMAKE_FLAGS .. + + echo $(date): Build everything... + ninja + echo $(date): Build completed. + + if [ $CONFIG = "COVERAGE" ]; then + echo $(date): Check coverage... + ninja report-coverage + echo $(date): Check coverage completed. + fi + + echo $(date): Starting ctest... + if [ $SKIP_TESTS = "False" ]; then + ctest -j4 --output-on-failure --timeout 300 + fi + echo $(date): ctest completed. + + # Package the build. + ninja install + cd $KOKORO_ARTIFACTS_DIR + tar czf install.tgz install +elif [ $TOOL = "cmake-smoketest" ]; then + using cmake-3.17.2 + using ninja-1.10.0 + + # Get shaderc. + SHADERC_DIR=/tmp/shaderc + clean_dir "$SHADERC_DIR" + cd $SHADERC_DIR + git clone https://github.com/google/shaderc.git . + cd $SHADERC_DIR/third_party + + # Get shaderc dependencies. Link the appropriate SPIRV-Tools. + git clone https://github.com/google/googletest.git + git clone https://github.com/KhronosGroup/glslang.git + ln -s $ROOT_DIR spirv-tools + git clone https://github.com/KhronosGroup/SPIRV-Headers.git spirv-headers + git clone https://github.com/google/re2 + git clone https://github.com/google/effcee + + cd $SHADERC_DIR + mkdir build + cd $SHADERC_DIR/build + + # Invoke the build. + echo $(date): Starting build... + cmake -GNinja -DRE2_BUILD_TESTING=OFF -DCMAKE_BUILD_TYPE="Release" .. + + echo $(date): Build glslang... + ninja glslangValidator + + echo $(date): Build everything... + ninja + echo $(date): Build completed. + + echo $(date): Check Shaderc for copyright notices... + ninja check-copyright + + echo $(date): Starting ctest... + ctest --output-on-failure -j4 + echo $(date): ctest completed. +elif [ $TOOL = "cmake-android-ndk" ]; then + using cmake-3.17.2 + using ndk-r21d + using ninja-1.10.0 + + clean_dir "$ROOT_DIR/build" + cd "$ROOT_DIR/build" + + echo $(date): Starting build... + cmake -DCMAKE_BUILD_TYPE=Release \ + -DANDROID_NATIVE_API_LEVEL=android-16 \ + -DANDROID_ABI="armeabi-v7a with NEON" \ + -DSPIRV_SKIP_TESTS=ON \ + -DCMAKE_TOOLCHAIN_FILE="$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake" \ + -GNinja \ + -DANDROID_NDK=$ANDROID_NDK \ + .. + + echo $(date): Build everything... + ninja + echo $(date): Build completed. +elif [ $TOOL = "android-ndk-build" ]; then + using ndk-r21d + + clean_dir "$ROOT_DIR/build" + cd "$ROOT_DIR/build" + + echo $(date): Starting ndk-build ... + $ANDROID_NDK_HOME/ndk-build \ + -C $ROOT_DIR/android_test \ + NDK_PROJECT_PATH=. \ + NDK_LIBS_OUT=./libs \ + NDK_APP_OUT=./app \ + -j4 + + echo $(date): ndk-build completed. +elif [ $TOOL = "bazel" ]; then + using bazel-3.1.0 + + echo $(date): Build everything... + bazel build :all + echo $(date): Build completed. + + echo $(date): Starting bazel test... + bazel test :all + echo $(date): Bazel test completed. +fi diff --git a/kokoro/scripts/linux/build.sh b/kokoro/scripts/linux/build.sh index 347f353a..4731ebdc 100644 --- a/kokoro/scripts/linux/build.sh +++ b/kokoro/scripts/linux/build.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright (c) 2018 Google LLC. +# Copyright (c) 2021 Google LLC. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,89 +17,38 @@ # Fail on any error. set -e -# Display commands being run. -set -x -BUILD_ROOT=$PWD -SRC=$PWD/github/SPIRV-Tools +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd )" +ROOT_DIR="$( cd "${SCRIPT_DIR}/../../.." >/dev/null 2>&1 && pwd )" + CONFIG=$1 COMPILER=$2 - -SKIP_TESTS="False" -BUILD_TYPE="Debug" - -CMAKE_C_CXX_COMPILER="" -if [ $COMPILER = "clang" ] -then - PATH=/usr/lib/llvm-3.8/bin:$PATH - CMAKE_C_CXX_COMPILER="-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++" -fi - -# Possible configurations are: -# ASAN, COVERAGE, RELEASE, DEBUG, DEBUG_EXCEPTION, RELEASE_MINGW - -if [ $CONFIG = "RELEASE" ] || [ $CONFIG = "RELEASE_MINGW" ] -then - BUILD_TYPE="RelWithDebInfo" -fi - -ADDITIONAL_CMAKE_FLAGS="" -if [ $CONFIG = "ASAN" ] -then - ADDITIONAL_CMAKE_FLAGS="-DSPIRV_USE_SANITIZER=address,bounds,null" - [ $COMPILER = "clang" ] || { echo "$CONFIG requires clang"; exit 1; } -elif [ $CONFIG = "COVERAGE" ] -then - ADDITIONAL_CMAKE_FLAGS="-DENABLE_CODE_COVERAGE=ON" - SKIP_TESTS="True" -elif [ $CONFIG = "DEBUG_EXCEPTION" ] -then - ADDITIONAL_CMAKE_FLAGS="-DDISABLE_EXCEPTIONS=ON -DDISABLE_RTTI=ON" -elif [ $CONFIG = "RELEASE_MINGW" ] -then - ADDITIONAL_CMAKE_FLAGS="-Dgtest_disable_pthreads=ON -DCMAKE_TOOLCHAIN_FILE=$SRC/cmake/linux-mingw-toolchain.cmake" - SKIP_TESTS="True" -fi - -# Get NINJA. -wget -q https://github.com/ninja-build/ninja/releases/download/v1.8.2/ninja-linux.zip -unzip -q ninja-linux.zip -export PATH="$PWD:$PATH" - -cd $SRC -git clone --depth=1 https://github.com/KhronosGroup/SPIRV-Headers external/spirv-headers -git clone https://github.com/google/googletest external/googletest -cd external && cd googletest && git reset --hard 1fb1bb23bb8418dc73a5a9a82bbed31dc610fec7 && cd .. && cd .. -git clone --depth=1 https://github.com/google/effcee external/effcee -git clone --depth=1 https://github.com/google/re2 external/re2 -git clone --depth=1 --branch v3.13.0 https://github.com/protocolbuffers/protobuf external/protobuf - -mkdir build && cd $SRC/build - -# Invoke the build. +TOOL=$3 BUILD_SHA=${KOKORO_GITHUB_COMMIT:-$KOKORO_GITHUB_PULL_REQUEST_COMMIT} -echo $(date): Starting build... -cmake -DPYTHON_EXECUTABLE:FILEPATH=/usr/bin/python3 -GNinja -DCMAKE_INSTALL_PREFIX=$KOKORO_ARTIFACTS_DIR/install -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DRE2_BUILD_TESTING=OFF -DSPIRV_BUILD_FUZZER=ON $ADDITIONAL_CMAKE_FLAGS $CMAKE_C_CXX_COMPILER .. - -echo $(date): Build everything... -ninja -echo $(date): Build completed. - -if [ $CONFIG = "COVERAGE" ] -then - echo $(date): Check coverage... - ninja report-coverage - echo $(date): Check coverage completed. -fi - -echo $(date): Starting ctest... -if [ $SKIP_TESTS = "False" ] -then - ctest -j4 --output-on-failure --timeout 300 -fi -echo $(date): ctest completed. -# Package the build. -ninja install -cd $KOKORO_ARTIFACTS_DIR -tar czf install.tgz install +docker run --rm -i \ + --volume "${ROOT_DIR}:${ROOT_DIR}" \ + --volume "${KOKORO_ARTIFACTS_DIR}:${KOKORO_ARTIFACTS_DIR}" \ + --workdir "${ROOT_DIR}" \ + --env SCRIPT_DIR=${SCRIPT_DIR} \ + --env ROOT_DIR=${ROOT_DIR} \ + --env CONFIG=${CONFIG} \ + --env COMPILER=${COMPILER} \ + --env TOOL=${TOOL} \ + --env KOKORO_ARTIFACTS_DIR="${KOKORO_ARTIFACTS_DIR}" \ + --env BUILD_SHA="${BUILD_SHA}" \ + --entrypoint "${SCRIPT_DIR}/build-docker.sh" \ + "gcr.io/shaderc-build/radial-build:latest" + + +# chown the given directory to the current user, if it exists. +# Docker creates files with the root user - this can upset the Kokoro artifact copier. +function chown_dir() { + dir=$1 + if [[ -d "$dir" ]]; then + sudo chown -R "$(id -u):$(id -g)" "$dir" + fi +} + +chown_dir "${ROOT_DIR}/build" +chown_dir "${ROOT_DIR}/external" diff --git a/kokoro/shaderc-smoketest/build.sh b/kokoro/shaderc-smoketest/build.sh old mode 100644 new mode 100755 index 0856c9b2..60c816d4 --- a/kokoro/shaderc-smoketest/build.sh +++ b/kokoro/shaderc-smoketest/build.sh @@ -18,54 +18,5 @@ set -e # Display commands being run. set -x -BUILD_ROOT=$PWD -GITHUB_DIR=$BUILD_ROOT/github - -SKIP_TESTS="False" -BUILD_TYPE="Release" - -# Get NINJA. -wget -q https://github.com/ninja-build/ninja/releases/download/v1.8.2/ninja-linux.zip -unzip -q ninja-linux.zip -export PATH="$PWD:$PATH" - -# Get shaderc. -cd $GITHUB_DIR -git clone https://github.com/google/shaderc.git -SHADERC_DIR=$GITHUB_DIR/shaderc -cd $SHADERC_DIR/third_party - -# Get shaderc dependencies. Link the appropriate SPIRV-Tools. -git clone https://github.com/google/googletest.git -git clone https://github.com/KhronosGroup/glslang.git -ln -s $GITHUB_DIR/SPIRV-Tools spirv-tools -git clone https://github.com/KhronosGroup/SPIRV-Headers.git spirv-headers -git clone https://github.com/google/re2 -git clone https://github.com/google/effcee - -cd $SHADERC_DIR -mkdir build -cd $SHADERC_DIR/build - -# Invoke the build. -BUILD_SHA=${KOKORO_GITHUB_COMMIT:-$KOKORO_GITHUB_PULL_REQUEST_COMMIT} -echo $(date): Starting build... -cmake -GNinja -DRE2_BUILD_TESTING=OFF -DCMAKE_BUILD_TYPE=$BUILD_TYPE .. - -echo $(date): Build glslang... -ninja glslangValidator - -echo $(date): Build everything... -ninja -echo $(date): Build completed. - -echo $(date): Check Shaderc for copyright notices... -ninja check-copyright - -echo $(date): Starting ctest... -if [ $SKIP_TESTS = "False" ] -then - ctest --output-on-failure -j4 -fi -echo $(date): ctest completed. - +SCRIPT_DIR=`dirname "$BASH_SOURCE"` +source $SCRIPT_DIR/../scripts/linux/build.sh RELEASE gcc cmake-smoketest diff --git a/source/opt/instruction.h b/source/opt/instruction.h index 252e8cb5..47432210 100644 --- a/source/opt/instruction.h +++ b/source/opt/instruction.h @@ -97,10 +97,14 @@ struct Operand { assert(type == SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER); assert(1 <= words.size()); assert(words.size() <= 2); - // Load the low word. - uint64_t result = uint64_t(words[0]); + uint64_t result = 0; + if (words.size() > 0) { // Needed to avoid maybe-uninitialized GCC warning + uint32_t low = words[0]; + result = uint64_t(low); + } if (words.size() > 1) { - result = result | (uint64_t(words[1]) << 32); + uint32_t high = words[1]; + result = result | (uint64_t(high) << 32); } return result; } diff --git a/utils/check_copyright.py b/utils/check_copyright.py index 39d27cb7..b15bc206 100755 --- a/utils/check_copyright.py +++ b/utils/check_copyright.py @@ -39,7 +39,7 @@ AUTHORS = ['The Khronos Group Inc.', 'Stefano Milizia'] CURRENT_YEAR='2020' -YEARS = '(2014-2016|2015-2016|2015-2020|2016|2016-2017|2017|2017-2019|2018|2019|2020)' +YEARS = '(2014-2016|2015-2016|2015-2020|2016|2016-2017|2017|2017-2019|2018|2019|2020|2021)' COPYRIGHT_RE = re.compile( 'Copyright \(c\) {} ({})'.format(YEARS, '|'.join(AUTHORS))) -- cgit v1.2.3 From e25db023c47a3aa82454f75d722e1b9840c7807f Mon Sep 17 00:00:00 2001 From: sfricke-samsung <46493288+sfricke-samsung@users.noreply.github.com> Date: Tue, 19 Jan 2021 05:37:42 -0800 Subject: spirv-val: Add Vulkan Memory Scope VUs (#4106) * Fix test using Fragment execution --- source/val/validate_scopes.cpp | 29 +++++++++++++++++++++---- source/val/validation_state.cpp | 6 ++++++ test/val/val_atomics_test.cpp | 48 +++++++++++++++++++++++++++++++++-------- test/val/val_barriers_test.cpp | 40 ++++++++++++++++++++++++++++++++++ 4 files changed, 110 insertions(+), 13 deletions(-) diff --git a/source/val/validate_scopes.cpp b/source/val/validate_scopes.cpp index 636d54c4..a92f7fd3 100644 --- a/source/val/validate_scopes.cpp +++ b/source/val/validate_scopes.cpp @@ -190,7 +190,7 @@ spv_result_t ValidateMemoryScope(ValidationState_t& _, const Instruction* inst, if (spvIsVulkanEnv(_.context()->target_env)) { if (value == SpvScopeCrossDevice) { return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) + << _.VkErrorID(4638) << spvOpcodeString(opcode) << ": in Vulkan environment, Memory Scope cannot be CrossDevice"; } // Vulkan 1.0 specifc rules @@ -198,7 +198,7 @@ spv_result_t ValidateMemoryScope(ValidationState_t& _, const Instruction* inst, value != SpvScopeDevice && value != SpvScopeWorkgroup && value != SpvScopeInvocation) { return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) + << _.VkErrorID(4638) << spvOpcodeString(opcode) << ": in Vulkan 1.0 environment Memory Scope is limited to " << "Device, Workgroup and Invocation"; } @@ -209,15 +209,16 @@ spv_result_t ValidateMemoryScope(ValidationState_t& _, const Instruction* inst, value != SpvScopeSubgroup && value != SpvScopeInvocation && value != SpvScopeShaderCallKHR) { return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) + << _.VkErrorID(4638) << spvOpcodeString(opcode) << ": in Vulkan 1.1 and 1.2 environment Memory Scope is limited " << "to Device, Workgroup, Invocation, and ShaderCall"; } if (value == SpvScopeShaderCallKHR) { + std::string errorVUID = _.VkErrorID(4640); _.function(inst->function()->id()) ->RegisterExecutionModelLimitation( - [](SpvExecutionModel model, std::string* message) { + [errorVUID](SpvExecutionModel model, std::string* message) { if (model != SpvExecutionModelRayGenerationKHR && model != SpvExecutionModelIntersectionKHR && model != SpvExecutionModelAnyHitKHR && @@ -226,6 +227,7 @@ spv_result_t ValidateMemoryScope(ValidationState_t& _, const Instruction* inst, model != SpvExecutionModelCallableKHR) { if (message) { *message = + errorVUID + "ShaderCallKHR Memory Scope requires a ray tracing " "execution model"; } @@ -234,6 +236,25 @@ spv_result_t ValidateMemoryScope(ValidationState_t& _, const Instruction* inst, return true; }); } + + if (value == SpvScopeWorkgroup) { + std::string errorVUID = _.VkErrorID(4639); + _.function(inst->function()->id()) + ->RegisterExecutionModelLimitation( + [errorVUID](SpvExecutionModel model, std::string* message) { + if (model != SpvExecutionModelGLCompute && + model != SpvExecutionModelTaskNV && + model != SpvExecutionModelMeshNV) { + if (message) { + *message = errorVUID + + "Workgroup Memory Scope is limited to MeshNV, " + "TaskNV, and GLCompute execution model"; + } + return false; + } + return true; + }); + } } // TODO(atgoo@github.com) Add checks for OpenCL and OpenGL environments. diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index 367506e4..92b51c74 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -1652,6 +1652,12 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-None-04633); case 4635: return VUID_WRAP(VUID-StandaloneSpirv-None-04635); + case 4638: + return VUID_WRAP(VUID-StandaloneSpirv-None-04638); + case 4639: + return VUID_WRAP(VUID-StandaloneSpirv-None-04639); + case 4640: + return VUID_WRAP(VUID-StandaloneSpirv-None-04640); case 4642: return VUID_WRAP(VUID-StandaloneSpirv-None-04642); case 4649: diff --git a/test/val/val_atomics_test.cpp b/test/val/val_atomics_test.cpp index 8a79e456..c7e36f5d 100644 --- a/test/val/val_atomics_test.cpp +++ b/test/val/val_atomics_test.cpp @@ -30,16 +30,16 @@ using ValidateAtomics = spvtest::ValidateBase; std::string GenerateShaderCodeImpl( const std::string& body, const std::string& capabilities_and_extensions, - const std::string& definitions, const std::string& memory_model) { + const std::string& definitions, const std::string& memory_model, + const std::string& execution) { std::ostringstream ss; ss << R"( OpCapability Shader )"; ss << capabilities_and_extensions; ss << "OpMemoryModel Logical " << memory_model << "\n"; + ss << execution; ss << R"( -OpEntryPoint Fragment %main "main" -OpExecutionMode %main OriginUpperLeft %void = OpTypeVoid %func = OpTypeFunction %void %bool = OpTypeBool @@ -96,6 +96,35 @@ std::string GenerateShaderCode( const std::string& body, const std::string& capabilities_and_extensions = "", const std::string& memory_model = "GLSL450") { + const std::string execution = R"( +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +)"; + const std::string defintions = R"( +%u64 = OpTypeInt 64 0 +%s64 = OpTypeInt 64 1 + +%u64_1 = OpConstant %u64 1 +%s64_1 = OpConstant %s64 1 + +%u64_ptr = OpTypePointer Workgroup %u64 +%s64_ptr = OpTypePointer Workgroup %s64 +%u64_var = OpVariable %u64_ptr Workgroup +%s64_var = OpVariable %s64_ptr Workgroup +)"; + return GenerateShaderCodeImpl( + body, "OpCapability Int64\n" + capabilities_and_extensions, defintions, + memory_model, execution); +} + +std::string GenerateShaderComputeCode( + const std::string& body, + const std::string& capabilities_and_extensions = "", + const std::string& memory_model = "GLSL450") { + const std::string execution = R"( +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 32 1 1 +)"; const std::string defintions = R"( %u64 = OpTypeInt 64 0 %s64 = OpTypeInt 64 1 @@ -110,7 +139,7 @@ std::string GenerateShaderCode( )"; return GenerateShaderCodeImpl( body, "OpCapability Int64\n" + capabilities_and_extensions, defintions, - memory_model); + memory_model, execution); } std::string GenerateKernelCode( @@ -217,7 +246,7 @@ TEST_F(ValidateAtomics, AtomicLoadInt32VulkanSuccess) { %val2 = OpAtomicLoad %u32 %u32_var %workgroup %acquire )"; - CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0); + CompileSuccessfully(GenerateShaderComputeCode(body), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0)); } @@ -341,7 +370,7 @@ TEST_F(ValidateAtomics, AtomicLoadFloatVulkan) { %val2 = OpAtomicLoad %f32 %f32_var %workgroup %acquire )"; - CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0); + CompileSuccessfully(GenerateShaderComputeCode(body), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0)); } @@ -369,8 +398,9 @@ TEST_F(ValidateAtomics, AtomicLoadInt64WithCapabilityVulkanSuccess) { %val2 = OpAtomicLoad %u64 %u64_var %workgroup %acquire )"; - CompileSuccessfully(GenerateShaderCode(body, "OpCapability Int64Atomics\n"), - SPV_ENV_VULKAN_1_0); + CompileSuccessfully( + GenerateShaderComputeCode(body, "OpCapability Int64Atomics\n"), + SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0)); } @@ -380,7 +410,7 @@ TEST_F(ValidateAtomics, AtomicLoadInt64WithoutCapabilityVulkan) { %val2 = OpAtomicLoad %u64 %u64_var %workgroup %acquire )"; - CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0); + CompileSuccessfully(GenerateShaderComputeCode(body), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); EXPECT_THAT(getDiagnosticString(), HasSubstr("64-bit atomics require the Int64Atomics capability")); diff --git a/test/val/val_barriers_test.cpp b/test/val/val_barriers_test.cpp index 579ec69d..9a4beba3 100644 --- a/test/val/val_barriers_test.cpp +++ b/test/val/val_barriers_test.cpp @@ -121,6 +121,15 @@ OpCapability Int64 execution_model, memory_model); } +std::string GenerateVulkanVertexShaderCode( + const std::string& body, + const std::string& capabilities_and_extensions = "", + const std::string& execution_model = "Vertex") { + const std::string memory_model = "OpMemoryModel Logical GLSL450"; + return GenerateShaderCodeImpl(body, capabilities_and_extensions, "", + execution_model, memory_model); +} + std::string GenerateKernelCode( const std::string& body, const std::string& capabilities_and_extensions = "") { @@ -348,6 +357,8 @@ OpControlBarrier %subgroup %subgroup %none CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-None-04638")); EXPECT_THAT( getDiagnosticString(), HasSubstr("ControlBarrier: in Vulkan 1.0 environment Memory Scope is " @@ -370,11 +381,36 @@ OpControlBarrier %subgroup %cross_device %none CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_1); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-None-04638")); EXPECT_THAT(getDiagnosticString(), HasSubstr("ControlBarrier: in Vulkan environment, Memory Scope " "cannot be CrossDevice")); } +TEST_F(ValidateBarriers, OpControlBarrierVulkan1p1WorkgroupNonComputeFailure) { + const std::string body = R"( +OpControlBarrier %workgroup %workgroup %acquire +)"; + + CompileSuccessfully(GenerateVulkanVertexShaderCode(body), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-None-04639")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Workgroup Memory Scope is limited to MeshNV, TaskNV, " + "and GLCompute execution model")); +} + +TEST_F(ValidateBarriers, OpControlBarrierVulkan1p1WorkgroupNonComputeSuccess) { + const std::string body = R"( +OpControlBarrier %workgroup %workgroup %acquire +)"; + + CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_1); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1)); +} + TEST_F(ValidateBarriers, OpControlBarrierAcquireAndRelease) { const std::string body = R"( OpControlBarrier %device %device %acquire_and_release_uniform @@ -647,6 +683,8 @@ OpMemoryBarrier %subgroup %acquire_release_uniform_workgroup CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-None-04638")); EXPECT_THAT( getDiagnosticString(), HasSubstr("MemoryBarrier: in Vulkan 1.0 environment Memory Scope is " @@ -1397,6 +1435,8 @@ TEST_F(ValidateBarriers, OpMemoryBarrierShaderCallComputeFailure) { SPV_ENV_VULKAN_1_1); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-None-04640")); EXPECT_THAT( getDiagnosticString(), HasSubstr( -- cgit v1.2.3 From 56f8ed48efd5d7e315a3815de0c70ef1b45fc677 Mon Sep 17 00:00:00 2001 From: David Neto Date: Tue, 19 Jan 2021 17:44:45 -0500 Subject: Validate Sampled=1 for Vulkan ImageQuerySizeLod, ImageQueryLevels, ImageQueryLod (#4103) Also require image type parameter to OpTypeSampledImage to have Sampled=0 or Sampled=1 Fixes #4102 --- source/val/validate_image.cpp | 40 ++++++ test/val/val_image_test.cpp | 293 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 302 insertions(+), 31 deletions(-) diff --git a/source/val/validate_image.cpp b/source/val/validate_image.cpp index f5ba5d1a..fc37f08b 100644 --- a/source/val/validate_image.cpp +++ b/source/val/validate_image.cpp @@ -877,6 +877,20 @@ spv_result_t ValidateTypeSampledImage(ValidationState_t& _, return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected Image to be of type OpTypeImage"; } + + ImageTypeInfo info; + if (!GetImageTypeInfo(_, image_type, &info)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Corrupt image type definition"; + } + // OpenCL requires Sampled=0, checked elsewhere. + // Vulkan uses the Sampled=1 case. + if ((info.sampled != 0) && (info.sampled != 1)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Sampled image type requires an image type with \"Sampled\" " + "operand set to 0 or 1"; + } + return SPV_SUCCESS; } @@ -1728,6 +1742,16 @@ spv_result_t ValidateImageQuerySizeLod(ValidationState_t& _, return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Image 'MS' must be 0"; } + const auto target_env = _.context()->target_env; + if (spvIsVulkanEnv(target_env)) { + if (info.sampled != 1) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << _.VkErrorID(4659) + << "OpImageQuerySizeLod must only consume an \"Image\" operand " + "whose type has its \"Sampled\" operand set to 1"; + } + } + uint32_t result_num_components = _.GetDimension(result_type); if (result_num_components != expected_num_components) { return _.diag(SPV_ERROR_INVALID_DATA, inst) @@ -1902,6 +1926,13 @@ spv_result_t ValidateImageQueryLod(ValidationState_t& _, << "Expected Coordinate to have at least " << min_coord_size << " components, but given only " << actual_coord_size; } + + // The operad is a sampled image. + // The sampled image type is already checked to be parameterized by an image + // type with Sampled=0 or Sampled=1. Vulkan bans Sampled=0, and so we have + // Sampled=1. So the validator already enforces Vulkan VUID 4659: + // OpImageQuerySizeLod must only consume an “Image” operand whose type has + // its "Sampled" operand set to 1 return SPV_SUCCESS; } @@ -1938,6 +1969,15 @@ spv_result_t ValidateImageQueryLevelsOrSamples(ValidationState_t& _, return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Image 'Dim' must be 1D, 2D, 3D or Cube"; } + const auto target_env = _.context()->target_env; + if (spvIsVulkanEnv(target_env)) { + if (info.sampled != 1) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << _.VkErrorID(4659) + << "OpImageQueryLevels must only consume an \"Image\" operand " + "whose type has its \"Sampled\" operand set to 1"; + } + } } else { assert(opcode == SpvOpImageQuerySamples); if (info.dim != SpvDim2D) { diff --git a/test/val/val_image_test.cpp b/test/val/val_image_test.cpp index bcee6231..ce4bf1be 100644 --- a/test/val/val_image_test.cpp +++ b/test/val/val_image_test.cpp @@ -224,7 +224,6 @@ OpDecorate %uniform_sampler Binding 0 %type_image_f32_1d_0002_rgba32f = OpTypeImage %f32 1D 0 0 0 2 Rgba32f %ptr_image_f32_1d_0002_rgba32f = OpTypePointer UniformConstant %type_image_f32_1d_0002_rgba32f %uniform_image_f32_1d_0002_rgba32f = OpVariable %ptr_image_f32_1d_0002_rgba32f UniformConstant -%type_sampled_image_f32_1d_0002_rgba32f = OpTypeSampledImage %type_image_f32_1d_0002_rgba32f %type_image_f32_2d_0001 = OpTypeImage %f32 2D 0 0 0 1 Unknown %ptr_image_f32_2d_0001 = OpTypePointer UniformConstant %type_image_f32_2d_0001 @@ -244,7 +243,6 @@ OpDecorate %uniform_sampler Binding 0 %type_image_u32_2d_0002 = OpTypeImage %u32 2D 0 0 0 2 Unknown %ptr_image_u32_2d_0002 = OpTypePointer UniformConstant %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 = OpVariable %ptr_image_u32_2d_0002 UniformConstant -%type_sampled_image_u32_2d_0002 = OpTypeSampledImage %type_image_u32_2d_0002 %type_image_s32_3d_0001 = OpTypeImage %s32 3D 0 0 0 1 Unknown %ptr_image_s32_3d_0001 = OpTypePointer UniformConstant %type_image_s32_3d_0001 @@ -254,17 +252,14 @@ OpDecorate %uniform_sampler Binding 0 %type_image_f32_2d_0002 = OpTypeImage %f32 2D 0 0 0 2 Unknown %ptr_image_f32_2d_0002 = OpTypePointer UniformConstant %type_image_f32_2d_0002 %uniform_image_f32_2d_0002 = OpVariable %ptr_image_f32_2d_0002 UniformConstant -%type_sampled_image_f32_2d_0002 = OpTypeSampledImage %type_image_f32_2d_0002 %type_image_s32_2d_0002 = OpTypeImage %s32 2D 0 0 0 2 Unknown %ptr_image_s32_2d_0002 = OpTypePointer UniformConstant %type_image_s32_2d_0002 %uniform_image_s32_2d_0002 = OpVariable %ptr_image_s32_2d_0002 UniformConstant -%type_sampled_image_s32_2d_0002 = OpTypeSampledImage %type_image_s32_2d_0002 %type_image_f32_spd_0002 = OpTypeImage %f32 SubpassData 0 0 0 2 Unknown %ptr_image_f32_spd_0002 = OpTypePointer UniformConstant %type_image_f32_spd_0002 %uniform_image_f32_spd_0002 = OpVariable %ptr_image_f32_spd_0002 UniformConstant -%type_sampled_image_f32_spd_0002 = OpTypeSampledImage %type_image_f32_spd_0002 %type_image_f32_3d_0111 = OpTypeImage %f32 3D 0 1 1 1 Unknown %ptr_image_f32_3d_0111 = OpTypePointer UniformConstant %type_image_f32_3d_0111 @@ -279,7 +274,6 @@ OpDecorate %uniform_sampler Binding 0 %type_image_f32_cube_0102_rgba32f = OpTypeImage %f32 Cube 0 1 0 2 Rgba32f %ptr_image_f32_cube_0102_rgba32f = OpTypePointer UniformConstant %type_image_f32_cube_0102_rgba32f %uniform_image_f32_cube_0102_rgba32f = OpVariable %ptr_image_f32_cube_0102_rgba32f UniformConstant -%type_sampled_image_f32_cube_0102_rgba32f = OpTypeSampledImage %type_image_f32_cube_0102_rgba32f %type_sampler = OpTypeSampler %ptr_sampler = OpTypePointer UniformConstant %type_sampler @@ -312,7 +306,6 @@ OpDecorate %uniform_sampler Binding 0 %type_image_void_2d_0002 = OpTypeImage %void 2D 0 0 0 2 Unknown %ptr_image_void_2d_0002 = OpTypePointer UniformConstant %type_image_void_2d_0002 %uniform_image_void_2d_0002 = OpVariable %ptr_image_void_2d_0002 UniformConstant -%type_sampled_image_void_2d_0002 = OpTypeSampledImage %type_image_void_2d_0002 %type_image_f32_rect_0001 = OpTypeImage %f32 Rect 0 0 0 1 Unknown %ptr_image_f32_rect_0001 = OpTypePointer UniformConstant %type_image_f32_rect_0001 @@ -863,7 +856,7 @@ TEST_F(ValidateImage, TypeImageMultisampleSubpassData_OK) { EXPECT_THAT(getDiagnosticString(), Eq("")); } -TEST_F(ValidateImage, TypeSampledImageNotImage) { +TEST_F(ValidateImage, TypeSampledImage_NotImage_Error) { const std::string code = GetShaderHeader("", false) + R"( %simg_type = OpTypeSampledImage %f32 )"; @@ -874,6 +867,43 @@ TEST_F(ValidateImage, TypeSampledImageNotImage) { HasSubstr("Expected Image to be of type OpTypeImage")); } +TEST_F(ValidateImage, TypeSampledImage_Sampled0_Success) { + // This is ok in the OpenCL and universal environments. + // Vulkan will reject an OpTypeImage with Sampled=0, checked elsewhere. + const std::string code = GetShaderHeader() + R"( +%imty = OpTypeImage %f32 2D 0 0 0 0 Unknown +%simg_type = OpTypeSampledImage %imty +)" + TrivialMain(); + + CompileSuccessfully(code.c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_EQ(getDiagnosticString(), ""); +} + +TEST_F(ValidateImage, TypeSampledImage_Sampled2_Error) { + const std::string code = GetShaderHeader() + R"( +%storage_image = OpTypeImage %f32 2D 0 0 0 2 Rgba32f +%simg_type = OpTypeSampledImage %storage_image +)" + TrivialMain(); + + CompileSuccessfully(code.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Sampled image type requires an image type with " + "\"Sampled\" operand set to 0 or 1")); +} + +TEST_F(ValidateImage, TypeSampledImage_Sampled1_Success) { + const std::string code = GetShaderHeader() + R"( +%im = OpTypeImage %f32 2D 0 0 0 1 Unknown +%simg_type = OpTypeSampledImage %im +)" + TrivialMain(); + + CompileSuccessfully(code.c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_EQ(getDiagnosticString(), ""); +} + TEST_F(ValidateImage, SampledImageSuccess) { const std::string body = R"( %img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 @@ -925,31 +955,32 @@ TEST_F(ValidateImage, SampledImageNotImage) { } TEST_F(ValidateImage, SampledImageImageNotForSampling) { - const std::string body = R"( -%img = OpLoad %type_image_f32_2d_0002 %uniform_image_f32_2d_0002 -%sampler = OpLoad %type_sampler %uniform_sampler -%simg = OpSampledImage %type_sampled_image_f32_2d_0002 %img %sampler -)"; + const std::string code = GetShaderHeader() + R"( +%im_ty = OpTypeImage %f32 2D 0 0 0 2 Unknown +%sampler_ty = OpTypeSampler +%sampled_image_ty = OpTypeSampledImage %im_ty ; will fail here first! - CompileSuccessfully(GenerateShaderCode(body).c_str()); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Expected Image 'Sampled' parameter to be 0 or 1")); -} +%ptr_im_ty = OpTypePointer UniformConstant %im_ty +%var_im = OpVariable %ptr_im_ty UniformConstant -TEST_F(ValidateImage, SampledImageVulkanUnknownSampled) { - const std::string body = R"( -%img = OpLoad %type_image_u32_2d_0002 %uniform_image_u32_2d_0002 -%sampler = OpLoad %type_sampler %uniform_sampler -%simg = OpSampledImage %type_sampled_image_u32_2d_0002 %img %sampler +%ptr_sampler_ty = OpTypePointer UniformConstant %sampler_ty +%var_sampler = OpVariable %ptr_sampler_ty UniformConstant + +%main = OpFunction %void None %func +%entry = OpLabel +%im = OpLoad %im_ty %var_im +%sampler = OpLoad %sampler_ty %var_sampler +%sampled_image = OpSampledImage %sampled_image_ty %im %sampler +OpReturn +OpFunctionEnd )"; - const spv_target_env env = SPV_ENV_VULKAN_1_0; - CompileSuccessfully(GenerateShaderCode(body, "", "Fragment", "", env), env); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(env)); + CompileSuccessfully(code.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("Expected Image 'Sampled' parameter to " - "be 1 for Vulkan environment.")); + HasSubstr("Sampled image type requires an image type with " + "\"Sampled\" operand set to 0 or 1")) + << code; } TEST_F(ValidateImage, SampledImageNotSampler) { @@ -1022,7 +1053,7 @@ TEST_F(ValidateImage, ImageTexelPointerImageNotResultTypePointer) { CompileSuccessfully(GenerateShaderCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand 142[%142] cannot be a " + EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand 136[%136] cannot be a " "type")); } @@ -3399,7 +3430,6 @@ OpImageWrite %img %u32vec2_01 %f32vec4_0000 Sample %u32_1 %type_image_f32_2d_0012 = OpTypeImage %f32 2D 0 0 1 2 Unknown %ptr_image_f32_2d_0012 = OpTypePointer UniformConstant %type_image_f32_2d_0012 %uniform_image_f32_2d_0012 = OpVariable %ptr_image_f32_2d_0012 UniformConstant -%type_sampled_image_f32_2d_0012 = OpTypeSampledImage %type_image_f32_2d_0012 )"; CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "", SPV_ENV_UNIVERSAL_1_0, "GLSL450", @@ -3581,7 +3611,6 @@ OpImageWrite %img %u32vec2_01 %f32vec4_0000 Sample %f32_1 %type_image_f32_2d_0012 = OpTypeImage %f32 2D 0 0 1 2 Unknown %ptr_image_f32_2d_0012 = OpTypePointer UniformConstant %type_image_f32_2d_0012 %uniform_image_f32_2d_0012 = OpVariable %ptr_image_f32_2d_0012 UniformConstant -%type_sampled_image_f32_2d_0012 = OpTypeSampledImage %type_image_f32_2d_0012 )"; CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "", SPV_ENV_UNIVERSAL_1_0, "GLSL450", @@ -3810,6 +3839,67 @@ TEST_F(ValidateImage, QuerySizeLodSampledImageDirectly) { "for OpImageQuerySizeLod")); } +TEST_F(ValidateImage, QuerySizeLodMultisampledError) { + const std::string body = R"( +%img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011 +%res1 = OpImageQuerySizeLod %u32vec2 %img %u32_1 +)"; + + CompileSuccessfully(GenerateKernelCode(body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Image 'MS' must be 0")); +} + +TEST_F(ValidateImage, QuerySizeLodNonSampledUniversalSuccess) { + const std::string body = R"( +%img = OpLoad %type_image_f32_2d_0002 %uniform_image_f32_2d_0002 +%res1 = OpImageQuerySizeLod %u32vec2 %img %u32_1 +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_EQ(getDiagnosticString(), ""); +} + +TEST_F(ValidateImage, QuerySizeLodVulkanNonSampledError) { + // Create a whole shader module. Avoid Vulkan incompatibility with + // SampledRrect images inserted by helper function GenerateShaderCode. + const std::string body = R"( +OpCapability Shader +OpCapability ImageQuery +OpMemoryModel Logical Simple +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft + +%f32 = OpTypeFloat 32 +%u32 = OpTypeInt 32 0 +%u32_0 = OpConstant %u32 0 +%u32vec2 = OpTypeVector %u32 2 +%void = OpTypeVoid +%voidfn = OpTypeFunction %void + +; Test with a storage image. +%type_image_f32_2d_0002 = OpTypeImage %f32 2D 0 0 0 2 Rgba32f +%ptr_image_f32_2d_0002 = OpTypePointer UniformConstant %type_image_f32_2d_0002 +%uniform_image_f32_2d_0002 = OpVariable %ptr_image_f32_2d_0002 UniformConstant + +%main = OpFunction %void None %voidfn +%entry = OpLabel +%img = OpLoad %type_image_f32_2d_0002 %uniform_image_f32_2d_0002 +%res1 = OpImageQuerySizeLod %u32vec2 %img %u32_0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "OpImageQuerySizeLod must only consume an \"Image\" operand whose " + "type has its \"Sampled\" operand set to 1")); +} + TEST_F(ValidateImage, QuerySizeLodWrongImageDim) { const std::string body = R"( %img = OpLoad %type_image_f32_rect_0001 %uniform_image_f32_rect_0001 @@ -4096,6 +4186,53 @@ TEST_F(ValidateImage, QueryLevelsWrongDim) { HasSubstr("Image 'Dim' must be 1D, 2D, 3D or Cube")); } +TEST_F(ValidateImage, QuerySizeLevelsNonSampledUniversalSuccess) { + const std::string body = R"( +%img = OpLoad %type_image_f32_2d_0002 %uniform_image_f32_2d_0002 +%res1 = OpImageQueryLevels %u32 %img +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_EQ(getDiagnosticString(), ""); +} + +TEST_F(ValidateImage, QuerySizeLevelsVulkanNonSampledError) { + // Create a whole shader module. Avoid Vulkan incompatibility with + // SampledRrect images inserted by helper function GenerateShaderCode. + const std::string body = R"( +OpCapability Shader +OpCapability ImageQuery +OpMemoryModel Logical Simple +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft + +%f32 = OpTypeFloat 32 +%u32 = OpTypeInt 32 0 +%void = OpTypeVoid +%voidfn = OpTypeFunction %void + +; Test with a storage image. +%type_image_f32_2d_0002 = OpTypeImage %f32 2D 0 0 0 2 Rgba32f +%ptr_image_f32_2d_0002 = OpTypePointer UniformConstant %type_image_f32_2d_0002 +%uniform_image_f32_2d_0002 = OpVariable %ptr_image_f32_2d_0002 UniformConstant + +%main = OpFunction %void None %voidfn +%entry = OpLabel +%img = OpLoad %type_image_f32_2d_0002 %uniform_image_f32_2d_0002 +%res1 = OpImageQueryLevels %u32 %img +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("OpImageQueryLevels must only consume an \"Image\" operand " + "whose type has its \"Sampled\" operand set to 1")); +} + TEST_F(ValidateImage, QuerySamplesSuccess) { const std::string body = R"( %img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011 @@ -4186,6 +4323,100 @@ OpExecutionMode %main DerivativeGroupLinearNV ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } +TEST_F(ValidateImage, QueryLodUniversalSuccess) { + // Create a whole shader module. Avoid Vulkan incompatibility with + // SampledRrect images inserted by helper function GenerateShaderCode. + const std::string body = R"( +OpCapability Shader +OpCapability ImageQuery +OpMemoryModel Logical Simple +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft + +OpDecorate %uniform_image_f32_2d_0000 DescriptorSet 0 +OpDecorate %uniform_image_f32_2d_0000 Binding 0 +OpDecorate %sampler DescriptorSet 0 +OpDecorate %sampler Binding 1 + +%f32 = OpTypeFloat 32 +%f32vec2 = OpTypeVector %f32 2 +%f32vec2_null = OpConstantNull %f32vec2 +%u32 = OpTypeInt 32 0 +%u32vec2 = OpTypeVector %u32 2 +%void = OpTypeVoid +%voidfn = OpTypeFunction %void + +; Test with an image with sampled = 0 +%type_image_f32_2d_0000 = OpTypeImage %f32 2D 0 0 0 0 Rgba32f +%ptr_image_f32_2d_0000 = OpTypePointer UniformConstant %type_image_f32_2d_0000 +%uniform_image_f32_2d_0000 = OpVariable %ptr_image_f32_2d_0000 UniformConstant +%sampled_image_ty = OpTypeSampledImage %type_image_f32_2d_0000 + +%sampler_ty = OpTypeSampler +%ptr_sampler_ty = OpTypePointer UniformConstant %sampler_ty +%sampler = OpVariable %ptr_sampler_ty UniformConstant + + +%main = OpFunction %void None %voidfn +%entry = OpLabel +%img = OpLoad %type_image_f32_2d_0000 %uniform_image_f32_2d_0000 +%s = OpLoad %sampler_ty %sampler +%simg = OpSampledImage %sampled_image_ty %img %s +%res1 = OpImageQueryLod %f32vec2 %simg %f32vec2_null +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateImage, QueryLodVulkanNonSampledError) { + // Create a whole shader module. Avoid Vulkan incompatibility with + // SampledRrect images inserted by helper function GenerateShaderCode. + const std::string body = R"( +OpCapability Shader +OpCapability ImageQuery +OpMemoryModel Logical Simple +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft + +OpDecorate %sampled_image DescriptorSet 0 +OpDecorate %sampled_image Binding 0 + +%f32 = OpTypeFloat 32 +%f32vec2 = OpTypeVector %f32 2 +%f32vec2_null = OpConstantNull %f32vec2 +%u32 = OpTypeInt 32 0 +%u32vec2 = OpTypeVector %u32 2 +%void = OpTypeVoid +%voidfn = OpTypeFunction %void + +; Test with an image with Sampled = 2 +; In Vulkan it Sampled must be 1 or 2, checked in another part of the +; validation flow. +%type_image_f32_2d_0002 = OpTypeImage %f32 2D 0 0 0 2 Rgba32f + +; Expect to fail here. +%sampled_image_ty = OpTypeSampledImage %type_image_f32_2d_0002 +%ptr_sampled_image_ty = OpTypePointer UniformConstant %sampled_image_ty +%sampled_image = OpVariable %ptr_sampled_image_ty UniformConstant + +%main = OpFunction %void None %voidfn +%entry = OpLabel +%simg = OpLoad %sampled_image_ty %sampled_image +%res1 = OpImageQueryLod %f32vec2 %simg %f32vec2_null +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Sampled image type requires an image type with " + "\"Sampled\" operand set to 0 or 1")); +} + TEST_F(ValidateImage, QueryLodComputeShaderDerivativesMissingMode) { const std::string body = R"( %img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 -- cgit v1.2.3 From 1bd539b9bfc4d1eebf42cb466f824f9311dccc0a Mon Sep 17 00:00:00 2001 From: David Neto Date: Wed, 20 Jan 2021 09:39:51 -0500 Subject: Support pending Intel extensions (#4116) This patch supports new Intel extensions added via https://github.com/KhronosGroup/SPIRV-Headers/pull/176 SPV_INTEL_fooat_controls2 requires extra support to add two new operand types: SPV_OPERAND_TYPE_FPDENORM_MODE SPV_OPERAND_TYPE_FPOPERATION_MODE --- include/spirv-tools/libspirv.h | 5 +++++ source/binary.cpp | 4 +++- source/disassemble.cpp | 4 +++- source/operand.cpp | 7 +++++++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/include/spirv-tools/libspirv.h b/include/spirv-tools/libspirv.h index 8f412a66..201ee58b 100644 --- a/include/spirv-tools/libspirv.h +++ b/include/spirv-tools/libspirv.h @@ -260,6 +260,11 @@ typedef enum spv_operand_type_t { SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_OPERATION, // Sec 3.6 SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_IMPORTED_ENTITY, // Sec 3.7 + // The following are concrete enum types from SPV_INTEL_float_controls2 + // https://github.com/intel/llvm/blob/39fa9b0cbfbae88327118990a05c5b387b56d2ef/sycl/doc/extensions/SPIRV/SPV_INTEL_float_controls2.asciidoc + SPV_OPERAND_TYPE_FPDENORM_MODE, // Sec 3.17 FP Denorm Mode + SPV_OPERAND_TYPE_FPOPERATION_MODE, // Sec 3.18 FP Operation Mode + // This is a sentinel value, and does not represent an operand type. // It should come last. SPV_OPERAND_TYPE_NUM_OPERAND_TYPES, diff --git a/source/binary.cpp b/source/binary.cpp index 75a997d3..7448721b 100644 --- a/source/binary.cpp +++ b/source/binary.cpp @@ -655,7 +655,9 @@ spv_result_t Parser::parseOperand(size_t inst_offset, case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_COMPOSITE_TYPE: case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_TYPE_QUALIFIER: case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_OPERATION: - case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_IMPORTED_ENTITY: { + case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_IMPORTED_ENTITY: + case SPV_OPERAND_TYPE_FPDENORM_MODE: + case SPV_OPERAND_TYPE_FPOPERATION_MODE: { // A single word that is a plain enum value. // Map an optional operand type to its corresponding concrete type. diff --git a/source/disassemble.cpp b/source/disassemble.cpp index e7632512..966a59c7 100644 --- a/source/disassemble.cpp +++ b/source/disassemble.cpp @@ -326,7 +326,9 @@ void Disassembler::EmitOperand(const spv_parsed_instruction_t& inst, case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_COMPOSITE_TYPE: case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_TYPE_QUALIFIER: case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_OPERATION: - case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_IMPORTED_ENTITY: { + case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_IMPORTED_ENTITY: + case SPV_OPERAND_TYPE_FPDENORM_MODE: + case SPV_OPERAND_TYPE_FPOPERATION_MODE: { spv_operand_desc entry; if (grammar_.lookupOperand(operand.type, word, &entry)) assert(false && "should have caught this earlier"); diff --git a/source/operand.cpp b/source/operand.cpp index 6755eaba..5a69fb24 100644 --- a/source/operand.cpp +++ b/source/operand.cpp @@ -265,6 +265,11 @@ const char* spvOperandTypeStr(spv_operand_type_t type) { case SPV_OPERAND_TYPE_IMAGE_CHANNEL_DATA_TYPE: return "image channel data type"; + case SPV_OPERAND_TYPE_FPDENORM_MODE: + return "FP denorm mode"; + case SPV_OPERAND_TYPE_FPOPERATION_MODE: + return "FP operation mode"; + case SPV_OPERAND_TYPE_NONE: return "NONE"; default: @@ -348,6 +353,8 @@ bool spvOperandIsConcrete(spv_operand_type_t type) { case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_TYPE_QUALIFIER: case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_OPERATION: case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_IMPORTED_ENTITY: + case SPV_OPERAND_TYPE_FPDENORM_MODE: + case SPV_OPERAND_TYPE_FPOPERATION_MODE: return true; default: break; -- cgit v1.2.3 From f37547c73a981bcf3f8b1a471e3000e606dd41a8 Mon Sep 17 00:00:00 2001 From: sfricke-samsung <46493288+sfricke-samsung@users.noreply.github.com> Date: Wed, 20 Jan 2021 07:40:31 -0800 Subject: spirv-val: Add Vulkan EXT builtins (#4115) --- source/val/validate_builtins.cpp | 353 ++++++++++++++++++++++++++++++++++++++- source/val/validation_state.cpp | 24 +++ test/val/val_builtins_test.cpp | 178 ++++++++++++++++++++ 3 files changed, 549 insertions(+), 6 deletions(-) diff --git a/source/val/validate_builtins.cpp b/source/val/validate_builtins.cpp index 7fb99089..3c9df9fc 100644 --- a/source/val/validate_builtins.cpp +++ b/source/val/validate_builtins.cpp @@ -120,7 +120,7 @@ typedef enum VUIDError_ { VUIDErrorMax, } VUIDError; -const static uint32_t NumVUIDBuiltins = 29; +const static uint32_t NumVUIDBuiltins = 33; typedef struct { SpvBuiltIn builtIn; @@ -158,6 +158,10 @@ std::array builtinVUIDInfo = {{ {SpvBuiltInWorldRayOriginKHR, {4431, 4432, 4433}}, {SpvBuiltInLaunchIdKHR, {4266, 4267, 4268}}, {SpvBuiltInLaunchSizeKHR, {4269, 4270, 4271}}, + {SpvBuiltInFragInvocationCountEXT, {4217, 4218, 4219}}, + {SpvBuiltInFragSizeEXT, {4220, 4221, 4222}}, + {SpvBuiltInFragStencilRefEXT, {4223, 4224, 4225}}, + {SpvBuiltInFullyCoveredEXT, {4232, 4233, 4234}}, // clang-format off } }; @@ -314,6 +318,14 @@ class BuiltInsValidator { const Instruction& inst); spv_result_t ValidateDeviceIndexAtDefinition(const Decoration& decoration, const Instruction& inst); + spv_result_t ValidateFragInvocationCountAtDefinition(const Decoration& decoration, + const Instruction& inst); + spv_result_t ValidateFragSizeAtDefinition(const Decoration& decoration, + const Instruction& inst); + spv_result_t ValidateFragStencilRefAtDefinition(const Decoration& decoration, + const Instruction& inst); + spv_result_t ValidateFullyCoveredAtDefinition(const Decoration& decoration, + const Instruction& inst); // Used for GlobalInvocationId, LocalInvocationId, NumWorkgroups, WorkgroupId. spv_result_t ValidateComputeShaderI32Vec3InputAtDefinition( const Decoration& decoration, const Instruction& inst); @@ -472,6 +484,26 @@ class BuiltInsValidator { const Instruction& referenced_inst, const Instruction& referenced_from_inst); + spv_result_t ValidateFragInvocationCountAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst); + + spv_result_t ValidateFragSizeAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst); + + spv_result_t ValidateFragStencilRefAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst); + + spv_result_t ValidateFullyCoveredAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst); + // Used for GlobalInvocationId, LocalInvocationId, NumWorkgroups, WorkgroupId. spv_result_t ValidateComputeShaderI32Vec3InputAtReference( const Decoration& decoration, const Instruction& built_in_inst, @@ -525,6 +557,9 @@ class BuiltInsValidator { spv_result_t ValidateBool( const Decoration& decoration, const Instruction& inst, const std::function& diag); + spv_result_t ValidateI( + const Decoration& decoration, const Instruction& inst, + const std::function& diag); spv_result_t ValidateI32( const Decoration& decoration, const Instruction& inst, const std::function& diag); @@ -717,6 +752,22 @@ spv_result_t BuiltInsValidator::ValidateBool( return SPV_SUCCESS; } +spv_result_t BuiltInsValidator::ValidateI( + const Decoration& decoration, const Instruction& inst, + const std::function& diag) { + uint32_t underlying_type = 0; + if (spv_result_t error = + GetUnderlyingType(_, decoration, inst, &underlying_type)) { + return error; + } + + if (!_.IsIntScalarType(underlying_type)) { + return diag(GetDefinitionDesc(decoration, inst) + " is not an int scalar."); + } + + return SPV_SUCCESS; +} + spv_result_t BuiltInsValidator::ValidateI32( const Decoration& decoration, const Instruction& inst, const std::function& diag) { @@ -3296,6 +3347,287 @@ spv_result_t BuiltInsValidator::ValidateDeviceIndexAtReference( return SPV_SUCCESS; } +spv_result_t BuiltInsValidator::ValidateFragInvocationCountAtDefinition(const Decoration& decoration, + const Instruction& inst) { + + if (spvIsVulkanEnv(_.context()->target_env)) { + const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]); + if (spv_result_t error = ValidateI32( + decoration, inst, + [this, &inst, &builtin](const std::string& message) -> spv_result_t { + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType); + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(vuid) << "According to the " + << spvLogStringForEnv(_.context()->target_env) + << " spec BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + builtin) + << " variable needs to be a 32-bit int scalar. " + << message; + })) { + return error; + } + } + + return ValidateFragInvocationCountAtReference(decoration, inst, inst, inst); +} + +spv_result_t BuiltInsValidator::ValidateFragInvocationCountAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst) { + + if (spvIsVulkanEnv(_.context()->target_env)) { + const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]); + const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); + if (storage_class != SpvStorageClassMax && + storage_class != SpvStorageClassInput) { + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass); + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin) + << " to be only used for variables with Input storage class. " + << GetReferenceDesc(decoration, built_in_inst, referenced_inst, + referenced_from_inst) + << " " << GetStorageClassDesc(referenced_from_inst); + } + + for (const SpvExecutionModel execution_model : execution_models_) { + if (execution_model != SpvExecutionModelFragment) { + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel); + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(vuid) + << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin) + << " to be used only with Fragment execution model. " + << GetReferenceDesc(decoration, built_in_inst, referenced_inst, + referenced_from_inst, execution_model); + } + } + } + + if (function_id_ == 0) { + // Propagate this rule to all dependant ids in the global scope. + id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind( + &BuiltInsValidator::ValidateFragInvocationCountAtReference, this, decoration, + built_in_inst, referenced_from_inst, std::placeholders::_1)); + } + + return SPV_SUCCESS; +} + +spv_result_t BuiltInsValidator::ValidateFragSizeAtDefinition(const Decoration& decoration, + const Instruction& inst) { + if (spvIsVulkanEnv(_.context()->target_env)) { + const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]); + if (spv_result_t error = ValidateI32Vec( + decoration, inst, 2, + [this, &inst, &builtin](const std::string& message) -> spv_result_t { + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType); + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(vuid) << "According to the " + << spvLogStringForEnv(_.context()->target_env) + << " spec BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + builtin) + << " variable needs to be a 2-component 32-bit int vector. " + << message; + })) { + return error; + } + } + + return ValidateFragSizeAtReference(decoration, inst, inst, inst); +} + +spv_result_t BuiltInsValidator::ValidateFragSizeAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst) { + + if (spvIsVulkanEnv(_.context()->target_env)) { + const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]); + const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); + if (storage_class != SpvStorageClassMax && + storage_class != SpvStorageClassInput) { + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass); + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin) + << " to be only used for variables with Input storage class. " + << GetReferenceDesc(decoration, built_in_inst, referenced_inst, + referenced_from_inst) + << " " << GetStorageClassDesc(referenced_from_inst); + } + + for (const SpvExecutionModel execution_model : execution_models_) { + if (execution_model != SpvExecutionModelFragment) { + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel); + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(vuid) + << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin) + << " to be used only with Fragment execution model. " + << GetReferenceDesc(decoration, built_in_inst, referenced_inst, + referenced_from_inst, execution_model); + } + } + } + + if (function_id_ == 0) { + // Propagate this rule to all dependant ids in the global scope. + id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind( + &BuiltInsValidator::ValidateFragSizeAtReference, this, decoration, + built_in_inst, referenced_from_inst, std::placeholders::_1)); + } + + return SPV_SUCCESS; +} + +spv_result_t BuiltInsValidator::ValidateFragStencilRefAtDefinition(const Decoration& decoration, + const Instruction& inst) { + if (spvIsVulkanEnv(_.context()->target_env)) { + const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]); + if (spv_result_t error = ValidateI( + decoration, inst, + [this, &inst, &builtin](const std::string& message) -> spv_result_t { + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType); + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(vuid) << "According to the " + << spvLogStringForEnv(_.context()->target_env) + << " spec BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + builtin) + << " variable needs to be a int scalar. " + << message; + })) { + return error; + } + } + + return ValidateFragStencilRefAtReference(decoration, inst, inst, inst); +} + +spv_result_t BuiltInsValidator::ValidateFragStencilRefAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst) { + + if (spvIsVulkanEnv(_.context()->target_env)) { + const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]); + const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); + if (storage_class != SpvStorageClassMax && + storage_class != SpvStorageClassOutput) { + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass); + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin) + << " to be only used for variables with Output storage class. " + << GetReferenceDesc(decoration, built_in_inst, referenced_inst, + referenced_from_inst) + << " " << GetStorageClassDesc(referenced_from_inst); + } + + for (const SpvExecutionModel execution_model : execution_models_) { + if (execution_model != SpvExecutionModelFragment) { + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel); + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(vuid) + << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin) + << " to be used only with Fragment execution model. " + << GetReferenceDesc(decoration, built_in_inst, referenced_inst, + referenced_from_inst, execution_model); + } + } + } + + if (function_id_ == 0) { + // Propagate this rule to all dependant ids in the global scope. + id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind( + &BuiltInsValidator::ValidateFragStencilRefAtReference, this, decoration, + built_in_inst, referenced_from_inst, std::placeholders::_1)); + } + + return SPV_SUCCESS; +} + +spv_result_t BuiltInsValidator::ValidateFullyCoveredAtDefinition(const Decoration& decoration, + const Instruction& inst) { + if (spvIsVulkanEnv(_.context()->target_env)) { + const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]); + if (spv_result_t error = ValidateBool( + decoration, inst, + [this, &inst, &builtin](const std::string& message) -> spv_result_t { + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType); + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(vuid) << "According to the " + << spvLogStringForEnv(_.context()->target_env) + << " spec BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + builtin) + << " variable needs to be a bool scalar. " + << message; + })) { + return error; + } + } + + return ValidateFullyCoveredAtReference(decoration, inst, inst, inst); +} + +spv_result_t BuiltInsValidator::ValidateFullyCoveredAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst) { + + if (spvIsVulkanEnv(_.context()->target_env)) { + const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]); + const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); + if (storage_class != SpvStorageClassMax && + storage_class != SpvStorageClassInput) { + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass); + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin) + << " to be only used for variables with Input storage class. " + << GetReferenceDesc(decoration, built_in_inst, referenced_inst, + referenced_from_inst) + << " " << GetStorageClassDesc(referenced_from_inst); + } + + for (const SpvExecutionModel execution_model : execution_models_) { + if (execution_model != SpvExecutionModelFragment) { + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel); + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(vuid) + << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, builtin) + << " to be used only with Fragment execution model. " + << GetReferenceDesc(decoration, built_in_inst, referenced_inst, + referenced_from_inst, execution_model); + } + } + } + + if (function_id_ == 0) { + // Propagate this rule to all dependant ids in the global scope. + id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind( + &BuiltInsValidator::ValidateFullyCoveredAtReference, this, decoration, + built_in_inst, referenced_from_inst, std::placeholders::_1)); + } + + return SPV_SUCCESS; +} + spv_result_t BuiltInsValidator::ValidateSMBuiltinsAtDefinition( const Decoration& decoration, const Instruction& inst) { if (spvIsVulkanEnv(_.context()->target_env)) { @@ -3793,6 +4125,20 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition( case SpvBuiltInDeviceIndex: { return ValidateDeviceIndexAtDefinition(decoration, inst); } + case SpvBuiltInFragInvocationCountEXT: { + // alias SpvBuiltInInvocationsPerPixelNV + return ValidateFragInvocationCountAtDefinition(decoration, inst); + } + case SpvBuiltInFragSizeEXT: { + // alias SpvBuiltInFragmentSizeNV + return ValidateFragSizeAtDefinition(decoration, inst); + } + case SpvBuiltInFragStencilRefEXT: { + return ValidateFragStencilRefAtDefinition(decoration, inst); + } + case SpvBuiltInFullyCoveredEXT:{ + return ValidateFullyCoveredAtDefinition(decoration, inst); + } // Ray tracing builtins case SpvBuiltInHitKindKHR: // alias SpvBuiltInHitKindNV case SpvBuiltInHitTNV: // NOT present in KHR @@ -3828,13 +4174,11 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition( case SpvBuiltInBaryCoordSmoothCentroidAMD: case SpvBuiltInBaryCoordSmoothSampleAMD: case SpvBuiltInBaryCoordPullModelAMD: - case SpvBuiltInFragStencilRefEXT: case SpvBuiltInViewportMaskNV: case SpvBuiltInSecondaryPositionNV: case SpvBuiltInSecondaryViewportMaskNV: case SpvBuiltInPositionPerViewNV: case SpvBuiltInViewportMaskPerViewNV: - case SpvBuiltInFullyCoveredEXT: case SpvBuiltInMax: case SpvBuiltInTaskCountNV: case SpvBuiltInPrimitiveCountNV: @@ -3846,9 +4190,6 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition( case SpvBuiltInMeshViewIndicesNV: case SpvBuiltInBaryCoordNV: case SpvBuiltInBaryCoordNoPerspNV: - case SpvBuiltInFragmentSizeNV: // alias SpvBuiltInFragSizeEXT - case SpvBuiltInInvocationsPerPixelNV: // alias - // SpvBuiltInFragInvocationCountEXT // No validation rules (for the moment). break; diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index 92b51c74..b9269db7 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -1340,12 +1340,36 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-FragDepth-FragDepth-04215); case 4216: return VUID_WRAP(VUID-FragDepth-FragDepth-04216); + case 4217: + return VUID_WRAP(VUID-FragInvocationCountEXT-FragInvocationCountEXT-04217); + case 4218: + return VUID_WRAP(VUID-FragInvocationCountEXT-FragInvocationCountEXT-04218); + case 4219: + return VUID_WRAP(VUID-FragInvocationCountEXT-FragInvocationCountEXT-04219); + case 4220: + return VUID_WRAP(VUID-FragSizeEXT-FragSizeEXT-04220); + case 4221: + return VUID_WRAP(VUID-FragSizeEXT-FragSizeEXT-04221); + case 4222: + return VUID_WRAP(VUID-FragSizeEXT-FragSizeEXT-04222); + case 4223: + return VUID_WRAP(VUID-FragStencilRefEXT-FragStencilRefEXT-04223); + case 4224: + return VUID_WRAP(VUID-FragStencilRefEXT-FragStencilRefEXT-04224); + case 4225: + return VUID_WRAP(VUID-FragStencilRefEXT-FragStencilRefEXT-04225); case 4229: return VUID_WRAP(VUID-FrontFacing-FrontFacing-04229); case 4230: return VUID_WRAP(VUID-FrontFacing-FrontFacing-04230); case 4231: return VUID_WRAP(VUID-FrontFacing-FrontFacing-04231); + case 4232: + return VUID_WRAP(VUID-FullyCoveredEXT-FullyCoveredEXT-04232); + case 4233: + return VUID_WRAP(VUID-FullyCoveredEXT-FullyCoveredEXT-04233); + case 4234: + return VUID_WRAP(VUID-FullyCoveredEXT-FullyCoveredEXT-04234); case 4236: return VUID_WRAP(VUID-GlobalInvocationId-GlobalInvocationId-04236); case 4237: diff --git a/test/val/val_builtins_test.cpp b/test/val/val_builtins_test.cpp index 66e73be6..bbcdbb11 100644 --- a/test/val/val_builtins_test.cpp +++ b/test/val/val_builtins_test.cpp @@ -3941,6 +3941,184 @@ INSTANTIATE_TEST_SUITE_P( Values(TestResult(SPV_ERROR_INVALID_DATA, "According to the Vulkan spec BuiltIn ShadingRateKHR " "variable needs to be a 32-bit int scalar.")))); + +INSTANTIATE_TEST_SUITE_P( + FragInvocationCountInputSuccess, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("FragInvocationCountEXT"), Values("Fragment"), + Values("Input"), Values("%u32"), + Values("OpCapability FragmentDensityEXT\n"), + Values("OpExtension \"SPV_EXT_fragment_invocation_density\"\n"), + Values(nullptr), Values(TestResult()))); + +INSTANTIATE_TEST_SUITE_P( + FragInvocationCountInvalidExecutionModel, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine( + Values("FragInvocationCountEXT"), Values("Vertex"), Values("Input"), + Values("%u32"), Values("OpCapability FragmentDensityEXT\n"), + Values("OpExtension \"SPV_EXT_fragment_invocation_density\"\n"), + Values("VUID-FragInvocationCountEXT-FragInvocationCountEXT-04217"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "Vulkan spec allows BuiltIn FragInvocationCountEXT " + "to be used only with Fragment execution model.")))); + +INSTANTIATE_TEST_SUITE_P( + FragInvocationCountInvalidStorageClass, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("FragInvocationCountEXT"), Values("Fragment"), + Values("Output"), Values("%u32"), + Values("OpCapability FragmentDensityEXT\n"), + Values("OpExtension \"SPV_EXT_fragment_invocation_density\"\n"), + Values("VUID-FragInvocationCountEXT-FragInvocationCountEXT-04218"), + Values(TestResult( + SPV_ERROR_INVALID_DATA, + "Vulkan spec allows BuiltIn FragInvocationCountEXT to be only " + "used for variables with Input storage class.")))); + +INSTANTIATE_TEST_SUITE_P( + FragInvocationCountInvalidType, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("FragInvocationCountEXT"), Values("Fragment"), + Values("Input"), Values("%f32"), + Values("OpCapability FragmentDensityEXT\n"), + Values("OpExtension \"SPV_EXT_fragment_invocation_density\"\n"), + Values("VUID-FragInvocationCountEXT-FragInvocationCountEXT-04219"), + Values(TestResult( + SPV_ERROR_INVALID_DATA, + "According to the Vulkan spec BuiltIn FragInvocationCountEXT " + "variable needs to be a 32-bit int scalar.")))); + +INSTANTIATE_TEST_SUITE_P( + FragSizeInputSuccess, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("FragSizeEXT"), Values("Fragment"), Values("Input"), + Values("%u32vec2"), Values("OpCapability FragmentDensityEXT\n"), + Values("OpExtension \"SPV_EXT_fragment_invocation_density\"\n"), + Values(nullptr), Values(TestResult()))); + +INSTANTIATE_TEST_SUITE_P( + FragSizeInvalidExecutionModel, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("FragSizeEXT"), Values("Vertex"), Values("Input"), + Values("%u32vec2"), Values("OpCapability FragmentDensityEXT\n"), + Values("OpExtension \"SPV_EXT_fragment_invocation_density\"\n"), + Values("VUID-FragSizeEXT-FragSizeEXT-04220"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "Vulkan spec allows BuiltIn FragSizeEXT to be " + "used only with Fragment execution model.")))); + +INSTANTIATE_TEST_SUITE_P( + FragSizeInvalidStorageClass, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine( + Values("FragSizeEXT"), Values("Fragment"), Values("Output"), + Values("%u32vec2"), Values("OpCapability FragmentDensityEXT\n"), + Values("OpExtension \"SPV_EXT_fragment_invocation_density\"\n"), + Values("VUID-FragSizeEXT-FragSizeEXT-04221"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "Vulkan spec allows BuiltIn FragSizeEXT to be only " + "used for variables with Input storage class.")))); + +INSTANTIATE_TEST_SUITE_P( + FragSizeInvalidType, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("FragSizeEXT"), Values("Fragment"), Values("Input"), + Values("%u32vec3"), Values("OpCapability FragmentDensityEXT\n"), + Values("OpExtension \"SPV_EXT_fragment_invocation_density\"\n"), + Values("VUID-FragSizeEXT-FragSizeEXT-04222"), + Values(TestResult( + SPV_ERROR_INVALID_DATA, + "According to the Vulkan spec BuiltIn FragSizeEXT variable " + "needs to be a 2-component 32-bit int vector.")))); + +INSTANTIATE_TEST_SUITE_P( + FragStencilRefOutputSuccess, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("FragStencilRefEXT"), Values("Fragment"), Values("Output"), + Values("%u32", "%u64"), Values("OpCapability StencilExportEXT\n"), + Values("OpExtension \"SPV_EXT_shader_stencil_export\"\n"), + Values(nullptr), Values(TestResult()))); + +INSTANTIATE_TEST_SUITE_P( + FragStencilRefInvalidExecutionModel, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("FragStencilRefEXT"), Values("Vertex"), Values("Output"), + Values("%u32", "%u64"), Values("OpCapability StencilExportEXT\n"), + Values("OpExtension \"SPV_EXT_shader_stencil_export\"\n"), + Values("VUID-FragStencilRefEXT-FragStencilRefEXT-04223"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "Vulkan spec allows BuiltIn FragStencilRefEXT to " + "be used only with Fragment execution model.")))); + +INSTANTIATE_TEST_SUITE_P( + FragStencilRefInvalidStorageClass, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("FragStencilRefEXT"), Values("Fragment"), Values("Input"), + Values("%u32", "%u64"), Values("OpCapability StencilExportEXT\n"), + Values("OpExtension \"SPV_EXT_shader_stencil_export\"\n"), + Values("VUID-FragStencilRefEXT-FragStencilRefEXT-04224"), + Values(TestResult( + SPV_ERROR_INVALID_DATA, + "Vulkan spec allows BuiltIn FragStencilRefEXT to be only used " + "for variables with Output storage class.")))); + +INSTANTIATE_TEST_SUITE_P( + FragStencilRefInvalidType, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("FragStencilRefEXT"), Values("Fragment"), Values("Output"), + Values("%f32", "%f64", "%u32vec2"), + Values("OpCapability StencilExportEXT\n"), + Values("OpExtension \"SPV_EXT_shader_stencil_export\"\n"), + Values("VUID-FragStencilRefEXT-FragStencilRefEXT-04225"), + Values(TestResult( + SPV_ERROR_INVALID_DATA, + "According to the Vulkan spec BuiltIn FragStencilRefEXT " + "variable needs to be a int scalar.")))); + +INSTANTIATE_TEST_SUITE_P( + FullyCoveredEXTInputSuccess, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("FullyCoveredEXT"), Values("Fragment"), Values("Input"), + Values("%bool"), Values("OpCapability FragmentFullyCoveredEXT\n"), + Values("OpExtension \"SPV_EXT_fragment_fully_covered\"\n"), + Values(nullptr), Values(TestResult()))); + +INSTANTIATE_TEST_SUITE_P( + FullyCoveredEXTInvalidExecutionModel, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("FullyCoveredEXT"), Values("Vertex"), Values("Input"), + Values("%bool"), Values("OpCapability FragmentFullyCoveredEXT\n"), + Values("OpExtension \"SPV_EXT_fragment_fully_covered\"\n"), + Values("VUID-FullyCoveredEXT-FullyCoveredEXT-04232"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "Vulkan spec allows BuiltIn FullyCoveredEXT to " + "be used only with Fragment execution model.")))); + +INSTANTIATE_TEST_SUITE_P( + FullyCoveredEXTInvalidStorageClass, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("FullyCoveredEXT"), Values("Fragment"), Values("Output"), + Values("%bool"), Values("OpCapability FragmentFullyCoveredEXT\n"), + Values("OpExtension \"SPV_EXT_fragment_fully_covered\"\n"), + Values("VUID-FullyCoveredEXT-FullyCoveredEXT-04233"), + Values(TestResult( + SPV_ERROR_INVALID_DATA, + "Vulkan spec allows BuiltIn FullyCoveredEXT to be only used " + "for variables with Input storage class.")))); + +INSTANTIATE_TEST_SUITE_P( + FullyCoveredEXTInvalidType, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("FullyCoveredEXT"), Values("Fragment"), Values("Input"), + Values("%f32"), Values("OpCapability FragmentFullyCoveredEXT\n"), + Values("OpExtension \"SPV_EXT_fragment_fully_covered\"\n"), + Values("VUID-FullyCoveredEXT-FullyCoveredEXT-04234"), + Values(TestResult( + SPV_ERROR_INVALID_DATA, + "According to the Vulkan spec BuiltIn FullyCoveredEXT variable " + "needs to be a bool scalar.")))); + } // namespace } // namespace val } // namespace spvtools -- cgit v1.2.3 From 968659aee8af594139e59a2ed7b3bd099b2d0a4a Mon Sep 17 00:00:00 2001 From: mi-ac Date: Fri, 22 Jan 2021 16:28:49 +0100 Subject: Remove obsolete GN config (#4110) --- build_overrides/build.gni | 3 --- 1 file changed, 3 deletions(-) diff --git a/build_overrides/build.gni b/build_overrides/build.gni index 833fcd34..cf3d6b79 100644 --- a/build_overrides/build.gni +++ b/build_overrides/build.gni @@ -16,9 +16,6 @@ # Chromium specific targets in a client project's GN file etc. build_with_chromium = false -# Don't use Chromium's third_party/binutils. -linux_use_bundled_binutils_override = false - declare_args() { # Android 32-bit non-component, non-clang builds cannot have symbol_level=2 # due to 4GiB file size limit, see https://crbug.com/648948. -- cgit v1.2.3 From 89ad2272baae9649b71312df0b1ca94a02be7814 Mon Sep 17 00:00:00 2001 From: sfricke-samsung <46493288+sfricke-samsung@users.noreply.github.com> Date: Mon, 25 Jan 2021 06:38:19 -0800 Subject: spirv-val: Label VUID 04683 (#4121) --- source/val/validate_mode_setting.cpp | 1 + source/val/validation_state.cpp | 2 ++ test/val/val_modes_test.cpp | 2 ++ 3 files changed, 5 insertions(+) diff --git a/source/val/validate_mode_setting.cpp b/source/val/validate_mode_setting.cpp index c816b75c..79f82d8d 100644 --- a/source/val/validate_mode_setting.cpp +++ b/source/val/validate_mode_setting.cpp @@ -228,6 +228,7 @@ spv_result_t ValidateEntryPoint(ValidationState_t& _, const Instruction* inst) { } if (!ok) { return _.diag(SPV_ERROR_INVALID_DATA, inst) + << _.VkErrorID(4683) << "In the Vulkan environment, GLCompute execution model " "entry points require either the LocalSize execution " "mode or an object decorated with WorkgroupSize must be " diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index b9269db7..cbe97584 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -1704,6 +1704,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-GLSLShared-04669); case 4675: return VUID_WRAP(VUID-StandaloneSpirv-FPRoundingMode-04675); + case 4683: + return VUID_WRAP(VUID-StandaloneSpirv-LocalSize-04683); case 4685: return VUID_WRAP(VUID-StandaloneSpirv-OpGroupNonUniformBallotBitCount-04685); case 4686: diff --git a/test/val/val_modes_test.cpp b/test/val/val_modes_test.cpp index 7b231594..99f5c9cf 100644 --- a/test/val/val_modes_test.cpp +++ b/test/val/val_modes_test.cpp @@ -62,6 +62,8 @@ OpEntryPoint GLCompute %main "main" spv_target_env env = SPV_ENV_VULKAN_1_0; CompileSuccessfully(spirv, env); EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-LocalSize-04683")); EXPECT_THAT( getDiagnosticString(), HasSubstr("In the Vulkan environment, GLCompute execution model entry " -- cgit v1.2.3 From 819117cd48e7e03e2f145527177c7020cfb97721 Mon Sep 17 00:00:00 2001 From: sfricke-samsung <46493288+sfricke-samsung@users.noreply.github.com> Date: Mon, 25 Jan 2021 06:51:21 -0800 Subject: spirv-val: Label VUID 04662 (#4123) --- source/val/validate_image.cpp | 1 + source/val/validation_state.cpp | 2 ++ test/val/val_image_test.cpp | 18 ++++++++++++++++++ 3 files changed, 21 insertions(+) diff --git a/source/val/validate_image.cpp b/source/val/validate_image.cpp index fc37f08b..78dfefa2 100644 --- a/source/val/validate_image.cpp +++ b/source/val/validate_image.cpp @@ -285,6 +285,7 @@ spv_result_t ValidateImageOperands(ValidationState_t& _, mask & (SpvImageOperandsOffsetMask | SpvImageOperandsConstOffsetMask | SpvImageOperandsConstOffsetsMask)) > 1) { return _.diag(SPV_ERROR_INVALID_DATA, inst) + << _.VkErrorID(4662) << "Image Operands Offset, ConstOffset, ConstOffsets cannot be used " << "together"; } diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index cbe97584..791f0b9c 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -1700,6 +1700,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-OpTypeImage-04657); case 4658: return VUID_WRAP(VUID-StandaloneSpirv-OpImageTexelPointer-04658); + case 4662: + return VUID_WRAP(VUID-StandaloneSpirv-Offset-04662); case 4669: return VUID_WRAP(VUID-StandaloneSpirv-GLSLShared-04669); case 4675: diff --git a/test/val/val_image_test.cpp b/test/val/val_image_test.cpp index ce4bf1be..6fa5f22b 100644 --- a/test/val/val_image_test.cpp +++ b/test/val/val_image_test.cpp @@ -1782,6 +1782,24 @@ TEST_F(ValidateImage, SampleImplicitLodMoreThanOneOffset) { "cannot be used together")); } +TEST_F(ValidateImage, SampleImplicitLodVulkanMoreThanOneOffset) { + const std::string body = R"( +%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 +%sampler = OpLoad %type_sampler %uniform_sampler +%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler +%res4 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec4_0000 ConstOffset|Offset %s32vec2_01 %s32vec2_01 +)"; + + CompileSuccessfully( + GenerateShaderCode(body, "", "Fragment", "", SPV_ENV_VULKAN_1_0).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-Offset-04662")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Image Operands Offset, ConstOffset, ConstOffsets " + "cannot be used together")); +} + TEST_F(ValidateImage, SampleImplicitLodMinLodWrongType) { const std::string body = R"( %img = OpLoad %type_image_f32_cube_0101 %uniform_image_f32_cube_0101 -- cgit v1.2.3 From a61600c7639c1a03df4967806fb8cc48ea3c45ca Mon Sep 17 00:00:00 2001 From: sfricke-samsung <46493288+sfricke-samsung@users.noreply.github.com> Date: Mon, 25 Jan 2021 08:19:06 -0800 Subject: spirv-val: Label Vulkan atomic semantics VUIDs (#4120) --- source/val/validate_memory_semantics.cpp | 6 ++++-- source/val/validation_state.cpp | 10 ++++++++-- test/val/val_atomics_test.cpp | 12 ++++++++++++ test/val/val_barriers_test.cpp | 6 +++--- 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/source/val/validate_memory_semantics.cpp b/source/val/validate_memory_semantics.cpp index 8e47f8a3..6c3e1d44 100644 --- a/source/val/validate_memory_semantics.cpp +++ b/source/val/validate_memory_semantics.cpp @@ -172,7 +172,7 @@ spv_result_t ValidateMemorySemantics(ValidationState_t& _, if (opcode == SpvOpMemoryBarrier && !num_memory_order_set_bits) { return _.diag(SPV_ERROR_INVALID_DATA, inst) - << _.VkErrorID(4649) << spvOpcodeString(opcode) + << _.VkErrorID(4732) << spvOpcodeString(opcode) << ": Vulkan specification requires Memory Semantics to have " "one " "of the following bits set: Acquire, Release, " @@ -182,7 +182,7 @@ spv_result_t ValidateMemorySemantics(ValidationState_t& _, if (opcode == SpvOpMemoryBarrier && !includes_storage_class) { return _.diag(SPV_ERROR_INVALID_DATA, inst) - << _.VkErrorID(4649) << spvOpcodeString(opcode) + << _.VkErrorID(4733) << spvOpcodeString(opcode) << ": expected Memory Semantics to include a Vulkan-supported " "storage class"; } @@ -223,6 +223,7 @@ spv_result_t ValidateMemorySemantics(ValidationState_t& _, value & SpvMemorySemanticsAcquireReleaseMask || value & SpvMemorySemanticsSequentiallyConsistentMask)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) + << _.VkErrorID(4731) << "Vulkan spec disallows OpAtomicLoad with Memory Semantics " "Release, AcquireRelease and SequentiallyConsistent"; } @@ -232,6 +233,7 @@ spv_result_t ValidateMemorySemantics(ValidationState_t& _, value & SpvMemorySemanticsAcquireReleaseMask || value & SpvMemorySemanticsSequentiallyConsistentMask)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) + << _.VkErrorID(4730) << "Vulkan spec disallows OpAtomicStore with Memory Semantics " "Acquire, AcquireRelease and SequentiallyConsistent"; } diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index 791f0b9c..d61956d0 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -1684,8 +1684,6 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-None-04640); case 4642: return VUID_WRAP(VUID-StandaloneSpirv-None-04642); - case 4649: - return VUID_WRAP(VUID-StandaloneSpirv-OpMemoryBarrier-04649); case 4651: return VUID_WRAP(VUID-StandaloneSpirv-OpVariable-04651); case 4652: @@ -1714,6 +1712,14 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-None-04686); case 4711: return VUID_WRAP(VUID-StandaloneSpirv-OpTypeForwardPointer-04711); + case 4730: + return VUID_WRAP(VUID-StandaloneSpirv-OpAtomicStore-04730); + case 4731: + return VUID_WRAP(VUID-StandaloneSpirv-OpAtomicLoad-04731); + case 4732: + return VUID_WRAP(VUID-StandaloneSpirv-OpMemoryBarrier-04732); + case 4733: + return VUID_WRAP(VUID-StandaloneSpirv-OpMemoryBarrier-04733); default: return ""; // unknown id }; diff --git a/test/val/val_atomics_test.cpp b/test/val/val_atomics_test.cpp index c7e36f5d..fccfabc3 100644 --- a/test/val/val_atomics_test.cpp +++ b/test/val/val_atomics_test.cpp @@ -477,6 +477,8 @@ TEST_F(ValidateAtomics, AtomicLoadVulkanRelease) { CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpAtomicLoad-04731")); EXPECT_THAT( getDiagnosticString(), HasSubstr("Vulkan spec disallows OpAtomicLoad with Memory Semantics " @@ -490,6 +492,8 @@ TEST_F(ValidateAtomics, AtomicLoadVulkanAcquireRelease) { CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpAtomicLoad-04731")); EXPECT_THAT( getDiagnosticString(), HasSubstr("Vulkan spec disallows OpAtomicLoad with Memory Semantics " @@ -503,6 +507,8 @@ TEST_F(ValidateAtomics, AtomicLoadVulkanSequentiallyConsistent) { CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpAtomicLoad-04731")); EXPECT_THAT( getDiagnosticString(), HasSubstr("Vulkan spec disallows OpAtomicLoad with Memory Semantics " @@ -675,6 +681,8 @@ OpAtomicStore %u32_var %device %acquire %u32_1 CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpAtomicStore-04730")); EXPECT_THAT( getDiagnosticString(), HasSubstr("Vulkan spec disallows OpAtomicStore with Memory Semantics " @@ -688,6 +696,8 @@ OpAtomicStore %u32_var %device %acquire_release %u32_1 CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpAtomicStore-04730")); EXPECT_THAT( getDiagnosticString(), HasSubstr("Vulkan spec disallows OpAtomicStore with Memory Semantics " @@ -701,6 +711,8 @@ OpAtomicStore %u32_var %device %sequentially_consistent %u32_1 CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpAtomicStore-04730")); EXPECT_THAT( getDiagnosticString(), HasSubstr("Vulkan spec disallows OpAtomicStore with Memory Semantics " diff --git a/test/val/val_barriers_test.cpp b/test/val/val_barriers_test.cpp index 9a4beba3..46f5b5a1 100644 --- a/test/val/val_barriers_test.cpp +++ b/test/val/val_barriers_test.cpp @@ -721,7 +721,7 @@ OpMemoryBarrier %device %none CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); EXPECT_THAT(getDiagnosticString(), - AnyVUID("VUID-StandaloneSpirv-OpMemoryBarrier-04649")); + AnyVUID("VUID-StandaloneSpirv-OpMemoryBarrier-04732")); EXPECT_THAT( getDiagnosticString(), HasSubstr("MemoryBarrier: Vulkan specification requires Memory Semantics " @@ -737,7 +737,7 @@ OpMemoryBarrier %device %acquire CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); EXPECT_THAT(getDiagnosticString(), - AnyVUID("VUID-StandaloneSpirv-OpMemoryBarrier-04649")); + AnyVUID("VUID-StandaloneSpirv-OpMemoryBarrier-04733")); EXPECT_THAT(getDiagnosticString(), HasSubstr("MemoryBarrier: expected Memory Semantics to include a " "Vulkan-supported storage class")); @@ -751,7 +751,7 @@ OpMemoryBarrier %device %acquire_release_subgroup CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); EXPECT_THAT(getDiagnosticString(), - AnyVUID("VUID-StandaloneSpirv-OpMemoryBarrier-04649")); + AnyVUID("VUID-StandaloneSpirv-OpMemoryBarrier-04733")); EXPECT_THAT(getDiagnosticString(), HasSubstr("MemoryBarrier: expected Memory Semantics to include a " "Vulkan-supported storage class")); -- cgit v1.2.3 From a4f97da409f267281f54a4f84bd95bb06dc4128e Mon Sep 17 00:00:00 2001 From: alan-baker Date: Wed, 27 Jan 2021 18:00:56 -0500 Subject: Add cmake to windows path for kokoro (#4129) * Add cmake to windows path for kokoro --- kokoro/scripts/windows/build.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kokoro/scripts/windows/build.bat b/kokoro/scripts/windows/build.bat index fa7a71a0..a4ce792a 100644 --- a/kokoro/scripts/windows/build.bat +++ b/kokoro/scripts/windows/build.bat @@ -22,7 +22,7 @@ set BUILD_TYPE=%1 set VS_VERSION=%2 :: Force usage of python 3.6 -set PATH=C:\python36;%PATH% +set PATH=C:\python36;"C:\Program Files\CMake\bin";%PATH% cd %SRC% git clone --depth=1 https://github.com/KhronosGroup/SPIRV-Headers external/spirv-headers -- cgit v1.2.3 From d71ac38b8ee14f9acad22a3bcb0c294d489bedf4 Mon Sep 17 00:00:00 2001 From: sfricke-samsung <46493288+sfricke-samsung@users.noreply.github.com> Date: Wed, 27 Jan 2021 16:37:45 -0800 Subject: spirv-val: Add Vulkan image gather offset VUID (#4118) --- source/val/validate_image.cpp | 11 +++++++++++ source/val/validation_state.cpp | 2 ++ test/val/val_image_test.cpp | 18 ++++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/source/val/validate_image.cpp b/source/val/validate_image.cpp index 78dfefa2..3f3f7902 100644 --- a/source/val/validate_image.cpp +++ b/source/val/validate_image.cpp @@ -441,6 +441,17 @@ spv_result_t ValidateImageOperands(ValidationState_t& _, << "Expected Image Operand Offset to have " << plane_size << " components, but given " << offset_size; } + + if (spvIsVulkanEnv(_.context()->target_env)) { + if (opcode != SpvOpImageGather && opcode != SpvOpImageDrefGather && + opcode != SpvOpImageSparseGather && + opcode != SpvOpImageSparseDrefGather) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << _.VkErrorID(4663) + << "Image Operand Offset can only be used with " + "OpImage*Gather operations"; + } + } } if (mask & SpvImageOperandsConstOffsetsMask) { diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index d61956d0..c2ca893c 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -1700,6 +1700,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-OpImageTexelPointer-04658); case 4662: return VUID_WRAP(VUID-StandaloneSpirv-Offset-04662); + case 4663: + return VUID_WRAP(VUID-StandaloneSpirv-Offset-04663); case 4669: return VUID_WRAP(VUID-StandaloneSpirv-GLSLShared-04669); case 4675: diff --git a/test/val/val_image_test.cpp b/test/val/val_image_test.cpp index 6fa5f22b..d7d40f5b 100644 --- a/test/val/val_image_test.cpp +++ b/test/val/val_image_test.cpp @@ -1767,6 +1767,24 @@ TEST_F(ValidateImage, SampleImplicitLodOffsetWrongSize) { "Expected Image Operand Offset to have 2 components, but given 3")); } +TEST_F(ValidateImage, SampleImplicitLodVulkanOffsetWrongSize) { + const std::string body = R"( +%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 +%sampler = OpLoad %type_sampler %uniform_sampler +%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler +%res4 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec4_0000 Offset %s32vec2_01 +)"; + + CompileSuccessfully( + GenerateShaderCode(body, "", "Fragment", "", SPV_ENV_VULKAN_1_0).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-Offset-04663")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Image Operand Offset can only be used with " + "OpImage*Gather operations")); +} + TEST_F(ValidateImage, SampleImplicitLodMoreThanOneOffset) { const std::string body = R"( %img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 -- cgit v1.2.3 From cc81f53d3d6146638b302694d319a580e4d88f70 Mon Sep 17 00:00:00 2001 From: alan-baker Date: Wed, 27 Jan 2021 19:38:09 -0500 Subject: Validate VK_KHR_zero_initialize_workgroup_memory (#4124) * Allow OpConstantNull for Workgroup variable initializer in Vulkan environment * tests --- source/val/validate_memory.cpp | 30 ++++++++++++++++-------- test/val/val_memory_test.cpp | 52 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 71 insertions(+), 11 deletions(-) diff --git a/source/val/validate_memory.cpp b/source/val/validate_memory.cpp index 45a232da..baa35031 100644 --- a/source/val/validate_memory.cpp +++ b/source/val/validate_memory.cpp @@ -584,16 +584,26 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { storage_class != SpvStorageClassPrivate && storage_class != SpvStorageClassFunction) { if (spvIsVulkanEnv(_.context()->target_env)) { - return _.diag(SPV_ERROR_INVALID_ID, inst) - << _.VkErrorID(4651) << "OpVariable, '" - << _.getIdName(inst->id()) - << "', has a disallowed initializer & storage class " - << "combination.\n" - << "From " << spvLogStringForEnv(_.context()->target_env) - << " spec:\n" - << "Variable declarations that include initializers must have " - << "one of the following storage classes: Output, Private, or " - << "Function"; + if (storage_class == SpvStorageClassWorkgroup) { + auto init_id = inst->GetOperandAs(3); + auto init = _.FindDef(init_id); + if (init->opcode() != SpvOpConstantNull) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Variable initializers in Workgroup storage class are " + "limited to OpConstantNull"; + } + } else { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << _.VkErrorID(4651) << "OpVariable, '" + << _.getIdName(inst->id()) + << "', has a disallowed initializer & storage class " + << "combination.\n" + << "From " << spvLogStringForEnv(_.context()->target_env) + << " spec:\n" + << "Variable declarations that include initializers must have " + << "one of the following storage classes: Output, Private, " + << "Function or Workgroup"; + } } } diff --git a/test/val/val_memory_test.cpp b/test/val/val_memory_test.cpp index 8142f859..0d97c66b 100644 --- a/test/val/val_memory_test.cpp +++ b/test/val/val_memory_test.cpp @@ -451,7 +451,8 @@ OpFunctionEnd HasSubstr("OpVariable, '5[%5]', has a disallowed initializer & " "storage class combination.\nFrom Vulkan spec:\nVariable " "declarations that include initializers must have one of the " - "following storage classes: Output, Private, or Function\n %5 " + "following storage classes: Output, Private, Function or " + "Workgroup\n %5 " "= OpVariable %_ptr_Input_float Input %float_1\n")); } @@ -4080,6 +4081,55 @@ OpFunctionEnd "Cannot use a pointer in the PhysicalStorageBuffer storage class")); } +TEST_F(ValidateMemory, VulkanInitializerWithWorkgroupStorageClassBad) { + std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%float = OpTypeFloat 32 +%float_ptr = OpTypePointer Workgroup %float +%init_val = OpConstant %float 1.0 +%1 = OpVariable %float_ptr Workgroup %init_val +%void = OpTypeVoid +%functy = OpTypeFunction %void +%func = OpFunction %void None %functy +%2 = OpLabel +OpReturn +OpFunctionEnd +)"; + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Variable initializers in Workgroup storage class are " + "limited to OpConstantNull")); +} + +TEST_F(ValidateMemory, VulkanInitializerWithWorkgroupStorageClassGood) { + std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%float = OpTypeFloat 32 +%float_ptr = OpTypePointer Workgroup %float +%init_val = OpConstantNull %float +%1 = OpVariable %float_ptr Workgroup %init_val +%void = OpTypeVoid +%functy = OpTypeFunction %void +%func = OpFunction %void None %functy +%2 = OpLabel +OpReturn +OpFunctionEnd +)"; + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0)); +} + } // namespace } // namespace val } // namespace spvtools -- cgit v1.2.3 From b812fd634ea5ff307c374fb2b6340169f7db8b16 Mon Sep 17 00:00:00 2001 From: Caio Marcelo de Oliveira Filho Date: Wed, 27 Jan 2021 16:38:38 -0800 Subject: Validate SPV_KHR_workgroup_memory_explicit_layout (#4128) * Validate SPV_KHR_workgroup_memory_explicit_layout * Check if SPIR-V is at least 1.4 to use the extension. * Check if either only Workgroup Blocks or only Workgroup non-Blocks are used. * Check that if more than one Workgroup Block is used, variables are decorated with Aliased. * Check layout decorations for Workgroup Blocks. * Implicitly use main capability if the ...8BitAccess or ...16BitAccess are used. * Allow 8-bit and 16-bit types when ...8BitAccess and ...16BitAccess are used respectively. * Update SPIRV-Headers dependency Bump it to include SPV_KHR_workgroup_memory_explicit_layout. * Add option to validate Workgroup blocks with scalar layout Validate the equivalent of scalarBlockLayout for Workgroup storage class Block variables from SPV_KHR_workgroup_memory_explicit_layout. Add option to the API and command line tool. --- DEPS | 2 +- include/spirv-tools/libspirv.h | 6 + include/spirv-tools/libspirv.hpp | 6 + source/spirv_validator_options.cpp | 5 + source/spirv_validator_options.h | 2 + source/val/validate_decorations.cpp | 70 +++++- source/val/validate_extensions.cpp | 16 ++ source/val/validate_memory.cpp | 10 + source/val/validation_state.cpp | 2 + source/val/validation_state.h | 4 + test/val/val_decoration_test.cpp | 463 ++++++++++++++++++++++++++++++++++++ test/val/val_memory_test.cpp | 89 +++++-- tools/opt/opt.cpp | 6 + tools/val/val.cpp | 3 + 14 files changed, 654 insertions(+), 30 deletions(-) diff --git a/DEPS b/DEPS index 3762681d..75581c5a 100644 --- a/DEPS +++ b/DEPS @@ -6,7 +6,7 @@ vars = { 'effcee_revision': '2ec8f8738118cc483b67c04a759fee53496c5659', 'googletest_revision': '3af06fe1664d30f98de1e78c53a7087e842a2547', 're2_revision': 'ca11026a032ce2a3de4b3c389ee53d2bdc8794d6', - 'spirv_headers_revision': 'f027d53ded7e230e008d37c8b47ede7cd308e19d', + 'spirv_headers_revision': 'faa570afbc91ac73d594d787486bcf8f2df1ace0', } deps = { diff --git a/include/spirv-tools/libspirv.h b/include/spirv-tools/libspirv.h index 201ee58b..658c4dd5 100644 --- a/include/spirv-tools/libspirv.h +++ b/include/spirv-tools/libspirv.h @@ -625,6 +625,12 @@ SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetUniformBufferStandardLayout( SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetScalarBlockLayout( spv_validator_options options, bool val); +// Records whether the validator should use "scalar" block layout +// rules (as defined above) for Workgroup blocks. See Vulkan +// extension VK_KHR_workgroup_memory_explicit_layout. +SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetWorkgroupScalarBlockLayout( + spv_validator_options options, bool val); + // Records whether or not the validator should skip validating standard // uniform/storage block layout. SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetSkipBlockLayout( diff --git a/include/spirv-tools/libspirv.hpp b/include/spirv-tools/libspirv.hpp index 2018e461..e7e7fc7a 100644 --- a/include/spirv-tools/libspirv.hpp +++ b/include/spirv-tools/libspirv.hpp @@ -104,6 +104,12 @@ class ValidatorOptions { spvValidatorOptionsSetScalarBlockLayout(options_, val); } + // Enables scalar layout when validating Workgroup blocks. See + // VK_KHR_workgroup_memory_explicit_layout. + void SetWorkgroupScalarBlockLayout(bool val) { + spvValidatorOptionsSetWorkgroupScalarBlockLayout(options_, val); + } + // Skips validating standard uniform/storage buffer/push-constant layout. void SetSkipBlockLayout(bool val) { spvValidatorOptionsSetSkipBlockLayout(options_, val); diff --git a/source/spirv_validator_options.cpp b/source/spirv_validator_options.cpp index 01aa7974..2716cca9 100644 --- a/source/spirv_validator_options.cpp +++ b/source/spirv_validator_options.cpp @@ -111,6 +111,11 @@ void spvValidatorOptionsSetScalarBlockLayout(spv_validator_options options, options->scalar_block_layout = val; } +void spvValidatorOptionsSetWorkgroupScalarBlockLayout(spv_validator_options options, + bool val) { + options->workgroup_scalar_block_layout = val; +} + void spvValidatorOptionsSetSkipBlockLayout(spv_validator_options options, bool val) { options->skip_block_layout = val; diff --git a/source/spirv_validator_options.h b/source/spirv_validator_options.h index b7da5d8e..baaa5359 100644 --- a/source/spirv_validator_options.h +++ b/source/spirv_validator_options.h @@ -45,6 +45,7 @@ struct spv_validator_options_t { relax_block_layout(false), uniform_buffer_standard_layout(false), scalar_block_layout(false), + workgroup_scalar_block_layout(false), skip_block_layout(false), before_hlsl_legalization(false) {} @@ -54,6 +55,7 @@ struct spv_validator_options_t { bool relax_block_layout; bool uniform_buffer_standard_layout; bool scalar_block_layout; + bool workgroup_scalar_block_layout; bool skip_block_layout; bool before_hlsl_legalization; }; diff --git a/source/val/validate_decorations.cpp b/source/val/validate_decorations.cpp index 01b0ecab..ed336b47 100644 --- a/source/val/validate_decorations.cpp +++ b/source/val/validate_decorations.cpp @@ -379,6 +379,7 @@ bool IsAlignedTo(uint32_t offset, uint32_t alignment) { // or row major-ness. spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str, const char* decoration_str, bool blockRules, + bool scalar_block_layout, uint32_t incoming_offset, MemberConstraints& constraints, ValidationState_t& vstate) { @@ -392,7 +393,6 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str, // For example, relaxed layout is implied by Vulkan 1.1. But scalar layout // is more permissive than relaxed layout. const bool relaxed_block_layout = vstate.IsRelaxedBlockLayout(); - const bool scalar_block_layout = vstate.options()->scalar_block_layout; auto fail = [&vstate, struct_id, storage_class_str, decoration_str, blockRules, relaxed_block_layout, @@ -501,6 +501,7 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str, if (SpvOpTypeStruct == opcode && SPV_SUCCESS != (recursive_status = checkLayout( id, storage_class_str, decoration_str, blockRules, + scalar_block_layout, offset, constraints, vstate))) return recursive_status; // Check matrix stride. @@ -553,7 +554,8 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str, if (SpvOpTypeStruct == element_inst->opcode() && SPV_SUCCESS != (recursive_status = checkLayout( typeId, storage_class_str, decoration_str, - blockRules, next_offset, constraints, vstate))) + blockRules, scalar_block_layout, + next_offset, constraints, vstate))) return recursive_status; // If offsets accumulate up to a 16-byte multiple stop checking since // it will just repeat. @@ -698,6 +700,9 @@ spv_result_t CheckDecorationsOfEntryPoints(ValidationState_t& vstate) { const auto& descs = vstate.entry_point_descriptions(entry_point); int num_builtin_inputs = 0; int num_builtin_outputs = 0; + int num_workgroup_variables = 0; + int num_workgroup_variables_with_block = 0; + int num_workgroup_variables_with_aliased = 0; for (const auto& desc : descs) { std::unordered_set seen_vars; for (auto interface : desc.interfaces) { @@ -754,6 +759,16 @@ spv_result_t CheckDecorationsOfEntryPoints(ValidationState_t& vstate) { if (auto error = CheckBuiltInVariable(interface, vstate)) return error; } + + if (storage_class == SpvStorageClassWorkgroup) { + ++num_workgroup_variables; + if (type_instr && SpvOpTypeStruct == type_instr->opcode()) { + if (hasDecoration(type_id, SpvDecorationBlock, vstate)) + ++num_workgroup_variables_with_block; + if (hasDecoration(var_instr->id(), SpvDecorationAliased, vstate)) + ++num_workgroup_variables_with_aliased; + } + } } if (num_builtin_inputs > 1 || num_builtin_outputs > 1) { return vstate.diag(SPV_ERROR_INVALID_BINARY, @@ -777,6 +792,30 @@ spv_result_t CheckDecorationsOfEntryPoints(ValidationState_t& vstate) { << " because it is targeted by an OpEntryPoint instruction."; } } + + if (vstate.HasCapability(SpvCapabilityWorkgroupMemoryExplicitLayoutKHR) && + num_workgroup_variables > 0 && + num_workgroup_variables_with_block > 0) { + if (num_workgroup_variables != num_workgroup_variables_with_block) { + return vstate.diag(SPV_ERROR_INVALID_BINARY, vstate.FindDef(entry_point)) + << "When declaring WorkgroupMemoryExplicitLayoutKHR, " + "either all or none of the Workgroup Storage Class variables " + "in the entry point interface must point to struct types " + "decorated with Block. Entry point id " + << entry_point << " does not meet this requirement."; + } + if (num_workgroup_variables_with_block > 1 && + num_workgroup_variables_with_block != + num_workgroup_variables_with_aliased) { + return vstate.diag(SPV_ERROR_INVALID_BINARY, vstate.FindDef(entry_point)) + << "When declaring WorkgroupMemoryExplicitLayoutKHR, " + "if more than one Workgroup Storage Class variable in " + "the entry point interface point to a type decorated " + "with Block, all of them must be decorated with Aliased. " + "Entry point id " + << entry_point << " does not meet this requirement."; + } + } } } return SPV_SUCCESS; @@ -942,14 +981,16 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) { const bool phys_storage_buffer = storageClass == SpvStorageClassPhysicalStorageBufferEXT; - if (uniform || push_constant || storage_buffer || phys_storage_buffer) { + const bool workgroup = storageClass == SpvStorageClassWorkgroup; + if (uniform || push_constant || storage_buffer || phys_storage_buffer || + workgroup) { const auto ptrInst = vstate.FindDef(words[1]); assert(SpvOpTypePointer == ptrInst->opcode()); auto id = ptrInst->words()[3]; auto id_inst = vstate.FindDef(id); // Jump through one level of arraying. - if (id_inst->opcode() == SpvOpTypeArray || - id_inst->opcode() == SpvOpTypeRuntimeArray) { + if (!workgroup && (id_inst->opcode() == SpvOpTypeArray || + id_inst->opcode() == SpvOpTypeRuntimeArray)) { id = id_inst->GetOperandAs(1u); id_inst = vstate.FindDef(id); } @@ -961,7 +1002,9 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) { // Prepare for messages const char* sc_str = uniform ? "Uniform" - : (push_constant ? "PushConstant" : "StorageBuffer"); + : (push_constant ? "PushConstant" + : (workgroup ? "Workgroup" + : "StorageBuffer")); if (spvIsVulkanEnv(vstate.context()->target_env)) { const bool block = hasDecoration(id, SpvDecorationBlock, vstate); @@ -1029,8 +1072,9 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) { const bool bufferDeco = SpvDecorationBufferBlock == dec.dec_type(); const bool blockRules = uniform && blockDeco; const bool bufferRules = - (uniform && bufferDeco) || (push_constant && blockDeco) || - ((storage_buffer || phys_storage_buffer) && blockDeco); + (uniform && bufferDeco) || + ((push_constant || storage_buffer || + phys_storage_buffer || workgroup) && blockDeco); if (uniform && blockDeco) { vstate.RegisterPointerToUniformBlock(ptrInst->id()); vstate.RegisterStructForUniformBlock(id); @@ -1044,6 +1088,10 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) { if (blockRules || bufferRules) { const char* deco_str = blockDeco ? "Block" : "BufferBlock"; spv_result_t recursive_status = SPV_SUCCESS; + const bool scalar_block_layout = workgroup ? + vstate.options()->workgroup_scalar_block_layout : + vstate.options()->scalar_block_layout; + if (isMissingOffsetInStruct(id, vstate)) { return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id)) << "Structure id " << id << " decorated as " << deco_str @@ -1072,12 +1120,14 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) { "decorations."; } else if (blockRules && (SPV_SUCCESS != (recursive_status = checkLayout( - id, sc_str, deco_str, true, 0, + id, sc_str, deco_str, true, + scalar_block_layout, 0, constraints, vstate)))) { return recursive_status; } else if (bufferRules && (SPV_SUCCESS != (recursive_status = checkLayout( - id, sc_str, deco_str, false, 0, + id, sc_str, deco_str, false, + scalar_block_layout, 0, constraints, vstate)))) { return recursive_status; } diff --git a/source/val/validate_extensions.cpp b/source/val/validate_extensions.cpp index af6ae2b7..dc8c0243 100644 --- a/source/val/validate_extensions.cpp +++ b/source/val/validate_extensions.cpp @@ -27,6 +27,7 @@ #include "source/latest_version_glsl_std_450_header.h" #include "source/latest_version_opencl_std_header.h" #include "source/opcode.h" +#include "source/spirv_constant.h" #include "source/spirv_target_env.h" #include "source/val/instruction.h" #include "source/val/validate.h" @@ -685,6 +686,20 @@ bool IsDebugVariableWithIntScalarType(ValidationState_t& _, } // anonymous namespace +spv_result_t ValidateExtension(ValidationState_t& _, const Instruction* inst) { + if (_.version() < SPV_SPIRV_VERSION_WORD(1, 4)) { + std::string extension = GetExtensionString(&(inst->c_inst())); + if (extension == + ExtensionToString(kSPV_KHR_workgroup_memory_explicit_layout)) { + return _.diag(SPV_ERROR_WRONG_VERSION, inst) + << "SPV_KHR_workgroup_memory_explicit_layout extension " + "requires SPIR-V version 1.4 or later."; + } + } + + return SPV_SUCCESS; +} + spv_result_t ValidateExtInstImport(ValidationState_t& _, const Instruction* inst) { const auto name_id = 1; @@ -3124,6 +3139,7 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) { spv_result_t ExtensionPass(ValidationState_t& _, const Instruction* inst) { const SpvOp opcode = inst->opcode(); + if (opcode == SpvOpExtension) return ValidateExtension(_, inst); if (opcode == SpvOpExtInstImport) return ValidateExtInstImport(_, inst); if (opcode == SpvOpExtInst) return ValidateExtInst(_, inst); diff --git a/source/val/validate_memory.cpp b/source/val/validate_memory.cpp index baa35031..edc2a0ce 100644 --- a/source/val/validate_memory.cpp +++ b/source/val/validate_memory.cpp @@ -759,6 +759,11 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { storage_class_ok = false; } break; + case SpvStorageClassWorkgroup: + if (!_.HasCapability(SpvCapabilityWorkgroupMemoryExplicitLayout16BitAccessKHR)) { + storage_class_ok = false; + } + break; default: return _.diag(SPV_ERROR_INVALID_ID, inst) << "Cannot allocate a variable containing a 16-bit type in " @@ -810,6 +815,11 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { storage_class_ok = false; } break; + case SpvStorageClassWorkgroup: + if (!_.HasCapability(SpvCapabilityWorkgroupMemoryExplicitLayout8BitAccessKHR)) { + storage_class_ok = false; + } + break; default: return _.diag(SPV_ERROR_INVALID_ID, inst) << "Cannot allocate a variable containing a 8-bit type in " diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index c2ca893c..3268e424 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -359,6 +359,7 @@ void ValidationState_t::RegisterCapability(SpvCapability cap) { case SpvCapabilityStorageBuffer8BitAccess: case SpvCapabilityUniformAndStorageBuffer8BitAccess: case SpvCapabilityStoragePushConstant8: + case SpvCapabilityWorkgroupMemoryExplicitLayout8BitAccessKHR: features_.declare_int8_type = true; break; case SpvCapabilityInt16: @@ -372,6 +373,7 @@ void ValidationState_t::RegisterCapability(SpvCapability cap) { case SpvCapabilityStorageUniform16: case SpvCapabilityStoragePushConstant16: case SpvCapabilityStorageInputOutput16: + case SpvCapabilityWorkgroupMemoryExplicitLayout16BitAccessKHR: features_.declare_int16_type = true; features_.declare_float16_type = true; features_.free_fp_rounding_mode = true; diff --git a/source/val/validation_state.h b/source/val/validation_state.h index aeb1ca86..85111391 100644 --- a/source/val/validation_state.h +++ b/source/val/validation_state.h @@ -103,6 +103,10 @@ class ValidationState_t { // Members need not be listed in offset order bool scalar_block_layout = false; + // Use scalar block layout (as defined above) for Workgroup block + // variables. See VK_KHR_workgroup_memory_explicit_layout. + bool workgroup_scalar_block_layout = false; + // SPIR-V 1.4 allows us to select between any two composite values // of the same type. bool select_between_composites = false; diff --git a/test/val/val_decoration_test.cpp b/test/val/val_decoration_test.cpp index 8fe1aa6c..cbf6d7c1 100644 --- a/test/val/val_decoration_test.cpp +++ b/test/val/val_decoration_test.cpp @@ -7183,6 +7183,469 @@ OpDecorate %float Location 0 "or member of a structure type")); } +TEST_F(ValidateDecorations, WorkgroupSingleBlockVariable) { + std::string spirv = R"( + OpCapability Shader + OpCapability WorkgroupMemoryExplicitLayoutKHR + OpExtension "SPV_KHR_workgroup_memory_explicit_layout" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" %_ + OpExecutionMode %main LocalSize 8 1 1 + OpMemberDecorate %first 0 Offset 0 + OpDecorate %first Block + %void = OpTypeVoid + %3 = OpTypeFunction %void + %int = OpTypeInt 32 1 + %first = OpTypeStruct %int +%_ptr_Workgroup_first = OpTypePointer Workgroup %first + %_ = OpVariable %_ptr_Workgroup_first Workgroup + %int_0 = OpConstant %int 0 + %int_2 = OpConstant %int 2 +%_ptr_Workgroup_int = OpTypePointer Workgroup %int + %main = OpFunction %void None %3 + %5 = OpLabel + %13 = OpAccessChain %_ptr_Workgroup_int %_ %int_0 + OpStore %13 %int_2 + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, + ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4)); +} + +TEST_F(ValidateDecorations, WorkgroupBlockVariableRequiresV14) { + std::string spirv = R"( + OpCapability Shader + OpCapability WorkgroupMemoryExplicitLayoutKHR + OpExtension "SPV_KHR_workgroup_memory_explicit_layout" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" %_ + OpExecutionMode %main LocalSize 8 1 1 + OpMemberDecorate %first 0 Offset 0 + OpDecorate %first Block + %void = OpTypeVoid + %3 = OpTypeFunction %void + %int = OpTypeInt 32 1 + %first = OpTypeStruct %int +%_ptr_Workgroup_first = OpTypePointer Workgroup %first + %_ = OpVariable %_ptr_Workgroup_first Workgroup + %int_0 = OpConstant %int 0 + %int_2 = OpConstant %int 2 +%_ptr_Workgroup_int = OpTypePointer Workgroup %int + %main = OpFunction %void None %3 + %5 = OpLabel + %13 = OpAccessChain %_ptr_Workgroup_int %_ %int_0 + OpStore %13 %int_2 + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_WRONG_VERSION, + ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("requires SPIR-V version 1.4 or later")); +} + +TEST_F(ValidateDecorations, WorkgroupSingleNonBlockVariable) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" %a + OpExecutionMode %main LocalSize 8 1 1 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %int = OpTypeInt 32 1 +%_ptr_Workgroup_int = OpTypePointer Workgroup %int + %a = OpVariable %_ptr_Workgroup_int Workgroup + %int_2 = OpConstant %int 2 + %main = OpFunction %void None %3 + %5 = OpLabel + OpStore %a %int_2 + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, + ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4)); +} + +TEST_F(ValidateDecorations, WorkgroupMultiBlockVariable) { + std::string spirv = R"( + OpCapability Shader + OpCapability WorkgroupMemoryExplicitLayoutKHR + OpExtension "SPV_KHR_workgroup_memory_explicit_layout" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" %_ %__0 + OpExecutionMode %main LocalSize 8 1 1 + OpMemberDecorate %first 0 Offset 0 + OpDecorate %first Block + OpMemberDecorate %second 0 Offset 0 + OpDecorate %second Block + OpDecorate %_ Aliased + OpDecorate %__0 Aliased + %void = OpTypeVoid + %3 = OpTypeFunction %void + %int = OpTypeInt 32 1 + %first = OpTypeStruct %int +%_ptr_Workgroup_first = OpTypePointer Workgroup %first + %_ = OpVariable %_ptr_Workgroup_first Workgroup + %int_0 = OpConstant %int 0 + %int_2 = OpConstant %int 2 +%_ptr_Workgroup_int = OpTypePointer Workgroup %int + %second = OpTypeStruct %int +%_ptr_Workgroup_second = OpTypePointer Workgroup %second + %__0 = OpVariable %_ptr_Workgroup_second Workgroup + %int_3 = OpConstant %int 3 + %main = OpFunction %void None %3 + %5 = OpLabel + %13 = OpAccessChain %_ptr_Workgroup_int %_ %int_0 + OpStore %13 %int_2 + %18 = OpAccessChain %_ptr_Workgroup_int %__0 %int_0 + OpStore %18 %int_3 + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, + ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4)); +} + +TEST_F(ValidateDecorations, WorkgroupBlockVariableWith8BitType) { + std::string spirv = R"( + OpCapability Shader + OpCapability Int8 + OpCapability WorkgroupMemoryExplicitLayout8BitAccessKHR + OpExtension "SPV_KHR_workgroup_memory_explicit_layout" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" %_ + OpExecutionMode %main LocalSize 2 1 1 + OpMemberDecorate %first 0 Offset 0 + OpDecorate %first Block + %void = OpTypeVoid + %3 = OpTypeFunction %void + %char = OpTypeInt 8 1 + %first = OpTypeStruct %char +%_ptr_Workgroup_first = OpTypePointer Workgroup %first + %_ = OpVariable %_ptr_Workgroup_first Workgroup + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %char_2 = OpConstant %char 2 +%_ptr_Workgroup_char = OpTypePointer Workgroup %char + %main = OpFunction %void None %3 + %5 = OpLabel + %14 = OpAccessChain %_ptr_Workgroup_char %_ %int_0 + OpStore %14 %char_2 + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, + ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4)); +} + +TEST_F(ValidateDecorations, WorkgroupMultiNonBlockVariable) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" %a %b + OpExecutionMode %main LocalSize 8 1 1 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %int = OpTypeInt 32 1 +%_ptr_Workgroup_int = OpTypePointer Workgroup %int + %a = OpVariable %_ptr_Workgroup_int Workgroup + %int_2 = OpConstant %int 2 + %b = OpVariable %_ptr_Workgroup_int Workgroup + %int_3 = OpConstant %int 3 + %main = OpFunction %void None %3 + %5 = OpLabel + OpStore %a %int_2 + OpStore %b %int_3 + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, + ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4)); +} + +TEST_F(ValidateDecorations, WorkgroupBlockVariableWith16BitType) { + std::string spirv = R"( + OpCapability Shader + OpCapability Float16 + OpCapability Int16 + OpCapability WorkgroupMemoryExplicitLayout16BitAccessKHR + OpExtension "SPV_KHR_workgroup_memory_explicit_layout" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" %_ + OpExecutionMode %main LocalSize 2 1 1 + OpMemberDecorate %first 0 Offset 0 + OpMemberDecorate %first 1 Offset 2 + OpDecorate %first Block + %void = OpTypeVoid + %3 = OpTypeFunction %void + %short = OpTypeInt 16 1 + %half = OpTypeFloat 16 + %first = OpTypeStruct %short %half +%_ptr_Workgroup_first = OpTypePointer Workgroup %first + %_ = OpVariable %_ptr_Workgroup_first Workgroup + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %short_3 = OpConstant %short 3 +%_ptr_Workgroup_short = OpTypePointer Workgroup %short + %int_1 = OpConstant %int 1 +%half_0x1_898p_3 = OpConstant %half 0x1.898p+3 +%_ptr_Workgroup_half = OpTypePointer Workgroup %half + %main = OpFunction %void None %3 + %5 = OpLabel + %15 = OpAccessChain %_ptr_Workgroup_short %_ %int_0 + OpStore %15 %short_3 + %19 = OpAccessChain %_ptr_Workgroup_half %_ %int_1 + OpStore %19 %half_0x1_898p_3 + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, + ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4)); +} + +TEST_F(ValidateDecorations, WorkgroupBlockVariableScalarLayout) { + std::string spirv = R"( + OpCapability Shader + OpCapability WorkgroupMemoryExplicitLayoutKHR + OpExtension "SPV_KHR_workgroup_memory_explicit_layout" + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" %B + OpSource GLSL 450 + OpMemberDecorate %S 0 Offset 0 + OpMemberDecorate %S 1 Offset 4 + OpMemberDecorate %S 2 Offset 16 + OpMemberDecorate %S 3 Offset 28 + OpDecorate %S Block + OpDecorate %B Aliased + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v3float = OpTypeVector %float 3 + %S = OpTypeStruct %float %v3float %v3float %v3float +%_ptr_Workgroup_S = OpTypePointer Workgroup %S + %B = OpVariable %_ptr_Workgroup_S Workgroup + %main = OpFunction %void None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + spvValidatorOptionsSetWorkgroupScalarBlockLayout(getValidatorOptions(), true); + EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4)) + << getDiagnosticString(); +} + +TEST_F(ValidateDecorations, WorkgroupMixBlockAndNonBlockBad) { + std::string spirv = R"( + OpCapability Shader + OpCapability WorkgroupMemoryExplicitLayoutKHR + OpExtension "SPV_KHR_workgroup_memory_explicit_layout" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" %_ %b + OpExecutionMode %main LocalSize 8 1 1 + OpMemberDecorate %first 0 Offset 0 + OpDecorate %first Block + OpDecorate %_ Aliased + OpDecorate %b Aliased + %void = OpTypeVoid + %3 = OpTypeFunction %void + %int = OpTypeInt 32 1 + %first = OpTypeStruct %int +%_ptr_Workgroup_first = OpTypePointer Workgroup %first + %_ = OpVariable %_ptr_Workgroup_first Workgroup + %int_0 = OpConstant %int 0 + %int_2 = OpConstant %int 2 +%_ptr_Workgroup_int = OpTypePointer Workgroup %int + %b = OpVariable %_ptr_Workgroup_int Workgroup + %int_3 = OpConstant %int 3 + %main = OpFunction %void None %3 + %5 = OpLabel + %13 = OpAccessChain %_ptr_Workgroup_int %_ %int_0 + OpStore %13 %int_2 + OpStore %b %int_3 + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_BINARY, + ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("either all or none of the Workgroup Storage Class variables " + "in the entry point interface must point to struct types " + "decorated with Block")); +} + +TEST_F(ValidateDecorations, WorkgroupMultiBlockVariableMissingAliased) { + std::string spirv = R"( + OpCapability Shader + OpCapability WorkgroupMemoryExplicitLayoutKHR + OpExtension "SPV_KHR_workgroup_memory_explicit_layout" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" %_ %__0 + OpExecutionMode %main LocalSize 8 1 1 + OpMemberDecorate %first 0 Offset 0 + OpDecorate %first Block + OpMemberDecorate %second 0 Offset 0 + OpDecorate %second Block + OpDecorate %_ Aliased + %void = OpTypeVoid + %3 = OpTypeFunction %void + %int = OpTypeInt 32 1 + %first = OpTypeStruct %int +%_ptr_Workgroup_first = OpTypePointer Workgroup %first + %_ = OpVariable %_ptr_Workgroup_first Workgroup + %int_0 = OpConstant %int 0 + %int_2 = OpConstant %int 2 +%_ptr_Workgroup_int = OpTypePointer Workgroup %int + %second = OpTypeStruct %int +%_ptr_Workgroup_second = OpTypePointer Workgroup %second + %__0 = OpVariable %_ptr_Workgroup_second Workgroup + %int_3 = OpConstant %int 3 + %main = OpFunction %void None %3 + %5 = OpLabel + %13 = OpAccessChain %_ptr_Workgroup_int %_ %int_0 + OpStore %13 %int_2 + %18 = OpAccessChain %_ptr_Workgroup_int %__0 %int_0 + OpStore %18 %int_3 + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_BINARY, + ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("more than one Workgroup Storage Class variable in the " + "entry point interface point to a type decorated with Block, " + "all of them must be decorated with Aliased")); +} + +TEST_F(ValidateDecorations, WorkgroupSingleBlockVariableNotAStruct) { + std::string spirv = R"( + OpCapability Shader + OpCapability WorkgroupMemoryExplicitLayoutKHR + OpExtension "SPV_KHR_workgroup_memory_explicit_layout" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" %_ + OpExecutionMode %main LocalSize 8 1 1 + OpDecorate %first Block + %void = OpTypeVoid + %3 = OpTypeFunction %void + %int = OpTypeInt 32 1 + %int_3 = OpConstant %int 3 + %first = OpTypeArray %int %int_3 +%_ptr_Workgroup_first = OpTypePointer Workgroup %first + %_ = OpVariable %_ptr_Workgroup_first Workgroup + %int_0 = OpConstant %int 0 + %int_2 = OpConstant %int 2 +%_ptr_Workgroup_int = OpTypePointer Workgroup %int + %main = OpFunction %void None %3 + %5 = OpLabel + %13 = OpAccessChain %_ptr_Workgroup_int %_ %int_0 + OpStore %13 %int_2 + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_ID, + ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Block decoration on a non-struct type")); +} + +TEST_F(ValidateDecorations, WorkgroupSingleBlockVariableMissingLayout) { + std::string spirv = R"( + OpCapability Shader + OpCapability WorkgroupMemoryExplicitLayoutKHR + OpExtension "SPV_KHR_workgroup_memory_explicit_layout" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" %_ + OpExecutionMode %main LocalSize 8 1 1 + OpDecorate %first Block + %void = OpTypeVoid + %3 = OpTypeFunction %void + %int = OpTypeInt 32 1 + %first = OpTypeStruct %int +%_ptr_Workgroup_first = OpTypePointer Workgroup %first + %_ = OpVariable %_ptr_Workgroup_first Workgroup + %int_0 = OpConstant %int 0 + %int_2 = OpConstant %int 2 +%_ptr_Workgroup_int = OpTypePointer Workgroup %int + %main = OpFunction %void None %3 + %5 = OpLabel + %13 = OpAccessChain %_ptr_Workgroup_int %_ %int_0 + OpStore %13 %int_2 + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_ID, + ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Block must be explicitly laid out with Offset decorations")); +} + +TEST_F(ValidateDecorations, WorkgroupSingleBlockVariableBadLayout) { + std::string spirv = R"( + OpCapability Shader + OpCapability WorkgroupMemoryExplicitLayoutKHR + OpExtension "SPV_KHR_workgroup_memory_explicit_layout" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" %_ + OpExecutionMode %main LocalSize 8 1 1 + OpMemberDecorate %first 0 Offset 1 + OpDecorate %first Block + %void = OpTypeVoid + %3 = OpTypeFunction %void + %int = OpTypeInt 32 1 + %first = OpTypeStruct %int +%_ptr_Workgroup_first = OpTypePointer Workgroup %first + %_ = OpVariable %_ptr_Workgroup_first Workgroup + %int_0 = OpConstant %int 0 + %int_2 = OpConstant %int 2 +%_ptr_Workgroup_int = OpTypePointer Workgroup %int + %main = OpFunction %void None %3 + %5 = OpLabel + %13 = OpAccessChain %_ptr_Workgroup_int %_ %int_0 + OpStore %13 %int_2 + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_ID, + ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Block for variable in Workgroup storage class must follow " + "standard storage buffer layout rules: " + "member 0 at offset 1 is not aligned to 4")); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/test/val/val_memory_test.cpp b/test/val/val_memory_test.cpp index 0d97c66b..7d66dcd4 100644 --- a/test/val/val_memory_test.cpp +++ b/test/val/val_memory_test.cpp @@ -22,6 +22,16 @@ #include "test/val/val_code_generator.h" #include "test/val/val_fixtures.h" +// For pretty-printing tuples with spv_target_env. +std::ostream& operator<<(std::ostream& stream, spv_target_env target) +{ + switch (target) { + case SPV_ENV_UNIVERSAL_1_3: return stream << "SPV_ENV_UNIVERSAL_1_3"; + case SPV_ENV_UNIVERSAL_1_4: return stream << "SPV_ENV_UNIVERSAL_1_4"; + default: return stream << (unsigned)target; + } +} + namespace spvtools { namespace val { namespace { @@ -3444,9 +3454,10 @@ OpFunctionEnd } using ValidateSizedVariable = - spvtest::ValidateBase>; + spvtest::ValidateBase>; -CodeGenerator GetSizedVariableCodeGenerator(bool is_8bit) { +CodeGenerator GetSizedVariableCodeGenerator(bool is_8bit, bool buffer_block) { CodeGenerator generator; generator.capabilities_ = "OpCapability Shader\nOpCapability Linkage\n"; generator.extensions_ = @@ -3454,20 +3465,25 @@ CodeGenerator GetSizedVariableCodeGenerator(bool is_8bit) { "\"SPV_KHR_8bit_storage\"\n"; generator.memory_model_ = "OpMemoryModel Logical GLSL450\n"; if (is_8bit) { - generator.before_types_ = R"(OpDecorate %char_buffer_block BufferBlock -OpMemberDecorate %char_buffer_block 0 Offset 0 -)"; + generator.before_types_ = "OpMemberDecorate %char_buffer_block 0 Offset 0\n"; + if (buffer_block) + generator.before_types_ += "OpDecorate %char_buffer_block BufferBlock\n"; + generator.types_ = R"(%void = OpTypeVoid %char = OpTypeInt 8 0 %char4 = OpTypeVector %char 4 %char_buffer_block = OpTypeStruct %char )"; } else { - generator.before_types_ = R"(OpDecorate %half_buffer_block BufferBlock -OpDecorate %short_buffer_block BufferBlock -OpMemberDecorate %half_buffer_block 0 Offset 0 -OpMemberDecorate %short_buffer_block 0 Offset 0 -)"; + generator.before_types_ = + "OpMemberDecorate %half_buffer_block 0 Offset 0\n" + "OpMemberDecorate %short_buffer_block 0 Offset 0\n"; + if (buffer_block) { + generator.before_types_ += + "OpDecorate %half_buffer_block BufferBlock\n" + "OpDecorate %short_buffer_block BufferBlock\n"; + } + generator.types_ = R"(%void = OpTypeVoid %short = OpTypeInt 16 0 %half = OpTypeFloat 16 @@ -3490,6 +3506,10 @@ TEST_P(ValidateSizedVariable, Capability) { const std::string storage_class = std::get<0>(GetParam()); const std::string capability = std::get<1>(GetParam()); const std::string var_type = std::get<2>(GetParam()); + const spv_target_env target = std::get<3>(GetParam()); + + ASSERT_TRUE(target == SPV_ENV_UNIVERSAL_1_3 || + target == SPV_ENV_UNIVERSAL_1_4); bool type_8bit = false; if (var_type == "%char" || var_type == "%char4" || @@ -3497,7 +3517,16 @@ TEST_P(ValidateSizedVariable, Capability) { type_8bit = true; } - auto generator = GetSizedVariableCodeGenerator(type_8bit); + const bool buffer_block = var_type.find("buffer_block") != std::string::npos; + + auto generator = GetSizedVariableCodeGenerator(type_8bit, buffer_block); + + if (capability == "WorkgroupMemoryExplicitLayout8BitAccessKHR" || + capability == "WorkgroupMemoryExplicitLayout16BitAccessKHR") { + generator.extensions_ += + "OpExtension \"SPV_KHR_workgroup_memory_explicit_layout\"\n"; + } + generator.types_ += "%ptr_type = OpTypePointer " + storage_class + " " + var_type + "\n%var = OpVariable %ptr_type " + storage_class + "\n"; @@ -3527,7 +3556,6 @@ TEST_P(ValidateSizedVariable, Capability) { } storage_class_ok = true; } else if (storage_class == "Uniform") { - bool buffer_block = var_type.find("buffer_block") != std::string::npos; if (type_8bit) { capability_ok = capability == "UniformAndStorageBuffer8BitAccess" || (capability == "StorageBuffer8BitAccess" && buffer_block); @@ -3537,11 +3565,30 @@ TEST_P(ValidateSizedVariable, Capability) { (capability == "StorageBuffer16BitAccess" && buffer_block); } storage_class_ok = true; + } else if (storage_class == "Workgroup") { + if (type_8bit) { + capability_ok = + capability == "WorkgroupMemoryExplicitLayout8BitAccessKHR"; + } else { + capability_ok = + capability == "WorkgroupMemoryExplicitLayout16BitAccessKHR"; + } + storage_class_ok = true; } - CompileSuccessfully(generator.Build(), SPV_ENV_UNIVERSAL_1_3); - spv_result_t result = ValidateInstructions(SPV_ENV_UNIVERSAL_1_3); - if (capability_ok) { + CompileSuccessfully(generator.Build(), target); + spv_result_t result = ValidateInstructions(target); + if (target < SPV_ENV_UNIVERSAL_1_4 && + (capability == "WorkgroupMemoryExplicitLayout8BitAccessKHR" || + capability == "WorkgroupMemoryExplicitLayout16BitAccessKHR")) { + EXPECT_EQ(SPV_ERROR_WRONG_VERSION, result); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("requires SPIR-V version 1.4 or later")); + } else if (buffer_block && target > SPV_ENV_UNIVERSAL_1_3) { + EXPECT_EQ(SPV_ERROR_WRONG_VERSION, result); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("requires SPIR-V version 1.3 or earlier")); + } else if (capability_ok) { EXPECT_EQ(SPV_SUCCESS, result); } else { EXPECT_EQ(SPV_ERROR_INVALID_ID, result); @@ -3566,8 +3613,10 @@ INSTANTIATE_TEST_SUITE_P( Combine(Values("UniformConstant", "Input", "Output", "Workgroup", "CrossWorkgroup", "Private", "StorageBuffer", "Uniform"), Values("StorageBuffer8BitAccess", - "UniformAndStorageBuffer8BitAccess", "StoragePushConstant8"), - Values("%char", "%char4", "%char_buffer_block"))); + "UniformAndStorageBuffer8BitAccess", "StoragePushConstant8", + "WorkgroupMemoryExplicitLayout8BitAccessKHR"), + Values("%char", "%char4", "%char_buffer_block"), + Values(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_UNIVERSAL_1_4))); INSTANTIATE_TEST_SUITE_P( Storage16, ValidateSizedVariable, @@ -3575,9 +3624,11 @@ INSTANTIATE_TEST_SUITE_P( "CrossWorkgroup", "Private", "StorageBuffer", "Uniform"), Values("StorageBuffer16BitAccess", "UniformAndStorageBuffer16BitAccess", - "StoragePushConstant16", "StorageInputOutput16"), + "StoragePushConstant16", "StorageInputOutput16", + "WorkgroupMemoryExplicitLayout16BitAccessKHR"), Values("%short", "%half", "%short4", "%half4", "%mat4x4", - "%short_buffer_block", "%half_buffer_block"))); + "%short_buffer_block", "%half_buffer_block"), + Values(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_UNIVERSAL_1_4))); using ValidateSizedLoadStore = spvtest::ValidateBase>; diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp index e7e58998..6999b39a 100644 --- a/tools/opt/opt.cpp +++ b/tools/opt/opt.cpp @@ -490,6 +490,10 @@ Options (in lexicographical order):)", avoid triggering those bugs. Current workarounds: Avoid OpUnreachable in loops.)"); printf(R"( + --workgroup-scalar-block-layout + Forwards this option to the validator. See the validator help + for details.)"); + printf(R"( --wrap-opkill Replaces all OpKill instructions in functions that can be called from a continue construct with a function call to a function @@ -741,6 +745,8 @@ OptStatus ParseFlags(int argc, const char** argv, validator_options->SetRelaxBlockLayout(true); } else if (0 == strcmp(cur_arg, "--scalar-block-layout")) { validator_options->SetScalarBlockLayout(true); + } else if (0 == strcmp(cur_arg, "--workgroup-scalar-block-layout")) { + validator_options->SetWorkgroupScalarBlockLayout(true); } else if (0 == strcmp(cur_arg, "--skip-block-layout")) { validator_options->SetSkipBlockLayout(true); } else if (0 == strcmp(cur_arg, "--relax-struct-store")) { diff --git a/tools/val/val.cpp b/tools/val/val.cpp index da63245a..5450023a 100644 --- a/tools/val/val.cpp +++ b/tools/val/val.cpp @@ -58,6 +58,7 @@ Options: uniform, storage buffer, and push constant layouts. Scalar layout rules are more permissive than relaxed block layout so in effect this will override the --relax-block-layout option. + --workgroup-scalar-block-layout Enable scalar block layout when checking Workgroup block layouts. --skip-block-layout Skip checking standard uniform/storage buffer layout. Overrides any --relax-block-layout or --scalar-block-layout option. --relax-struct-store Allow store from one struct type to a @@ -148,6 +149,8 @@ int main(int argc, char** argv) { options.SetUniformBufferStandardLayout(true); } else if (0 == strcmp(cur_arg, "--scalar-block-layout")) { options.SetScalarBlockLayout(true); + } else if (0 == strcmp(cur_arg, "--workgroup-scalar-block-layout")) { + options.SetWorkgroupScalarBlockLayout(true); } else if (0 == strcmp(cur_arg, "--skip-block-layout")) { options.SetSkipBlockLayout(true); } else if (0 == strcmp(cur_arg, "--relax-struct-store")) { -- cgit v1.2.3 From e8bd26e1f83580fd483808f2a95ec36f4bceb787 Mon Sep 17 00:00:00 2001 From: Jaebaek Seo Date: Thu, 28 Jan 2021 12:57:35 -0500 Subject: Set correct scope and line info for DebugValue (#4125) The existing spirv-opt `DebugInfoManager::AddDebugValueForDecl()` sets the scope and line info of the new added DebugValue using the scope and line of DebugDeclare. This is wrong because only a single DebugDeclare must exist under a scope while we have to add DebugValue for all the places where the variable's value is updated. Therefore, we have to set the scope and line of DebugValue based on the places of the variable updates. This bug makes https://github.com/google/amber/blob/main/tests/cases/debugger_hlsl_shadowed_vars.amber fail. This commit fixes the bug. --- source/opt/debug_info_manager.cpp | 8 +-- source/opt/debug_info_manager.h | 11 +++-- source/opt/local_single_store_elim_pass.cpp | 2 +- source/opt/scalar_replacement_pass.cpp | 3 +- source/opt/ssa_rewrite_pass.cpp | 9 ++-- test/opt/debug_info_manager_test.cpp | 77 +++++++++++++++++++++++++++++ test/opt/local_single_store_elim_test.cpp | 6 ++- test/opt/local_ssa_elim_test.cpp | 14 ++++++ 8 files changed, 115 insertions(+), 15 deletions(-) diff --git a/source/opt/debug_info_manager.cpp b/source/opt/debug_info_manager.cpp index 11b5131d..e782641f 100644 --- a/source/opt/debug_info_manager.cpp +++ b/source/opt/debug_info_manager.cpp @@ -500,14 +500,15 @@ bool DebugInfoManager::AddDebugValueIfVarDeclIsVisible( insert_before->opcode() == SpvOpVariable) { insert_before = insert_before->NextNode(); } - modified |= AddDebugValueForDecl(dbg_decl_or_val, value_id, - insert_before) != nullptr; + modified |= AddDebugValueForDecl(dbg_decl_or_val, value_id, insert_before, + scope_and_line) != nullptr; } return modified; } Instruction* DebugInfoManager::AddDebugValueForDecl( - Instruction* dbg_decl, uint32_t value_id, Instruction* insert_before) { + Instruction* dbg_decl, uint32_t value_id, Instruction* insert_before, + Instruction* scope_and_line) { if (dbg_decl == nullptr || !IsDebugDeclare(dbg_decl)) return nullptr; std::unique_ptr dbg_val(dbg_decl->Clone(context())); @@ -517,6 +518,7 @@ Instruction* DebugInfoManager::AddDebugValueForDecl( dbg_val->SetOperand(kDebugDeclareOperandVariableIndex, {value_id}); dbg_val->SetOperand(kDebugValueOperandExpressionIndex, {GetEmptyDebugExpression()->result_id()}); + dbg_val->UpdateDebugInfoFrom(scope_and_line); auto* added_dbg_val = insert_before->InsertBefore(std::move(dbg_val)); AnalyzeDebugInst(added_dbg_val); diff --git a/source/opt/debug_info_manager.h b/source/opt/debug_info_manager.h index 92b38183..776e9baa 100644 --- a/source/opt/debug_info_manager.h +++ b/source/opt/debug_info_manager.h @@ -152,11 +152,14 @@ class DebugInfoManager { std::unordered_set* invisible_decls); // Creates a DebugValue for DebugDeclare |dbg_decl| and inserts it before - // |insert_before|. The new DebugValue has the same line, scope, and - // operands with DebugDeclare but it uses |value_id| for value. Returns - // the added DebugValue, or nullptr if it does not add a DebugValue. + // |insert_before|. The new DebugValue has the same line and scope as + // |scope_and_line|, or no scope and line information if |scope_and_line| + // is nullptr. The new DebugValue has the same operands as DebugDeclare + // but it uses |value_id| for the value. Returns the created DebugValue, + // or nullptr if fails to create one. Instruction* AddDebugValueForDecl(Instruction* dbg_decl, uint32_t value_id, - Instruction* insert_before); + Instruction* insert_before, + Instruction* scope_and_line); // Erases |instr| from data structures of this class. void ClearDebugInfo(Instruction* instr); diff --git a/source/opt/local_single_store_elim_pass.cpp b/source/opt/local_single_store_elim_pass.cpp index b8d9091a..d322a2fb 100644 --- a/source/opt/local_single_store_elim_pass.cpp +++ b/source/opt/local_single_store_elim_pass.cpp @@ -175,7 +175,7 @@ bool LocalSingleStoreElimPass::RewriteDebugDeclares(Instruction* store_inst, for (auto* decl : invisible_decls) { if (dominator_analysis->Dominates(store_inst, decl)) { context()->get_debug_info_mgr()->AddDebugValueForDecl(decl, value_id, - decl); + decl, store_inst); modified = true; } } diff --git a/source/opt/scalar_replacement_pass.cpp b/source/opt/scalar_replacement_pass.cpp index c8e0da5b..ba2d0675 100644 --- a/source/opt/scalar_replacement_pass.cpp +++ b/source/opt/scalar_replacement_pass.cpp @@ -175,7 +175,8 @@ bool ScalarReplacementPass::ReplaceWholeDebugDeclare( Instruction* added_dbg_value = context()->get_debug_info_mgr()->AddDebugValueForDecl( dbg_decl, /*value_id=*/var->result_id(), - /*insert_before=*/var->NextNode()); + /*insert_before=*/var->NextNode(), /*scope_and_line=*/dbg_decl); + if (added_dbg_value == nullptr) return false; added_dbg_value->AddOperand( {SPV_OPERAND_TYPE_ID, diff --git a/source/opt/ssa_rewrite_pass.cpp b/source/opt/ssa_rewrite_pass.cpp index 0489f03a..81770d77 100644 --- a/source/opt/ssa_rewrite_pass.cpp +++ b/source/opt/ssa_rewrite_pass.cpp @@ -658,8 +658,8 @@ Pass::Status SSARewriter::AddDebugValuesForInvisibleDebugDecls(Function* fp) { // a = 3; // foo(3); // After inlining: - // a = 3; // we want to specify "DebugValue: %x = %int_3" - // foo and x disappeared! + // a = 3; + // foo and x disappeared but we want to specify "DebugValue: %x = %int_3". // // We want to specify the value for the variable using |defs_at_block_[bb]|, // where |bb| is the basic block contains the decl. @@ -681,16 +681,17 @@ Pass::Status SSARewriter::AddDebugValuesForInvisibleDebugDecls(Function* fp) { if (value && (pass_->context()->get_instr_block(value) == nullptr || dom_tree->Dominates(value, decl))) { if (pass_->context()->get_debug_info_mgr()->AddDebugValueForDecl( - decl, value->result_id(), decl) == nullptr) { + decl, value->result_id(), decl, value) == nullptr) { return Pass::Status::Failure; } } else { // If |value| in the same basic block does not dominate |decl|, we can // assign the value in the immediate dominator. value_id = GetValueAtBlock(var_id, dom_tree->ImmediateDominator(bb)); + if (value_id) value = pass_->get_def_use_mgr()->GetDef(value_id); if (value_id && pass_->context()->get_debug_info_mgr()->AddDebugValueForDecl( - decl, value_id, decl) == nullptr) { + decl, value_id, decl, value) == nullptr) { return Pass::Status::Failure; } } diff --git a/test/opt/debug_info_manager_test.cpp b/test/opt/debug_info_manager_test.cpp index 911331a7..49407fd5 100644 --- a/test/opt/debug_info_manager_test.cpp +++ b/test/opt/debug_info_manager_test.cpp @@ -31,6 +31,9 @@ static const uint32_t kDebugFunctionOperandFunctionIndex = 13; static const uint32_t kDebugInlinedAtOperandLineIndex = 4; static const uint32_t kDebugInlinedAtOperandScopeIndex = 5; static const uint32_t kDebugInlinedAtOperandInlinedIndex = 6; +static const uint32_t kOpLineInOperandFileIndex = 0; +static const uint32_t kOpLineInOperandLineIndex = 1; +static const uint32_t kOpLineInOperandColumnIndex = 2; namespace spvtools { namespace opt { @@ -609,6 +612,80 @@ void main(float in_var_color : COLOR) { EXPECT_FALSE(dbg_info_mgr->IsVariableDebugDeclared(100)); } +TEST(DebugInfoManager, AddDebugValueForDecl) { + const std::string text = R"( + OpCapability Shader + %1 = OpExtInstImport "OpenCL.DebugInfo.100" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %in_var_COLOR + OpExecutionMode %main OriginUpperLeft + %5 = OpString "ps.hlsl" + %14 = OpString "#line 1 \"ps.hlsl\" +void main(float in_var_color : COLOR) { + float color = in_var_color; +} +" + %17 = OpString "float" + %21 = OpString "main" + %24 = OpString "color" + OpName %in_var_COLOR "in.var.COLOR" + OpName %main "main" + OpDecorate %in_var_COLOR Location 0 + %uint = OpTypeInt 32 0 + %uint_32 = OpConstant %uint 32 + %float = OpTypeFloat 32 +%_ptr_Input_float = OpTypePointer Input %float + %void = OpTypeVoid + %27 = OpTypeFunction %void +%_ptr_Function_float = OpTypePointer Function %float +%in_var_COLOR = OpVariable %_ptr_Input_float Input + %13 = OpExtInst %void %1 DebugExpression + %15 = OpExtInst %void %1 DebugSource %5 %14 + %16 = OpExtInst %void %1 DebugCompilationUnit 1 4 %15 HLSL + %18 = OpExtInst %void %1 DebugTypeBasic %17 %uint_32 Float + %20 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %18 %18 + %22 = OpExtInst %void %1 DebugFunction %21 %20 %15 1 1 %16 %21 FlagIsProtected|FlagIsPrivate 1 %main + %12 = OpExtInst %void %1 DebugInfoNone + %25 = OpExtInst %void %1 DebugLocalVariable %24 %18 %15 1 20 %22 FlagIsLocal 0 + %main = OpFunction %void None %27 + %28 = OpLabel + %100 = OpVariable %_ptr_Function_float Function + %31 = OpLoad %float %in_var_COLOR + %101 = OpExtInst %void %1 DebugScope %22 + OpLine %5 13 7 + OpStore %100 %31 + OpNoLine + %102 = OpExtInst %void %1 DebugNoScope + %36 = OpExtInst %void %1 DebugDeclare %25 %100 %13 + OpReturn + OpFunctionEnd + )"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + auto* def_use_mgr = context->get_def_use_mgr(); + auto* dbg_decl = def_use_mgr->GetDef(36); + EXPECT_EQ(dbg_decl->GetOpenCL100DebugOpcode(), + OpenCLDebugInfo100DebugDeclare); + + auto* dbg_info_mgr = context->get_debug_info_mgr(); + Instruction* store = dbg_decl->PreviousNode(); + auto* dbg_value = + dbg_info_mgr->AddDebugValueForDecl(dbg_decl, 100, dbg_decl, store); + + EXPECT_EQ(dbg_value->GetOpenCL100DebugOpcode(), OpenCLDebugInfo100DebugValue); + EXPECT_EQ(dbg_value->dbg_line_inst()->GetSingleWordInOperand( + kOpLineInOperandFileIndex), + 5); + EXPECT_EQ(dbg_value->dbg_line_inst()->GetSingleWordInOperand( + kOpLineInOperandLineIndex), + 13); + EXPECT_EQ(dbg_value->dbg_line_inst()->GetSingleWordInOperand( + kOpLineInOperandColumnIndex), + 7); +} + } // namespace } // namespace analysis } // namespace opt diff --git a/test/opt/local_single_store_elim_test.cpp b/test/opt/local_single_store_elim_test.cpp index d015dfba..c94ff372 100644 --- a/test/opt/local_single_store_elim_test.cpp +++ b/test/opt/local_single_store_elim_test.cpp @@ -1403,18 +1403,20 @@ TEST_F(LocalSingleStoreElimTest, AddDebugValueforStoreOutOfDebugDeclareScope) { %param_var_pos = OpVariable %_ptr_Function_v4float Function %param_var_color = OpVariable %_ptr_Function_v4float Function %55 = OpLoad %v4float %in_var_POSITION + OpLine %7 6 23 OpStore %param_var_pos %55 + OpNoLine %56 = OpLoad %v4float %in_var_COLOR ;CHECK: DebugNoScope ;CHECK-NOT: OpLine ;CHECK: [[pos:%\w+]] = OpLoad %v4float %in_var_POSITION ;CHECK: [[color:%\w+]] = OpLoad %v4float %in_var_COLOR + OpLine %7 7 23 OpStore %param_var_color %56 + OpNoLine %93 = OpExtInst %void %1 DebugScope %48 - OpLine %7 6 23 %73 = OpExtInst %void %1 DebugDeclare %53 %param_var_pos %52 - OpLine %7 7 23 %74 = OpExtInst %void %1 DebugDeclare %51 %param_var_color %52 ;CHECK: OpLine [[file:%\w+]] 6 23 ;CHECK-NEXT: {{%\w+}} = OpExtInst %void {{%\w+}} DebugValue [[dbg_pos]] [[pos]] [[empty_expr:%\w+]] diff --git a/test/opt/local_ssa_elim_test.cpp b/test/opt/local_ssa_elim_test.cpp index 9baf8da8..ca9aba33 100644 --- a/test/opt/local_ssa_elim_test.cpp +++ b/test/opt/local_ssa_elim_test.cpp @@ -2261,9 +2261,13 @@ TEST_F(LocalSSAElimTest, AddDebugValueForFunctionParameterWithPhi) { %69 = OpExtInst %void %1 DebugLexicalBlock %60 7 21 %68 %70 = OpExtInst %void %1 DebugLocalVariable %11 %59 %60 6 26 %67 FlagIsLocal 2 +; CHECK: [[color_name:%\w+]] = OpString "color" +; CHECK: [[pos_name:%\w+]] = OpString "pos" ; CHECK: [[i_name:%\w+]] = OpString "i" ; CHECK: [[null_expr:%\w+]] = OpExtInst %void [[ext:%\w+]] DebugExpression ; CHECK: [[dbg_i:%\w+]] = OpExtInst %void [[ext]] DebugLocalVariable [[i_name]] {{%\w+}} {{%\w+}} 6 16 {{%\w+}} FlagIsLocal 1 +; CHECK: [[dbg_color:%\w+]] = OpExtInst %void [[ext]] DebugLocalVariable [[color_name]] {{%\w+}} {{%\w+}} 15 23 +; CHECK: [[dbg_pos:%\w+]] = OpExtInst %void [[ext]] DebugLocalVariable [[pos_name]] {{%\w+}} {{%\w+}} 14 23 %71 = OpExtInst %void %1 DebugLocalVariable %15 %65 %60 6 16 %67 FlagIsLocal 1 %72 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %62 %59 %59 %73 = OpExtInst %void %1 DebugFunction %16 %72 %60 14 1 %61 %14 FlagIsProtected|FlagIsPrivate 15 %156 @@ -2282,13 +2286,23 @@ TEST_F(LocalSSAElimTest, AddDebugValueForFunctionParameterWithPhi) { %169 = OpExtInst %void %1 DebugNoScope %param_var_pos = OpVariable %_ptr_Function_v4float Function %param_var_color = OpVariable %_ptr_Function_v4float Function + OpLine %7 100 105 %80 = OpLoad %v4float %in_var_POSITION OpStore %param_var_pos %80 + OpNoLine + OpLine %7 200 205 %81 = OpLoad %v4float %in_var_COLOR OpStore %param_var_color %81 + OpNoLine %170 = OpExtInst %void %1 DebugScope %73 + +; CHECK: OpLine {{%\w+}} 100 105 +; CHECK: DebugValue [[dbg_pos]] %124 = OpExtInst %void %1 DebugDeclare %78 %param_var_pos %77 +; CHECK: OpLine {{%\w+}} 200 205 +; CHECK: DebugValue [[dbg_color]] %125 = OpExtInst %void %1 DebugDeclare %76 %param_var_color %77 + %171 = OpExtInst %void %1 DebugScope %74 OpLine %7 17 18 -- cgit v1.2.3 From 297723d75af4244d1cdad1178da0689dec8fd9a0 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Thu, 28 Jan 2021 15:53:34 -0500 Subject: Mark module as modified if convert-to-half removes decorations. (#4127) * Mark module as modified if convert-to-half removes decorations. If the convert-to-half pass does not change the body of the function, but removes decorations, it returns that nothing changed. This is incorrect, and will be fixed. Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/4117 * Update comment for RemoveDecorationsFrom --- source/opt/convert_to_half_pass.cpp | 12 ++++-- source/opt/convert_to_half_pass.h | 2 +- source/opt/decoration_manager.cpp | 9 +++-- source/opt/decoration_manager.h | 11 +++--- test/opt/convert_relaxed_to_half_test.cpp | 66 +++++++++++++++++++++++++++++++ 5 files changed, 87 insertions(+), 13 deletions(-) diff --git a/source/opt/convert_to_half_pass.cpp b/source/opt/convert_to_half_pass.cpp index 5022e1b6..6b3b540a 100644 --- a/source/opt/convert_to_half_pass.cpp +++ b/source/opt/convert_to_half_pass.cpp @@ -147,8 +147,8 @@ bool ConvertToHalfPass::MatConvertCleanup(Instruction* inst) { return true; } -void ConvertToHalfPass::RemoveRelaxedDecoration(uint32_t id) { - context()->get_decoration_mgr()->RemoveDecorationsFrom( +bool ConvertToHalfPass::RemoveRelaxedDecoration(uint32_t id) { + return context()->get_decoration_mgr()->RemoveDecorationsFrom( id, [](const Instruction& dec) { if (dec.opcode() == SpvOpDecorate && dec.GetSingleWordInOperand(1u) == SpvDecorationRelaxedPrecision) @@ -344,10 +344,14 @@ Pass::Status ConvertToHalfPass::ProcessImpl() { // If modified, make sure module has Float16 capability if (modified) context()->AddCapability(SpvCapabilityFloat16); // Remove all RelaxedPrecision decorations from instructions and globals - for (auto c_id : relaxed_ids_set_) RemoveRelaxedDecoration(c_id); + for (auto c_id : relaxed_ids_set_) { + modified |= RemoveRelaxedDecoration(c_id); + } for (auto& val : get_module()->types_values()) { uint32_t v_id = val.result_id(); - if (v_id != 0) RemoveRelaxedDecoration(v_id); + if (v_id != 0) { + modified |= RemoveRelaxedDecoration(v_id); + } } return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; } diff --git a/source/opt/convert_to_half_pass.h b/source/opt/convert_to_half_pass.h index 143aebfa..b647dd4a 100644 --- a/source/opt/convert_to_half_pass.h +++ b/source/opt/convert_to_half_pass.h @@ -74,7 +74,7 @@ class ConvertToHalfPass : public Pass { void GenConvert(uint32_t* val_idp, uint32_t width, Instruction* inst); // Remove RelaxedPrecision decoration of |id|. - void RemoveRelaxedDecoration(uint32_t id); + bool RemoveRelaxedDecoration(uint32_t id); // Add |inst| to relaxed instruction set if warranted. Specifically, if // it is float32 and either decorated relaxed or a composite or phi diff --git a/source/opt/decoration_manager.cpp b/source/opt/decoration_manager.cpp index 8b4aee58..4bf026ef 100644 --- a/source/opt/decoration_manager.cpp +++ b/source/opt/decoration_manager.cpp @@ -53,11 +53,12 @@ namespace spvtools { namespace opt { namespace analysis { -void DecorationManager::RemoveDecorationsFrom( +bool DecorationManager::RemoveDecorationsFrom( uint32_t id, std::function pred) { + bool was_modified = false; const auto ids_iter = id_to_decoration_insts_.find(id); if (ids_iter == id_to_decoration_insts_.end()) { - return; + return was_modified; } TargetData& decorations_info = ids_iter->second; @@ -99,7 +100,6 @@ void DecorationManager::RemoveDecorationsFrom( // Otherwise, remove |id| from the targets of |group_id| const uint32_t stride = inst->opcode() == SpvOpGroupDecorate ? 1u : 2u; - bool was_modified = false; for (uint32_t i = 1u; i < inst->NumInOperands();) { if (inst->GetSingleWordInOperand(i) != id) { i += stride; @@ -155,6 +155,7 @@ void DecorationManager::RemoveDecorationsFrom( }), indirect_decorations.end()); + was_modified |= !insts_to_kill.empty(); for (Instruction* inst : insts_to_kill) context->KillInst(inst); insts_to_kill.clear(); @@ -165,6 +166,7 @@ void DecorationManager::RemoveDecorationsFrom( for (Instruction* inst : decorations_info.decorate_insts) insts_to_kill.push_back(inst); } + was_modified |= !insts_to_kill.empty(); for (Instruction* inst : insts_to_kill) context->KillInst(inst); if (decorations_info.direct_decorations.empty() && @@ -172,6 +174,7 @@ void DecorationManager::RemoveDecorationsFrom( decorations_info.decorate_insts.empty()) { id_to_decoration_insts_.erase(ids_iter); } + return was_modified; } std::vector DecorationManager::GetDecorationsFor( diff --git a/source/opt/decoration_manager.h b/source/opt/decoration_manager.h index e1ae8d57..b753e6be 100644 --- a/source/opt/decoration_manager.h +++ b/source/opt/decoration_manager.h @@ -36,8 +36,9 @@ class DecorationManager { } DecorationManager() = delete; - // Changes all of the decorations (direct and through groups) where |pred| is - // true and that apply to |id| so that they no longer apply to |id|. + // Removes all decorations (direct and through groups) where |pred| is + // true and that apply to |id| so that they no longer apply to |id|. Returns + // true if something changed. // // If |id| is part of a group, it will be removed from the group if it // does not use all of the group's decorations, or, if there are no @@ -52,9 +53,9 @@ class DecorationManager { // removed, then the |OpGroupDecorate| and // |OpGroupMemberDecorate| for the group will be killed, but not the defining // |OpDecorationGroup| instruction. - void RemoveDecorationsFrom(uint32_t id, - std::function pred = - [](const Instruction&) { return true; }); + bool RemoveDecorationsFrom( + uint32_t id, std::function pred = + [](const Instruction&) { return true; }); // Removes all decorations from the result id of |inst|. // diff --git a/test/opt/convert_relaxed_to_half_test.cpp b/test/opt/convert_relaxed_to_half_test.cpp index c1381547..ca6ee583 100644 --- a/test/opt/convert_relaxed_to_half_test.cpp +++ b/test/opt/convert_relaxed_to_half_test.cpp @@ -1331,6 +1331,72 @@ OpFunctionEnd SinglePassRunAndMatch(defs + func, true); } +TEST_F(ConvertToHalfTest, RemoveRelaxDec) { + // See https://github.com/KhronosGroup/SPIRV-Tools/issues/4117 + + // This test is a case where the relax precision decorations need to be + // removed, but the body of the function does not change because there are not + // arithmetic operations. So, there is not need for the Float16 capability. + const std::string test = + R"( +; CHECK-NOT: OpCapability Float16 +; GLSL seems to generate this decoration on the load of a texture, which seems odd to me. +; This pass does not currently remove it, and I'm not sure what we should do with it, so I will leave it. +; CHECK: OpDecorate [[tex:%\w+]] RelaxedPrecision +; CHECK-NOT: OpDecorate {{%\w+}} RelaxedPrecision +; CHECK: OpLabel +; CHECK: [[tex]] = OpLoad {{%\w+}} %sTexture +; CHECK: [[coord:%\w+]] = OpLoad %v2float +; CHECK: [[retval:%\w+]] = OpImageSampleImplicitLod %v4float {{%\w+}} [[coord]] +; CHECK: OpStore %outFragColor [[retval]] + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %outFragColor %v_texcoord + OpExecutionMode %main OriginUpperLeft + OpSource ESSL 310 + OpName %main "main" + OpName %outFragColor "outFragColor" + OpName %sTexture "sTexture" + OpName %v_texcoord "v_texcoord" + OpDecorate %outFragColor RelaxedPrecision + OpDecorate %outFragColor Location 0 + OpDecorate %sTexture RelaxedPrecision + OpDecorate %sTexture DescriptorSet 0 + OpDecorate %sTexture Binding 0 + OpDecorate %14 RelaxedPrecision + OpDecorate %v_texcoord RelaxedPrecision + OpDecorate %v_texcoord Location 0 + OpDecorate %18 RelaxedPrecision + OpDecorate %19 RelaxedPrecision + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Output_v4float = OpTypePointer Output %v4float +%outFragColor = OpVariable %_ptr_Output_v4float Output + %10 = OpTypeImage %float 2D 0 0 0 1 Unknown + %11 = OpTypeSampledImage %10 +%_ptr_UniformConstant_11 = OpTypePointer UniformConstant %11 + %sTexture = OpVariable %_ptr_UniformConstant_11 UniformConstant + %v2float = OpTypeVector %float 2 +%_ptr_Input_v2float = OpTypePointer Input %v2float + %v_texcoord = OpVariable %_ptr_Input_v2float Input + %main = OpFunction %void None %3 + %5 = OpLabel + %14 = OpLoad %11 %sTexture + %18 = OpLoad %v2float %v_texcoord + %19 = OpImageSampleImplicitLod %v4float %14 %18 + OpStore %outFragColor %19 + OpReturn + OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + auto result = SinglePassRunAndMatch(test, true); + EXPECT_EQ(Pass::Status::SuccessWithChange, std::get<1>(result)); +} + } // namespace } // namespace opt } // namespace spvtools -- cgit v1.2.3 From d61a7d110d93c244222364d67099bd3bbba1c307 Mon Sep 17 00:00:00 2001 From: sfricke-samsung <46493288+sfricke-samsung@users.noreply.github.com> Date: Mon, 1 Feb 2021 07:39:44 -0800 Subject: spirv-val: Add Vulkan PSB64 convert VUID (#4122) --- source/val/validate_conversion.cpp | 38 +++++++++++----- source/val/validation_state.cpp | 2 + test/val/val_conversion_test.cpp | 91 +++++++++++++++++++++++++++++++++----- 3 files changed, 109 insertions(+), 22 deletions(-) diff --git a/source/val/validate_conversion.cpp b/source/val/validate_conversion.cpp index 0060d0b7..b4e39cfe 100644 --- a/source/val/validate_conversion.cpp +++ b/source/val/validate_conversion.cpp @@ -14,12 +14,12 @@ // Validates correctness of conversion instructions. -#include "source/val/validate.h" - #include "source/diagnostic.h" #include "source/opcode.h" #include "source/spirv_constant.h" +#include "source/spirv_target_env.h" #include "source/val/instruction.h" +#include "source/val/validate.h" #include "source/val/validation_state.h" namespace spvtools { @@ -263,16 +263,25 @@ spv_result_t ConversionPass(ValidationState_t& _, const Instruction* inst) { << "Logical addressing not supported: " << spvOpcodeString(opcode); - if (_.addressing_model() == - SpvAddressingModelPhysicalStorageBuffer64EXT) { + if (_.addressing_model() == SpvAddressingModelPhysicalStorageBuffer64) { uint32_t input_storage_class = 0; uint32_t input_data_type = 0; _.GetPointerTypeInfo(input_type, &input_data_type, &input_storage_class); - if (input_storage_class != SpvStorageClassPhysicalStorageBufferEXT) + if (input_storage_class != SpvStorageClassPhysicalStorageBuffer) return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Pointer storage class must be PhysicalStorageBufferEXT: " + << "Pointer storage class must be PhysicalStorageBuffer: " << spvOpcodeString(opcode); + + if (spvIsVulkanEnv(_.context()->target_env)) { + if (_.GetBitWidth(result_type) != 64) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << _.VkErrorID(4710) + << "PhysicalStorageBuffer64 addressing mode requires the " + "result integer type to have a 64-bit width for Vulkan " + "environment."; + } + } } break; } @@ -314,16 +323,25 @@ spv_result_t ConversionPass(ValidationState_t& _, const Instruction* inst) { << "Logical addressing not supported: " << spvOpcodeString(opcode); - if (_.addressing_model() == - SpvAddressingModelPhysicalStorageBuffer64EXT) { + if (_.addressing_model() == SpvAddressingModelPhysicalStorageBuffer64) { uint32_t result_storage_class = 0; uint32_t result_data_type = 0; _.GetPointerTypeInfo(result_type, &result_data_type, &result_storage_class); - if (result_storage_class != SpvStorageClassPhysicalStorageBufferEXT) + if (result_storage_class != SpvStorageClassPhysicalStorageBuffer) return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Pointer storage class must be PhysicalStorageBufferEXT: " + << "Pointer storage class must be PhysicalStorageBuffer: " << spvOpcodeString(opcode); + + if (spvIsVulkanEnv(_.context()->target_env)) { + if (_.GetBitWidth(input_type) != 64) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << _.VkErrorID(4710) + << "PhysicalStorageBuffer64 addressing mode requires the " + "input integer to have a 64-bit width for Vulkan " + "environment."; + } + } } break; } diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index 3268e424..746efd05 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -1714,6 +1714,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-OpGroupNonUniformBallotBitCount-04685); case 4686: return VUID_WRAP(VUID-StandaloneSpirv-None-04686); + case 4710: + return VUID_WRAP(VUID-StandaloneSpirv-PhysicalStorageBuffer64-04710); case 4711: return VUID_WRAP(VUID-StandaloneSpirv-OpTypeForwardPointer-04711); case 4730: diff --git a/test/val/val_conversion_test.cpp b/test/val/val_conversion_test.cpp index 47e67938..b9802ece 100644 --- a/test/val/val_conversion_test.cpp +++ b/test/val/val_conversion_test.cpp @@ -1464,16 +1464,16 @@ OpFunctionEnd TEST_F(ValidateConversion, ConvertUToPtrPSBSuccess) { const std::string body = R"( -OpCapability PhysicalStorageBufferAddressesEXT +OpCapability PhysicalStorageBufferAddresses OpCapability Int64 OpCapability Shader OpExtension "SPV_EXT_physical_storage_buffer" -OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +OpMemoryModel PhysicalStorageBuffer64 GLSL450 OpEntryPoint Fragment %main "main" OpExecutionMode %main OriginUpperLeft %uint64 = OpTypeInt 64 0 %u64_1 = OpConstant %uint64 1 -%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64 +%ptr = OpTypePointer PhysicalStorageBuffer %uint64 %void = OpTypeVoid %voidfn = OpTypeFunction %void %main = OpFunction %void None %voidfn @@ -1489,11 +1489,11 @@ OpFunctionEnd TEST_F(ValidateConversion, ConvertUToPtrPSBStorageClass) { const std::string body = R"( -OpCapability PhysicalStorageBufferAddressesEXT +OpCapability PhysicalStorageBufferAddresses OpCapability Int64 OpCapability Shader OpExtension "SPV_EXT_physical_storage_buffer" -OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +OpMemoryModel PhysicalStorageBuffer64 GLSL450 OpEntryPoint Fragment %main "main" OpExecutionMode %main OriginUpperLeft %uint64 = OpTypeInt 64 0 @@ -1513,22 +1513,54 @@ OpFunctionEnd ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("Pointer storage class must be " - "PhysicalStorageBufferEXT: ConvertUToPtr")); + "PhysicalStorageBuffer: ConvertUToPtr")); +} + +TEST_F(ValidateConversion, ConvertUToPtrVulkanWrongWidth) { + const std::string body = R"( +OpCapability PhysicalStorageBufferAddresses +OpCapability Int64 +OpCapability Shader +OpExtension "SPV_EXT_physical_storage_buffer" +OpMemoryModel PhysicalStorageBuffer64 GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +%uint32 = OpTypeInt 32 0 +%uint64 = OpTypeInt 64 0 +%u32_1 = OpConstant %uint32 1 +%ptr = OpTypePointer PhysicalStorageBuffer %uint64 +%void = OpTypeVoid +%voidfn = OpTypeFunction %void +%main = OpFunction %void None %voidfn +%entry = OpLabel +%val1 = OpConvertUToPtr %ptr %u32_1 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-PhysicalStorageBuffer64-04710")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("PhysicalStorageBuffer64 addressing mode requires the input " + "integer to have a 64-bit width for Vulkan environment.")); } TEST_F(ValidateConversion, ConvertPtrToUPSBSuccess) { const std::string body = R"( -OpCapability PhysicalStorageBufferAddressesEXT +OpCapability PhysicalStorageBufferAddresses OpCapability Int64 OpCapability Shader OpExtension "SPV_EXT_physical_storage_buffer" -OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +OpMemoryModel PhysicalStorageBuffer64 GLSL450 OpEntryPoint Fragment %main "main" OpExecutionMode %main OriginUpperLeft OpDecorate %val1 RestrictPointerEXT %uint64 = OpTypeInt 64 0 %u64_1 = OpConstant %uint64 1 -%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64 +%ptr = OpTypePointer PhysicalStorageBuffer %uint64 %pptr_f = OpTypePointer Function %ptr %void = OpTypeVoid %voidfn = OpTypeFunction %void @@ -1547,11 +1579,11 @@ OpFunctionEnd TEST_F(ValidateConversion, ConvertPtrToUPSBStorageClass) { const std::string body = R"( -OpCapability PhysicalStorageBufferAddressesEXT +OpCapability PhysicalStorageBufferAddresses OpCapability Int64 OpCapability Shader OpExtension "SPV_EXT_physical_storage_buffer" -OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +OpMemoryModel PhysicalStorageBuffer64 GLSL450 OpEntryPoint Fragment %main "main" OpExecutionMode %main OriginUpperLeft %uint64 = OpTypeInt 64 0 @@ -1571,7 +1603,42 @@ OpFunctionEnd ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("Pointer storage class must be " - "PhysicalStorageBufferEXT: ConvertPtrToU")); + "PhysicalStorageBuffer: ConvertPtrToU")); +} + +TEST_F(ValidateConversion, ConvertPtrToUVulkanWrongWidth) { + const std::string body = R"( +OpCapability PhysicalStorageBufferAddresses +OpCapability Int64 +OpCapability Shader +OpExtension "SPV_EXT_physical_storage_buffer" +OpMemoryModel PhysicalStorageBuffer64 GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpDecorate %val1 RestrictPointerEXT +%uint32 = OpTypeInt 32 0 +%uint64 = OpTypeInt 64 0 +%ptr = OpTypePointer PhysicalStorageBuffer %uint64 +%pptr_f = OpTypePointer Function %ptr +%void = OpTypeVoid +%voidfn = OpTypeFunction %void +%main = OpFunction %void None %voidfn +%entry = OpLabel +%val1 = OpVariable %pptr_f Function +%val2 = OpLoad %ptr %val1 +%val3 = OpConvertPtrToU %uint32 %val2 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-PhysicalStorageBuffer64-04710")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("PhysicalStorageBuffer64 addressing mode requires the result " + "integer type to have a 64-bit width for Vulkan environment.")); } using ValidateSmallConversions = spvtest::ValidateBase; -- cgit v1.2.3 From c91a25af13e112729be7272d58b0df25e772c3e0 Mon Sep 17 00:00:00 2001 From: sfricke-samsung <46493288+sfricke-samsung@users.noreply.github.com> Date: Tue, 2 Feb 2021 07:54:26 -0800 Subject: spirv-val: label tests for VUID 04657 (#4119) --- source/val/validate_image.cpp | 1 + source/val/validation_state.cpp | 2 ++ test/val/val_image_test.cpp | 6 ++++++ 3 files changed, 9 insertions(+) diff --git a/source/val/validate_image.cpp b/source/val/validate_image.cpp index 3f3f7902..f7ddec73 100644 --- a/source/val/validate_image.cpp +++ b/source/val/validate_image.cpp @@ -899,6 +899,7 @@ spv_result_t ValidateTypeSampledImage(ValidationState_t& _, // Vulkan uses the Sampled=1 case. if ((info.sampled != 0) && (info.sampled != 1)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) + << _.VkErrorID(4657) << "Sampled image type requires an image type with \"Sampled\" " "operand set to 0 or 1"; } diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index 746efd05..13323a39 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -1700,6 +1700,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-OpTypeImage-04657); case 4658: return VUID_WRAP(VUID-StandaloneSpirv-OpImageTexelPointer-04658); + case 4659: + return VUID_WRAP(VUID-StandaloneSpirv-OpImageQuerySizeLod-04659); case 4662: return VUID_WRAP(VUID-StandaloneSpirv-Offset-04662); case 4663: diff --git a/test/val/val_image_test.cpp b/test/val/val_image_test.cpp index d7d40f5b..5030e411 100644 --- a/test/val/val_image_test.cpp +++ b/test/val/val_image_test.cpp @@ -3929,6 +3929,8 @@ OpFunctionEnd CompileSuccessfully(body.c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpImageQuerySizeLod-04659")); EXPECT_THAT( getDiagnosticString(), HasSubstr( @@ -4263,6 +4265,8 @@ OpFunctionEnd CompileSuccessfully(body.c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpImageQuerySizeLod-04659")); EXPECT_THAT( getDiagnosticString(), HasSubstr("OpImageQueryLevels must only consume an \"Image\" operand " @@ -4448,6 +4452,8 @@ OpFunctionEnd CompileSuccessfully(body.c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpTypeImage-04657")); EXPECT_THAT(getDiagnosticString(), HasSubstr("Sampled image type requires an image type with " "\"Sampled\" operand set to 0 or 1")); -- cgit v1.2.3 From f11f7434815838bbad349124767b258ce7df41f0 Mon Sep 17 00:00:00 2001 From: sfricke-samsung <46493288+sfricke-samsung@users.noreply.github.com> Date: Fri, 5 Feb 2021 06:49:14 -0800 Subject: spirv-val: Add Vulkan Invariant Decoration VUID (#4132) --- source/val/validate_memory.cpp | 36 ++++++++++---- source/val/validation_state.cpp | 2 + test/val/val_memory_test.cpp | 103 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 133 insertions(+), 8 deletions(-) diff --git a/source/val/validate_memory.cpp b/source/val/validate_memory.cpp index edc2a0ce..2318c962 100644 --- a/source/val/validate_memory.cpp +++ b/source/val/validate_memory.cpp @@ -407,6 +407,10 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { << "' is not a pointer type."; } + const auto type_index = 2; + const auto value_id = result_type->GetOperandAs(type_index); + auto value_type = _.FindDef(value_id); + const auto initializer_index = 3; const auto storage_class_index = 2; if (initializer_index < inst->operands().size()) { @@ -423,7 +427,7 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { << "OpVariable Initializer '" << _.getIdName(initializer_id) << "' is not a constant or module-scope variable."; } - if (initializer->type_id() != result_type->GetOperandAs(2u)) { + if (initializer->type_id() != value_id) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "Initializer type must match the type pointed to by the Result " "Type"; @@ -440,9 +444,6 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { storage_class != SpvStorageClassHitAttributeNV && storage_class != SpvStorageClassCallableDataNV && storage_class != SpvStorageClassIncomingCallableDataNV) { - const auto storage_index = 2; - const auto storage_id = result_type->GetOperandAs(storage_index); - const auto storage = _.FindDef(storage_id); bool storage_input_or_output = storage_class == SpvStorageClassInput || storage_class == SpvStorageClassOutput; bool builtin = false; @@ -455,7 +456,7 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { } } if (!(storage_input_or_output && builtin) && - ContainsInvalidBool(_, storage, storage_input_or_output)) { + ContainsInvalidBool(_, value_type, storage_input_or_output)) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "If OpTypeBool is stored in conjunction with OpVariable, it " << "can only be used with non-externally visible shader Storage " @@ -576,6 +577,28 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { "of this type"; } } + + // Check for invalid use of Invariant + if (storage_class != SpvStorageClassInput && + storage_class != SpvStorageClassOutput) { + if (_.HasDecoration(inst->id(), SpvDecorationInvariant)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << _.VkErrorID(4677) + << "Variable decorated with Invariant must only be identified " + "with the Input or Output storage class in Vulkan " + "environment."; + } + // Need to check if only the members in a struct are decorated + if (value_type && value_type->opcode() == SpvOpTypeStruct) { + if (_.HasDecoration(value_id, SpvDecorationInvariant)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << _.VkErrorID(4677) + << "Variable struct member decorated with Invariant must only " + "be identified with the Input or Output storage class in " + "Vulkan environment."; + } + } + } } // Vulkan Appendix A: Check that if contains initializer, then @@ -640,9 +663,6 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { } // Vulkan specific validation rules for OpTypeRuntimeArray - const auto type_index = 2; - const auto value_id = result_type->GetOperandAs(type_index); - auto value_type = _.FindDef(value_id); if (spvIsVulkanEnv(_.context()->target_env)) { // OpTypeRuntimeArray should only ever be in a container like OpTypeStruct, // so should never appear as a bare variable. diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index 13323a39..10c0fcdf 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -1710,6 +1710,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-GLSLShared-04669); case 4675: return VUID_WRAP(VUID-StandaloneSpirv-FPRoundingMode-04675); + case 4677: + return VUID_WRAP(VUID-StandaloneSpirv-Invariant-04677); case 4683: return VUID_WRAP(VUID-StandaloneSpirv-LocalSize-04683); case 4685: diff --git a/test/val/val_memory_test.cpp b/test/val/val_memory_test.cpp index 7d66dcd4..958476cb 100644 --- a/test/val/val_memory_test.cpp +++ b/test/val/val_memory_test.cpp @@ -4042,6 +4042,109 @@ OpFunctionEnd "typed as OpTypeStruct, or an array of this type")); } +TEST_F(ValidateMemory, VulkanInvariantOutputSuccess) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %main "main" +OpDecorate %var Location 0 +OpDecorate %var Invariant +%void = OpTypeVoid +%f32 = OpTypeFloat 32 +%ptr_output = OpTypePointer Output %f32 +%var = OpVariable %ptr_output Output +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0)); +} + +TEST_F(ValidateMemory, VulkanInvariantInputStructSuccess) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpDecorate %var Location 0 +OpMemberDecorate %struct 1 Invariant +%void = OpTypeVoid +%f32 = OpTypeFloat 32 +%struct = OpTypeStruct %f32 %f32 +%ptr_input = OpTypePointer Input %struct +%var = OpVariable %ptr_input Input +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0)); +} + +TEST_F(ValidateMemory, VulkanInvariantWrongStorageClass) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %main "main" +OpDecorate %var Invariant +%void = OpTypeVoid +%f32 = OpTypeFloat 32 +%ptr_private = OpTypePointer Private %f32 +%var = OpVariable %ptr_private Private +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-Invariant-04677")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Variable decorated with Invariant must only be identified with the " + "Input or Output storage class in Vulkan environment.")); +} + +TEST_F(ValidateMemory, VulkanInvariantMemberWrongStorageClass) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpMemberDecorate %struct 1 Invariant +%void = OpTypeVoid +%f32 = OpTypeFloat 32 +%struct = OpTypeStruct %f32 %f32 +%ptr_private = OpTypePointer Private %struct +%var = OpVariable %ptr_private Private +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-Invariant-04677")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Variable struct member decorated with Invariant must " + "only be identified with the Input or Output storage " + "class in Vulkan environment.")); +} + TEST_F(ValidateMemory, PhysicalStorageBufferPtrEqual) { const std::string spirv = R"( OpCapability Shader -- cgit v1.2.3 From 3ad7e5fcc0eeec393cb072d503ed2979c59e8070 Mon Sep 17 00:00:00 2001 From: sfricke-samsung <46493288+sfricke-samsung@users.noreply.github.com> Date: Fri, 5 Feb 2021 06:57:00 -0800 Subject: spirv-val: Fix/Label UniformConstant VUID (#4134) --- source/val/validate_memory.cpp | 12 ++++-------- source/val/validation_state.cpp | 2 ++ test/val/val_memory_test.cpp | 16 ++++++++-------- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/source/val/validate_memory.cpp b/source/val/validate_memory.cpp index 2318c962..4dd6d941 100644 --- a/source/val/validate_memory.cpp +++ b/source/val/validate_memory.cpp @@ -536,18 +536,14 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { if (!IsAllowedTypeOrArrayOfSame( _, pointee, {SpvOpTypeImage, SpvOpTypeSampler, SpvOpTypeSampledImage, - SpvOpTypeAccelerationStructureNV, - SpvOpTypeAccelerationStructureKHR, SpvOpTypeRayQueryKHR})) { + SpvOpTypeAccelerationStructureKHR})) { return _.diag(SPV_ERROR_INVALID_ID, inst) - << "UniformConstant OpVariable '" << _.getIdName(inst->id()) - << "' has illegal type.\n" - << "From Vulkan spec, section 14.5.2:\n" + << _.VkErrorID(4655) << "UniformConstant OpVariable '" + << _.getIdName(inst->id()) << "' has illegal type.\n" << "Variables identified with the UniformConstant storage class " << "are used only as handles to refer to opaque resources. Such " << "variables must be typed as OpTypeImage, OpTypeSampler, " - << "OpTypeSampledImage, OpTypeAccelerationStructureNV, " - "OpTypeAccelerationStructureKHR, " - "OpTypeRayQueryKHR, " + << "OpTypeSampledImage, OpTypeAccelerationStructureKHR, " << "or an array of one of these types."; } } diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index 10c0fcdf..8050c96a 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -1694,6 +1694,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-OriginLowerLeft-04653); case 4654: return VUID_WRAP(VUID-StandaloneSpirv-PixelCenterInteger-04654); + case 4655: + return VUID_WRAP(VUID-StandaloneSpirv-UniformConstant-04655); case 4656: return VUID_WRAP(VUID-StandaloneSpirv-OpTypeImage-04656); case 4657: diff --git a/test/val/val_memory_test.cpp b/test/val/val_memory_test.cpp index 958476cb..9799b404 100644 --- a/test/val/val_memory_test.cpp +++ b/test/val/val_memory_test.cpp @@ -61,14 +61,14 @@ OpFunctionEnd )"; CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-UniformConstant-04655")); EXPECT_THAT( getDiagnosticString(), - HasSubstr("From Vulkan spec, section 14.5.2:\n" - "Variables identified with the UniformConstant storage class " + HasSubstr("Variables identified with the UniformConstant storage class " "are used only as handles to refer to opaque resources. Such " "variables must be typed as OpTypeImage, OpTypeSampler, " - "OpTypeSampledImage, OpTypeAccelerationStructureNV, " - "OpTypeAccelerationStructureKHR, OpTypeRayQueryKHR, " + "OpTypeSampledImage, OpTypeAccelerationStructureKHR, " "or an array of one of these types.")); } @@ -115,14 +115,14 @@ OpFunctionEnd )"; CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-UniformConstant-04655")); EXPECT_THAT( getDiagnosticString(), - HasSubstr("From Vulkan spec, section 14.5.2:\n" - "Variables identified with the UniformConstant storage class " + HasSubstr("Variables identified with the UniformConstant storage class " "are used only as handles to refer to opaque resources. Such " "variables must be typed as OpTypeImage, OpTypeSampler, " - "OpTypeSampledImage, OpTypeAccelerationStructureNV, " - "OpTypeAccelerationStructureKHR, OpTypeRayQueryKHR, " + "OpTypeSampledImage, OpTypeAccelerationStructureKHR, " "or an array of one of these types.")); } -- cgit v1.2.3 From f0c96f40c79d03e42688aae48642a4759a5e376f Mon Sep 17 00:00:00 2001 From: sfricke-samsung <46493288+sfricke-samsung@users.noreply.github.com> Date: Fri, 5 Feb 2021 12:12:38 -0800 Subject: spriv-val: Vulkan image gather constant component (#4133) --- source/val/validate_image.cpp | 11 ++++++++++- source/val/validation_state.cpp | 2 ++ test/val/val_image_test.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/source/val/validate_image.cpp b/source/val/validate_image.cpp index f7ddec73..bdb2516e 100644 --- a/source/val/validate_image.cpp +++ b/source/val/validate_image.cpp @@ -1457,12 +1457,21 @@ spv_result_t ValidateImageGather(ValidationState_t& _, } if (opcode == SpvOpImageGather || opcode == SpvOpImageSparseGather) { - const uint32_t component_index_type = _.GetOperandTypeId(inst, 4); + const uint32_t component = inst->GetOperandAs(4); + const uint32_t component_index_type = _.GetTypeId(component); if (!_.IsIntScalarType(component_index_type) || _.GetBitWidth(component_index_type) != 32) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected Component to be 32-bit int scalar"; } + if (spvIsVulkanEnv(_.context()->target_env)) { + if (!spvOpcodeIsConstant(_.GetIdOpcode(component))) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << _.VkErrorID(4664) + << "Expected Component Operand to be a const object for Vulkan " + "environment"; + } + } } else { assert(opcode == SpvOpImageDrefGather || opcode == SpvOpImageSparseDrefGather); diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index 8050c96a..6dfc7bf6 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -1708,6 +1708,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-Offset-04662); case 4663: return VUID_WRAP(VUID-StandaloneSpirv-Offset-04663); + case 4664: + return VUID_WRAP(VUID-StandaloneSpirv-OpImageGather-04664); case 4669: return VUID_WRAP(VUID-StandaloneSpirv-GLSLShared-04669); case 4675: diff --git a/test/val/val_image_test.cpp b/test/val/val_image_test.cpp index 5030e411..6a0333cd 100644 --- a/test/val/val_image_test.cpp +++ b/test/val/val_image_test.cpp @@ -80,6 +80,7 @@ OpCapability ImageBuffer %private_image_u32_buffer_0002_r32ui %private_image_u32_spd_0002 %private_image_f32_buffer_0002_r32ui +%input_flat_u32 )"; ss << capabilities_and_extensions; @@ -121,6 +122,8 @@ OpDecorate %uniform_image_f32_cube_0102_rgba32f DescriptorSet 2 OpDecorate %uniform_image_f32_cube_0102_rgba32f Binding 3 OpDecorate %uniform_sampler DescriptorSet 3 OpDecorate %uniform_sampler Binding 0 +OpDecorate %input_flat_u32 Flat +OpDecorate %input_flat_u32 Location 0 )"; } @@ -294,6 +297,9 @@ OpDecorate %uniform_sampler Binding 0 %ptr_Image_f32 = OpTypePointer Image %f32 %ptr_image_f32_buffer_0002_r32ui = OpTypePointer Private %type_image_f32_buffer_0002_r32ui %private_image_f32_buffer_0002_r32ui = OpVariable %ptr_image_f32_buffer_0002_r32ui Private + +%ptr_input_flat_u32 = OpTypePointer Input %u32 +%input_flat_u32 = OpVariable %ptr_input_flat_u32 Input )"; if (env == SPV_ENV_UNIVERSAL_1_0) { @@ -3016,6 +3022,40 @@ TEST_F(ValidateImage, GatherComponentNot32Bit) { HasSubstr("Expected Component to be 32-bit int scalar")); } +TEST_F(ValidateImage, GatherComponentSuccessVulkan) { + const std::string body = R"( +%img = OpLoad %type_image_f32_cube_0101 %uniform_image_f32_cube_0101 +%sampler = OpLoad %type_sampler %uniform_sampler +%simg = OpSampledImage %type_sampled_image_f32_cube_0101 %img %sampler +%res1 = OpImageGather %f32vec4 %simg %f32vec4_0000 %u32_0 +)"; + + spv_target_env env = SPV_ENV_VULKAN_1_0; + CompileSuccessfully(GenerateShaderCode(body, "", "Fragment", "", env).c_str(), + env); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(env)); +} + +TEST_F(ValidateImage, GatherComponentNotConstantVulkan) { + const std::string body = R"( +%input_u32 = OpLoad %u32 %input_flat_u32 +%img = OpLoad %type_image_f32_cube_0101 %uniform_image_f32_cube_0101 +%sampler = OpLoad %type_sampler %uniform_sampler +%simg = OpSampledImage %type_sampled_image_f32_cube_0101 %img %sampler +%res1 = OpImageGather %f32vec4 %simg %f32vec4_0000 %input_u32 +)"; + + spv_target_env env = SPV_ENV_VULKAN_1_0; + CompileSuccessfully(GenerateShaderCode(body, "", "Fragment", "", env).c_str(), + env); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(env)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpImageGather-04664")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Expected Component Operand to be a const object for " + "Vulkan environment")); +} + TEST_F(ValidateImage, GatherDimCube) { const std::string body = R"( %img = OpLoad %type_image_f32_cube_0101 %uniform_image_f32_cube_0101 -- cgit v1.2.3 From cfa1dadb1e62312655531de3cb97cecb0b21a737 Mon Sep 17 00:00:00 2001 From: dan sinclair Date: Wed, 10 Feb 2021 13:21:38 -0500 Subject: Update a few virtuals to overrides. (#4143) These methods are overriding their base class, so switch to override from virtual. --- source/opt/instruction.h | 2 +- source/opt/instruction_list.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/opt/instruction.h b/source/opt/instruction.h index 47432210..3e557dd7 100644 --- a/source/opt/instruction.h +++ b/source/opt/instruction.h @@ -209,7 +209,7 @@ class Instruction : public utils::IntrusiveNodeBase { Instruction(Instruction&&); Instruction& operator=(Instruction&&); - virtual ~Instruction() = default; + ~Instruction() override = default; // Returns a newly allocated instruction that has the same operands, result, // and type as |this|. The new instruction is not linked into any list. diff --git a/source/opt/instruction_list.h b/source/opt/instruction_list.h index 417cbd76..b3e42745 100644 --- a/source/opt/instruction_list.h +++ b/source/opt/instruction_list.h @@ -53,7 +53,7 @@ class InstructionList : public utils::IntrusiveList { } // Destroy this list and any instructions in the list. - inline virtual ~InstructionList(); + inline ~InstructionList() override; class iterator : public utils::IntrusiveList::iterator { public: -- cgit v1.2.3 From c79edd260c2b503f0eca57310057b4a100999cc5 Mon Sep 17 00:00:00 2001 From: greg-lunarg Date: Thu, 11 Feb 2021 15:24:04 -0700 Subject: Generate differentiated error codes for buffer oob checking (#4144) This allows the GPU-AV layer to differentiate between errors with uniform buffers versus storage buffers and map these to the relevant VUIDs. This is a resubmit of a previously reverted commit. The revert was done as someone erroneously attempted to build the latest validation layers with a TOT spirv-tools. The validation layers must be built with their known-good glslang and its known-good spirv-tools and spirv-headers. --- include/spirv-tools/instrument.hpp | 5 +- source/opt/inst_bindless_check_pass.cpp | 44 ++- source/opt/inst_bindless_check_pass.h | 1 + test/opt/inst_bindless_check_test.cpp | 506 ++++++++++++++++---------------- 4 files changed, 305 insertions(+), 251 deletions(-) diff --git a/include/spirv-tools/instrument.hpp b/include/spirv-tools/instrument.hpp index 2b47a564..05a0472e 100644 --- a/include/spirv-tools/instrument.hpp +++ b/include/spirv-tools/instrument.hpp @@ -170,7 +170,10 @@ static const int kInstMaxOutCnt = kInstStageOutCnt + 4; static const int kInstErrorBindlessBounds = 0; static const int kInstErrorBindlessUninit = 1; static const int kInstErrorBuffAddrUnallocRef = 2; -static const int kInstErrorBindlessBuffOOB = 3; +// Deleted: static const int kInstErrorBindlessBuffOOB = 3; +// This comment will will remain for 2 releases to allow +// for the transition of all builds. Buffer OOB is +// generating the following four differentiated codes instead: static const int kInstErrorBuffOOBUniform = 4; static const int kInstErrorBuffOOBStorage = 5; static const int kInstErrorBuffOOBUniformTexel = 6; diff --git a/source/opt/inst_bindless_check_pass.cpp b/source/opt/inst_bindless_check_pass.cpp index 00857343..5607239a 100644 --- a/source/opt/inst_bindless_check_pass.cpp +++ b/source/opt/inst_bindless_check_pass.cpp @@ -27,13 +27,16 @@ static const int kSpvCopyObjectOperandIdInIdx = 0; static const int kSpvLoadPtrIdInIdx = 0; static const int kSpvAccessChainBaseIdInIdx = 0; static const int kSpvAccessChainIndex0IdInIdx = 1; +static const int kSpvTypeArrayTypeIdInIdx = 0; static const int kSpvTypeArrayLengthIdInIdx = 1; static const int kSpvConstantValueInIdx = 0; static const int kSpvVariableStorageClassInIdx = 0; +static const int kSpvTypePtrTypeIdInIdx = 1; static const int kSpvTypeImageDim = 1; static const int kSpvTypeImageDepth = 2; static const int kSpvTypeImageArrayed = 3; static const int kSpvTypeImageMS = 4; +static const int kSpvTypeImageSampled = 5; } // anonymous namespace // Avoid unused variable warning/error on Linux @@ -206,13 +209,40 @@ bool InstBindlessCheckPass::AnalyzeDescriptorReference(Instruction* ref_inst, var_inst->GetSingleWordInOperand(kSpvVariableStorageClassInIdx); switch (storage_class) { case SpvStorageClassUniform: - case SpvStorageClassUniformConstant: case SpvStorageClassStorageBuffer: break; default: return false; break; } + // Check for deprecated storage block form + if (storage_class == SpvStorageClassUniform) { + uint32_t var_ty_id = var_inst->type_id(); + Instruction* var_ty_inst = get_def_use_mgr()->GetDef(var_ty_id); + uint32_t ptr_ty_id = + var_ty_inst->GetSingleWordInOperand(kSpvTypePtrTypeIdInIdx); + Instruction* ptr_ty_inst = get_def_use_mgr()->GetDef(ptr_ty_id); + SpvOp ptr_ty_op = ptr_ty_inst->opcode(); + uint32_t block_ty_id = + (ptr_ty_op == SpvOpTypeArray || ptr_ty_op == SpvOpTypeRuntimeArray) + ? ptr_ty_inst->GetSingleWordInOperand(kSpvTypeArrayTypeIdInIdx) + : ptr_ty_id; + assert(get_def_use_mgr()->GetDef(block_ty_id)->opcode() == + SpvOpTypeStruct && + "unexpected block type"); + bool block_found = get_decoration_mgr()->FindDecoration( + block_ty_id, SpvDecorationBlock, + [](const Instruction&) { return true; }); + if (!block_found) { + // If block decoration not found, verify deprecated form of SSBO + bool buffer_block_found = get_decoration_mgr()->FindDecoration( + block_ty_id, SpvDecorationBufferBlock, + [](const Instruction&) { return true; }); + USE_ASSERT(buffer_block_found && "block decoration not found"); + storage_class = SpvStorageClassStorageBuffer; + } + } + ref->strg_class = storage_class; Instruction* desc_type_inst = GetPointeeTypeInst(var_inst); switch (desc_type_inst->opcode()) { case SpvOpTypeArray: @@ -665,8 +695,10 @@ void InstBindlessCheckPass::GenDescInitCheckCode( // for the referenced value. Instruction* ult_inst = builder.AddBinaryOp(GetBoolId(), SpvOpULessThan, ref_id, init_id); - uint32_t error = - init_check ? kInstErrorBindlessUninit : kInstErrorBindlessBuffOOB; + uint32_t error = init_check ? kInstErrorBindlessUninit + : (ref.strg_class == SpvStorageClassUniform + ? kInstErrorBuffOOBUniform + : kInstErrorBuffOOBStorage); uint32_t error_id = builder.GetUintConstantId(error); GenCheckCode(ult_inst->result_id(), error_id, init_check ? 0 : ref_id, init_check ? builder.GetUintConstantId(0u) : init_id, stage_idx, @@ -732,7 +764,11 @@ void InstBindlessCheckPass::GenTexBuffCheckCode( // for the referenced value. Instruction* ult_inst = builder.AddBinaryOp(GetBoolId(), SpvOpULessThan, coord_id, size_id); - uint32_t error_id = builder.GetUintConstantId(kInstErrorBindlessBuffOOB); + uint32_t error = + (image_ty_inst->GetSingleWordInOperand(kSpvTypeImageSampled) == 2) + ? kInstErrorBuffOOBStorageTexel + : kInstErrorBuffOOBUniformTexel; + uint32_t error_id = builder.GetUintConstantId(error); GenCheckCode(ult_inst->result_id(), error_id, coord_id, size_id, stage_idx, &ref, new_blocks); // Move original block's remaining code into remainder/merge block and add diff --git a/source/opt/inst_bindless_check_pass.h b/source/opt/inst_bindless_check_pass.h index a7dff75f..cd961805 100644 --- a/source/opt/inst_bindless_check_pass.h +++ b/source/opt/inst_bindless_check_pass.h @@ -130,6 +130,7 @@ class InstBindlessCheckPass : public InstrumentPass { uint32_t ptr_id; uint32_t var_id; uint32_t desc_idx_id; + uint32_t strg_class; Instruction* ref_inst; } RefAnalysis; diff --git a/test/opt/inst_bindless_check_test.cpp b/test/opt/inst_bindless_check_test.cpp index f1899627..1a42329b 100644 --- a/test/opt/inst_bindless_check_test.cpp +++ b/test/opt/inst_bindless_check_test.cpp @@ -7308,15 +7308,15 @@ TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) { ;CHECK: %_ptr_StorageBuffer__struct_128 = OpTypePointer StorageBuffer %_struct_128 ;CHECK: %130 = OpVariable %_ptr_StorageBuffer__struct_128 StorageBuffer ;CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint - ;CHECK: %uint_3 = OpConstant %uint 3 + ;CHECK: %uint_4 = OpConstant %uint 4 ;CHECK: %148 = OpTypeFunction %void %uint %uint %uint %uint %uint ;CHECK: %_struct_155 = OpTypeStruct %uint %_runtimearr_uint ;CHECK: %_ptr_StorageBuffer__struct_155 = OpTypePointer StorageBuffer %_struct_155 ;CHECK: %157 = OpVariable %_ptr_StorageBuffer__struct_155 StorageBuffer ;CHECK: %uint_11 = OpConstant %uint 11 - ;CHECK: %uint_4 = OpConstant %uint 4 ;CHECK: %uint_23 = OpConstant %uint 23 ;CHECK: %uint_2 = OpConstant %uint 2 + ;CHECK: %uint_3 = OpConstant %uint 3 ;CHECK:%_ptr_Input_v4float = OpTypePointer Input %v4float ;CHECK:%gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: %v4uint = OpTypeVector %uint 4 @@ -7352,7 +7352,7 @@ TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) { ;CHECK: %146 = OpLoad %v2float %86 ;CHECK: OpBranch %143 ;CHECK: %145 = OpLabel - ;CHECK: %201 = OpFunctionCall %void %147 %uint_71 %uint_3 %uint_0 %119 %140 + ;CHECK: %201 = OpFunctionCall %void %147 %uint_71 %uint_4 %uint_0 %119 %140 ;CHECK: OpBranch %143 ;CHECK: %143 = OpLabel ;CHECK: %203 = OpPhi %v2float %146 %144 %202 %145 @@ -7369,7 +7369,7 @@ TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) { ;CHECK: %209 = OpLoad %v2float %89 ;CHECK: OpBranch %206 ;CHECK: %208 = OpLabel - ;CHECK: %211 = OpFunctionCall %void %147 %uint_75 %uint_3 %uint_0 %204 %140 + ;CHECK: %211 = OpFunctionCall %void %147 %uint_75 %uint_4 %uint_0 %204 %140 ;CHECK: OpBranch %206 ;CHECK: %206 = OpLabel ;CHECK: %212 = OpPhi %v2float %209 %207 %202 %208 @@ -7409,49 +7409,49 @@ TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) { ;CHECK: %153 = OpFunctionParameter %uint ;CHECK: %154 = OpLabel ;CHECK: %158 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_0 - ;CHECK: %161 = OpAtomicIAdd %uint %158 %uint_4 %uint_0 %uint_11 - ;CHECK: %162 = OpIAdd %uint %161 %uint_11 - ;CHECK: %163 = OpArrayLength %uint %157 1 - ;CHECK: %164 = OpULessThanEqual %bool %162 %163 - ;CHECK: OpSelectionMerge %165 None - ;CHECK: OpBranchConditional %164 %166 %165 - ;CHECK: %166 = OpLabel - ;CHECK: %167 = OpIAdd %uint %161 %uint_0 - ;CHECK: %168 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %167 - ;CHECK: OpStore %168 %uint_11 - ;CHECK: %170 = OpIAdd %uint %161 %uint_1 - ;CHECK: %171 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %170 - ;CHECK: OpStore %171 %uint_23 - ;CHECK: %173 = OpIAdd %uint %161 %uint_2 - ;CHECK: %174 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %173 - ;CHECK: OpStore %174 %149 - ;CHECK: %175 = OpIAdd %uint %161 %uint_3 + ;CHECK: %160 = OpAtomicIAdd %uint %158 %uint_4 %uint_0 %uint_11 + ;CHECK: %161 = OpIAdd %uint %160 %uint_11 + ;CHECK: %162 = OpArrayLength %uint %157 1 + ;CHECK: %163 = OpULessThanEqual %bool %161 %162 + ;CHECK: OpSelectionMerge %164 None + ;CHECK: OpBranchConditional %163 %165 %164 + ;CHECK: %165 = OpLabel + ;CHECK: %166 = OpIAdd %uint %160 %uint_0 + ;CHECK: %167 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %166 + ;CHECK: OpStore %167 %uint_11 + ;CHECK: %169 = OpIAdd %uint %160 %uint_1 + ;CHECK: %170 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %169 + ;CHECK: OpStore %170 %uint_23 + ;CHECK: %172 = OpIAdd %uint %160 %uint_2 + ;CHECK: %173 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %172 + ;CHECK: OpStore %173 %149 + ;CHECK: %175 = OpIAdd %uint %160 %uint_3 ;CHECK: %176 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %175 ;CHECK: OpStore %176 %uint_4 ;CHECK: %179 = OpLoad %v4float %gl_FragCoord ;CHECK: %181 = OpBitcast %v4uint %179 ;CHECK: %182 = OpCompositeExtract %uint %181 0 - ;CHECK: %183 = OpIAdd %uint %161 %uint_4 + ;CHECK: %183 = OpIAdd %uint %160 %uint_4 ;CHECK: %184 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %183 ;CHECK: OpStore %184 %182 ;CHECK: %185 = OpCompositeExtract %uint %181 1 - ;CHECK: %187 = OpIAdd %uint %161 %uint_5 + ;CHECK: %187 = OpIAdd %uint %160 %uint_5 ;CHECK: %188 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %187 ;CHECK: OpStore %188 %185 - ;CHECK: %189 = OpIAdd %uint %161 %uint_7 + ;CHECK: %189 = OpIAdd %uint %160 %uint_7 ;CHECK: %190 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %189 ;CHECK: OpStore %190 %150 - ;CHECK: %192 = OpIAdd %uint %161 %uint_8 + ;CHECK: %192 = OpIAdd %uint %160 %uint_8 ;CHECK: %193 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %192 ;CHECK: OpStore %193 %151 - ;CHECK: %195 = OpIAdd %uint %161 %uint_9 + ;CHECK: %195 = OpIAdd %uint %160 %uint_9 ;CHECK: %196 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %195 ;CHECK: OpStore %196 %152 - ;CHECK: %198 = OpIAdd %uint %161 %uint_10 + ;CHECK: %198 = OpIAdd %uint %160 %uint_10 ;CHECK: %199 = OpAccessChain %_ptr_StorageBuffer_uint %157 %uint_1 %198 ;CHECK: OpStore %199 %153 - ;CHECK: OpBranch %165 - ;CHECK: %165 = OpLabel + ;CHECK: OpBranch %164 + ;CHECK: %164 = OpLabel ;CHECK: OpReturn ;CHECK: OpFunctionEnd )"; @@ -7596,14 +7596,14 @@ TEST_F(InstBindlessTest, UniformArrayRefNoDescInit) { ;CHECK: %113 = OpVariable %_ptr_StorageBuffer__struct_111 StorageBuffer ;CHECK:%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint ;CHECK: %bool = OpTypeBool -;CHECK: %uint_3 = OpConstant %uint 3 +;CHECK: %uint_4 = OpConstant %uint 4 ;CHECK: %132 = OpTypeFunction %void %uint %uint %uint %uint %uint ;CHECK:%_struct_139 = OpTypeStruct %uint %_runtimearr_uint ;CHECK:%_ptr_StorageBuffer__struct_139 = OpTypePointer StorageBuffer %_struct_139 ;CHECK: %141 = OpVariable %_ptr_StorageBuffer__struct_139 StorageBuffer ;CHECK: %uint_11 = OpConstant %uint 11 -;CHECK: %uint_4 = OpConstant %uint 4 ;CHECK: %uint_23 = OpConstant %uint 23 +;CHECK: %uint_3 = OpConstant %uint 3 ;CHECK:%_ptr_Input_v4float = OpTypePointer Input %v4float ;CHECK:%gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: %v4uint = OpTypeVector %uint 4 @@ -7637,7 +7637,7 @@ TEST_F(InstBindlessTest, UniformArrayRefNoDescInit) { ;CHECK: %130 = OpLoad %v2float %81 ;CHECK: OpBranch %127 ;CHECK: %129 = OpLabel -;CHECK: %184 = OpFunctionCall %void %131 %uint_78 %uint_3 %uint_0 %101 %123 +;CHECK: %184 = OpFunctionCall %void %131 %uint_78 %uint_4 %uint_0 %101 %123 ;CHECK: OpBranch %127 ;CHECK: %127 = OpLabel ;CHECK: %186 = OpPhi %v2float %130 %128 %185 %129 @@ -7674,49 +7674,49 @@ TEST_F(InstBindlessTest, UniformArrayRefNoDescInit) { ;CHECK: %137 = OpFunctionParameter %uint ;CHECK: %138 = OpLabel ;CHECK: %142 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_0 -;CHECK: %145 = OpAtomicIAdd %uint %142 %uint_4 %uint_0 %uint_11 -;CHECK: %146 = OpIAdd %uint %145 %uint_11 -;CHECK: %147 = OpArrayLength %uint %141 1 -;CHECK: %148 = OpULessThanEqual %bool %146 %147 -;CHECK: OpSelectionMerge %149 None -;CHECK: OpBranchConditional %148 %150 %149 -;CHECK: %150 = OpLabel -;CHECK: %151 = OpIAdd %uint %145 %uint_0 -;CHECK: %152 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %151 -;CHECK: OpStore %152 %uint_11 -;CHECK: %154 = OpIAdd %uint %145 %uint_1 -;CHECK: %155 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %154 -;CHECK: OpStore %155 %uint_23 -;CHECK: %156 = OpIAdd %uint %145 %uint_2 -;CHECK: %157 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %156 -;CHECK: OpStore %157 %133 -;CHECK: %158 = OpIAdd %uint %145 %uint_3 +;CHECK: %144 = OpAtomicIAdd %uint %142 %uint_4 %uint_0 %uint_11 +;CHECK: %145 = OpIAdd %uint %144 %uint_11 +;CHECK: %146 = OpArrayLength %uint %141 1 +;CHECK: %147 = OpULessThanEqual %bool %145 %146 +;CHECK: OpSelectionMerge %148 None +;CHECK: OpBranchConditional %147 %149 %148 +;CHECK: %149 = OpLabel +;CHECK: %150 = OpIAdd %uint %144 %uint_0 +;CHECK: %151 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %150 +;CHECK: OpStore %151 %uint_11 +;CHECK: %153 = OpIAdd %uint %144 %uint_1 +;CHECK: %154 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %153 +;CHECK: OpStore %154 %uint_23 +;CHECK: %155 = OpIAdd %uint %144 %uint_2 +;CHECK: %156 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %155 +;CHECK: OpStore %156 %133 +;CHECK: %158 = OpIAdd %uint %144 %uint_3 ;CHECK: %159 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %158 ;CHECK: OpStore %159 %uint_4 ;CHECK: %162 = OpLoad %v4float %gl_FragCoord ;CHECK: %164 = OpBitcast %v4uint %162 ;CHECK: %165 = OpCompositeExtract %uint %164 0 -;CHECK: %166 = OpIAdd %uint %145 %uint_4 +;CHECK: %166 = OpIAdd %uint %144 %uint_4 ;CHECK: %167 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %166 ;CHECK: OpStore %167 %165 ;CHECK: %168 = OpCompositeExtract %uint %164 1 -;CHECK: %170 = OpIAdd %uint %145 %uint_5 +;CHECK: %170 = OpIAdd %uint %144 %uint_5 ;CHECK: %171 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %170 ;CHECK: OpStore %171 %168 -;CHECK: %172 = OpIAdd %uint %145 %uint_7 +;CHECK: %172 = OpIAdd %uint %144 %uint_7 ;CHECK: %173 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %172 ;CHECK: OpStore %173 %134 -;CHECK: %175 = OpIAdd %uint %145 %uint_8 +;CHECK: %175 = OpIAdd %uint %144 %uint_8 ;CHECK: %176 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %175 ;CHECK: OpStore %176 %135 -;CHECK: %178 = OpIAdd %uint %145 %uint_9 +;CHECK: %178 = OpIAdd %uint %144 %uint_9 ;CHECK: %179 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %178 ;CHECK: OpStore %179 %136 -;CHECK: %181 = OpIAdd %uint %145 %uint_10 +;CHECK: %181 = OpIAdd %uint %144 %uint_10 ;CHECK: %182 = OpAccessChain %_ptr_StorageBuffer_uint %141 %uint_1 %181 ;CHECK: OpStore %182 %137 -;CHECK: OpBranch %149 -;CHECK: %149 = OpLabel +;CHECK: OpBranch %148 +;CHECK: %148 = OpLabel ;CHECK: OpReturn ;CHECK: OpFunctionEnd )"; @@ -7743,11 +7743,11 @@ TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) { OpExecutionMode %MainPs OriginUpperLeft OpSource HLSL 500 OpName %MainPs "MainPs" - OpName %PerBatchEnvMapConstantBuffer_t -"PerBatchEnvMapConstantBuffer_t" OpMemberName %PerBatchEnvMapConstantBuffer_t 0 -"g_matEnvMapWorldToLocal" OpMemberName %PerBatchEnvMapConstantBuffer_t 1 -"g_vEnvironmentMapBoxMins" OpMemberName %PerBatchEnvMapConstantBuffer_t 2 -"g_TexOff" OpName %_BindlessFastEnvMapCB_PS_t "_BindlessFastEnvMapCB_PS_t" + OpName %PerBatchEnvMapConstantBuffer_t "PerBatchEnvMapConstantBuffer_t" + OpMemberName %PerBatchEnvMapConstantBuffer_t 0 "g_matEnvMapWorldToLocal" + OpMemberName %PerBatchEnvMapConstantBuffer_t 1 "g_vEnvironmentMapBoxMins" + OpMemberName %PerBatchEnvMapConstantBuffer_t 2 "g_TexOff" + OpName %_BindlessFastEnvMapCB_PS_t "_BindlessFastEnvMapCB_PS_t" OpMemberName %_BindlessFastEnvMapCB_PS_t 0 "g_envMapConstants" OpName %_ "" OpName %PerViewPushConst_t "PerViewPushConst_t" @@ -7831,15 +7831,15 @@ TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) { ;CHECK: %113 = OpVariable %_ptr_StorageBuffer__struct_111 StorageBuffer ;CHECK:%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint ;CHECK: %bool = OpTypeBool -;CHECK: %uint_3 = OpConstant %uint 3 +;CHECK: %uint_4 = OpConstant %uint 4 ;CHECK: %135 = OpTypeFunction %void %uint %uint %uint %uint %uint ;CHECK:%_struct_142 = OpTypeStruct %uint %_runtimearr_uint ;CHECK:%_ptr_StorageBuffer__struct_142 = OpTypePointer StorageBuffer %_struct_142 ;CHECK: %144 = OpVariable %_ptr_StorageBuffer__struct_142 StorageBuffer ;CHECK: %uint_11 = OpConstant %uint 11 -;CHECK: %uint_4 = OpConstant %uint 4 ;CHECK: %uint_1 = OpConstant %uint 1 ;CHECK: %uint_23 = OpConstant %uint 23 +;CHECK: %uint_3 = OpConstant %uint 3 ;CHECK:%_ptr_Input_v4float = OpTypePointer Input %v4float ;CHECK:%gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: %v4uint = OpTypeVector %uint 4 @@ -7878,13 +7878,15 @@ TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) { ;CHECK: %133 = OpLoad %v2float %81 ;CHECK: OpBranch %130 ;CHECK: %132 = OpLabel -;CHECK: %188 = OpFunctionCall %void %134 %uint_78 %uint_3 %uint_0 %101 %126 +;CHECK: %188 = OpFunctionCall %void %134 %uint_78 %uint_4 %uint_0 %101 %126 ;CHECK: OpBranch %130 ;CHECK: %130 = OpLabel ;CHECK: %190 = OpPhi %v2float %133 %131 %189 %132 ;CHECK: %86 = OpFAdd %v2float %66 %190 - %87 = OpLoad %46 %g_tColor %88 = OpLoad %50 %g_sAniso %89 = - OpSampledImage %54 %87 %88 %91 = OpImageSampleImplicitLod %v4float %89 %86 + %87 = OpLoad %46 %g_tColor + %88 = OpLoad %50 %g_sAniso + %89 = OpSampledImage %54 %87 %88 + %91 = OpImageSampleImplicitLod %v4float %89 %86 OpStore %_entryPointOutput_vColor %91 ;CHECK-NOT: %91 = OpImageSampleImplicitLod %v4float %89 %86 ;CHECK-NOT: OpStore %_entryPointOutput_vColor %91 @@ -7931,49 +7933,49 @@ TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) { ;CHECK: %140 = OpFunctionParameter %uint ;CHECK: %141 = OpLabel ;CHECK: %145 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_0 -;CHECK: %148 = OpAtomicIAdd %uint %145 %uint_4 %uint_0 %uint_11 -;CHECK: %149 = OpIAdd %uint %148 %uint_11 -;CHECK: %150 = OpArrayLength %uint %144 1 -;CHECK: %151 = OpULessThanEqual %bool %149 %150 -;CHECK: OpSelectionMerge %152 None -;CHECK: OpBranchConditional %151 %153 %152 -;CHECK: %153 = OpLabel -;CHECK: %154 = OpIAdd %uint %148 %uint_0 -;CHECK: %156 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %154 -;CHECK: OpStore %156 %uint_11 -;CHECK: %158 = OpIAdd %uint %148 %uint_1 -;CHECK: %159 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %158 -;CHECK: OpStore %159 %uint_23 -;CHECK: %160 = OpIAdd %uint %148 %uint_2 -;CHECK: %161 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %160 -;CHECK: OpStore %161 %136 -;CHECK: %162 = OpIAdd %uint %148 %uint_3 +;CHECK: %147 = OpAtomicIAdd %uint %145 %uint_4 %uint_0 %uint_11 +;CHECK: %148 = OpIAdd %uint %147 %uint_11 +;CHECK: %149 = OpArrayLength %uint %144 1 +;CHECK: %150 = OpULessThanEqual %bool %148 %149 +;CHECK: OpSelectionMerge %151 None +;CHECK: OpBranchConditional %150 %152 %151 +;CHECK: %152 = OpLabel +;CHECK: %153 = OpIAdd %uint %147 %uint_0 +;CHECK: %155 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %153 +;CHECK: OpStore %155 %uint_11 +;CHECK: %157 = OpIAdd %uint %147 %uint_1 +;CHECK: %158 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %157 +;CHECK: OpStore %158 %uint_23 +;CHECK: %159 = OpIAdd %uint %147 %uint_2 +;CHECK: %160 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %159 +;CHECK: OpStore %160 %136 +;CHECK: %162 = OpIAdd %uint %147 %uint_3 ;CHECK: %163 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %162 ;CHECK: OpStore %163 %uint_4 ;CHECK: %166 = OpLoad %v4float %gl_FragCoord ;CHECK: %168 = OpBitcast %v4uint %166 ;CHECK: %169 = OpCompositeExtract %uint %168 0 -;CHECK: %170 = OpIAdd %uint %148 %uint_4 +;CHECK: %170 = OpIAdd %uint %147 %uint_4 ;CHECK: %171 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %170 ;CHECK: OpStore %171 %169 ;CHECK: %172 = OpCompositeExtract %uint %168 1 -;CHECK: %174 = OpIAdd %uint %148 %uint_5 +;CHECK: %174 = OpIAdd %uint %147 %uint_5 ;CHECK: %175 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %174 ;CHECK: OpStore %175 %172 -;CHECK: %176 = OpIAdd %uint %148 %uint_7 +;CHECK: %176 = OpIAdd %uint %147 %uint_7 ;CHECK: %177 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %176 ;CHECK: OpStore %177 %137 -;CHECK: %179 = OpIAdd %uint %148 %uint_8 +;CHECK: %179 = OpIAdd %uint %147 %uint_8 ;CHECK: %180 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %179 ;CHECK: OpStore %180 %138 -;CHECK: %182 = OpIAdd %uint %148 %uint_9 +;CHECK: %182 = OpIAdd %uint %147 %uint_9 ;CHECK: %183 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %182 ;CHECK: OpStore %183 %139 -;CHECK: %185 = OpIAdd %uint %148 %uint_10 +;CHECK: %185 = OpIAdd %uint %147 %uint_10 ;CHECK: %186 = OpAccessChain %_ptr_StorageBuffer_uint %144 %uint_1 %185 ;CHECK: OpStore %186 %140 -;CHECK: OpBranch %152 -;CHECK: %152 = OpLabel +;CHECK: OpBranch %151 +;CHECK: %151 = OpLabel ;CHECK: OpReturn ;CHECK: OpFunctionEnd )"; @@ -8344,15 +8346,15 @@ TEST_F(InstBindlessTest, UniformArray16bitIdxRef) { ;CHECK: %69 = OpVariable %_ptr_StorageBuffer__struct_67 StorageBuffer ;CHECK:%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint ;CHECK: %bool = OpTypeBool -;CHECK: %uint_3 = OpConstant %uint 3 +;CHECK: %uint_4 = OpConstant %uint 4 ;CHECK: %88 = OpTypeFunction %void %uint %uint %uint %uint %uint ;CHECK: %_struct_95 = OpTypeStruct %uint %_runtimearr_uint ;CHECK:%_ptr_StorageBuffer__struct_95 = OpTypePointer StorageBuffer %_struct_95 ;CHECK: %97 = OpVariable %_ptr_StorageBuffer__struct_95 StorageBuffer ;CHECK: %uint_11 = OpConstant %uint 11 -;CHECK: %uint_4 = OpConstant %uint 4 ;CHECK: %uint_23 = OpConstant %uint 23 ;CHECK: %uint_2 = OpConstant %uint 2 +;CHECK: %uint_3 = OpConstant %uint 3 ;CHECK:%_ptr_Input_v4float = OpTypePointer Input %v4float ;CHECK:%gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: %v4uint = OpTypeVector %uint 4 @@ -8389,7 +8391,7 @@ TEST_F(InstBindlessTest, UniformArray16bitIdxRef) { ;CHECK: %86 = OpLoad %v2float %41 ;CHECK: OpBranch %83 ;CHECK: %85 = OpLabel -;CHECK: %141 = OpFunctionCall %void %87 %uint_81 %uint_3 %uint_0 %58 %79 +;CHECK: %141 = OpFunctionCall %void %87 %uint_81 %uint_4 %uint_0 %58 %79 ;CHECK: OpBranch %83 ;CHECK: %83 = OpLabel ;CHECK: %143 = OpPhi %v2float %86 %84 %142 %85 @@ -8424,49 +8426,49 @@ TEST_F(InstBindlessTest, UniformArray16bitIdxRef) { ;CHECK: %93 = OpFunctionParameter %uint ;CHECK: %94 = OpLabel ;CHECK: %98 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_0 -;CHECK: %101 = OpAtomicIAdd %uint %98 %uint_4 %uint_0 %uint_11 -;CHECK: %102 = OpIAdd %uint %101 %uint_11 -;CHECK: %103 = OpArrayLength %uint %97 1 -;CHECK: %104 = OpULessThanEqual %bool %102 %103 -;CHECK: OpSelectionMerge %105 None -;CHECK: OpBranchConditional %104 %106 %105 -;CHECK: %106 = OpLabel -;CHECK: %107 = OpIAdd %uint %101 %uint_0 -;CHECK: %108 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %107 -;CHECK: OpStore %108 %uint_11 -;CHECK: %110 = OpIAdd %uint %101 %uint_1 -;CHECK: %111 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %110 -;CHECK: OpStore %111 %uint_23 -;CHECK: %113 = OpIAdd %uint %101 %uint_2 -;CHECK: %114 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %113 -;CHECK: OpStore %114 %89 -;CHECK: %115 = OpIAdd %uint %101 %uint_3 +;CHECK: %100 = OpAtomicIAdd %uint %98 %uint_4 %uint_0 %uint_11 +;CHECK: %101 = OpIAdd %uint %100 %uint_11 +;CHECK: %102 = OpArrayLength %uint %97 1 +;CHECK: %103 = OpULessThanEqual %bool %101 %102 +;CHECK: OpSelectionMerge %104 None +;CHECK: OpBranchConditional %103 %105 %104 +;CHECK: %105 = OpLabel +;CHECK: %106 = OpIAdd %uint %100 %uint_0 +;CHECK: %107 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %106 +;CHECK: OpStore %107 %uint_11 +;CHECK: %109 = OpIAdd %uint %100 %uint_1 +;CHECK: %110 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %109 +;CHECK: OpStore %110 %uint_23 +;CHECK: %112 = OpIAdd %uint %100 %uint_2 +;CHECK: %113 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %112 +;CHECK: OpStore %113 %89 +;CHECK: %115 = OpIAdd %uint %100 %uint_3 ;CHECK: %116 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %115 ;CHECK: OpStore %116 %uint_4 ;CHECK: %119 = OpLoad %v4float %gl_FragCoord ;CHECK: %121 = OpBitcast %v4uint %119 ;CHECK: %122 = OpCompositeExtract %uint %121 0 -;CHECK: %123 = OpIAdd %uint %101 %uint_4 +;CHECK: %123 = OpIAdd %uint %100 %uint_4 ;CHECK: %124 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %123 ;CHECK: OpStore %124 %122 ;CHECK: %125 = OpCompositeExtract %uint %121 1 -;CHECK: %127 = OpIAdd %uint %101 %uint_5 +;CHECK: %127 = OpIAdd %uint %100 %uint_5 ;CHECK: %128 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %127 ;CHECK: OpStore %128 %125 -;CHECK: %129 = OpIAdd %uint %101 %uint_7 +;CHECK: %129 = OpIAdd %uint %100 %uint_7 ;CHECK: %130 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %129 ;CHECK: OpStore %130 %90 -;CHECK: %132 = OpIAdd %uint %101 %uint_8 +;CHECK: %132 = OpIAdd %uint %100 %uint_8 ;CHECK: %133 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %132 ;CHECK: OpStore %133 %91 -;CHECK: %135 = OpIAdd %uint %101 %uint_9 +;CHECK: %135 = OpIAdd %uint %100 %uint_9 ;CHECK: %136 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %135 ;CHECK: OpStore %136 %92 -;CHECK: %138 = OpIAdd %uint %101 %uint_10 +;CHECK: %138 = OpIAdd %uint %100 %uint_10 ;CHECK: %139 = OpAccessChain %_ptr_StorageBuffer_uint %97 %uint_1 %138 ;CHECK: OpStore %139 %93 -;CHECK: OpBranch %105 -;CHECK: %105 = OpLabel +;CHECK: OpBranch %104 +;CHECK: %104 = OpLabel ;CHECK: OpReturn ;CHECK: OpFunctionEnd )"; @@ -8557,6 +8559,7 @@ TEST_F(InstBindlessTest, UniformMatrixRefRowMajor) { %_ptr_Input_v4float = OpTypePointer Input %v4float %a_position = OpVariable %_ptr_Input_v4float Input ;CHECK; %uint_0 = OpConstant %uint 0 +;CHECK; %uint_16 = OpConstant %uint 16 ;CHECK; %uint_4 = OpConstant %uint 4 ;CHECK; %uint_3 = OpConstant %uint 3 ;CHECK; %37 = OpTypeFunction %uint %uint %uint %uint @@ -8583,10 +8586,13 @@ TEST_F(InstBindlessTest, UniformMatrixRefRowMajor) { ;CHECK; %uint_10 = OpConstant %uint 10 ;CHECK; %uint_45 = OpConstant %uint 45 ;CHECK; %115 = OpConstantNull %float -;CHECK; %uint_27 = OpConstant %uint 27 %main = OpFunction %void None %3 %5 = OpLabel ;CHECK: %55 = OpFunctionCall %uint %36 %uint_1 %uint_0 %uint_0 +;CHECK: OpBranch %26 +;CHECK: %26 = OpLabel +;CHECK: OpBranch %25 +;CHECK: %25 = OpLabel %20 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %int_2 %uint_1 %21 = OpLoad %float %20 ;CHECK-NOT: %21 = OpLoad %float %20 @@ -8602,7 +8608,7 @@ TEST_F(InstBindlessTest, UniformMatrixRefRowMajor) { ;CHECK: %61 = OpLoad %float %20 ;CHECK: OpBranch %58 ;CHECK: %60 = OpLabel -;CHECK: %114 = OpFunctionCall %void %62 %uint_45 %uint_3 %uint_0 %35 %55 +;CHECK: %114 = OpFunctionCall %void %62 %uint_45 %uint_4 %uint_0 %35 %55 ;CHECK: OpBranch %58 ;CHECK: %58 = OpLabel ;CHECK: %116 = OpPhi %float %61 %59 %115 %60 @@ -8790,9 +8796,14 @@ TEST_F(InstBindlessTest, UniformMatrixRefColumnMajor) { ;CHECK: %uint_9 = OpConstant %uint 9 ;CHECK: %uint_10 = OpConstant %uint 10 ;CHECK: %uint_45 = OpConstant %uint 45 +;CHECK: %114 = OpConstantNull %float %main = OpFunction %void None %3 %5 = OpLabel ;CHECK: %55 = OpFunctionCall %uint %36 %uint_1 %uint_0 %uint_0 +;CHECK: OpBranch %26 +;CHECK: %26 = OpLabel +;CHECK: OpBranch %25 +;CHECK: %25 = OpLabel %20 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %int_2 %uint_1 %21 = OpLoad %float %20 ;CHECK-NOT: %21 = OpLoad %float %20 @@ -8808,7 +8819,7 @@ TEST_F(InstBindlessTest, UniformMatrixRefColumnMajor) { ;CHECK: %61 = OpLoad %float %20 ;CHECK: OpBranch %58 ;CHECK: %60 = OpLabel -;CHECK: %113 = OpFunctionCall %void %62 %uint_45 %uint_3 %uint_0 %35 %55 +;CHECK: %113 = OpFunctionCall %void %62 %uint_45 %uint_4 %uint_0 %35 %55 ;CHECK: OpBranch %58 ;CHECK: %58 = OpLabel ;CHECK: %115 = OpPhi %float %61 %59 %114 %60 @@ -9032,7 +9043,7 @@ TEST_F(InstBindlessTest, UniformMatrixVecRefRowMajor) { ;CHECK: %70 = OpLoad %v2float %25 ;CHECK: OpBranch %67 ;CHECK: %69 = OpLabel -;CHECK: %123 = OpFunctionCall %void %71 %uint_51 %uint_3 %uint_0 %43 %64 +;CHECK: %123 = OpFunctionCall %void %71 %uint_51 %uint_4 %uint_0 %43 %64 ;CHECK: OpBranch %67 ;CHECK: %67 = OpLabel ;CHECK: %125 = OpPhi %v2float %70 %68 %124 %69 @@ -9167,7 +9178,7 @@ TEST_F(InstBindlessTest, ImageBufferOOBRead) { ;CHECK: %uint = OpTypeInt 32 0 ;CHECK: %uint_0 = OpConstant %uint 0 ;CHECK: %bool = OpTypeBool -;CHECK: %uint_3 = OpConstant %uint 3 +;CHECK: %uint_7 = OpConstant %uint 7 ;CHECK: %35 = OpTypeFunction %void %uint %uint %uint %uint %uint ;CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint ;CHECK: %_struct_43 = OpTypeStruct %uint %_runtimearr_uint @@ -9179,11 +9190,11 @@ TEST_F(InstBindlessTest, ImageBufferOOBRead) { ;CHECK: %uint_1 = OpConstant %uint 1 ;CHECK: %uint_23 = OpConstant %uint 23 ;CHECK: %uint_2 = OpConstant %uint 2 +;CHECK: %uint_3 = OpConstant %uint 3 ;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float ;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: %v4uint = OpTypeVector %uint 4 ;CHECK: %uint_5 = OpConstant %uint 5 -;CHECK: %uint_7 = OpConstant %uint 7 ;CHECK: %uint_8 = OpConstant %uint 8 ;CHECK: %uint_9 = OpConstant %uint 9 ;CHECK: %uint_10 = OpConstant %uint 10 @@ -9213,7 +9224,7 @@ TEST_F(InstBindlessTest, ImageBufferOOBRead) { ;CHECK: %33 = OpImageRead %v4float %32 %17 ;CHECK: OpBranch %29 ;CHECK: %31 = OpLabel -;CHECK: %92 = OpFunctionCall %void %34 %uint_33 %uint_3 %uint_0 %23 %25 +;CHECK: %92 = OpFunctionCall %void %34 %uint_33 %uint_7 %uint_0 %23 %25 ;CHECK: OpBranch %29 ;CHECK: %29 = OpLabel ;CHECK: %94 = OpPhi %v4float %33 %30 %93 %31 @@ -9244,19 +9255,19 @@ TEST_F(InstBindlessTest, ImageBufferOOBRead) { ;CHECK: %63 = OpIAdd %uint %50 %uint_2 ;CHECK: %64 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %63 ;CHECK: OpStore %64 %36 -;CHECK: %65 = OpIAdd %uint %50 %uint_3 -;CHECK: %66 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %65 -;CHECK: OpStore %66 %uint_4 -;CHECK: %69 = OpLoad %v4float %gl_FragCoord -;CHECK: %71 = OpBitcast %v4uint %69 -;CHECK: %72 = OpCompositeExtract %uint %71 0 -;CHECK: %73 = OpIAdd %uint %50 %uint_4 -;CHECK: %74 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %73 -;CHECK: OpStore %74 %72 -;CHECK: %75 = OpCompositeExtract %uint %71 1 -;CHECK: %77 = OpIAdd %uint %50 %uint_5 -;CHECK: %78 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %77 -;CHECK: OpStore %78 %75 +;CHECK: %66 = OpIAdd %uint %50 %uint_3 +;CHECK: %67 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %66 +;CHECK: OpStore %67 %uint_4 +;CHECK: %70 = OpLoad %v4float %gl_FragCoord +;CHECK: %72 = OpBitcast %v4uint %70 +;CHECK: %73 = OpCompositeExtract %uint %72 0 +;CHECK: %74 = OpIAdd %uint %50 %uint_4 +;CHECK: %75 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %74 +;CHECK: OpStore %75 %73 +;CHECK: %76 = OpCompositeExtract %uint %72 1 +;CHECK: %78 = OpIAdd %uint %50 %uint_5 +;CHECK: %79 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %78 +;CHECK: OpStore %79 %76 ;CHECK: %80 = OpIAdd %uint %50 %uint_7 ;CHECK: %81 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %80 ;CHECK: OpStore %81 %37 @@ -9336,7 +9347,7 @@ TEST_F(InstBindlessTest, ImageBufferOOBWrite) { ;CHECK: %uint = OpTypeInt 32 0 ;CHECK: %uint_0 = OpConstant %uint 0 ;CHECK: %bool = OpTypeBool -;CHECK: %uint_3 = OpConstant %uint 3 +;CHECK: %uint_7 = OpConstant %uint 7 ;CHECK: %34 = OpTypeFunction %void %uint %uint %uint %uint %uint ;CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint ;CHECK: %_struct_42 = OpTypeStruct %uint %_runtimearr_uint @@ -9348,11 +9359,11 @@ TEST_F(InstBindlessTest, ImageBufferOOBWrite) { ;CHECK: %uint_1 = OpConstant %uint 1 ;CHECK: %uint_23 = OpConstant %uint 23 ;CHECK: %uint_2 = OpConstant %uint 2 +;CHECK: %uint_3 = OpConstant %uint 3 ;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float ;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: %v4uint = OpTypeVector %uint 4 ;CHECK: %uint_5 = OpConstant %uint 5 -;CHECK: %uint_7 = OpConstant %uint 7 ;CHECK: %uint_8 = OpConstant %uint 8 ;CHECK: %uint_9 = OpConstant %uint 9 ;CHECK: %uint_10 = OpConstant %uint 10 @@ -9380,7 +9391,7 @@ TEST_F(InstBindlessTest, ImageBufferOOBWrite) { ;CHECK: OpImageWrite %32 %14 %18 ;CHECK: OpBranch %29 ;CHECK: %31 = OpLabel -;CHECK: %91 = OpFunctionCall %void %33 %uint_34 %uint_3 %uint_0 %23 %25 +;CHECK: %91 = OpFunctionCall %void %33 %uint_34 %uint_7 %uint_0 %23 %25 ;CHECK: OpBranch %29 ;CHECK: %29 = OpLabel OpReturn @@ -9409,19 +9420,19 @@ TEST_F(InstBindlessTest, ImageBufferOOBWrite) { ;CHECK: %62 = OpIAdd %uint %49 %uint_2 ;CHECK: %63 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %62 ;CHECK: OpStore %63 %35 -;CHECK: %64 = OpIAdd %uint %49 %uint_3 -;CHECK: %65 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %64 -;CHECK: OpStore %65 %uint_4 -;CHECK: %68 = OpLoad %v4float %gl_FragCoord -;CHECK: %70 = OpBitcast %v4uint %68 -;CHECK: %71 = OpCompositeExtract %uint %70 0 -;CHECK: %72 = OpIAdd %uint %49 %uint_4 -;CHECK: %73 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %72 -;CHECK: OpStore %73 %71 -;CHECK: %74 = OpCompositeExtract %uint %70 1 -;CHECK: %76 = OpIAdd %uint %49 %uint_5 -;CHECK: %77 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %76 -;CHECK: OpStore %77 %74 +;CHECK: %65 = OpIAdd %uint %49 %uint_3 +;CHECK: %66 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %65 +;CHECK: OpStore %66 %uint_4 +;CHECK: %69 = OpLoad %v4float %gl_FragCoord +;CHECK: %71 = OpBitcast %v4uint %69 +;CHECK: %72 = OpCompositeExtract %uint %71 0 +;CHECK: %73 = OpIAdd %uint %49 %uint_4 +;CHECK: %74 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %73 +;CHECK: OpStore %74 %72 +;CHECK: %75 = OpCompositeExtract %uint %71 1 +;CHECK: %77 = OpIAdd %uint %49 %uint_5 +;CHECK: %78 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %77 +;CHECK: OpStore %78 %75 ;CHECK: %79 = OpIAdd %uint %49 %uint_7 ;CHECK: %80 = OpAccessChain %_ptr_StorageBuffer_uint %44 %uint_1 %79 ;CHECK: OpStore %80 %36 @@ -9500,7 +9511,7 @@ TEST_F(InstBindlessTest, TextureBufferOOBFetch) { ;CHECK: %uint = OpTypeInt 32 0 ;CHECK: %uint_0 = OpConstant %uint 0 ;CHECK: %bool = OpTypeBool -;CHECK: %uint_3 = OpConstant %uint 3 +;CHECK: %uint_6 = OpConstant %uint 6 ;CHECK: %35 = OpTypeFunction %void %uint %uint %uint %uint %uint ;CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint ;CHECK: %_struct_43 = OpTypeStruct %uint %_runtimearr_uint @@ -9512,6 +9523,7 @@ TEST_F(InstBindlessTest, TextureBufferOOBFetch) { ;CHECK: %uint_1 = OpConstant %uint 1 ;CHECK: %uint_23 = OpConstant %uint 23 ;CHECK: %uint_2 = OpConstant %uint 2 +;CHECK: %uint_3 = OpConstant %uint 3 ;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float ;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: %v4uint = OpTypeVector %uint 4 @@ -9521,7 +9533,7 @@ TEST_F(InstBindlessTest, TextureBufferOOBFetch) { ;CHECK: %uint_9 = OpConstant %uint 9 ;CHECK: %uint_10 = OpConstant %uint 10 ;CHECK: %uint_32 = OpConstant %uint 32 -;CHECK: %93 = OpConstantNull %v4float +;CHECK: %94 = OpConstantNull %v4float %main = OpFunction %void None %3 %5 = OpLabel ;CHECK: OpBranch %21 @@ -9546,11 +9558,11 @@ TEST_F(InstBindlessTest, TextureBufferOOBFetch) { ;CHECK: %33 = OpImageFetch %v4float %32 %17 ;CHECK: OpBranch %29 ;CHECK: %31 = OpLabel -;CHECK: %92 = OpFunctionCall %void %34 %uint_32 %uint_3 %uint_0 %23 %25 +;CHECK: %93 = OpFunctionCall %void %34 %uint_32 %uint_6 %uint_0 %23 %25 ;CHECK: OpBranch %29 ;CHECK: %29 = OpLabel -;CHECK: %94 = OpPhi %v4float %33 %30 %93 %31 -;CHECK: OpStore %x %94 +;CHECK: %95 = OpPhi %v4float %33 %30 %94 %31 +;CHECK: OpStore %x %95 OpReturn OpFunctionEnd ;CHECK: %34 = OpFunction %void None %35 @@ -9577,31 +9589,31 @@ TEST_F(InstBindlessTest, TextureBufferOOBFetch) { ;CHECK: %63 = OpIAdd %uint %50 %uint_2 ;CHECK: %64 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %63 ;CHECK: OpStore %64 %36 -;CHECK: %65 = OpIAdd %uint %50 %uint_3 -;CHECK: %66 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %65 -;CHECK: OpStore %66 %uint_4 -;CHECK: %69 = OpLoad %v4float %gl_FragCoord -;CHECK: %71 = OpBitcast %v4uint %69 -;CHECK: %72 = OpCompositeExtract %uint %71 0 -;CHECK: %73 = OpIAdd %uint %50 %uint_4 -;CHECK: %74 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %73 -;CHECK: OpStore %74 %72 -;CHECK: %75 = OpCompositeExtract %uint %71 1 -;CHECK: %77 = OpIAdd %uint %50 %uint_5 -;CHECK: %78 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %77 -;CHECK: OpStore %78 %75 -;CHECK: %80 = OpIAdd %uint %50 %uint_7 -;CHECK: %81 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %80 -;CHECK: OpStore %81 %37 -;CHECK: %83 = OpIAdd %uint %50 %uint_8 -;CHECK: %84 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %83 -;CHECK: OpStore %84 %38 -;CHECK: %86 = OpIAdd %uint %50 %uint_9 -;CHECK: %87 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %86 -;CHECK: OpStore %87 %39 -;CHECK: %89 = OpIAdd %uint %50 %uint_10 -;CHECK: %90 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %89 -;CHECK: OpStore %90 %40 +;CHECK: %66 = OpIAdd %uint %50 %uint_3 +;CHECK: %67 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %66 +;CHECK: OpStore %67 %uint_4 +;CHECK: %70 = OpLoad %v4float %gl_FragCoord +;CHECK: %72 = OpBitcast %v4uint %70 +;CHECK: %73 = OpCompositeExtract %uint %72 0 +;CHECK: %74 = OpIAdd %uint %50 %uint_4 +;CHECK: %75 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %74 +;CHECK: OpStore %75 %73 +;CHECK: %76 = OpCompositeExtract %uint %72 1 +;CHECK: %78 = OpIAdd %uint %50 %uint_5 +;CHECK: %79 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %78 +;CHECK: OpStore %79 %76 +;CHECK: %81 = OpIAdd %uint %50 %uint_7 +;CHECK: %82 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %81 +;CHECK: OpStore %82 %37 +;CHECK: %84 = OpIAdd %uint %50 %uint_8 +;CHECK: %85 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %84 +;CHECK: OpStore %85 %38 +;CHECK: %87 = OpIAdd %uint %50 %uint_9 +;CHECK: %88 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %87 +;CHECK: OpStore %88 %39 +;CHECK: %90 = OpIAdd %uint %50 %uint_10 +;CHECK: %91 = OpAccessChain %_ptr_StorageBuffer_uint %45 %uint_1 %90 +;CHECK: OpStore %91 %40 ;CHECK: OpBranch %54 ;CHECK: %54 = OpLabel ;CHECK: OpReturn @@ -9669,7 +9681,7 @@ TEST_F(InstBindlessTest, SamplerBufferOOBFetch) { ;CHECK: %uint = OpTypeInt 32 0 ;CHECK: %uint_0 = OpConstant %uint 0 ;CHECK: %bool = OpTypeBool -;CHECK: %uint_3 = OpConstant %uint 3 +;CHECK: %uint_6 = OpConstant %uint 6 ;CHECK: %38 = OpTypeFunction %void %uint %uint %uint %uint %uint ;CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint ;CHECK: %_struct_46 = OpTypeStruct %uint %_runtimearr_uint @@ -9681,6 +9693,7 @@ TEST_F(InstBindlessTest, SamplerBufferOOBFetch) { ;CHECK: %uint_1 = OpConstant %uint 1 ;CHECK: %uint_23 = OpConstant %uint 23 ;CHECK: %uint_2 = OpConstant %uint 2 +;CHECK: %uint_3 = OpConstant %uint 3 ;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float ;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: %v4uint = OpTypeVector %uint 4 @@ -9690,7 +9703,7 @@ TEST_F(InstBindlessTest, SamplerBufferOOBFetch) { ;CHECK: %uint_9 = OpConstant %uint 9 ;CHECK: %uint_10 = OpConstant %uint 10 ;CHECK: %uint_34 = OpConstant %uint 34 -;CHECK: %96 = OpConstantNull %v4float +;CHECK: %97 = OpConstantNull %v4float %main = OpFunction %void None %3 %5 = OpLabel ;CHECK: OpBranch %23 @@ -9717,11 +9730,11 @@ TEST_F(InstBindlessTest, SamplerBufferOOBFetch) { ;CHECK: %36 = OpImageFetch %v4float %35 %18 ;CHECK: OpBranch %31 ;CHECK: %33 = OpLabel -;CHECK: %95 = OpFunctionCall %void %37 %uint_34 %uint_3 %uint_0 %25 %27 +;CHECK: %96 = OpFunctionCall %void %37 %uint_34 %uint_6 %uint_0 %25 %27 ;CHECK: OpBranch %31 ;CHECK: %31 = OpLabel -;CHECK: %97 = OpPhi %v4float %36 %32 %96 %33 -;CHECK: OpStore %x %97 +;CHECK: %98 = OpPhi %v4float %36 %32 %97 %33 +;CHECK: OpStore %x %98 OpReturn OpFunctionEnd ;CHECK: %37 = OpFunction %void None %38 @@ -9748,31 +9761,31 @@ TEST_F(InstBindlessTest, SamplerBufferOOBFetch) { ;CHECK: %66 = OpIAdd %uint %53 %uint_2 ;CHECK: %67 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %66 ;CHECK: OpStore %67 %39 -;CHECK: %68 = OpIAdd %uint %53 %uint_3 -;CHECK: %69 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %68 -;CHECK: OpStore %69 %uint_4 -;CHECK: %72 = OpLoad %v4float %gl_FragCoord -;CHECK: %74 = OpBitcast %v4uint %72 -;CHECK: %75 = OpCompositeExtract %uint %74 0 -;CHECK: %76 = OpIAdd %uint %53 %uint_4 -;CHECK: %77 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %76 -;CHECK: OpStore %77 %75 -;CHECK: %78 = OpCompositeExtract %uint %74 1 -;CHECK: %80 = OpIAdd %uint %53 %uint_5 -;CHECK: %81 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %80 -;CHECK: OpStore %81 %78 -;CHECK: %83 = OpIAdd %uint %53 %uint_7 -;CHECK: %84 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %83 -;CHECK: OpStore %84 %40 -;CHECK: %86 = OpIAdd %uint %53 %uint_8 -;CHECK: %87 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %86 -;CHECK: OpStore %87 %41 -;CHECK: %89 = OpIAdd %uint %53 %uint_9 -;CHECK: %90 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %89 -;CHECK: OpStore %90 %42 -;CHECK: %92 = OpIAdd %uint %53 %uint_10 -;CHECK: %93 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %92 -;CHECK: OpStore %93 %43 +;CHECK: %69 = OpIAdd %uint %53 %uint_3 +;CHECK: %70 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %69 +;CHECK: OpStore %70 %uint_4 +;CHECK: %73 = OpLoad %v4float %gl_FragCoord +;CHECK: %75 = OpBitcast %v4uint %73 +;CHECK: %76 = OpCompositeExtract %uint %75 0 +;CHECK: %77 = OpIAdd %uint %53 %uint_4 +;CHECK: %78 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %77 +;CHECK: OpStore %78 %76 +;CHECK: %79 = OpCompositeExtract %uint %75 1 +;CHECK: %81 = OpIAdd %uint %53 %uint_5 +;CHECK: %82 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %81 +;CHECK: OpStore %82 %79 +;CHECK: %84 = OpIAdd %uint %53 %uint_7 +;CHECK: %85 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %84 +;CHECK: OpStore %85 %40 +;CHECK: %87 = OpIAdd %uint %53 %uint_8 +;CHECK: %88 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %87 +;CHECK: OpStore %88 %41 +;CHECK: %90 = OpIAdd %uint %53 %uint_9 +;CHECK: %91 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %90 +;CHECK: OpStore %91 %42 +;CHECK: %93 = OpIAdd %uint %53 %uint_10 +;CHECK: %94 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_1 %93 +;CHECK: OpStore %94 %43 ;CHECK: OpBranch %57 ;CHECK: %57 = OpLabel ;CHECK: OpReturn @@ -9847,7 +9860,7 @@ TEST_F(InstBindlessTest, SamplerBufferConstructorOOBFetch) { ;CHECK: %uint = OpTypeInt 32 0 ;CHECK: %uint_0 = OpConstant %uint 0 ;CHECK: %bool = OpTypeBool -;CHECK: %uint_3 = OpConstant %uint 3 +;CHECK: %uint_6 = OpConstant %uint 6 ;CHECK: %44 = OpTypeFunction %void %uint %uint %uint %uint %uint ;CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint ;CHECK: %_struct_52 = OpTypeStruct %uint %_runtimearr_uint @@ -9859,6 +9872,7 @@ TEST_F(InstBindlessTest, SamplerBufferConstructorOOBFetch) { ;CHECK: %uint_1 = OpConstant %uint 1 ;CHECK: %uint_23 = OpConstant %uint 23 ;CHECK: %uint_2 = OpConstant %uint 2 +;CHECK: %uint_3 = OpConstant %uint 3 ;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float ;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: %v4uint = OpTypeVector %uint 4 @@ -9868,7 +9882,7 @@ TEST_F(InstBindlessTest, SamplerBufferConstructorOOBFetch) { ;CHECK: %uint_9 = OpConstant %uint 9 ;CHECK: %uint_10 = OpConstant %uint 10 ;CHECK: %uint_42 = OpConstant %uint 42 -;CHECK: %102 = OpConstantNull %v4float +;CHECK: %103 = OpConstantNull %v4float %main = OpFunction %void None %3 %5 = OpLabel ;CHECK: OpBranch %28 @@ -9898,11 +9912,11 @@ TEST_F(InstBindlessTest, SamplerBufferConstructorOOBFetch) { ;CHECK: %42 = OpImageFetch %v4float %41 %23 ;CHECK: OpBranch %36 ;CHECK: %38 = OpLabel -;CHECK: %101 = OpFunctionCall %void %43 %uint_42 %uint_3 %uint_0 %30 %32 +;CHECK: %102 = OpFunctionCall %void %43 %uint_42 %uint_6 %uint_0 %30 %32 ;CHECK: OpBranch %36 ;CHECK: %36 = OpLabel -;CHECK: %103 = OpPhi %v4float %42 %37 %102 %38 -;CHECK: OpStore %x %103 +;CHECK: %104 = OpPhi %v4float %42 %37 %103 %38 +;CHECK: OpStore %x %104 OpReturn OpFunctionEnd ;CHECK: %43 = OpFunction %void None %44 @@ -9929,31 +9943,31 @@ TEST_F(InstBindlessTest, SamplerBufferConstructorOOBFetch) { ;CHECK: %72 = OpIAdd %uint %59 %uint_2 ;CHECK: %73 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %72 ;CHECK: OpStore %73 %45 -;CHECK: %74 = OpIAdd %uint %59 %uint_3 -;CHECK: %75 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %74 -;CHECK: OpStore %75 %uint_4 -;CHECK: %78 = OpLoad %v4float %gl_FragCoord -;CHECK: %80 = OpBitcast %v4uint %78 -;CHECK: %81 = OpCompositeExtract %uint %80 0 -;CHECK: %82 = OpIAdd %uint %59 %uint_4 -;CHECK: %83 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %82 -;CHECK: OpStore %83 %81 -;CHECK: %84 = OpCompositeExtract %uint %80 1 -;CHECK: %86 = OpIAdd %uint %59 %uint_5 -;CHECK: %87 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %86 -;CHECK: OpStore %87 %84 -;CHECK: %89 = OpIAdd %uint %59 %uint_7 -;CHECK: %90 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %89 -;CHECK: OpStore %90 %46 -;CHECK: %92 = OpIAdd %uint %59 %uint_8 -;CHECK: %93 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %92 -;CHECK: OpStore %93 %47 -;CHECK: %95 = OpIAdd %uint %59 %uint_9 -;CHECK: %96 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %95 -;CHECK: OpStore %96 %48 -;CHECK: %98 = OpIAdd %uint %59 %uint_10 -;CHECK: %99 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %98 -;CHECK: OpStore %99 %49 +;CHECK: %75 = OpIAdd %uint %59 %uint_3 +;CHECK: %76 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %75 +;CHECK: OpStore %76 %uint_4 +;CHECK: %79 = OpLoad %v4float %gl_FragCoord +;CHECK: %81 = OpBitcast %v4uint %79 +;CHECK: %82 = OpCompositeExtract %uint %81 0 +;CHECK: %83 = OpIAdd %uint %59 %uint_4 +;CHECK: %84 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %83 +;CHECK: OpStore %84 %82 +;CHECK: %85 = OpCompositeExtract %uint %81 1 +;CHECK: %87 = OpIAdd %uint %59 %uint_5 +;CHECK: %88 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %87 +;CHECK: OpStore %88 %85 +;CHECK: %90 = OpIAdd %uint %59 %uint_7 +;CHECK: %91 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %90 +;CHECK: OpStore %91 %46 +;CHECK: %93 = OpIAdd %uint %59 %uint_8 +;CHECK: %94 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %93 +;CHECK: OpStore %94 %47 +;CHECK: %96 = OpIAdd %uint %59 %uint_9 +;CHECK: %97 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %96 +;CHECK: OpStore %97 %48 +;CHECK: %99 = OpIAdd %uint %59 %uint_10 +;CHECK: %100 = OpAccessChain %_ptr_StorageBuffer_uint %54 %uint_1 %99 +;CHECK: OpStore %100 %49 ;CHECK: OpBranch %63 ;CHECK: %63 = OpLabel ;CHECK: OpReturn -- cgit v1.2.3 From 05cda81aba8c6dbfefd38dfe3e12d366edd783fe Mon Sep 17 00:00:00 2001 From: Jaebaek Seo Date: Tue, 16 Feb 2021 16:57:29 -0500 Subject: Update CHANGES --- CHANGES | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index d7a49f72..66576282 100644 --- a/CHANGES +++ b/CHANGES @@ -1,7 +1,57 @@ Revision history for SPIRV-Tools -v2020.7-dev 2020-12-07 - - Start v2020.7-dev +v2021.0-dev 2021-02-16 + - Start SPIRV-Tools v2021.0 + +v2020.7 2021-02-16 + - General + - Support pending Intel extensions (#4116) + - Remove WebGPU support (#4108) + - Validator + - Vulkan image gather constant component (#4133) + - Add Vulkan PSB64 convert VUID (#4122) + - Validate SPV_KHR_workgroup_memory_explicit_layout (#4128) + - Validate VK_KHR_zero_initialize_workgroup_memory (#4124) + - Add Vulkan image gather offset VUID (#4118) + - Label Vulkan atomic semantics VUIDs (#4120) + - Label VUID 04662 (#4123) + - Label VUID 04683 (#4121) + - Add Vulkan EXT builtins (#4115) + - Validate Sampled=1 for Vulkan ImageQuerySizeLod, ImageQueryLevels, ImageQueryLod (#4103) + - Add Vulkan Memory Scope VUs (#4106) + - Add Vulkan Addressing Model check (#4107) + - Vulkan atomic storage class (#4079) + - Label standalone Vulkan VUID (#4091) + - Add Vulkan decroation VUID (#4090) + - Add Vulkan FP Mode VUID (#4088) + - Fix Vulkan image sampled check (#4085) + - Add Vulkan ForwardPointer VUID (#4089) + - Add Vulkan ImageTexelPointer format check (#4087) + - Add Vulkan Group Operation VUID (#4086) + - Add first StandAlone VUID 04633 (#4077) + - Add Subgroup VUIDs (#4074) + - validate return type of OpImageRead (#4072) + - tighter validation of multisampled images (#4059) + - validate OpTypeImage Sampled values for environemnts (#4064) + - validate StorageImageMultisampled capability (#4062) + - Add last TessLevelOuter and TessLevelInner VUID (#4055) + - Add last ClipDistance and CullDistance VUID (#4054) + - Add last ViewportIndex and Layer VUID (#4053) + - Add last Position VUID (#4052) + - Allow forward pointer to be used in types generally (#4044) + - Optimizer + - Mark module as modified if convert-to-half removes decorations. (#4127) + - Fix binding number calculation in desc sroa (#4095) + - Run DCE when SPV_KHR_shader_clock is used (#4049) + - Debug Info + - Set correct scope and line info for DebugValue (#4125) + - Avoid integrity check failures caused by propagating line instructions (#4096) + - Linker + - Linker usability improvements (#4084) + - Instrumentation + - Generate differentiated error codes for buffer oob checking (#4097) + - Fuzz + - Fix OpPhi handling in DuplicateRegionWithSelection (#4065) v2020.6 2020-12-07 - General -- cgit v1.2.3 From 07383c65d92896d07b305675f8c78a61ac88246e Mon Sep 17 00:00:00 2001 From: Jaebaek Seo Date: Thu, 18 Feb 2021 10:39:52 -0500 Subject: Finalize SPIRV-Tools v2020.7 --- CHANGES | 3 --- 1 file changed, 3 deletions(-) diff --git a/CHANGES b/CHANGES index 66576282..45e1ab6f 100644 --- a/CHANGES +++ b/CHANGES @@ -1,8 +1,5 @@ Revision history for SPIRV-Tools -v2021.0-dev 2021-02-16 - - Start SPIRV-Tools v2021.0 - v2020.7 2021-02-16 - General - Support pending Intel extensions (#4116) -- cgit v1.2.3 From 1b35745ad1c9a988bc427b976a9a2fe7afd4dada Mon Sep 17 00:00:00 2001 From: Jaebaek Seo Date: Thu, 18 Feb 2021 10:41:43 -0500 Subject: Start SPIRV-Tools v2021.0 --- CHANGES | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES b/CHANGES index 45e1ab6f..19eb18c4 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,8 @@ Revision history for SPIRV-Tools +v2021.0-dev 2021-02-16 + - Start SPIRV-Tools v2021.0-dev + v2020.7 2021-02-16 - General - Support pending Intel extensions (#4116) -- cgit v1.2.3 From ef3290bbea35935ba8fd623970511ed9f045bbd7 Mon Sep 17 00:00:00 2001 From: seppala2 Date: Fri, 19 Feb 2021 17:59:14 +0200 Subject: spirv-opt: Don't call GenerateCopy for mismatched image types (#4126) Avoid an assertion that will cause some HLSL shader to fail. They will be legalized by later passes that will do copy propagation. --- source/opt/fix_storage_class.cpp | 10 +++++++++ test/opt/fix_storage_class_test.cpp | 42 +++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/source/opt/fix_storage_class.cpp b/source/opt/fix_storage_class.cpp index 03da0d0d..04eb1326 100644 --- a/source/opt/fix_storage_class.cpp +++ b/source/opt/fix_storage_class.cpp @@ -222,6 +222,16 @@ bool FixStorageClass::PropagateType(Instruction* inst, uint32_t type_id, uint32_t pointee_type_id = GetPointeeTypeId(ptr_inst); if (obj_type_id != pointee_type_id) { + if (context()->get_type_mgr()->GetType(obj_type_id)->AsImage() && + context()->get_type_mgr()->GetType(pointee_type_id)->AsImage()) { + // When storing an image, allow the type mismatch + // and let the later legalization passes eliminate the OpStore. + // This is to support assigning an image to a variable, + // where the assigned image does not have a pre-defined + // image format. + return false; + } + uint32_t copy_id = GenerateCopy(obj_inst, pointee_type_id, inst); inst->SetInOperand(1, {copy_id}); context()->UpdateDefUse(inst); diff --git a/test/opt/fix_storage_class_test.cpp b/test/opt/fix_storage_class_test.cpp index 4c8504ae..1c0101a0 100644 --- a/test/opt/fix_storage_class_test.cpp +++ b/test/opt/fix_storage_class_test.cpp @@ -528,6 +528,48 @@ TEST_F(FixStorageClassTest, FixLinkedAccessChain2) { SinglePassRunAndMatch(text, false); } +TEST_F(FixStorageClassTest, AllowImageFormatMismatch) { + const std::string text = R"(OpCapability Shader +OpCapability SampledBuffer +OpCapability ImageBuffer +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpSource HLSL 600 +OpName %type_buffer_image "type.buffer.image" +OpName %Buf "Buf" +OpName %main "main" +OpName %src_main "src.main" +OpName %bb_entry "bb.entry" +OpName %type_buffer_image_0 "type.buffer.image" +OpName %b "b" +OpDecorate %Buf DescriptorSet 0 +OpDecorate %Buf Binding 0 +%float = OpTypeFloat 32 +%type_buffer_image = OpTypeImage %float Buffer 2 0 0 2 Rgba16f +%_ptr_UniformConstant_type_buffer_image = OpTypePointer UniformConstant %type_buffer_image +%void = OpTypeVoid +%11 = OpTypeFunction %void +%type_buffer_image_0 = OpTypeImage %float Buffer 2 0 0 2 Rgba32f +%_ptr_Function_type_buffer_image_0 = OpTypePointer Function %type_buffer_image_0 +%Buf = OpVariable %_ptr_UniformConstant_type_buffer_image UniformConstant +%main = OpFunction %void None %11 +%13 = OpLabel +%14 = OpFunctionCall %void %src_main +OpReturn +OpFunctionEnd +%src_main = OpFunction %void None %11 +%bb_entry = OpLabel +%b = OpVariable %_ptr_Function_type_buffer_image_0 Function +%15 = OpLoad %type_buffer_image %Buf +OpStore %b %15 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndCheck(text, text, false, false); +} + using FixTypeTest = PassTest<::testing::Test>; TEST_F(FixTypeTest, FixAccessChain) { -- cgit v1.2.3