${CMAKE_CURRENT_SOURCE_DIR}/diagnostic.cpp
${CMAKE_CURRENT_SOURCE_DIR}/disassemble.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ext_inst.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extensions.cpp
${CMAKE_CURRENT_SOURCE_DIR}/libspirv.cpp
${CMAKE_CURRENT_SOURCE_DIR}/message.cpp
${CMAKE_CURRENT_SOURCE_DIR}/name_mapper.cpp
--- /dev/null
+// 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 "extensions.h"
+
+#include <string>
+
+namespace libspirv {
+
+bool ParseSpvExtensionFromString(const std::string& str, Extension* extension) {
+ if (str == "SPV_KHR_shader_ballot") {
+ *extension = Extension::kSPV_KHR_shader_ballot;
+ } else if (str == "SPV_KHR_shader_draw_parameters") {
+ *extension = Extension::kSPV_KHR_shader_draw_parameters;
+ } else if (str == "SPV_KHR_subgroup_vote") {
+ *extension = Extension::kSPV_KHR_subgroup_vote;
+ } else if (str == "SPV_KHR_16bit_storage") {
+ *extension = Extension::kSPV_KHR_16bit_storage;
+ } else if (str == "SPV_KHR_device_group") {
+ *extension = Extension::kSPV_KHR_device_group;
+ } else if (str == "SPV_KHR_multiview") {
+ *extension = Extension::kSPV_KHR_multiview;
+ } else if (str == "SPV_NV_sample_mask_override_coverage") {
+ *extension = Extension::kSPV_NV_sample_mask_override_coverage;
+ } else if (str == "SPV_NV_geometry_shader_passthrough") {
+ *extension = Extension::kSPV_NV_geometry_shader_passthrough;
+ } else if (str == "SPV_NV_viewport_array2") {
+ *extension = Extension::kSPV_NV_viewport_array2;
+ } else if (str == "SPV_NV_stereo_view_rendering") {
+ *extension = Extension::kSPV_NV_stereo_view_rendering;
+ } else if (str == "SPV_NVX_multiview_per_view_attributes") {
+ *extension = Extension::kSPV_NVX_multiview_per_view_attributes;
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace libspirv
--- /dev/null
+// 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.
+
+#ifndef LIBSPIRV_EXTENSIONS_H_
+#define LIBSPIRV_EXTENSIONS_H_
+
+#include <string>
+
+#include "enum_set.h"
+#include "message.h"
+#include "spirv-tools/libspirv.hpp"
+
+namespace libspirv {
+
+// The known SPIR-V extensions.
+// TODO(dneto): Consider auto-generating this list?
+// When updating this list, consider also updating ParseSpvExtensionFromString.
+enum class Extension {
+ kSPV_KHR_shader_ballot,
+ kSPV_KHR_shader_draw_parameters,
+ kSPV_KHR_subgroup_vote,
+ kSPV_KHR_16bit_storage,
+ kSPV_KHR_device_group,
+ kSPV_KHR_multiview,
+ kSPV_NV_sample_mask_override_coverage,
+ kSPV_NV_geometry_shader_passthrough,
+ kSPV_NV_viewport_array2,
+ kSPV_NV_stereo_view_rendering,
+ kSPV_NVX_multiview_per_view_attributes,
+};
+
+using ExtensionSet = EnumSet<Extension>;
+
+// Finds Extension enum corresponding to |str|. Returns false if not found.
+bool ParseSpvExtensionFromString(const std::string& str, Extension* extension);
+
+} // namespace libspirv
+
+#endif // LIBSPIRV_EXTENSIONS_H_
#ifndef LIBSPIRV_TABLE_H_
#define LIBSPIRV_TABLE_H_
+#include <string>
+
#include "spirv/1.1/spirv.h"
-#include "enum_set.h"
+#include "extensions.h"
#include "message.h"
#include "spirv-tools/libspirv.hpp"
-namespace libspirv {
-
-// The known SPIR-V extensions.
-// TODO(dneto): Consider auto-generating this list?
-enum class Extension {
- kSPV_KHR_shader_ballot,
-};
-
-using ExtensionSet = EnumSet<Extension>;
-
-} // namespace libspirv
-
typedef struct spv_opcode_desc_t {
const char* name;
const SpvOp opcode;
current_layout_section_(kLayoutCapabilities),
module_functions_(),
module_capabilities_(),
+ module_extensions_(),
ordered_instructions_(),
all_definitions_(),
global_vars_(),
}
}
+void ValidationState_t::RegisterExtension(Extension ext) {
+ if (module_extensions_.Contains(ext)) return;
+
+ module_extensions_.Add(ext);
+}
+
bool ValidationState_t::HasAnyOf(const CapabilitySet& capabilities) const {
bool found = false;
bool any_queried = false;
/// Registers the capability and its dependent capabilities
void RegisterCapability(SpvCapability cap);
+ /// Registers the extension.
+ void RegisterExtension(Extension ext);
+
/// Registers the function in the module. Subsequent instructions will be
/// called against this function
spv_result_t RegisterFunction(uint32_t id, uint32_t ret_type_id,
/// A list of functions in the module
std::deque<Function> module_functions_;
- /// The capabilities available in the module
- libspirv::CapabilitySet
- module_capabilities_; /// Module's declared capabilities.
+ /// Capabilities declared in the module
+ libspirv::CapabilitySet module_capabilities_;
+
+ /// Extensions declared in the module
+ libspirv::ExtensionSet module_extensions_;
/// List of all instructions in the order they appear in the binary
std::deque<Instruction> ordered_instructions_;
#include <sstream>
#include <string>
+#include "binary.h"
#include "diagnostic.h"
#include "enum_set.h"
#include "opcode.h"
return SPV_SUCCESS;
}
+// Parses OpExtension instruction and registers extension.
+void RegisterExtension(ValidationState_t& _,
+ const spv_parsed_instruction_t* inst) {
+ assert(inst->opcode == SpvOpExtension);
+ assert(inst->num_operands == 1);
+
+ const auto& operand = inst->operands[0];
+ assert(operand.type == SPV_OPERAND_TYPE_LITERAL_STRING);
+ assert(inst->num_words > operand.offset);
+
+ const char* extension_str =
+ reinterpret_cast<const char*>(inst->words + operand.offset);
+
+ Extension extension;
+ if (!ParseSpvExtensionFromString(extension_str, &extension)) {
+ _.diag(SPV_SUCCESS) << "Failed to parse OpExtension " << extension_str;
+ return;
+ }
+
+ _.RegisterExtension(extension);
+}
+
spv_result_t InstructionPass(ValidationState_t& _,
const spv_parsed_instruction_t* inst) {
const SpvOp opcode = static_cast<SpvOp>(inst->opcode);
+ if (opcode == SpvOpExtension)
+ RegisterExtension(_, inst);
if (opcode == SpvOpCapability)
_.RegisterCapability(
static_cast<SpvCapability>(inst->words[inst->operands[0].offset]));
${VAL_TEST_COMMON_SRCS}
LIBS ${SPIRV_TOOLS}
)
+
+add_spvtools_unittest(TARGET val_extensions
+ SRCS val_extensions_test.cpp
+ ${VAL_TEST_COMMON_SRCS}
+ LIBS ${SPIRV_TOOLS}
+)
--- /dev/null
+// 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.
+
+// Tests for OpExtension validator rules.
+
+#include <string>
+
+#include "gmock/gmock.h"
+#include "test_fixture.h"
+#include "unit_spirv.h"
+#include "val_fixtures.h"
+
+namespace {
+
+using ::testing::HasSubstr;
+using ::testing::Not;
+using ::testing::Values;
+
+using std::string;
+
+using ValidateKnownExtensions = spvtest::ValidateBase<string>;
+using ValidateUnknownExtensions = spvtest::ValidateBase<string>;
+
+// Returns expected error string if |extension| is not recognized.
+string GetErrorString(const std::string& extension) {
+ return "Failed to parse OpExtension " + extension;
+}
+
+INSTANTIATE_TEST_CASE_P(ExpectSuccess, ValidateKnownExtensions, Values(
+ "SPV_KHR_shader_ballot",
+ "SPV_KHR_shader_draw_parameters",
+ "SPV_KHR_subgroup_vote",
+ "SPV_KHR_16bit_storage",
+ "SPV_KHR_device_group",
+ "SPV_KHR_multiview",
+ "SPV_NV_sample_mask_override_coverage",
+ "SPV_NV_geometry_shader_passthrough",
+ "SPV_NV_viewport_array2",
+ "SPV_NV_stereo_view_rendering",
+ "SPV_NVX_multiview_per_view_attributes"
+ ));
+
+INSTANTIATE_TEST_CASE_P(FailSilently, ValidateUnknownExtensions, Values(
+ "ERROR_unknown_extension",
+ "SPV_KHR_",
+ "SPV_KHR_shader_ballot_ERROR"
+ ));
+
+TEST_P(ValidateKnownExtensions, ExpectSuccess) {
+ const std::string extension = GetParam();
+ const string str =
+ "OpCapability Shader\nOpCapability Linkage\nOpExtension \"" + extension +
+ "\"\nOpMemoryModel Logical GLSL450";
+ CompileSuccessfully(str.c_str());
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(), Not(HasSubstr(GetErrorString(extension))));
+}
+
+TEST_P(ValidateUnknownExtensions, FailSilently) {
+ const std::string extension = GetParam();
+ const string str =
+ "OpCapability Shader\nOpCapability Linkage\nOpExtension \"" + extension +
+ "\"\nOpMemoryModel Logical GLSL450";
+ CompileSuccessfully(str.c_str());
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(), HasSubstr(GetErrorString(extension)));
+}
+
+} // anonymous namespace