Adding decoration class and tests.

* Added the decoration class as well as the code that registers the
decorations for each <id> and also decorations for struct members.

* Added unit tests for decorations in ValidationState as well as
decoration id tests.
This commit is contained in:
Ehsan Nasiri 2017-01-11 10:51:23 -05:00 committed by David Neto
parent 1c11c8690f
commit fcf7df069d
9 changed files with 469 additions and 25 deletions

View File

@ -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

84
source/val/decoration.h Normal file
View File

@ -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 <unordered_map>
#include <vector>
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
// <id>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 <id>s (and they
// might be assigned using separate SPIR-V instructions, possibly using an
// assignment through GroupDecorate).
//
// Example 1: Decoration for an object<id> with no parameters:
// OpDecorate %obj Flat
// dec_type_ = SpvDecorationFlat
// params_ = empty vector
// struct_member_index_ = kInvalidMember
//
// Example 2: Decoration for an object<id> 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<uint32_t>& parameters = std::vector<uint32_t>(),
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<uint32_t>& 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<uint32_t> 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_

View File

@ -22,6 +22,7 @@
#include <vector>
#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 <id>
void RegisterDecorationForId(uint32_t id, const Decoration& dec) {
id_decorations_[id].push_back(dec);
}
/// Registers the list of decorations for the given <id>
template <class InputIt>
void RegisterDecorationsForId(uint32_t id, InputIt begin, InputIt end) {
std::vector<Decoration>& 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 <class InputIt>
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 <id>. If no decorations exist
/// for the <id>, it registers an empty vector for it in the map and
/// returns the empty vector.
std::vector<Decoration>& 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<uint32_t, uint32_t> struct_nesting_depth_;
/// Stores the list of decorations for a given <id>
std::unordered_map<uint32_t, std::vector<Decoration>> id_decorations_;
AssemblyGrammar grammar_;
SpvAddressingModel addressing_model_;

View File

@ -147,9 +147,12 @@ bool idUsage::isValid<SpvOpMemberDecorate>(const spv_instruction_t* inst,
auto member = inst->words[memberIndex];
auto memberCount = static_cast<uint32_t>(structType->words().size() - 2);
if (memberCount < member) {
DIAG(memberIndex) << "OpMemberDecorate Structure type <id> '"
<< inst->words[memberIndex]
<< "' member count is less than Member";
DIAG(memberIndex) << "Index " << member
<< " provided in OpMemberDecorate for struct <id> "
<< 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<SpvOpGroupDecorate>(const spv_instruction_t* inst,
return true;
}
#if 0
template <>
bool idUsage::isValid<SpvOpGroupMemberDecorate>(
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 <id> '"
<< 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 <id> '" << struct_id
<< "' is not a struct type.";
return false;
}
const uint32_t num_struct_members =
static_cast<uint32_t>(struct_instr->words().size() - 2);
if (index >= num_struct_members) {
DIAG(i) << "Index " << index
<< " provided in OpGroupMemberDecorate for struct <id> "
<< 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<SpvOpAccessChain>(const spv_instruction_t* inst,
const uint32_t num_struct_members =
static_cast<uint32_t>(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 <id> '" << typePointedTo->id()
<< "'. This structure has " << num_struct_members
@ -1651,7 +1684,7 @@ bool walkCompositeTypeHierarchy(
const uint32_t num_struct_members =
static_cast<uint32_t>(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 <id> '" << 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)

View File

@ -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<SpvDecoration>(inst->words[2]);
std::vector<uint32_t> 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<SpvDecoration>(inst->words[3]);
std::vector<uint32_t> 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 <id>. All subsequent words are target <id>s that
// are going to be decorated with the decorations.
const uint32_t decoration_group_id = inst->words[1];
std::vector<Decoration>& 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 <id> followed by (struct<id>,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<Decoration>& 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<SpvOp>(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 <id>.
RegisterDecorations(_, inst);
if (auto error = CapCheck(_, inst)) return error;
if (auto error = LimitCheckIdBound(_, inst)) return error;
if (auto error = LimitCheckStruct(_, inst)) return error;

View File

@ -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}
)

View File

@ -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<bool>;
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>{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>{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>{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>{
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>{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

View File

@ -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 <id> '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 <id> "
"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 <id> '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 <id> '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 <id> '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 "
"<id> 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 "
"<id> '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 <id> '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 <id> '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 <id> '26'. This structure "
"has 3 members. Largest valid index is 2."));
}
#if 0

View File

@ -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)))