SPIRV-Tools/test/opt/optimizer_test.cpp
Ryan Harrison 048dcd38ce
Implement WebGPU->Vulkan initializer conversion for 'Function' variables (#2513)
WebGPU requires certain variables to be initialized, whereas there are
known issues with using initializers in Vulkan. This PR is the first
of three implementing a pass to decompose initialized variables into
a variable declaration followed by a store. This has been broken up
into multiple PRs, because there 3 distinct cases that need to be
handled, which require separate implementations.

This first PR implements the basic infrastructure that is needed, and
handling of Function storage class variables. Private and Output will
be handled in future PRs.

This is part of resolving #2388
2019-04-16 14:31:36 -04:00

627 lines
22 KiB
C++

// Copyright (c) 2017 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 <string>
#include <vector>
#include "gmock/gmock.h"
#include "spirv-tools/libspirv.hpp"
#include "spirv-tools/optimizer.hpp"
#include "test/opt/pass_fixture.h"
namespace spvtools {
namespace opt {
namespace {
using ::testing::Eq;
// Return a string that contains the minimum instructions needed to form
// a valid module. Other instructions can be appended to this string.
std::string Header() {
return R"(OpCapability Shader
OpCapability Linkage
OpMemoryModel Logical GLSL450
)";
}
TEST(Optimizer, CanRunNullPassWithDistinctInputOutputVectors) {
SpirvTools tools(SPV_ENV_UNIVERSAL_1_0);
std::vector<uint32_t> binary_in;
tools.Assemble(Header() + "OpName %foo \"foo\"\n%foo = OpTypeVoid",
&binary_in);
Optimizer opt(SPV_ENV_UNIVERSAL_1_0);
opt.RegisterPass(CreateNullPass());
std::vector<uint32_t> binary_out;
opt.Run(binary_in.data(), binary_in.size(), &binary_out);
std::string disassembly;
tools.Disassemble(binary_out.data(), binary_out.size(), &disassembly);
EXPECT_THAT(disassembly,
Eq(Header() + "OpName %foo \"foo\"\n%foo = OpTypeVoid\n"));
}
TEST(Optimizer, CanRunTransformingPassWithDistinctInputOutputVectors) {
SpirvTools tools(SPV_ENV_UNIVERSAL_1_0);
std::vector<uint32_t> binary_in;
tools.Assemble(Header() + "OpName %foo \"foo\"\n%foo = OpTypeVoid",
&binary_in);
Optimizer opt(SPV_ENV_UNIVERSAL_1_0);
opt.RegisterPass(CreateStripDebugInfoPass());
std::vector<uint32_t> binary_out;
opt.Run(binary_in.data(), binary_in.size(), &binary_out);
std::string disassembly;
tools.Disassemble(binary_out.data(), binary_out.size(), &disassembly);
EXPECT_THAT(disassembly, Eq(Header() + "%void = OpTypeVoid\n"));
}
TEST(Optimizer, CanRunNullPassWithAliasedVectors) {
SpirvTools tools(SPV_ENV_UNIVERSAL_1_0);
std::vector<uint32_t> binary;
tools.Assemble("OpName %foo \"foo\"\n%foo = OpTypeVoid", &binary);
Optimizer opt(SPV_ENV_UNIVERSAL_1_0);
opt.RegisterPass(CreateNullPass());
opt.Run(binary.data(), binary.size(), &binary); // This is the key.
std::string disassembly;
tools.Disassemble(binary.data(), binary.size(), &disassembly);
EXPECT_THAT(disassembly, Eq("OpName %foo \"foo\"\n%foo = OpTypeVoid\n"));
}
TEST(Optimizer, CanRunNullPassWithAliasedVectorDataButDifferentSize) {
SpirvTools tools(SPV_ENV_UNIVERSAL_1_0);
std::vector<uint32_t> binary;
tools.Assemble(Header() + "OpName %foo \"foo\"\n%foo = OpTypeVoid", &binary);
Optimizer opt(SPV_ENV_UNIVERSAL_1_0);
opt.RegisterPass(CreateNullPass());
auto orig_size = binary.size();
// Now change the size. Add a word that will be ignored
// by the optimizer.
binary.push_back(42);
EXPECT_THAT(orig_size + 1, Eq(binary.size()));
opt.Run(binary.data(), orig_size, &binary); // This is the key.
// The binary vector should have been rewritten.
EXPECT_THAT(binary.size(), Eq(orig_size));
std::string disassembly;
tools.Disassemble(binary.data(), binary.size(), &disassembly);
EXPECT_THAT(disassembly,
Eq(Header() + "OpName %foo \"foo\"\n%foo = OpTypeVoid\n"));
}
TEST(Optimizer, CanRunTransformingPassWithAliasedVectors) {
SpirvTools tools(SPV_ENV_UNIVERSAL_1_0);
std::vector<uint32_t> binary;
tools.Assemble(Header() + "OpName %foo \"foo\"\n%foo = OpTypeVoid", &binary);
Optimizer opt(SPV_ENV_UNIVERSAL_1_0);
opt.RegisterPass(CreateStripDebugInfoPass());
opt.Run(binary.data(), binary.size(), &binary); // This is the key
std::string disassembly;
tools.Disassemble(binary.data(), binary.size(), &disassembly);
EXPECT_THAT(disassembly, Eq(Header() + "%void = OpTypeVoid\n"));
}
TEST(Optimizer, CanValidateFlags) {
Optimizer opt(SPV_ENV_UNIVERSAL_1_0);
EXPECT_FALSE(opt.FlagHasValidForm("bad-flag"));
EXPECT_TRUE(opt.FlagHasValidForm("-O"));
EXPECT_TRUE(opt.FlagHasValidForm("-Os"));
EXPECT_FALSE(opt.FlagHasValidForm("-O2"));
EXPECT_TRUE(opt.FlagHasValidForm("--this_flag"));
}
TEST(Optimizer, CanRegisterPassesFromFlags) {
SpirvTools tools(SPV_ENV_UNIVERSAL_1_0);
Optimizer opt(SPV_ENV_UNIVERSAL_1_0);
spv_message_level_t msg_level;
const char* msg_fname;
spv_position_t msg_position;
const char* msg;
auto examine_message = [&msg_level, &msg_fname, &msg_position, &msg](
spv_message_level_t ml, const char* f,
const spv_position_t& p, const char* m) {
msg_level = ml;
msg_fname = f;
msg_position = p;
msg = m;
};
opt.SetMessageConsumer(examine_message);
std::vector<std::string> pass_flags = {
"--strip-debug",
"--strip-reflect",
"--set-spec-const-default-value=23:42 21:12",
"--if-conversion",
"--freeze-spec-const",
"--inline-entry-points-exhaustive",
"--inline-entry-points-opaque",
"--convert-local-access-chains",
"--eliminate-dead-code-aggressive",
"--eliminate-insert-extract",
"--eliminate-local-single-block",
"--eliminate-local-single-store",
"--merge-blocks",
"--merge-return",
"--eliminate-dead-branches",
"--eliminate-dead-functions",
"--eliminate-local-multi-store",
"--eliminate-common-uniform",
"--eliminate-dead-const",
"--eliminate-dead-inserts",
"--eliminate-dead-variables",
"--fold-spec-const-op-composite",
"--loop-unswitch",
"--scalar-replacement=300",
"--scalar-replacement",
"--strength-reduction",
"--unify-const",
"--flatten-decorations",
"--compact-ids",
"--cfg-cleanup",
"--local-redundancy-elimination",
"--loop-invariant-code-motion",
"--reduce-load-size",
"--redundancy-elimination",
"--private-to-local",
"--remove-duplicates",
"--workaround-1209",
"--replace-invalid-opcode",
"--simplify-instructions",
"--ssa-rewrite",
"--copy-propagate-arrays",
"--loop-fission=20",
"--loop-fusion=2",
"--loop-unroll",
"--vector-dce",
"--loop-unroll-partial=3",
"--loop-peeling",
"--ccp",
"-O",
"-Os",
"--legalize-hlsl"};
EXPECT_TRUE(opt.RegisterPassesFromFlags(pass_flags));
// Test some invalid flags.
EXPECT_FALSE(opt.RegisterPassFromFlag("-O2"));
EXPECT_EQ(msg_level, SPV_MSG_ERROR);
EXPECT_FALSE(opt.RegisterPassFromFlag("-loop-unroll"));
EXPECT_EQ(msg_level, SPV_MSG_ERROR);
EXPECT_FALSE(opt.RegisterPassFromFlag("--set-spec-const-default-value"));
EXPECT_EQ(msg_level, SPV_MSG_ERROR);
EXPECT_FALSE(opt.RegisterPassFromFlag("--scalar-replacement=s"));
EXPECT_EQ(msg_level, SPV_MSG_ERROR);
EXPECT_FALSE(opt.RegisterPassFromFlag("--loop-fission=-4"));
EXPECT_EQ(msg_level, SPV_MSG_ERROR);
EXPECT_FALSE(opt.RegisterPassFromFlag("--loop-fusion=xx"));
EXPECT_EQ(msg_level, SPV_MSG_ERROR);
EXPECT_FALSE(opt.RegisterPassFromFlag("--loop-unroll-partial"));
EXPECT_EQ(msg_level, SPV_MSG_ERROR);
}
TEST(Optimizer, VulkanToWebGPUSetsCorrectPasses) {
Optimizer opt(SPV_ENV_WEBGPU_0);
opt.RegisterVulkanToWebGPUPasses();
std::vector<const char*> pass_names = opt.GetPassNames();
std::vector<std::string> registered_passes;
for (auto name = pass_names.begin(); name != pass_names.end(); ++name)
registered_passes.push_back(*name);
std::vector<std::string> expected_passes = {"eliminate-dead-branches",
"eliminate-dead-code-aggressive",
"eliminate-dead-const",
"flatten-decorations",
"strip-debug",
"strip-atomic-counter-memory",
"generate-webgpu-initializers",
"legalize-vector-shuffle"};
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<VulkanToWebGPUPassCase>>;
TEST_P(VulkanToWebGPUPassTest, Ran) {
std::vector<uint32_t> binary;
{
SpirvTools tools(SPV_ENV_VULKAN_1_1);
tools.Assemble(GetParam().input, &binary);
}
Optimizer opt(SPV_ENV_WEBGPU_0);
opt.RegisterVulkanToWebGPUPasses();
std::vector<uint32_t> optimized;
class ValidatorOptions validator_options;
ASSERT_TRUE(opt.Run(binary.data(), binary.size(), &optimized,
validator_options, true));
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<VulkanToWebGPUPassCase>{
// FlattenDecorations
{// input
"OpCapability Shader\n"
"OpCapability VulkanMemoryModelKHR\n"
"OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
"OpMemoryModel Logical VulkanKHR\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 VulkanMemoryModelKHR\n"
"OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
"OpMemoryModel Logical VulkanKHR\n"
"OpEntryPoint Fragment %1 \"main\" %2 %3 %4\n"
"OpExecutionMode %1 OriginUpperLeft\n"
"%void = OpTypeVoid\n"
"%7 = 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 %7\n"
"%10 = OpLabel\n"
"OpReturn\n"
"OpFunctionEnd\n",
// pass
"flatten-decorations"},
// Strip Debug
{// input
"OpCapability Shader\n"
"OpCapability VulkanMemoryModelKHR\n"
"OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
"OpMemoryModel Logical VulkanKHR\n"
"OpEntryPoint Vertex %func \"shader\"\n"
"OpName %main \"main\"\n"
"OpName %void_fn \"void_fn\"\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 VulkanMemoryModelKHR\n"
"OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
"OpMemoryModel Logical VulkanKHR\n"
"OpEntryPoint Vertex %1 \"shader\"\n"
"%void = OpTypeVoid\n"
"%5 = OpTypeFunction %void\n"
"%1 = OpFunction %void None %5\n"
"%6 = OpLabel\n"
"OpReturn\n"
"OpFunctionEnd\n",
// pass
"strip-debug"},
// Eliminate Dead Constants
{// input
"OpCapability Shader\n"
"OpCapability VulkanMemoryModelKHR\n"
"OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
"OpMemoryModel Logical VulkanKHR\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 VulkanMemoryModelKHR\n"
"OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
"OpMemoryModel Logical VulkanKHR\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"
"%10 = OpTypeFunction %void\n"
"%1 = OpFunction %void None %10\n"
"%11 = OpLabel\n"
"OpReturn\n"
"OpFunctionEnd\n",
"eliminate-dead-const"},
// Strip Atomic Counter Memory
{// input
"OpCapability Shader\n"
"OpCapability VulkanMemoryModelKHR\n"
"OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
"OpMemoryModel Logical VulkanKHR\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"
"%val0 = 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 VulkanMemoryModelKHR\n"
"OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
"OpMemoryModel Logical VulkanKHR\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"
"%10 = OpTypeFunction %void\n"
"%uint_264 = OpConstant %uint 264\n"
"%1 = OpFunction %void None %10\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 VulkanMemoryModelKHR\n"
"OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
"OpMemoryModel Logical VulkanKHR\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 VulkanMemoryModelKHR\n"
"OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
"OpMemoryModel Logical VulkanKHR\n"
"OpEntryPoint Vertex %1 \"shader\"\n"
"%uint = OpTypeInt 32 0\n"
"%_ptr_Private_uint = OpTypePointer Private %uint\n"
"%9 = OpConstantNull %uint\n"
"%4 = OpVariable %_ptr_Private_uint Private %9\n"
"%uint_0 = OpConstant %uint 0\n"
"%void = OpTypeVoid\n"
"%7 = OpTypeFunction %void\n"
"%1 = OpFunction %void None %7\n"
"%8 = OpLabel\n"
"OpStore %4 %uint_0\n"
"OpReturn\n"
"OpFunctionEnd\n",
// pass
"generate-webgpu-initializers"},
// Legalize Vector Shuffle
{// input
"OpCapability Shader\n"
"OpCapability VulkanMemoryModelKHR\n"
"OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
"OpMemoryModel Logical VulkanKHR\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 VulkanMemoryModelKHR\n"
"OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
"OpMemoryModel Logical VulkanKHR\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"
"%12 = OpConstantNull %v3uint\n"
"%1 = OpFunction %void None %6\n"
"%7 = OpLabel\n"
"%8 = OpVariable %_ptr_Function_v3uint Function %12\n"
"%9 = OpLoad %v3uint %8\n"
"%10 = OpLoad %v3uint %8\n"
"%11 = OpVectorShuffle %v3uint %9 %10 2 1 0\n"
"OpReturn\n"
"OpFunctionEnd\n",
// pass
"legalize-vector-shuffle"}}));
TEST(Optimizer, WebGPUToVulkanSetsCorrectPasses) {
Optimizer opt(SPV_ENV_VULKAN_1_1);
opt.RegisterWebGPUToVulkanPasses();
std::vector<const char*> pass_names = opt.GetPassNames();
std::vector<std::string> registered_passes;
for (auto name = pass_names.begin(); name != pass_names.end(); ++name)
registered_passes.push_back(*name);
std::vector<std::string> expected_passes = {
"decompose-initialized-variables"};
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<WebGPUToVulkanPassCase>>;
TEST_P(WebGPUToVulkanPassTest, Ran) {
std::vector<uint32_t> binary;
{
SpirvTools tools(SPV_ENV_WEBGPU_0);
tools.Assemble(GetParam().input, &binary);
}
Optimizer opt(SPV_ENV_VULKAN_1_1);
opt.RegisterWebGPUToVulkanPasses();
std::vector<uint32_t> 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<WebGPUToVulkanPassCase>{
// Decompose Initialized Variables
{// input
"OpCapability Shader\n"
"OpCapability VulkanMemoryModelKHR\n"
"OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
"OpMemoryModel Logical VulkanKHR\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 VulkanMemoryModelKHR\n"
"OpExtension \"SPV_KHR_vulkan_memory_model\"\n"
"OpMemoryModel Logical VulkanKHR\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"}}));
} // namespace
} // namespace opt
} // namespace spvtools