348 lines
14 KiB
C++
348 lines
14 KiB
C++
// 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 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<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 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<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 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<GenerateWebGPUInitializersPass>(str, str,
|
|
/* skip_nop = */ false);
|
|
}
|
|
|
|
TEST_F(GenerateWebGPUInitializersTest, AmbigiousArrays) {
|
|
std::vector<const char*> 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<const char*> 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<GenerateWebGPUInitializersPass>(input_str, expected_str,
|
|
/* skip_nop = */ false);
|
|
}
|
|
|
|
TEST_F(GenerateWebGPUInitializersTest, AmbigiousStructs) {
|
|
std::vector<const char*> 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<const char*> 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<GenerateWebGPUInitializersPass>(input_str, expected_str,
|
|
/* skip_nop = */ false);
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace opt
|
|
} // namespace spvtools
|