From fcf7df069d9ed00c42e00ae2717107f9772cb426 Mon Sep 17 00:00:00 2001 From: Ehsan Nasiri Date: Wed, 11 Jan 2017 10:51:23 -0500 Subject: [PATCH] Adding decoration class and tests. * Added the decoration class as well as the code that registers the decorations for each and also decorations for struct members. * Added unit tests for decorations in ValidationState as well as decoration id tests. --- source/CMakeLists.txt | 1 + source/val/decoration.h | 84 +++++++++++++++++ source/val/validation_state.h | 35 ++++++++ source/validate_id.cpp | 51 +++++++++-- source/validate_instruction.cpp | 77 ++++++++++++++++ test/val/CMakeLists.txt | 6 ++ test/val/val_decoration_test.cpp | 150 +++++++++++++++++++++++++++++++ test/val/val_id_test.cpp | 86 +++++++++++++++--- utils/check_copyright.py | 4 +- 9 files changed, 469 insertions(+), 25 deletions(-) create mode 100644 source/val/decoration.h create mode 100644 test/val/val_decoration_test.cpp diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 67e712e29..24d412c8d 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -195,6 +195,7 @@ set(SPIRV_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/validate_instruction.cpp ${CMAKE_CURRENT_SOURCE_DIR}/validate_datarules.cpp ${CMAKE_CURRENT_SOURCE_DIR}/validate_layout.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/val/decoration.h ${CMAKE_CURRENT_SOURCE_DIR}/val/basic_block.cpp ${CMAKE_CURRENT_SOURCE_DIR}/val/construct.cpp ${CMAKE_CURRENT_SOURCE_DIR}/val/function.cpp diff --git a/source/val/decoration.h b/source/val/decoration.h new file mode 100644 index 000000000..161dada56 --- /dev/null +++ b/source/val/decoration.h @@ -0,0 +1,84 @@ +// 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_VAL_DECORATION_H_ +#define LIBSPIRV_VAL_DECORATION_H_ + +#include +#include + +namespace libspirv { + +// An object of this class represents a specific decoration including its +// parameters (if any). Decorations are used by OpDecorate and OpMemberDecorate, +// and they describe certain properties that can be assigned to one or several +// s. +// +// A Decoration object contains the decoration type (an enum), associated +// literal parameters, and struct member index. If the decoration does not apply +// to a struct member, then the index is kInvalidIndex. A Decoration object does +// not store the target Id, i.e. the Id to which it applies. It is +// possible for the same decoration to be applied to several s (and they +// might be assigned using separate SPIR-V instructions, possibly using an +// assignment through GroupDecorate). +// +// Example 1: Decoration for an object with no parameters: +// OpDecorate %obj Flat +// dec_type_ = SpvDecorationFlat +// params_ = empty vector +// struct_member_index_ = kInvalidMember +// +// Example 2: Decoration for an object with two parameters: +// OpDecorate %obj LinkageAttributes "link" Import +// dec_type_ = SpvDecorationLinkageAttributes +// params_ = vector { link, Import } +// struct_member_index_ = kInvalidMember +// +// Example 3: Decoration for a member of a structure with one parameter: +// OpMemberDecorate %struct 2 Offset 2 +// dec_type_ = SpvDecorationOffset +// params_ = vector { 2 } +// struct_member_index_ = 2 +// +class Decoration { + public: + enum { kInvalidMember = -1 }; + Decoration(SpvDecoration t, + const std::vector& parameters = std::vector(), + uint32_t member_index = kInvalidMember) + : dec_type_(t), params_(parameters), struct_member_index_(member_index) {} + + void set_struct_member_index(uint32_t index) { struct_member_index_ = index; } + int struct_member_index() { return struct_member_index_; } + SpvDecoration dec_type() { return dec_type_; } + std::vector& params() { return params_; } + + inline bool operator==(const Decoration& rhs) const { + return (dec_type_ == rhs.dec_type_ && params_ == rhs.params_ && + struct_member_index_ == rhs.struct_member_index_); + } + + private: + SpvDecoration dec_type_; + std::vector params_; + + // If the decoration applies to a member of a structure type, then the index + // of the member is stored here. Otherwise, this is kInvalidIndex. + int struct_member_index_; +}; + +} // namespace libspirv + +#endif /// LIBSPIRV_VAL_DECORATION_H_ + diff --git a/source/val/validation_state.h b/source/val/validation_state.h index a4a414065..5bdcac225 100644 --- a/source/val/validation_state.h +++ b/source/val/validation_state.h @@ -22,6 +22,7 @@ #include #include "assembly_grammar.h" +#include "decoration.h" #include "diagnostic.h" #include "enum_set.h" #include "spirv-tools/libspirv.h" @@ -177,6 +178,37 @@ class ValidationState_t { /// Registers the instruction void RegisterInstruction(const spv_parsed_instruction_t& inst); + /// Registers the decoration for the given + void RegisterDecorationForId(uint32_t id, const Decoration& dec) { + id_decorations_[id].push_back(dec); + } + + /// Registers the list of decorations for the given + template + void RegisterDecorationsForId(uint32_t id, InputIt begin, InputIt end) { + std::vector& cur_decs = id_decorations_[id]; + cur_decs.insert(cur_decs.end(), begin, end); + } + + /// Registers the list of decorations for the given member of the given + /// structure. + template + void RegisterDecorationsForStructMember(uint32_t struct_id, + uint32_t member_index, InputIt begin, + InputIt end) { + RegisterDecorationsForId(struct_id, begin, end); + for (auto& decoration : id_decorations_[struct_id]) { + decoration.set_struct_member_index(member_index); + } + } + + /// Returns all the decorations for the given . If no decorations exist + /// for the , it registers an empty vector for it in the map and + /// returns the empty vector. + std::vector& id_decorations(uint32_t id) { + return id_decorations_[id]; + } + /// Finds id's def, if it exists. If found, returns the definition otherwise /// nullptr const Instruction* FindDef(uint32_t id) const; @@ -280,6 +312,9 @@ class ValidationState_t { /// Structure Nesting Depth std::unordered_map struct_nesting_depth_; + /// Stores the list of decorations for a given + std::unordered_map> id_decorations_; + AssemblyGrammar grammar_; SpvAddressingModel addressing_model_; diff --git a/source/validate_id.cpp b/source/validate_id.cpp index 34a5b7a87..0e1c745fb 100644 --- a/source/validate_id.cpp +++ b/source/validate_id.cpp @@ -147,9 +147,12 @@ bool idUsage::isValid(const spv_instruction_t* inst, auto member = inst->words[memberIndex]; auto memberCount = static_cast(structType->words().size() - 2); if (memberCount < member) { - DIAG(memberIndex) << "OpMemberDecorate Structure type '" - << inst->words[memberIndex] - << "' member count is less than Member"; + DIAG(memberIndex) << "Index " << member + << " provided in OpMemberDecorate for struct " + << inst->words[structTypeIndex] + << " is out of bounds. The structure has " << memberCount + << " members. Largest valid index is " << memberCount - 1 + << "."; return false; } return true; @@ -169,11 +172,41 @@ bool idUsage::isValid(const spv_instruction_t* inst, return true; } -#if 0 template <> bool idUsage::isValid( - const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} -#endif // 0 + const spv_instruction_t* inst, const spv_opcode_desc) { + auto decorationGroupIndex = 1; + auto decorationGroup = module_.FindDef(inst->words[decorationGroupIndex]); + if (!decorationGroup || SpvOpDecorationGroup != decorationGroup->opcode()) { + DIAG(decorationGroupIndex) + << "OpGroupMemberDecorate Decoration group '" + << inst->words[decorationGroupIndex] << "' is not a decoration group."; + return false; + } + // Grammar checks ensures that the number of arguments to this instruction + // is an odd number: 1 decoration group + (id,literal) pairs. + for (size_t i = 2; i + 1 < inst->words.size(); i = i + 2) { + const uint32_t struct_id = inst->words[i]; + const uint32_t index = inst->words[i + 1]; + auto struct_instr = module_.FindDef(struct_id); + if (!struct_instr || SpvOpTypeStruct != struct_instr->opcode()) { + DIAG(i) << "OpGroupMemberDecorate Structure type '" << struct_id + << "' is not a struct type."; + return false; + } + const uint32_t num_struct_members = + static_cast(struct_instr->words().size() - 2); + if (index >= num_struct_members) { + DIAG(i) << "Index " << index + << " provided in OpGroupMemberDecorate for struct " + << struct_id << " is out of bounds. The structure has " + << num_struct_members << " members. Largest valid index is " + << num_struct_members - 1 << "."; + return false; + } + } + return true; +} #if 0 template <> @@ -1302,7 +1335,7 @@ bool idUsage::isValid(const spv_instruction_t* inst, const uint32_t num_struct_members = static_cast(typePointedTo->words().size() - 2); if (cur_index >= num_struct_members) { - DIAG(i) << "Index is out of bound: " << instr_name + DIAG(i) << "Index is out of bounds: " << instr_name << " can not find index " << cur_index << " into the structure '" << typePointedTo->id() << "'. This structure has " << num_struct_members @@ -1651,7 +1684,7 @@ bool walkCompositeTypeHierarchy( const uint32_t num_struct_members = static_cast(cur_type->words().size() - 2); if (cur_index >= num_struct_members) { - *error << "Index is out of bound: " << instr_name() + *error << "Index is out of bounds: " << instr_name() << " can not find index " << cur_index << " into the structure '" << cur_type->id() << "'. This structure has " << num_struct_members @@ -2752,7 +2785,7 @@ bool idUsage::isValid(const spv_instruction_t* inst) { CASE(OpLine) CASE(OpMemberDecorate) CASE(OpGroupDecorate) - TODO(OpGroupMemberDecorate) + CASE(OpGroupMemberDecorate) TODO(OpExtInst) CASE(OpEntryPoint) CASE(OpExecutionMode) diff --git a/source/validate_instruction.cpp b/source/validate_instruction.cpp index 507d07304..9343f6729 100644 --- a/source/validate_instruction.cpp +++ b/source/validate_instruction.cpp @@ -233,6 +233,79 @@ spv_result_t LimitCheckNumVars(ValidationState_t& _, return SPV_SUCCESS; } +// Registers necessary decoration(s) for the appropriate IDs based on the +// instruction. +spv_result_t RegisterDecorations(ValidationState_t& _, + const spv_parsed_instruction_t* inst) { + switch (inst->opcode) { + case SpvOpDecorate: { + const uint32_t target_id = inst->words[1]; + const SpvDecoration dec_type = static_cast(inst->words[2]); + std::vector dec_params; + if (inst->num_words > 3) { + dec_params.insert(dec_params.end(), inst->words + 3, + inst->words + inst->num_words); + } + _.RegisterDecorationForId(target_id, Decoration(dec_type, dec_params)); + break; + } + case SpvOpMemberDecorate: { + const uint32_t struct_id = inst->words[1]; + const uint32_t index = inst->words[2]; + const SpvDecoration dec_type = static_cast(inst->words[3]); + std::vector dec_params; + if (inst->num_words > 4) { + dec_params.insert(dec_params.end(), inst->words + 4, + inst->words + inst->num_words); + } + _.RegisterDecorationForId(struct_id, + Decoration(dec_type, dec_params, index)); + break; + } + case SpvOpDecorationGroup: { + // We don't need to do anything right now. Assigning decorations to groups + // will be taken care of via OpGroupDecorate. + break; + } + case SpvOpGroupDecorate: { + // Word 1 is the group . All subsequent words are target s that + // are going to be decorated with the decorations. + const uint32_t decoration_group_id = inst->words[1]; + std::vector& group_decorations = + _.id_decorations(decoration_group_id); + for (int i = 2; i < inst->num_words; ++i) { + const uint32_t target_id = inst->words[i]; + _.RegisterDecorationsForId(target_id, group_decorations.begin(), + group_decorations.end()); + } + break; + } + case SpvOpGroupMemberDecorate: { + // Word 1 is the Decoration Group followed by (struct,literal) + // pairs. All decorations of the group should be applied to all the struct + // members that are specified in the instructions. + const uint32_t decoration_group_id = inst->words[1]; + std::vector& group_decorations = + _.id_decorations(decoration_group_id); + // Grammar checks ensures that the number of arguments to this instruction + // is an odd number: 1 decoration group + (id,literal) pairs. + for (int i = 2; i + 1 < inst->num_words; i = i + 2) { + const uint32_t struct_id = inst->words[i]; + const uint32_t index = inst->words[i + 1]; + // ID validation phase ensures this is in fact a struct instruction and + // that the index is not out of bound. + _.RegisterDecorationsForStructMember(struct_id, index, + group_decorations.begin(), + group_decorations.end()); + } + break; + } + default: + break; + } + return SPV_SUCCESS; +} + spv_result_t InstructionPass(ValidationState_t& _, const spv_parsed_instruction_t* inst) { const SpvOp opcode = static_cast(inst->opcode); @@ -275,6 +348,10 @@ spv_result_t InstructionPass(ValidationState_t& _, } } + // In order to validate decoration rules, we need to know all the decorations + // that are applied to any given . + RegisterDecorations(_, inst); + if (auto error = CapCheck(_, inst)) return error; if (auto error = LimitCheckIdBound(_, inst)) return error; if (auto error = LimitCheckStruct(_, inst)) return error; diff --git a/test/val/CMakeLists.txt b/test/val/CMakeLists.txt index 1e4becdd6..80b02601e 100644 --- a/test/val/CMakeLists.txt +++ b/test/val/CMakeLists.txt @@ -81,3 +81,9 @@ add_spvtools_unittest(TARGET val_validation_state LIBS ${SPIRV_TOOLS} ) +add_spvtools_unittest(TARGET val_decoration + SRCS val_decoration_test.cpp + ${VAL_TEST_COMMON_SRCS} + LIBS ${SPIRV_TOOLS} +) + diff --git a/test/val/val_decoration_test.cpp b/test/val/val_decoration_test.cpp new file mode 100644 index 000000000..9fce5ae64 --- /dev/null +++ b/test/val/val_decoration_test.cpp @@ -0,0 +1,150 @@ +// 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. + +// Common validation fixtures for unit tests + +#include "gmock/gmock.h" +#include "unit_spirv.h" +#include "val_fixtures.h" +#include "source/val/decoration.h" + +namespace { + +using std::string; +using std::vector; +using ::testing::HasSubstr; +using ::testing::Eq; +using libspirv::Decoration; + +using ValidateDecorations = spvtest::ValidateBase; + +TEST_F(ValidateDecorations, ValidateOpDecorateRegistration) { + string spirv = R"( + OpCapability Shader + OpCapability Linkage + OpMemoryModel Logical GLSL450 + OpDecorate %1 ArrayStride 4 + OpDecorate %1 Uniform + %2 = OpTypeFloat 32 + %1 = OpTypeRuntimeArray %2 + ; Since %1 is used first in Decoration, it gets id 1. +)"; + const uint32_t id = 1; + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState()); + // Must have 2 decorations. + EXPECT_THAT(vstate_->id_decorations(id), + Eq(vector{Decoration(SpvDecorationArrayStride, {4}), + Decoration(SpvDecorationUniform)})); +} + +TEST_F(ValidateDecorations, ValidateOpMemberDecorateRegistration) { + string spirv = R"( + OpCapability Shader + OpCapability Linkage + OpMemoryModel Logical GLSL450 + OpDecorate %_arr_double_uint_6 ArrayStride 4 + OpMemberDecorate %_struct_115 2 NonReadable + OpMemberDecorate %_struct_115 2 Offset 2 + OpDecorate %_struct_115 BufferBlock + %float = OpTypeFloat 32 + %uint = OpTypeInt 32 0 + %uint_6 = OpConstant %uint 6 + %_arr_double_uint_6 = OpTypeArray %float %uint_6 + %_struct_115 = OpTypeStruct %float %float %_arr_double_uint_6 +)"; + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState()); + + // The array must have 1 decoration. + const uint32_t arr_id = 1; + EXPECT_THAT( + vstate_->id_decorations(arr_id), + Eq(vector{Decoration(SpvDecorationArrayStride, {4})})); + + // The struct must have 3 decorations. + const uint32_t struct_id = 2; + EXPECT_THAT(vstate_->id_decorations(struct_id), + Eq(vector{Decoration(SpvDecorationNonReadable, {}, 2), + Decoration(SpvDecorationOffset, {2}, 2), + Decoration(SpvDecorationBufferBlock)})); +} + +TEST_F(ValidateDecorations, ValidateGroupDecorateRegistration) { + string spirv = R"( + OpCapability Shader + OpCapability Linkage + OpMemoryModel Logical GLSL450 + OpDecorate %1 DescriptorSet 0 + OpDecorate %1 NonWritable + OpDecorate %1 Restrict + %1 = OpDecorationGroup + OpGroupDecorate %1 %2 %3 + OpGroupDecorate %1 %4 + %float = OpTypeFloat 32 +%_runtimearr_float = OpTypeRuntimeArray %float + %_struct_9 = OpTypeStruct %_runtimearr_float +%_ptr_Uniform__struct_9 = OpTypePointer Uniform %_struct_9 + %2 = OpVariable %_ptr_Uniform__struct_9 Uniform + %_struct_10 = OpTypeStruct %_runtimearr_float +%_ptr_Uniform__struct_10 = OpTypePointer Uniform %_struct_10 + %3 = OpVariable %_ptr_Uniform__struct_10 Uniform + %_struct_11 = OpTypeStruct %_runtimearr_float +%_ptr_Uniform__struct_11 = OpTypePointer Uniform %_struct_11 + %4 = OpVariable %_ptr_Uniform__struct_11 Uniform + )"; + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState()); + + // Decoration group has 3 decorations. + auto expected_decorations = vector{ + Decoration(SpvDecorationDescriptorSet, {0}), + Decoration(SpvDecorationNonWritable), Decoration(SpvDecorationRestrict)}; + + // Decoration group is applied to id 1, 2, 3, and 4. Note that id 1 (which is + // the decoration group id) also has all the decorations. + EXPECT_THAT(vstate_->id_decorations(1), Eq(expected_decorations)); + EXPECT_THAT(vstate_->id_decorations(2), Eq(expected_decorations)); + EXPECT_THAT(vstate_->id_decorations(3), Eq(expected_decorations)); + EXPECT_THAT(vstate_->id_decorations(4), Eq(expected_decorations)); +} + +TEST_F(ValidateDecorations, ValidateGroupMemberDecorateRegistration) { + string spirv = R"( + OpCapability Shader + OpCapability Linkage + OpMemoryModel Logical GLSL450 + OpDecorate %1 Offset 3 + %1 = OpDecorationGroup + OpGroupMemberDecorate %1 %_struct_1 3 %_struct_2 3 %_struct_3 3 + %float = OpTypeFloat 32 +%_runtimearr = OpTypeRuntimeArray %float + %_struct_1 = OpTypeStruct %float %float %float %_runtimearr + %_struct_2 = OpTypeStruct %float %float %float %_runtimearr + %_struct_3 = OpTypeStruct %float %float %float %_runtimearr + )"; + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState()); + // Decoration group has 1 decoration. + auto expected_decorations = + vector{Decoration(SpvDecorationOffset, {3}, 3)}; + + // Decoration group is applied to id 2, 3, and 4. + EXPECT_THAT(vstate_->id_decorations(2), Eq(expected_decorations)); + EXPECT_THAT(vstate_->id_decorations(3), Eq(expected_decorations)); + EXPECT_THAT(vstate_->id_decorations(4), Eq(expected_decorations)); +} + +} // anonymous namespace + diff --git a/test/val/val_id_test.cpp b/test/val/val_id_test.cpp index 9d583742f..94b7cdb5b 100644 --- a/test/val/val_id_test.cpp +++ b/test/val/val_id_test.cpp @@ -163,6 +163,8 @@ TEST_F(ValidateIdWithMessage, OpDecorateBad) { OpDecorate %1 GLSLShared)"; CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("forward referenced IDs have not been defined")); } TEST_F(ValidateIdWithMessage, OpMemberDecorateGood) { @@ -179,14 +181,22 @@ TEST_F(ValidateIdWithMessage, OpMemberDecorateBad) { %1 = OpTypeInt 32 0)"; CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "OpMemberDecorate Structure type '1' is not a struct type.")); } TEST_F(ValidateIdWithMessage, OpMemberDecorateMemberBad) { string spirv = kGLSL450MemoryModel + R"( - OpMemberDecorate %2 3 Uniform -%1 = OpTypeInt 32 0 -%2 = OpTypeStruct %1 %1)"; + OpMemberDecorate %1 3 Uniform +%int = OpTypeInt 32 0 +%1 = OpTypeStruct %int %int)"; CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Index 3 provided in OpMemberDecorate for struct " + "1 is out of bounds. The structure has 2 members. " + "Largest valid index is 1.")); } TEST_F(ValidateIdWithMessage, OpGroupDecorateGood) { @@ -202,13 +212,19 @@ TEST_F(ValidateIdWithMessage, OpGroupDecorateGood) { EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_F(ValidateIdWithMessage, OpGroupDecorateDecorationGroupBad) { - string spirv = kGLSL450MemoryModel + R"( - OpGroupDecorate %2 %3 %4 + string spirv = R"( + OpCapability Shader + OpCapability Linkage + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpGroupDecorate %1 %2 %3 %2 = OpTypeInt 32 0 -%3 = OpConstant %2 42 -%4 = OpConstant %2 23)"; +%3 = OpConstant %2 42)"; CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpGroupDecorate Decoration group '1' is not a " + "decoration group.")); } TEST_F(ValidateIdWithMessage, OpGroupDecorateTargetBad) { string spirv = kGLSL450MemoryModel + R"( @@ -219,9 +235,50 @@ TEST_F(ValidateIdWithMessage, OpGroupDecorateTargetBad) { %2 = OpTypeInt 32 0)"; CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("forward referenced IDs have not been defined")); +} +TEST_F(ValidateIdWithMessage, OpGroupMemberDecorateDecorationGroupBad) { + string spirv = R"( + OpCapability Shader + OpCapability Linkage + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpGroupMemberDecorate %1 %2 0 +%2 = OpTypeInt 32 0)"; + CompileSuccessfully(spirv.c_str()); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpGroupMemberDecorate Decoration group '1' is " + "not a decoration group.")); +} +TEST_F(ValidateIdWithMessage, OpGroupMemberDecorateIdNotStructBad) { + string spirv = kGLSL450MemoryModel + R"( + %1 = OpDecorationGroup + OpGroupMemberDecorate %1 %2 0 +%2 = OpTypeInt 32 0)"; + CompileSuccessfully(spirv.c_str()); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpGroupMemberDecorate Structure type '2' is not " + "a struct type.")); +} +TEST_F(ValidateIdWithMessage, OpGroupMemberDecorateIndexOutOfBoundBad) { + string spirv = kGLSL450MemoryModel + R"( + OpDecorate %1 Offset 0 + %1 = OpDecorationGroup + OpGroupMemberDecorate %1 %struct 3 +%float = OpTypeFloat 32 +%struct = OpTypeStruct %float %float %float +)"; + CompileSuccessfully(spirv.c_str()); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Index 3 provided in OpGroupMemberDecorate for struct " + " 2 is out of bounds. The structure has 3 members. " + "Largest valid index is 2.")); } -// TODO: OpGroupMemberDecorate // TODO: OpExtInst TEST_F(ValidateIdWithMessage, OpEntryPointGood) { @@ -2179,7 +2236,7 @@ TEST_P(AccessChainInstructionTest, AccessChainStructIndexOutOfBoundBad) { OpReturn OpFunctionEnd )"; - const std::string expected_err = "Index is out of bound: " + instr + + const std::string expected_err = "Index is out of bounds: " + instr + " can not find index 3 into the structure " " '26'. This structure has 3 members. " "Largest valid index is 2."; @@ -2828,7 +2885,7 @@ TEST_F(ValidateIdWithMessage, CompositeExtractStructIndexOutOfBoundBad) { CompileSuccessfully(spirv.str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("Index is out of bound: OpCompositeExtract can not " + HasSubstr("Index is out of bounds: OpCompositeExtract can not " "find index 3 into the structure '26'. This " "structure has 3 members. Largest valid index is 2.")); } @@ -2847,10 +2904,11 @@ TEST_F(ValidateIdWithMessage, CompositeInsertStructIndexOutOfBoundBad) { CompileSuccessfully(spirv.str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Index is out of bound: OpCompositeInsert can not find " - "index 3 into the structure '26'. This structure " - "has 3 members. Largest valid index is 2.")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Index is out of bounds: OpCompositeInsert can not find " + "index 3 into the structure '26'. This structure " + "has 3 members. Largest valid index is 2.")); } #if 0 diff --git a/utils/check_copyright.py b/utils/check_copyright.py index c6fb5e83d..08fb08288 100755 --- a/utils/check_copyright.py +++ b/utils/check_copyright.py @@ -30,9 +30,9 @@ import sys AUTHORS = ['The Khronos Group Inc.', 'LunarG Inc.', 'Google Inc.'] -CURRENT_YEAR='2016' +CURRENT_YEAR='2017' -YEARS = '(2014-2016|2015-2016|2016)' +YEARS = '(2014-2016|2015-2016|2016|2016-2017|2017)' COPYRIGHT_RE = re.compile( 'Copyright \(c\) {} ({})'.format(YEARS, '|'.join(AUTHORS)))