diff --git a/include/spirv-tools/libspirv.h b/include/spirv-tools/libspirv.h index b549efbada..84a7726e78 100644 --- a/include/spirv-tools/libspirv.h +++ b/include/spirv-tools/libspirv.h @@ -441,6 +441,8 @@ typedef struct spv_reducer_options_t spv_reducer_options_t; typedef struct spv_fuzzer_options_t spv_fuzzer_options_t; +typedef struct spv_optimizer_t spv_optimizer_t; + // Type Definitions typedef spv_const_binary_t* spv_const_binary; @@ -900,6 +902,63 @@ SPIRV_TOOLS_EXPORT spv_result_t spvBinaryParse( const size_t num_words, spv_parsed_header_fn_t parse_header, spv_parsed_instruction_fn_t parse_instruction, spv_diagnostic* diagnostic); +// The optimizer interface. + +// A pointer to a function that accepts a log message from an optimizer. +typedef void (*spv_message_consumer)( + spv_message_level_t, const char*, const spv_position_t*, const char*); + +// Creates and returns an optimizer object. This object must be passed to +// optimizer APIs below and is valid until passed to spvOptimizerDestroy. +SPIRV_TOOLS_EXPORT spv_optimizer_t* spvOptimizerCreate(spv_target_env env); + +// Destroys the given optimizer object. +SPIRV_TOOLS_EXPORT void spvOptimizerDestroy(spv_optimizer_t* optimizer); + +// Sets an spv_message_consumer on an optimizer object. +SPIRV_TOOLS_EXPORT void spvOptimizerSetMessageConsumer( + spv_optimizer_t* optimizer, spv_message_consumer consumer); + +// Registers passes that attempt to legalize the generated code. +SPIRV_TOOLS_EXPORT void spvOptimizerRegisterLegalizationPasses( + spv_optimizer_t* optimizer); + +// Registers passes that attempt to improve performance of generated code. +SPIRV_TOOLS_EXPORT void spvOptimizerRegisterPerformancePasses( + spv_optimizer_t* optimizer); + +// Registers passes that attempt to improve the size of generated code. +SPIRV_TOOLS_EXPORT void spvOptimizerRegisterSizePasses( + spv_optimizer_t* optimizer); + +// Registers a pass specified by a flag in an optimizer object. +SPIRV_TOOLS_EXPORT bool spvOptimizerRegisterPassFromFlag( + spv_optimizer_t* optimizer, const char* flag); + +// Registers passes specified by length number of flags in an optimizer object. +SPIRV_TOOLS_EXPORT bool spvOptimizerRegisterPassesFromFlags( + spv_optimizer_t* optimizer, const char** flags, const size_t flag_count); + +// Optimizes the SPIR-V code of size |word_count| pointed to by |binary| and +// returns an optimized spv_binary in |optimized_binary|. +// +// Returns SPV_SUCCESS on successful optimization, whether or not the module is +// modified. Returns an SPV_ERROR_* if the module fails to validate or if +// errors occur when processing using any of the registered passes. In that +// case, no further passes are executed and the |optimized_binary| contents may +// be invalid. +// +// By default, the binary is validated before any transforms are performed, +// and optionally after each transform. Validation uses SPIR-V spec rules +// for the SPIR-V version named in the binary's header (at word offset 1). +// Additionally, if the target environment is a client API (such as +// Vulkan 1.1), then validate for that client API version, to the extent +// that it is verifiable from data in the binary itself, or from the +// validator options set on the optimizer options. +SPIRV_TOOLS_EXPORT spv_result_t spvOptimizerRun( + spv_optimizer_t* optimizer, const uint32_t* binary, const size_t word_count, + spv_binary* optimized_binary, const spv_optimizer_options options); + #ifdef __cplusplus } #endif diff --git a/source/opt/optimizer.cpp b/source/opt/optimizer.cpp index be0daebda8..cbc4b82f77 100644 --- a/source/opt/optimizer.cpp +++ b/source/opt/optimizer.cpp @@ -1065,3 +1065,95 @@ Optimizer::PassToken CreateFixFuncCallArgumentsPass() { MakeUnique()); } } // namespace spvtools + +extern "C" { + +SPIRV_TOOLS_EXPORT spv_optimizer_t* spvOptimizerCreate(spv_target_env env) { + return reinterpret_cast(new spvtools::Optimizer(env)); +} + +SPIRV_TOOLS_EXPORT void spvOptimizerDestroy(spv_optimizer_t* optimizer) { + delete reinterpret_cast(optimizer); +} + +SPIRV_TOOLS_EXPORT void spvOptimizerSetMessageConsumer( + spv_optimizer_t* optimizer, spv_message_consumer consumer) { + reinterpret_cast(optimizer)-> + SetMessageConsumer( + [consumer](spv_message_level_t level, const char* source, + const spv_position_t& position, const char* message) { + return consumer(level, source, &position, message); + }); +} + +SPIRV_TOOLS_EXPORT void spvOptimizerRegisterLegalizationPasses( + spv_optimizer_t* optimizer) { + reinterpret_cast(optimizer)-> + RegisterLegalizationPasses(); +} + +SPIRV_TOOLS_EXPORT void spvOptimizerRegisterPerformancePasses( + spv_optimizer_t* optimizer) { + reinterpret_cast(optimizer)-> + RegisterPerformancePasses(); +} + +SPIRV_TOOLS_EXPORT void spvOptimizerRegisterSizePasses( + spv_optimizer_t* optimizer) { + reinterpret_cast(optimizer)->RegisterSizePasses(); +} + +SPIRV_TOOLS_EXPORT bool spvOptimizerRegisterPassFromFlag( + spv_optimizer_t* optimizer, const char* flag) +{ + return reinterpret_cast(optimizer)-> + RegisterPassFromFlag(flag); +} + +SPIRV_TOOLS_EXPORT bool spvOptimizerRegisterPassesFromFlags( + spv_optimizer_t* optimizer, const char** flags, const size_t flag_count) { + std::vector opt_flags; + for (uint32_t i = 0; i < flag_count; i++) { + opt_flags.emplace_back(flags[i]); + } + + return reinterpret_cast(optimizer)-> + RegisterPassesFromFlags(opt_flags); +} + +SPIRV_TOOLS_EXPORT +spv_result_t spvOptimizerRun(spv_optimizer_t* optimizer, + const uint32_t* binary, + const size_t word_count, + spv_binary* optimized_binary, + const spv_optimizer_options options) { + std::vector optimized; + + if (!reinterpret_cast(optimizer)-> + Run(binary, word_count, &optimized, options)) { + return SPV_ERROR_INTERNAL; + } + + auto result_binary = new spv_binary_t(); + if (!result_binary) { + *optimized_binary = nullptr; + return SPV_ERROR_OUT_OF_MEMORY; + } + + result_binary->code = new uint32_t[optimized.size()]; + if (!result_binary->code) { + delete result_binary; + *optimized_binary = nullptr; + return SPV_ERROR_OUT_OF_MEMORY; + } + result_binary->wordCount = optimized.size(); + + memcpy(result_binary->code, optimized.data(), + optimized.size() * sizeof(uint32_t)); + + *optimized_binary = result_binary; + + return SPV_SUCCESS; +} + +} // extern "C" diff --git a/test/opt/CMakeLists.txt b/test/opt/CMakeLists.txt index af24e6599c..3b2d3844eb 100644 --- a/test/opt/CMakeLists.txt +++ b/test/opt/CMakeLists.txt @@ -21,6 +21,7 @@ add_spvtools_unittest(TARGET opt analyze_live_input_test.cpp assembly_builder_test.cpp block_merge_test.cpp + c_interface_test.cpp ccp_test.cpp cfg_cleanup_test.cpp cfg_test.cpp diff --git a/test/opt/c_interface_test.cpp b/test/opt/c_interface_test.cpp new file mode 100644 index 0000000000..a1725255ce --- /dev/null +++ b/test/opt/c_interface_test.cpp @@ -0,0 +1,534 @@ +// Copyright (c) 2023 Nintendo +// +// 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 "gtest/gtest.h" +#include "spirv-tools/libspirv.h" + +namespace spvtools { +namespace { + +TEST(OptimizerCInterface, DefaultConsumerWithValidationNoPassesForInvalidInput) { + const uint32_t spirv[] = { + 0xDEADFEED, // Invalid Magic + 0x00010100, // Version 1.1 + 0x00000000, // No Generator + 0x01000000, // Bound + 0x00000000, // Schema + 0x00020011, // OpCapability + 0x00000001, // Shader + 0x00020011, // OpCapability + 0x00000005, // Linkage + 0x0003000E, // OpMemoryModel + 0x00000000, // Logical + 0x00000001 // GLSL450 + }; + + auto optimizer = spvOptimizerCreate(SPV_ENV_UNIVERSAL_1_1); + ASSERT_NE(optimizer, nullptr); + + // Do not register any passes + + auto options = spvOptimizerOptionsCreate(); + ASSERT_NE(options, nullptr); + spvOptimizerOptionsSetRunValidator(options, true); + + spv_binary binary = nullptr; + EXPECT_NE(SPV_SUCCESS, + spvOptimizerRun(optimizer, spirv, sizeof(spirv) / sizeof(uint32_t), + &binary, options)); + ASSERT_EQ(binary, nullptr); + + spvOptimizerOptionsDestroy(options); + + spvOptimizerDestroy(optimizer); +} + +TEST(OptimizerCInterface, SpecifyConsumerWithValidationNoPassesForInvalidInput) { + const uint32_t spirv[] = { + 0xDEADFEED, // Invalid Magic + 0x00010100, // Version 1.1 + 0x00000000, // No Generator + 0x01000000, // Bound + 0x00000000, // Schema + 0x00020011, // OpCapability + 0x00000001, // Shader + 0x00020011, // OpCapability + 0x00000005, // Linkage + 0x0003000E, // OpMemoryModel + 0x00000000, // Logical + 0x00000001 // GLSL450 + }; + + auto optimizer = spvOptimizerCreate(SPV_ENV_UNIVERSAL_1_1); + ASSERT_NE(optimizer, nullptr); + + spvOptimizerSetMessageConsumer( + optimizer, + [](spv_message_level_t, const char*, const spv_position_t*, + const char* message) { + std::cout << message << std::endl; + }); + + // Do not register any passes + + auto options = spvOptimizerOptionsCreate(); + ASSERT_NE(options, nullptr); + spvOptimizerOptionsSetRunValidator(options, true); + + testing::internal::CaptureStdout(); + + spv_binary binary = nullptr; + EXPECT_NE(SPV_SUCCESS, + spvOptimizerRun(optimizer, spirv, sizeof(spirv) / sizeof(uint32_t), + &binary, options)); + ASSERT_EQ(binary, nullptr); + + auto output = testing::internal::GetCapturedStdout(); + EXPECT_STRNE(output.c_str(), ""); + + spvOptimizerOptionsDestroy(options); + + spvOptimizerDestroy(optimizer); +} + +TEST(OptimizerCInterface, DefaultConsumerWithValidationNoPassesForValidInput) { + const uint32_t spirv[] = { + 0x07230203, // Magic + 0x00010100, // Version 1.1 + 0x00000000, // No Generator + 0x00000001, // Bound + 0x00000000, // Schema + 0x00020011, // OpCapability + 0x00000001, // Shader + 0x00020011, // OpCapability + 0x00000005, // Linkage + 0x0003000E, // OpMemoryModel + 0x00000000, // Logical + 0x00000001 // GLSL450 + }; + + auto optimizer = spvOptimizerCreate(SPV_ENV_UNIVERSAL_1_1); + ASSERT_NE(optimizer, nullptr); + + // Do not register any passes + + auto options = spvOptimizerOptionsCreate(); + ASSERT_NE(options, nullptr); + spvOptimizerOptionsSetRunValidator(options, true); + + spv_binary binary = nullptr; + EXPECT_EQ(SPV_SUCCESS, + spvOptimizerRun(optimizer, spirv, sizeof(spirv) / sizeof(uint32_t), + &binary, options)); + ASSERT_NE(binary, nullptr); + + spvOptimizerOptionsDestroy(options); + + // Should remain unchanged + EXPECT_EQ(binary->wordCount, sizeof(spirv) / sizeof(uint32_t)); + EXPECT_EQ(memcmp(binary->code, spirv, sizeof(spirv) / sizeof(uint32_t)), 0); + + spvBinaryDestroy(binary); + spvOptimizerDestroy(optimizer); +} + +TEST(OptimizerCInterface, DefaultConsumerNoPassesForValidInput) { + const uint32_t spirv[] = { + 0x07230203, // Magic + 0x00010100, // Version 1.1 + 0x00000000, // No Generator + 0x00000003, // Bound + 0x00000000, // Schema + 0x00020011, // OpCapability + 0x00000001, // Shader + 0x00020011, // OpCapability + 0x00000005, // Linkage + 0x0003000E, // OpMemoryModel + 0x00000000, // Logical + 0x00000001, // GLSL450 + 0x00040015, // OpTypeInt + 0x00000001, // %1 + 0x00000020, // 32 Bits + 0x00000000, // Unsigned + 0x0004002B, // OpConstant + 0x00000001, // %1 + 0x00000002, // %2 + 0x00000001 // 1 + }; + + auto optimizer = spvOptimizerCreate(SPV_ENV_UNIVERSAL_1_1); + ASSERT_NE(optimizer, nullptr); + + // Do not register any passes + + auto options = spvOptimizerOptionsCreate(); + ASSERT_NE(options, nullptr); + spvOptimizerOptionsSetRunValidator(options, true); + + spv_binary binary = nullptr; + EXPECT_EQ(SPV_SUCCESS, + spvOptimizerRun(optimizer, spirv, sizeof(spirv) / sizeof(uint32_t), + &binary, options)); + ASSERT_NE(binary, nullptr); + + spvOptimizerOptionsDestroy(options); + + // Should remain unchanged + EXPECT_EQ(binary->wordCount, sizeof(spirv) / sizeof(uint32_t)); + EXPECT_EQ(memcmp(binary->code, spirv, sizeof(spirv) / sizeof(uint32_t)), 0); + + spvBinaryDestroy(binary); + spvOptimizerDestroy(optimizer); +} + +TEST(OptimizerCInterface, DefaultConsumerLegalizationPassesForValidInput) { + const uint32_t spirv[] = { + 0x07230203, // Magic + 0x00010100, // Version 1.1 + 0x00000000, // No Generator + 0x00000003, // Bound + 0x00000000, // Schema + 0x00020011, // OpCapability + 0x00000001, // Shader + 0x00020011, // OpCapability + 0x00000005, // Linkage + 0x0003000E, // OpMemoryModel + 0x00000000, // Logical + 0x00000001, // GLSL450 + 0x00040015, // OpTypeInt + 0x00000001, // %1 + 0x00000020, // 32 Bits + 0x00000000, // Unsigned + 0x0004002B, // OpConstant + 0x00000001, // %1 + 0x00000002, // %2 + 0x00000001 // 1 + }; + + auto optimizer = spvOptimizerCreate(SPV_ENV_UNIVERSAL_1_1); + ASSERT_NE(optimizer, nullptr); + + spvOptimizerRegisterLegalizationPasses(optimizer); + + auto options = spvOptimizerOptionsCreate(); + ASSERT_NE(options, nullptr); + spvOptimizerOptionsSetRunValidator(options, false); + + spv_binary binary = nullptr; + EXPECT_EQ(SPV_SUCCESS, + spvOptimizerRun(optimizer, spirv, sizeof(spirv) / sizeof(uint32_t), + &binary, options)); + ASSERT_NE(binary, nullptr); + + spvOptimizerOptionsDestroy(options); + + // Only check that SPV_SUCCESS is returned, do not verify output + + spvBinaryDestroy(binary); + spvOptimizerDestroy(optimizer); +} + +TEST(OptimizerCInterface, DefaultConsumerPerformancePassesForValidInput) { + const uint32_t spirv[] = { + 0x07230203, // Magic + 0x00010100, // Version 1.1 + 0x00000000, // No Generator + 0x00000003, // Bound + 0x00000000, // Schema + 0x00020011, // OpCapability + 0x00000001, // Shader + 0x00020011, // OpCapability + 0x00000005, // Linkage + 0x0003000E, // OpMemoryModel + 0x00000000, // Logical + 0x00000001, // GLSL450 + 0x00040015, // OpTypeInt + 0x00000001, // %1 + 0x00000020, // 32 Bits + 0x00000000, // Unsigned + 0x0004002B, // OpConstant + 0x00000001, // %1 + 0x00000002, // %2 + 0x00000001 // 1 + }; + const uint32_t expected_spirv[] = { + 0x07230203, // Magic + 0x00010100, // Version 1.1 + 0x00000000, // No Generator + 0x00000001, // Bound + 0x00000000, // Schema + 0x00020011, // OpCapability + 0x00000001, // Shader + 0x00020011, // OpCapability + 0x00000005, // Linkage + 0x0003000E, // OpMemoryModel + 0x00000000, // Logical + 0x00000001 // GLSL450 + }; + + auto optimizer = spvOptimizerCreate(SPV_ENV_UNIVERSAL_1_1); + ASSERT_NE(optimizer, nullptr); + + spvOptimizerRegisterPerformancePasses(optimizer); + + auto options = spvOptimizerOptionsCreate(); + ASSERT_NE(options, nullptr); + spvOptimizerOptionsSetRunValidator(options, false); + + spv_binary binary = nullptr; + EXPECT_EQ(SPV_SUCCESS, + spvOptimizerRun(optimizer, spirv, sizeof(spirv) / sizeof(uint32_t), + &binary, options)); + ASSERT_NE(binary, nullptr); + + spvOptimizerOptionsDestroy(options); + + // Unreferenced OpTypeInt and OpConstant should be removed + EXPECT_EQ(binary->wordCount, sizeof(expected_spirv) / sizeof(uint32_t)); + EXPECT_EQ(memcmp(binary->code, expected_spirv, + sizeof(expected_spirv) / sizeof(uint32_t)), 0); + + spvBinaryDestroy(binary); + spvOptimizerDestroy(optimizer); +} + +TEST(OptimizerCInterface, DefaultConsumerSizePassesForValidInput) { + const uint32_t spirv[] = { + 0x07230203, // Magic + 0x00010100, // Version 1.1 + 0x00000000, // No Generator + 0x00000003, // Bound + 0x00000000, // Schema + 0x00020011, // OpCapability + 0x00000001, // Shader + 0x00020011, // OpCapability + 0x00000005, // Linkage + 0x0003000E, // OpMemoryModel + 0x00000000, // Logical + 0x00000001, // GLSL450 + 0x00040015, // OpTypeInt + 0x00000001, // %1 + 0x00000020, // 32 Bits + 0x00000000, // Unsigned + 0x0004002B, // OpConstant + 0x00000001, // %1 + 0x00000002, // %2 + 0x00000001 // 1 + }; + const uint32_t expected_spirv[] = { + 0x07230203, // Magic + 0x00010100, // Version 1.1 + 0x00000000, // No Generator + 0x00000001, // Bound + 0x00000000, // Schema + 0x00020011, // OpCapability + 0x00000001, // Shader + 0x00020011, // OpCapability + 0x00000005, // Linkage + 0x0003000E, // OpMemoryModel + 0x00000000, // Logical + 0x00000001 // GLSL450 + }; + + auto optimizer = spvOptimizerCreate(SPV_ENV_UNIVERSAL_1_1); + ASSERT_NE(optimizer, nullptr); + + spvOptimizerRegisterSizePasses(optimizer); + + auto options = spvOptimizerOptionsCreate(); + ASSERT_NE(options, nullptr); + spvOptimizerOptionsSetRunValidator(options, false); + + spv_binary binary = nullptr; + EXPECT_EQ(SPV_SUCCESS, + spvOptimizerRun(optimizer, spirv, sizeof(spirv) / sizeof(uint32_t), + &binary, options)); + ASSERT_NE(binary, nullptr); + + spvOptimizerOptionsDestroy(options); + + // Unreferenced OpTypeInt and OpConstant should be removed + EXPECT_EQ(binary->wordCount, sizeof(expected_spirv) / sizeof(uint32_t)); + EXPECT_EQ(memcmp(binary->code, expected_spirv, + sizeof(expected_spirv) / sizeof(uint32_t)), 0); + + spvBinaryDestroy(binary); + spvOptimizerDestroy(optimizer); +} + +TEST(OptimizerCInterface, DefaultConsumerPassFromFlagForValidInput) { + const uint32_t spirv[] = { + 0x07230203, // Magic + 0x00010100, // Version 1.1 + 0x00000000, // No Generator + 0x00000003, // Bound + 0x00000000, // Schema + 0x00020011, // OpCapability + 0x00000001, // Shader + 0x00020011, // OpCapability + 0x00000005, // Linkage + 0x0003000E, // OpMemoryModel + 0x00000000, // Logical + 0x00000001, // GLSL450 + 0x00040015, // OpTypeInt + 0x00000001, // %1 + 0x00000020, // 32 Bits + 0x00000000, // Unsigned + 0x0004002B, // OpConstant + 0x00000001, // %1 + 0x00000002, // %2 + 0x00000001 // 1 + }; + const uint32_t expected_spirv[] = { + 0x07230203, // Magic + 0x00010100, // Version 1.1 + 0x00000000, // No Generator + 0x00000001, // Bound + 0x00000000, // Schema + 0x00020011, // OpCapability + 0x00000001, // Shader + 0x00020011, // OpCapability + 0x00000005, // Linkage + 0x0003000E, // OpMemoryModel + 0x00000000, // Logical + 0x00000001 // GLSL450 + }; + + auto optimizer = spvOptimizerCreate(SPV_ENV_UNIVERSAL_1_1); + ASSERT_NE(optimizer, nullptr); + + EXPECT_TRUE(spvOptimizerRegisterPassFromFlag( + optimizer, "--eliminate-dead-code-aggressive")); + + auto options = spvOptimizerOptionsCreate(); + ASSERT_NE(options, nullptr); + spvOptimizerOptionsSetRunValidator(options, false); + + spv_binary binary = nullptr; + EXPECT_EQ(SPV_SUCCESS, + spvOptimizerRun(optimizer, spirv, sizeof(spirv) / sizeof(uint32_t), + &binary, options)); + ASSERT_NE(binary, nullptr); + + spvOptimizerOptionsDestroy(options); + + // Unreferenced OpTypeInt and OpConstant should be removed + EXPECT_EQ(binary->wordCount, sizeof(expected_spirv) / sizeof(uint32_t)); + EXPECT_EQ(memcmp(binary->code, expected_spirv, + sizeof(expected_spirv) / sizeof(uint32_t)), 0); + + spvBinaryDestroy(binary); + spvOptimizerDestroy(optimizer); +} + +TEST(OptimizerCInterface, DefaultConsumerPassesFromFlagsForValidInput) { + const uint32_t spirv[] = { + 0x07230203, // Magic + 0x00010100, // Version 1.1 + 0x00000000, // No Generator + 0x00000003, // Bound + 0x00000000, // Schema + 0x00020011, // OpCapability + 0x00000001, // Shader + 0x00020011, // OpCapability + 0x00000005, // Linkage + 0x0003000E, // OpMemoryModel + 0x00000000, // Logical + 0x00000001, // GLSL450 + 0x00040015, // OpTypeInt + 0x00000001, // %1 + 0x00000020, // 32 Bits + 0x00000000, // Unsigned + 0x0004002B, // OpConstant + 0x00000001, // %1 + 0x00000002, // %2 + 0x00000001 // 1 + }; + const uint32_t expected_spirv[] = { + 0x07230203, // Magic + 0x00010100, // Version 1.1 + 0x00000000, // No Generator + 0x00000001, // Bound + 0x00000000, // Schema + 0x00020011, // OpCapability + 0x00000001, // Shader + 0x00020011, // OpCapability + 0x00000005, // Linkage + 0x0003000E, // OpMemoryModel + 0x00000000, // Logical + 0x00000001 // GLSL450 + }; + + auto optimizer = spvOptimizerCreate(SPV_ENV_UNIVERSAL_1_1); + ASSERT_NE(optimizer, nullptr); + + const char* flags[2] = { + "--eliminate-dead-const", + "--eliminate-dead-code-aggressive" + }; + + EXPECT_TRUE(spvOptimizerRegisterPassesFromFlags( + optimizer, flags, sizeof(flags) / sizeof(const char*))); + + auto options = spvOptimizerOptionsCreate(); + ASSERT_NE(options, nullptr); + spvOptimizerOptionsSetRunValidator(options, false); + + spv_binary binary = nullptr; + EXPECT_EQ(SPV_SUCCESS, + spvOptimizerRun(optimizer, spirv, sizeof(spirv) / sizeof(uint32_t), + &binary, options)); + ASSERT_NE(binary, nullptr); + + spvOptimizerOptionsDestroy(options); + + // Unreferenced OpTypeInt and OpConstant should be removed + EXPECT_EQ(binary->wordCount, sizeof(expected_spirv) / sizeof(uint32_t)); + EXPECT_EQ(memcmp(binary->code, expected_spirv, + sizeof(expected_spirv) / sizeof(uint32_t)), 0); + + spvBinaryDestroy(binary); + spvOptimizerDestroy(optimizer); +} + +TEST(OptimizerCInterface, DefaultConsumerInvalidPassFromFlag) { + auto optimizer = spvOptimizerCreate(SPV_ENV_UNIVERSAL_1_1); + ASSERT_NE(optimizer, nullptr); + + EXPECT_FALSE(spvOptimizerRegisterPassFromFlag( + optimizer, "--this-is-not-a-valid-pass")); + + spvOptimizerDestroy(optimizer); +} + +TEST(OptimizerCInterface, DefaultConsumerInvalidPassesFromFlags) { + auto optimizer = spvOptimizerCreate(SPV_ENV_UNIVERSAL_1_1); + ASSERT_NE(optimizer, nullptr); + + const char* flags[2] = { + "--eliminate-dead-const", + "--this-is-not-a-valid-pass" + }; + + EXPECT_FALSE(spvOptimizerRegisterPassesFromFlags( + optimizer, flags, sizeof(flags) / sizeof(const char*))); + + spvOptimizerDestroy(optimizer); +} + +} // namespace +} // namespace spvtools diff --git a/utils/check_copyright.py b/utils/check_copyright.py index aa647af58b..e3e74bc9d2 100755 --- a/utils/check_copyright.py +++ b/utils/check_copyright.py @@ -41,8 +41,9 @@ 'Alastair F. Donaldson', 'Mostafa Ashraf', 'Shiyu Liu', - 'ZHOU He'] -CURRENT_YEAR = 2022 + 'ZHOU He', + 'Nintendo'] +CURRENT_YEAR = 2023 FIRST_YEAR = 2014 FINAL_YEAR = CURRENT_YEAR + 5