| // 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 <vector> | |
| #include "test/opt/pass_fixture.h" | |
| #include "test/opt/pass_utils.h" | |
| namespace spvtools { | |
| namespace opt { | |
| namespace { | |
| typedef std::tuple<std::string, bool> GenerateWebGPUInitializersParam; | |
| using GlobalVariableTest = | |
| PassTest<::testing::TestWithParam<GenerateWebGPUInitializersParam>>; | |
| using LocalVariableTest = | |
| PassTest<::testing::TestWithParam<GenerateWebGPUInitializersParam>>; | |
| using GenerateWebGPUInitializersTest = PassTest<::testing::Test>; | |
| void operator+=(std::vector<const char*>& lhs, const char* rhs) { | |
| lhs.push_back(rhs); | |
| } | |
| void operator+=(std::vector<const char*>& lhs, | |
| const std::vector<const char*>& 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<const char*> result = { | |
| // clang-format off | |
| "OpCapability Shader", | |
| "OpCapability VulkanMemoryModelKHR", | |
| "OpExtension \"SPV_KHR_vulkan_memory_model\"", | |
| "OpMemoryModel Logical VulkanKHR", | |
| "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<GenerateWebGPUInitializersPass>(input, expected, | |
| /* skip_nop = */ false); | |
| } | |
| // clang-format off | |
| INSTANTIATE_TEST_SUITE_P( | |
| GenerateWebGPUInitializers, GlobalVariableTest, | |
| ::testing::ValuesIn(std::vector<GenerateWebGPUInitializersParam>({ | |
| 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<const char*> result = { | |
| // clang-format off | |
| "OpCapability Shader", | |
| "OpCapability VulkanMemoryModelKHR", | |
| "OpExtension \"SPV_KHR_vulkan_memory_model\"", | |
| "OpMemoryModel Logical VulkanKHR", | |
| "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<GenerateWebGPUInitializersPass>(input, expected, | |
| /* skip_nop = */ false); | |
| } | |
| // clang-format off | |
| INSTANTIATE_TEST_SUITE_P( | |
| GenerateWebGPUInitializers, LocalVariableTest, | |
| ::testing::ValuesIn(std::vector<GenerateWebGPUInitializersParam>({ | |
| 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<const char*> spirv = { | |
| // clang-format off | |
| "OpCapability Shader", | |
| "OpCapability VulkanMemoryModelKHR", | |
| "OpExtension \"SPV_KHR_vulkan_memory_model\"", | |
| "OpMemoryModel Logical VulkanKHR", | |
| "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<GenerateWebGPUInitializersPass>(str, str, | |
| /* skip_nop = */ false); | |
| } | |
| TEST_F(GenerateWebGPUInitializersTest, AmbigiousArrays) { | |
| std::vector<const char*> input_spirv = { | |
| // clang-format off | |
| "OpCapability Shader", | |
| "OpCapability VulkanMemoryModelKHR", | |
| "OpExtension \"SPV_KHR_vulkan_memory_model\"", | |
| "OpMemoryModel Logical VulkanKHR", | |
| "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<const char*> expected_spirv = { | |
| // clang-format off | |
| "OpCapability Shader", | |
| "OpCapability VulkanMemoryModelKHR", | |
| "OpExtension \"SPV_KHR_vulkan_memory_model\"", | |
| "OpMemoryModel Logical VulkanKHR", | |
| "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<GenerateWebGPUInitializersPass>(input_str, expected_str, | |
| /* skip_nop = */ false); | |
| } | |
| TEST_F(GenerateWebGPUInitializersTest, AmbigiousStructs) { | |
| std::vector<const char*> input_spirv = { | |
| // clang-format off | |
| "OpCapability Shader", | |
| "OpCapability VulkanMemoryModelKHR", | |
| "OpExtension \"SPV_KHR_vulkan_memory_model\"", | |
| "OpMemoryModel Logical VulkanKHR", | |
| "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<const char*> expected_spirv = { | |
| // clang-format off | |
| "OpCapability Shader", | |
| "OpCapability VulkanMemoryModelKHR", | |
| "OpExtension \"SPV_KHR_vulkan_memory_model\"", | |
| "OpMemoryModel Logical VulkanKHR", | |
| "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<GenerateWebGPUInitializersPass>(input_str, expected_str, | |
| /* skip_nop = */ false); | |
| } | |
| } // namespace | |
| } // namespace opt | |
| } // namespace spvtools |