mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2025-01-12 09:20:15 +00:00
Add primitive instruction validation pass
This commit is contained in:
parent
af7d5799a5
commit
cdfbf26c13
@ -48,6 +48,7 @@ SPVTOOLS_SRC_FILES := \
|
||||
source/validate_instruction.cpp \
|
||||
source/validate_layout.cpp \
|
||||
source/validate_logicals.cpp \
|
||||
source/validate_primitives.cpp \
|
||||
source/validate_type_unique.cpp
|
||||
|
||||
SPVTOOLS_OPT_SRC_FILES := \
|
||||
|
@ -271,6 +271,7 @@ set(SPIRV_SOURCES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/validate_instruction.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/validate_layout.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/validate_logicals.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/validate_primitives.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/validate_type_unique.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/val/decoration.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/val/basic_block.cpp
|
||||
|
@ -187,6 +187,7 @@ spv_result_t ProcessInstruction(void* user_data,
|
||||
if (auto error = BitwisePass(_, inst)) return error;
|
||||
if (auto error = ImagePass(_, inst)) return error;
|
||||
if (auto error = AtomicsPass(_, inst)) return error;
|
||||
if (auto error = PrimitivesPass(_, inst)) return error;
|
||||
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
@ -148,6 +148,10 @@ spv_result_t AtomicsPass(ValidationState_t& _,
|
||||
spv_result_t CapabilityPass(ValidationState_t& _,
|
||||
const spv_parsed_instruction_t* inst);
|
||||
|
||||
/// Validates correctness of primitive instructions.
|
||||
spv_result_t PrimitivesPass(ValidationState_t& _,
|
||||
const spv_parsed_instruction_t* inst);
|
||||
|
||||
} // namespace libspirv
|
||||
|
||||
/// @brief Validate the ID usage of the instruction stream
|
||||
|
57
source/validate_primitives.cpp
Normal file
57
source/validate_primitives.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
// Copyright (c) 2017 LunarG 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.
|
||||
|
||||
// Validates correctness of primitive SPIR-V instructions.
|
||||
|
||||
#include "validate.h"
|
||||
|
||||
#include "diagnostic.h"
|
||||
#include "opcode.h"
|
||||
#include "val/instruction.h"
|
||||
#include "val/validation_state.h"
|
||||
|
||||
namespace libspirv {
|
||||
|
||||
// Validates correctness of composite instructions.
|
||||
spv_result_t PrimitivesPass(ValidationState_t& _,
|
||||
const spv_parsed_instruction_t* inst) {
|
||||
const SpvOp opcode = static_cast<SpvOp>(inst->opcode);
|
||||
|
||||
switch (opcode) {
|
||||
case SpvOpEmitStreamVertex:
|
||||
case SpvOpEndStreamPrimitive: {
|
||||
const uint32_t stream_type = _.GetOperandTypeId(inst, 0);
|
||||
if (!_.IsIntScalarType(stream_type)) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA)
|
||||
<< spvOpcodeString(opcode)
|
||||
<< ": expected Stream to be int scalar";
|
||||
}
|
||||
|
||||
const uint32_t stream_id = inst->words[1];
|
||||
const SpvOp stream_opcode = _.GetIdOpcode(stream_id);
|
||||
if (!spvOpcodeIsConstant(stream_opcode)) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA)
|
||||
<< spvOpcodeString(opcode)
|
||||
<< ": expected Stream to be constant instruction";
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
} // namespace libspirv
|
@ -122,6 +122,12 @@ add_spvtools_unittest(TARGET val_atomics
|
||||
LIBS ${SPIRV_TOOLS}
|
||||
)
|
||||
|
||||
add_spvtools_unittest(TARGET val_primitives
|
||||
SRCS val_primitives_test.cpp
|
||||
${VAL_TEST_COMMON_SRCS}
|
||||
LIBS ${SPIRV_TOOLS}
|
||||
)
|
||||
|
||||
add_spvtools_unittest(TARGET val_limits
|
||||
SRCS val_limits_test.cpp
|
||||
${VAL_TEST_COMMON_SRCS}
|
||||
|
162
test/val/val_primitives_test.cpp
Normal file
162
test/val/val_primitives_test.cpp
Normal file
@ -0,0 +1,162 @@
|
||||
// Copyright (c) 2017 LunarG 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 <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "unit_spirv.h"
|
||||
#include "val_fixtures.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using ::testing::HasSubstr;
|
||||
using ::testing::Not;
|
||||
|
||||
using ValidatePrimitives = spvtest::ValidateBase<bool>;
|
||||
|
||||
std::string GenerateShaderCode(
|
||||
const std::string& body,
|
||||
const std::string& capabilities_and_extensions = "",
|
||||
const std::string& execution_model = "Geometry") {
|
||||
std::ostringstream ss;
|
||||
ss << R"(
|
||||
OpCapability Geometry
|
||||
OpCapability GeometryStreams
|
||||
)";
|
||||
|
||||
ss << capabilities_and_extensions;
|
||||
ss << "OpMemoryModel Logical GLSL450\n";
|
||||
ss << "OpEntryPoint " << execution_model << " %main \"main\"\n";
|
||||
|
||||
ss << R"(
|
||||
%void = OpTypeVoid
|
||||
%func = OpTypeFunction %void
|
||||
%f32 = OpTypeFloat 32
|
||||
%u32 = OpTypeInt 32 0
|
||||
%u32vec4 = OpTypeVector %u32 4
|
||||
|
||||
%f32_0 = OpConstant %f32 0
|
||||
%u32_0 = OpConstant %u32 0
|
||||
%u32_1 = OpConstant %u32 1
|
||||
%u32_2 = OpConstant %u32 2
|
||||
%u32_3 = OpConstant %u32 3
|
||||
%u32vec4_0123 = OpConstantComposite %u32vec4 %u32_0 %u32_1 %u32_2 %u32_3
|
||||
|
||||
%main = OpFunction %void None %func
|
||||
%main_entry = OpLabel
|
||||
)";
|
||||
|
||||
ss << body;
|
||||
|
||||
ss << R"(
|
||||
OpReturn
|
||||
OpFunctionEnd)";
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
TEST_F(ValidatePrimitives, EmitStreamVertexSuccess) {
|
||||
const std::string body = R"(
|
||||
OpEmitStreamVertex %u32_0
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
}
|
||||
|
||||
TEST_F(ValidatePrimitives, EmitStreamVertexNonInt) {
|
||||
const std::string body = R"(
|
||||
OpEmitStreamVertex %f32_0
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("EmitStreamVertex: "
|
||||
"expected Stream to be int scalar"));
|
||||
}
|
||||
|
||||
TEST_F(ValidatePrimitives, EmitStreamVertexNonScalar) {
|
||||
const std::string body = R"(
|
||||
OpEmitStreamVertex %u32vec4_0123
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("EmitStreamVertex: "
|
||||
"expected Stream to be int scalar"));
|
||||
}
|
||||
|
||||
TEST_F(ValidatePrimitives, EmitStreamVertexNonConstant) {
|
||||
const std::string body = R"(
|
||||
%val1 = OpIAdd %u32 %u32_0 %u32_1
|
||||
OpEmitStreamVertex %val1
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("EmitStreamVertex: "
|
||||
"expected Stream to be constant instruction"));
|
||||
}
|
||||
|
||||
TEST_F(ValidatePrimitives, EndStreamPrimitiveSuccess) {
|
||||
const std::string body = R"(
|
||||
OpEndStreamPrimitive %u32_0
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||
}
|
||||
|
||||
TEST_F(ValidatePrimitives, EndStreamPrimitiveNonInt) {
|
||||
const std::string body = R"(
|
||||
OpEndStreamPrimitive %f32_0
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("EndStreamPrimitive: "
|
||||
"expected Stream to be int scalar"));
|
||||
}
|
||||
|
||||
TEST_F(ValidatePrimitives, EndStreamPrimitiveNonScalar) {
|
||||
const std::string body = R"(
|
||||
OpEndStreamPrimitive %u32vec4_0123
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("EndStreamPrimitive: "
|
||||
"expected Stream to be int scalar"));
|
||||
}
|
||||
|
||||
TEST_F(ValidatePrimitives, EndStreamPrimitiveNonConstant) {
|
||||
const std::string body = R"(
|
||||
%val1 = OpIAdd %u32 %u32_0 %u32_1
|
||||
OpEndStreamPrimitive %val1
|
||||
)";
|
||||
|
||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("EndStreamPrimitive: "
|
||||
"expected Stream to be constant instruction"));
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
Loading…
Reference in New Issue
Block a user