diff --git a/include/spirv-tools/libspirv.hpp b/include/spirv-tools/libspirv.hpp index fc9531054..dcd85a574 100644 --- a/include/spirv-tools/libspirv.hpp +++ b/include/spirv-tools/libspirv.hpp @@ -31,6 +31,23 @@ using MessageConsumer = std::function; +// A RAII wrapper around a validator options object. +class ValidatorOptions { + public: + ValidatorOptions() : options_(spvValidatorOptionsCreate()) {} + ~ValidatorOptions() { spvValidatorOptionsDestroy(options_); } + // Allow implicit conversion to the underlying object. + operator spv_validator_options() const { return options_; } + + // Sets a limit. + void SetUniversalLimit(spv_validator_limit limit_type, uint32_t limit) { + spvValidatorOptionsSetUniversalLimit(options_, limit_type, limit); + } + + private: + spv_validator_options options_; +}; + // C++ interface for SPIRV-Tools functionalities. It wraps the context // (including target environment and the corresponding SPIR-V grammar) and // provides methods for assembling, disassembling, and validating. @@ -91,6 +108,8 @@ class SpirvTools { bool Validate(const std::vector& binary) const; // |binary_size| specifies the number of words in |binary|. bool Validate(const uint32_t* binary, size_t binary_size) const; + // Like the previous overload, but takes an options object. + bool Validate(const uint32_t* binary, size_t binary_size, const ValidatorOptions& options) const; private: struct Impl; // Opaque struct for holding the data fields used by this class. diff --git a/source/libspirv.cpp b/source/libspirv.cpp index 02e87ea5e..e390ffe88 100644 --- a/source/libspirv.cpp +++ b/source/libspirv.cpp @@ -82,4 +82,11 @@ bool SpirvTools::Validate(const uint32_t* binary, SPV_SUCCESS; } +bool SpirvTools::Validate(const uint32_t* binary, const size_t binary_size, + const spvtools::ValidatorOptions& options) const { + spv_const_binary_t the_binary{binary, binary_size}; + return spvValidateWithOptions(impl_->context, options, &the_binary, + nullptr) == SPV_SUCCESS; +} + } // namespace spvtools diff --git a/test/cpp_interface_test.cpp b/test/cpp_interface_test.cpp index 307ee93b3..2bab430b2 100644 --- a/test/cpp_interface_test.cpp +++ b/test/cpp_interface_test.cpp @@ -22,6 +22,7 @@ namespace { using namespace spvtools; using ::testing::ContainerEq; +using ::testing::HasSubstr; TEST(CppInterface, SuccessfulRoundTrip) { const std::string input_text = "%2 = OpSizeOf %1 %3\n"; @@ -221,6 +222,46 @@ TEST(CppInterface, ValidateEmptyModule) { EXPECT_EQ(1, invocation_count); } +// Returns the assembly for a SPIR-V module with a struct declaration +// with the given number of members. +std::string MakeModuleHavingStruct(int num_members) { + std::stringstream os; + os << R"(OpCapability Shader + OpCapability Linkage + OpMemoryModel Logical GLSL450 + %1 = OpTypeInt 32 0 + %2 = OpTypeStruct)"; + for (int i = 0; i < num_members; i++) os << " %1"; + return os.str(); +} + +TEST(CppInterface, ValidateWithOptionsPass) { + SpirvTools t(SPV_ENV_UNIVERSAL_1_1); + std::vector binary; + EXPECT_TRUE(t.Assemble(MakeModuleHavingStruct(10), &binary)); + const spvtools::ValidatorOptions opts; + + EXPECT_TRUE(t.Validate(binary.data(), binary.size(), opts)); +} + +TEST(CppInterface, ValidateWithOptionsFail) { + SpirvTools t(SPV_ENV_UNIVERSAL_1_1); + std::vector binary; + EXPECT_TRUE(t.Assemble(MakeModuleHavingStruct(10), &binary)); + spvtools::ValidatorOptions opts; + opts.SetUniversalLimit(spv_validator_limit_max_struct_members, 9); + std::stringstream os; + t.SetMessageConsumer([&os](spv_message_level_t, const char*, + const spv_position_t&, + const char* message) { os << message; }); + + EXPECT_FALSE(t.Validate(binary.data(), binary.size(), opts)); + EXPECT_THAT( + os.str(), + HasSubstr( + "Number of OpTypeStruct members (10) has exceeded the limit (9)")); +} + // Checks that after running the given optimizer |opt| on the given |original| // source code, we can get the given |optimized| source code. void CheckOptimization(const char* original, const char* optimized,