mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-11-22 11:40:05 +00:00
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:
parent
1c11c8690f
commit
fcf7df069d
@ -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
84
source/val/decoration.h
Normal 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_
|
||||
|
@ -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_;
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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}
|
||||
)
|
||||
|
||||
|
150
test/val/val_decoration_test.cpp
Normal file
150
test/val/val_decoration_test.cpp
Normal 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
|
||||
|
@ -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
|
||||
|
@ -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)))
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user