blob: 72bbde8760f41a5f797ee6a1574fe945baaa7afd [file] [log] [blame] [edit]
// Copyright (c) 2023-2025 Arm Ltd.
//
// 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 "gmock/gmock.h"
#include "test/unit_spirv.h"
#include "test/val/val_fixtures.h"
// TODO(kpet) Tests with spec constants
namespace spvtools {
namespace val {
namespace {
using ::testing::ContainsRegex;
using ::testing::HasSubstr;
using ValidateGraph = spvtest::ValidateBase<std::string>;
constexpr spv_target_env SPVENV = SPV_ENV_VULKAN_1_3;
std::string GenerateModule(const std::string& src) {
const std::string boilerplate = R"(
OpCapability Shader
OpCapability VulkanMemoryModel
OpCapability Int8
OpCapability GraphARM
OpCapability TensorsARM
OpCapability RuntimeDescriptorArray
OpExtension "SPV_ARM_graph"
OpExtension "SPV_ARM_tensors"
OpMemoryModel Logical Vulkan
OpDecorate %var_int8tensor DescriptorSet 0
OpDecorate %var_int8tensor Binding 0
OpDecorate %var_int32tensor DescriptorSet 0
OpDecorate %var_int32tensor Binding 1
OpDecorate %var_int8tensor_array3 DescriptorSet 0
OpDecorate %var_int8tensor_array3 Binding 2
OpDecorate %var_int8tensor_runtime_array DescriptorSet 0
OpDecorate %var_int8tensor_runtime_array Binding 3
%void = OpTypeVoid
%uint = OpTypeInt 32 0
%int8 = OpTypeInt 8 1
%int32 = OpTypeInt 32 1
%float = OpTypeFloat 32
%uint_0 = OpConstant %uint 0
%uint_1 = OpConstant %uint 1
%uint_2 = OpConstant %uint 2
%uint_3 = OpConstant %uint 3
%uint_4 = OpConstant %uint 4
%float_1 = OpConstant %float 1.0
%int8tensor = OpTypeTensorARM %int8 %uint_4
%int8r3tensor = OpTypeTensorARM %int8 %uint_3
%int32tensor = OpTypeTensorARM %int32 %uint_4
%int8tensor_array3 = OpTypeArray %int8tensor %uint_3
%int32tensor_array3 = OpTypeArray %int32tensor %uint_3
%int8tensor_runtime_array = OpTypeRuntimeArray %int8tensor
%int32tensor_runtime_array = OpTypeRuntimeArray %int32tensor
%ptr_Input_int8tensor = OpTypePointer Input %int8tensor
%var_int8tensor_wrong_storage_class = OpVariable %ptr_Input_int8tensor Input
%ptr_UniformConstant_int8tensor = OpTypePointer UniformConstant %int8tensor
%ptr_UniformConstant_int32tensor = OpTypePointer UniformConstant %int32tensor
%ptr_UniformConstant_int8tensor_array3 = OpTypePointer UniformConstant %int8tensor_array3
%ptr_UniformConstant_int8tensor_runtime_array = OpTypePointer UniformConstant %int8tensor_runtime_array
%var_int8tensor = OpVariable %ptr_UniformConstant_int8tensor UniformConstant
%var_int32tensor = OpVariable %ptr_UniformConstant_int32tensor UniformConstant
%var_int8tensor_array3 = OpVariable %ptr_UniformConstant_int8tensor_array3 UniformConstant
%var_int8tensor_runtime_array = OpVariable %ptr_UniformConstant_int8tensor_runtime_array UniformConstant
)";
return boilerplate + src;
}
std::string GenerateModuleWithGraphEntryPoint(const std::string& header) {
const std::string src = R"(
%default_graph_type = OpTypeGraphARM 1 %int8tensor %int8tensor
OpGraphEntryPointARM %default_graph "default_entry_point" %var_int8tensor %var_int8tensor
%default_graph = OpGraphARM %default_graph_type
%in = OpGraphInputARM %int8tensor %uint_0
OpGraphSetOutputARM %in %uint_0
OpGraphEndARM
)";
return GenerateModule(header) + src;
}
//
// Layout tests
//
TEST_F(ValidateGraph, InvalidNoGraphEntryPoint) {
std::string spvasm = GenerateModule("");
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions(SPVENV));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("No OpGraphEntryPointARM instruction was found but the "
"GraphARM capability is declared."));
}
TEST_F(ValidateGraph, InvalidGraphInGraph) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor %int8tensor
%graph = OpGraphARM %graph_type
%graph2 = OpGraphARM %graph_type
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions(SPVENV));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Cannot define a graph in a graph"));
}
TEST_F(ValidateGraph, InvalidGraphEndOutsideGraph) {
const std::string src = R"(
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions(SPVENV));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("GraphEndARM must be preceded by at least one "
"OpGraphSetOutputARM instruction"));
}
TEST_F(ValidateGraph, InvalidGraphEntryPointInsideGraph) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor %int8tensor
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor %uint_0
OpGraphEntryPointARM %graph "main" %in %in
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions(SPVENV));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
"GraphEntryPointARM cannot appear in the definition of a graph"));
}
TEST_F(ValidateGraph, InvalidNonGraphInstructionInGraphSection) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor %int8tensor
%ftype = OpTypeFunction %void %void
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor %uint_0
OpGraphSetOutputARM %in %uint_0
OpGraphEndARM
%fn = OpFunction %void None %ftype
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions(SPVENV));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("Function cannot appear in the graph definitions section"));
}
TEST_F(ValidateGraph, InvalidGraphInputOusideGraph) {
const std::string src = R"(
%in = OpGraphInputARM %int8tensor %uint_0
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions(SPVENV));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("OpGraphInputARM must immediately follow an OpGraphARM "
"or OpGraphInputARM instruction."));
}
TEST_F(ValidateGraph, InvalidGraphSetOutputsOusideGraph) {
const std::string src = R"(
OpGraphSetOutputARM %uint_0 %uint_0
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions(SPVENV));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("OpGraphSetOutputARM must immediately precede an "
"OpGraphEndARM or OpGraphSetOutputARM instruction"));
}
TEST_F(ValidateGraph, ValidGraphConstantOusideGraph) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor %int8tensor
%cst = OpGraphConstantARM %int8tensor 1
OpGraphEntryPointARM %graph "longname" %var_int8tensor %var_int8tensor
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor %uint_0
OpGraphSetOutputARM %in %uint_0
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPVENV));
}
TEST_F(ValidateGraph, ValidGraphWithNoInputsNoBody) {
const std::string src = R"(
%cst = OpGraphConstantARM %int8tensor 1
%graph_type = OpTypeGraphARM 0 %int8tensor
OpGraphEntryPointARM %graph "longname" %var_int8tensor
%graph = OpGraphARM %graph_type
OpGraphSetOutputARM %cst %uint_0
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPVENV));
}
TEST_F(ValidateGraph, InvalidGraphWithDisallowedBodyInstructions) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor %int8tensor
OpGraphEntryPointARM %graph "longname" %var_int8tensor %var_int8tensor
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor %uint_0
%val = OpCompositeExtract %int8r3tensor %in 0
%out = OpCompositeInsert %int8tensor %val %in 0
OpGraphSetOutputARM %out %uint_0
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions(SPVENV));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
"OpCompositeInsert cannot appear in the graph definitions section"));
}
TEST_F(ValidateGraph, InvalidInstructionOutsideGraphAfterGraph) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor %int8tensor
%cst = OpGraphConstantARM %int8tensor 1
OpGraphEntryPointARM %graph "longname" %var_int8tensor %var_int8tensor
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor %uint_0
OpGraphSetOutputARM %in %uint_0
OpGraphEndARM
%val = OpCompositeExtract %int8r3tensor %cst 0
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions(SPVENV));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("OpCompositeExtract must appear in a graph body"));
}
//
// Type tests
//
TEST_F(ValidateGraph, ValidGraphTypeOneTensorOutputNoInputs) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 0 %int8tensor
)";
std::string spvasm = GenerateModuleWithGraphEntryPoint(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPVENV));
}
TEST_F(ValidateGraph, ValidGraphTypeOneTensorArrayOutputNoInputs) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 0 %int8tensor_array3
)";
std::string spvasm = GenerateModuleWithGraphEntryPoint(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPVENV));
}
TEST_F(ValidateGraph, ValidGraphTypeOneTensorRuntimeArrayOutputNoInputs) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 0 %int8tensor_runtime_array
)";
std::string spvasm = GenerateModuleWithGraphEntryPoint(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPVENV));
}
TEST_F(ValidateGraph, ValidGraphTypeOneTensorOutputOneTensorInput) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor %int32tensor
)";
std::string spvasm = GenerateModuleWithGraphEntryPoint(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPVENV));
}
TEST_F(ValidateGraph, ValidGraphTypeOneTensorOutputOneTensorArrayInput) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor_array3 %int32tensor
)";
std::string spvasm = GenerateModuleWithGraphEntryPoint(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPVENV));
}
TEST_F(ValidateGraph, ValidGraphTypeOneTensorOutputOneTensorRuntimeArrayInput) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor_runtime_array %int32tensor
)";
std::string spvasm = GenerateModuleWithGraphEntryPoint(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPVENV));
}
TEST_F(ValidateGraph,
ValidGraphTypeOneTensorOutputOneTensorInputOneTensorArrayInput) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 2 %int8tensor %int8tensor_array3 %int32tensor
)";
std::string spvasm = GenerateModuleWithGraphEntryPoint(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPVENV));
}
TEST_F(
ValidateGraph,
ValidGraphTypeOneTensorOutputOneTensorRuntimeArrayInputOneTensorArrayInput) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor_runtime_array %int8tensor_array3 %int32tensor
)";
std::string spvasm = GenerateModuleWithGraphEntryPoint(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPVENV));
}
TEST_F(ValidateGraph, ValidGraphTypeOneTensorArrayOutputOneTensorInput) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor %int32tensor_array3
)";
std::string spvasm = GenerateModuleWithGraphEntryPoint(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPVENV));
}
TEST_F(ValidateGraph, ValidGraphTypeOneTensorRuntimeArrayOutputOneTensorInput) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor %int32tensor_runtime_array
)";
std::string spvasm = GenerateModuleWithGraphEntryPoint(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPVENV));
}
TEST_F(ValidateGraph,
ValidGraphTypeOneTensorRuntimeArrayOutputOneTensorOuputOneTensorInput) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor %int32tensor_runtime_array %int32tensor
)";
std::string spvasm = GenerateModuleWithGraphEntryPoint(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPVENV));
}
TEST_F(
ValidateGraph,
ValidGraphTypeOneTensorRuntimeArrayOutputOneTensorArrayOutputOneTensorOuputOneTensorInput) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor %int32tensor_runtime_array %int32tensor_array3 %int32tensor
)";
std::string spvasm = GenerateModuleWithGraphEntryPoint(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPVENV));
}
TEST_F(ValidateGraph,
ValidGraphTypeOneTensorRuntimeArrayOutputOnteTensorOuputOneTensorInput) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor_array3 %int32tensor_array3
)";
std::string spvasm = GenerateModuleWithGraphEntryPoint(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPVENV));
}
TEST_F(ValidateGraph, InvalidGraphTypeWithNotEnoughIOTypes) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 10 %int8tensor %int8tensor
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPVENV));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("2 I/O types were provided but the graph has 10 inputs"));
}
TEST_F(ValidateGraph, InvalidGraphTypeWithNonGraphInterfaceTypeIO) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor %uint
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPVENV));
EXPECT_THAT(getDiagnosticString(),
ContainsRegex("I/O type '.*' is not a Graph Interface Type.*"));
}
TEST_F(ValidateGraph, InvalidGraphTypeWithOneInputZeroOutputs) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPVENV));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("A graph type must have at least one output"));
}
TEST_F(ValidateGraph, InvalidGraphTypeWithZeroInputsZeroOutputs) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 0
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPVENV));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("A graph type must have at least one output"));
}
//
// Constant tests
//
TEST_F(ValidateGraph, ValidGraphConstantTensorUnranked) {
const std::string src = R"(
%tensor_type = OpTypeTensorARM %uint
%cst = OpGraphConstantARM %tensor_type 25
)";
std::string spvasm = GenerateModuleWithGraphEntryPoint(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPVENV));
}
TEST_F(ValidateGraph, ValidGraphConstantTensorRanked) {
const std::string src = R"(
%tensor_type = OpTypeTensorARM %uint %uint_4
%cst = OpGraphConstantARM %tensor_type 25
)";
std::string spvasm = GenerateModuleWithGraphEntryPoint(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPVENV));
}
TEST_F(ValidateGraph, ValidGraphConstantTensorShaped) {
const std::string src = R"(
%uint_array2 = OpTypeArray %uint %uint_2
%tensor_shape = OpConstantComposite %uint_array2 %uint_1 %uint_4
%tensor_type = OpTypeTensorARM %uint %uint_2 %tensor_shape
%cst = OpGraphConstantARM %tensor_type 25
)";
std::string spvasm = GenerateModuleWithGraphEntryPoint(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPVENV));
}
TEST_F(ValidateGraph, InvalidGraphConstantDuplicateIDs) {
const std::string src = R"(
%cst = OpGraphConstantARM %int8tensor 25
%cst2 = OpGraphConstantARM %int32tensor 25
)";
std::string spvasm = GenerateModuleWithGraphEntryPoint(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPVENV));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("No two OpGraphConstantARM instructions may have the "
"same GraphConstantID"));
}
TEST_F(ValidateGraph, InvalidGraphConstantWithNonTensorType) {
const std::string src = R"(
%cst = OpGraphConstantARM %uint 25
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPVENV));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
"GraphConstantARM must have a Result Type that is a tensor type"));
}
//
// EntryPoint tests
//
TEST_F(ValidateGraph, InvalidModuleWithNoGraphEntryPoint) {
std::string spvasm = GenerateModule("");
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions(SPVENV));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("No OpGraphEntryPointARM instruction was found but the "
"GraphARM capability is declared."));
}
TEST_F(ValidateGraph, InvalidGraphEntryPointNotAGraph) {
const std::string src = R"(
OpGraphEntryPointARM %uint_0 "longname"
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPVENV));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
"GraphEntryPointARM Graph must be a OpGraphARM but found Constant"));
}
TEST_F(ValidateGraph, InvalidGraphEntryPointInterfaceIDNotOpVariable) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor %int8tensor
OpGraphEntryPointARM %graph "longname" %uint_0 %uint_0
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor %uint_0
OpGraphSetOutputARM %in %uint_0
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPVENV));
EXPECT_THAT(getDiagnosticString(),
ContainsRegex(
"GraphEntryPointARM Interface ID '.*' must "
"come from OpVariable with UniformConstant Storage Class.*"));
}
TEST_F(ValidateGraph, InvalidGraphEntryPointInterfaceIDWrongStorageClass) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor %int8tensor
OpGraphEntryPointARM %graph "longname" %var_int8tensor_wrong_storage_class %var_int8tensor_wrong_storage_class
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor %uint_0
OpGraphSetOutputARM %in %uint_0
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPVENV));
EXPECT_THAT(getDiagnosticString(),
ContainsRegex(
"GraphEntryPointARM Interface ID '.*' must "
"come from OpVariable with UniformConstant Storage Class.*"));
}
TEST_F(ValidateGraph, InvalidGraphEntryPointNotEnoughInterfaceIDs) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor %int8tensor
OpGraphEntryPointARM %graph "longname" %var_int8tensor
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor %uint_0
OpGraphSetOutputARM %in %uint_0
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPVENV));
EXPECT_THAT(
getDiagnosticString(),
ContainsRegex(
"GraphEntryPointARM Interface list contains 1 IDs but Graph's type "
"'.*' has 2 inputs and outputs.*"));
}
TEST_F(ValidateGraph, InvalidGraphEntryPointTooManyInterfaceIDs) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor %int8tensor
OpGraphEntryPointARM %graph "longname" %var_int8tensor %var_int8tensor %var_int8tensor
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor %uint_0
OpGraphSetOutputARM %in %uint_0
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPVENV));
EXPECT_THAT(
getDiagnosticString(),
ContainsRegex(
"GraphEntryPointARM Interface list contains 3 IDs but Graph's type "
"'.*' has 2 inputs and outputs.*"));
}
TEST_F(ValidateGraph,
InvalidGraphEntryPointInterfaceIDTypeMismatchesGraphIOType) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor %int8tensor
OpGraphEntryPointARM %graph "longname" %var_int8tensor %var_int32tensor
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor %uint_0
OpGraphSetOutputARM %in %uint_0
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPVENV));
EXPECT_THAT(getDiagnosticString(),
ContainsRegex("GraphEntryPointARM Interface ID type "
"'.*' must match the type of the "
"corresponding graph I/O '.*'.*"));
}
//
// Graph tests
//
TEST_F(ValidateGraph, InvalidGraphResultType) {
const std::string src = R"(
OpGraphEntryPointARM %graph "foo"
%graph = OpGraphARM %uint
%in = OpGraphInputARM %int8tensor %uint_0
OpGraphSetOutputARM %in %uint_0
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPVENV));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("GraphARM Result Type must be an OpTypeGraphARM"));
}
//
// Input tests
//
TEST_F(ValidateGraph, ValidTensorInput) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor %int8tensor
OpGraphEntryPointARM %graph "longname" %var_int8tensor %var_int8tensor
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor %uint_0
OpGraphSetOutputARM %in %uint_0
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPVENV));
}
TEST_F(ValidateGraph, ValidTensorArrayInputCompositeExtract) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor_array3 %int8tensor
OpGraphEntryPointARM %graph "longname" %var_int8tensor_array3 %var_int8tensor
%graph = OpGraphARM %graph_type
%in_tensors = OpGraphInputARM %int8tensor_array3 %uint_0
%out = OpCompositeExtract %int8tensor %in_tensors 1
OpGraphSetOutputARM %out %uint_0
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPVENV));
}
TEST_F(ValidateGraph, ValidTensorArrayInputWithElementIndex) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor_array3 %int8tensor
OpGraphEntryPointARM %graph "longname" %var_int8tensor_array3 %var_int8tensor
%graph = OpGraphARM %graph_type
%out = OpGraphInputARM %int8tensor %uint_0 %uint_1
OpGraphSetOutputARM %out %uint_0
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPVENV));
}
TEST_F(ValidateGraph, ValidTensorRuntimeArrayInputCompositeExtract) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor_runtime_array %int8tensor
OpGraphEntryPointARM %graph "longname" %var_int8tensor_runtime_array %var_int8tensor
%graph = OpGraphARM %graph_type
%in_tensors = OpGraphInputARM %int8tensor_runtime_array %uint_0
%out = OpCompositeExtract %int8tensor %in_tensors 1
OpGraphSetOutputARM %out %uint_0
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPVENV));
}
TEST_F(ValidateGraph, ValidTensorRuntimeArrayInputWithElementIndex) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor_runtime_array %int8tensor
OpGraphEntryPointARM %graph "longname" %var_int8tensor_runtime_array %var_int8tensor
%graph = OpGraphARM %graph_type
%out = OpGraphInputARM %int8tensor %uint_0 %uint_1
OpGraphSetOutputARM %out %uint_0
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPVENV));
}
TEST_F(ValidateGraph, InvalidGraphInputIndexWrongType) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor %int8tensor
OpGraphEntryPointARM %graph "longname" %var_int8tensor %var_int8tensor
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor %float_1
OpGraphSetOutputARM %in %uint_0
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPVENV));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("GraphInputARM InputIndex must be a 32-bit integer"));
}
TEST_F(ValidateGraph, InvalidGraphInputElementIndexWrongType) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor_array3 %int8tensor
OpGraphEntryPointARM %graph "longname" %var_int8tensor_array3 %var_int8tensor
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor %uint_0 %float_1
OpGraphSetOutputARM %in %uint_0
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPVENV));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("GraphInputARM ElementIndex must be a 32-bit integer"));
}
TEST_F(ValidateGraph, InvalidGraphInputIndexDuplicate) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor %int8tensor
OpGraphEntryPointARM %graph "longname" %var_int8tensor %var_int8tensor
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor %uint_0
%in2 = OpGraphInputARM %int8tensor %uint_0
OpGraphSetOutputARM %in %uint_0
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPVENV));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Two OpGraphInputARM instructions with the same "
"InputIndex must not be part of the same "
"graph definition unless ElementIndex is present in "
"both with different values."));
}
TEST_F(ValidateGraph, InvalidGraphInputAndElementIndexDuplicate) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor_array3 %int8tensor
OpGraphEntryPointARM %graph "longname" %var_int8tensor_array3 %var_int8tensor
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor %uint_0 %uint_1
%in2 = OpGraphInputARM %int8tensor %uint_0 %uint_1
OpGraphSetOutputARM %in %uint_0
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPVENV));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Two OpGraphInputARM instructions with the same "
"InputIndex must not be part of the same "
"graph definition unless ElementIndex is present in "
"both with different values."));
}
TEST_F(ValidateGraph,
InvalidGraphInputIndexDuplicateWithAndWithoutElementIndex) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor_array3 %int8tensor
OpGraphEntryPointARM %graph "longname" %var_int8tensor_array3 %var_int8tensor
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor_array3 %uint_0
%in2 = OpGraphInputARM %int8tensor %uint_0 %uint_1
OpGraphSetOutputARM %in2 %uint_0
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPVENV));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Two OpGraphInputARM instructions with the same "
"InputIndex must not be part of the same "
"graph definition unless ElementIndex is present in "
"both with different values."));
}
TEST_F(ValidateGraph, ValidGraphInputIndexDuplicateWithDifferentElementIndex) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor_runtime_array %int8tensor
OpGraphEntryPointARM %graph "longname" %var_int8tensor_runtime_array %var_int8tensor
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor %uint_0 %uint_2
%in2 = OpGraphInputARM %int8tensor %uint_0 %uint_1
OpGraphSetOutputARM %in2 %uint_0
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPVENV));
}
TEST_F(ValidateGraph, InvalidGraphInputElementIndexWithNonArrayInput) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor %int8tensor
OpGraphEntryPointARM %graph "longname" %var_int8tensor %var_int8tensor
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor %uint_0 %uint_1
OpGraphSetOutputARM %in %uint_0
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPVENV));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("OpGraphInputARM ElementIndex not allowed when the graph input "
"selected by "
"InputIndex is not an OpTypeArray or OpTypeRuntimeArray"));
}
TEST_F(ValidateGraph, InvalidGraphInputElementIndexOutOfRange) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor_array3 %int8tensor
OpGraphEntryPointARM %graph "longname" %var_int8tensor_array3 %var_int8tensor
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor %uint_0 %uint_3
OpGraphSetOutputARM %in %uint_0
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPVENV));
EXPECT_THAT(getDiagnosticString(),
ContainsRegex("OpGraphInputARM ElementIndex out of range. The "
"type of the graph input being accessed '.*' is an "
"array of 3 elements but ElementIndex is 3.*"));
}
TEST_F(ValidateGraph, InvalidGraphInputIndexOutOfRange) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 2 %int8tensor %int8tensor %int8tensor
OpGraphEntryPointARM %graph "longname" %var_int8tensor %var_int8tensor %var_int8tensor
%graph = OpGraphARM %graph_type
%in0 = OpGraphInputARM %int8tensor %uint_0
%in1 = OpGraphInputARM %int8tensor %uint_1
%in2 = OpGraphInputARM %int8tensor %uint_2
OpGraphSetOutputARM %in0 %uint_0
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPVENV));
EXPECT_THAT(getDiagnosticString(),
ContainsRegex("Type '.*' for graph '.*' "
"has 2 inputs but found an OpGraphInputARM "
"instruction with an InputIndex that is 2.*"));
}
TEST_F(ValidateGraph, InvalidGraphFirstInputTypeDoesNotMatchGraphType) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 2 %int8tensor %int8tensor %int8tensor
OpGraphEntryPointARM %graph "longname" %var_int8tensor %var_int8tensor %var_int8tensor
%graph = OpGraphARM %graph_type
%in0 = OpGraphInputARM %int32tensor %uint_0
%in1 = OpGraphInputARM %int8tensor %uint_1
OpGraphSetOutputARM %in1 %uint_0
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPVENV));
EXPECT_THAT(getDiagnosticString(),
ContainsRegex("Result Type '.*' of graph input instruction "
"'.*' does not match the type "
"'.*' of input 0 in the graph type.*"));
}
TEST_F(ValidateGraph, InvalidGraphLastInputTypeDoesNotMatchGraphType) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 2 %int8tensor %int8tensor %int8tensor
OpGraphEntryPointARM %graph "longname" %var_int8tensor %var_int8tensor %var_int8tensor
%graph = OpGraphARM %graph_type
%in0 = OpGraphInputARM %int8tensor %uint_0
%in1 = OpGraphInputARM %int32tensor %uint_1
OpGraphSetOutputARM %in0 %uint_0
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPVENV));
EXPECT_THAT(getDiagnosticString(),
ContainsRegex("Result Type '.*' of graph input instruction "
"'.*' does not match the type "
"'.*' of input 1 in the graph type.*"));
}
TEST_F(ValidateGraph, InvalidGraphInputAfterNonGraphInputOrGraph) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 2 %int8tensor_array3 %int8tensor %int8tensor
OpGraphEntryPointARM %graph "longname" %var_int8tensor_array3 %var_int8tensor %var_int8tensor
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor_array3 %uint_0
%val = OpCompositeExtract %int8tensor %in 0
%in2 = OpGraphInputARM %int8tensor %uint_1
OpGraphSetOutputARM %val %uint_0
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions(SPVENV));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("OpGraphInputARM must immediately follow an OpGraphARM "
"or OpGraphInputARM instruction"));
}
//
// Output tests
//
TEST_F(ValidateGraph, ValidTensorOutput) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor %int8tensor
OpGraphEntryPointARM %graph "longname" %var_int8tensor %var_int8tensor
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor %uint_0
OpGraphSetOutputARM %in %uint_0
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPVENV));
}
TEST_F(ValidateGraph, ValidTensorOutputWholeArray) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor_array3 %int8tensor_array3
OpGraphEntryPointARM %graph "longname" %var_int8tensor_array3 %var_int8tensor_array3
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor_array3 %uint_0
OpGraphSetOutputARM %in %uint_0
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPVENV));
}
TEST_F(ValidateGraph, ValidTensorOutputArraySingleElement) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor %int8tensor_array3
OpGraphEntryPointARM %graph "longname" %var_int8tensor %var_int8tensor_array3
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor %uint_0
OpGraphSetOutputARM %in %uint_0 %uint_1
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPVENV));
}
TEST_F(ValidateGraph, ValidTensorOutputArrayMultipleElements) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor %int8tensor_array3
OpGraphEntryPointARM %graph "longname" %var_int8tensor %var_int8tensor_array3
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor %uint_0
OpGraphSetOutputARM %in %uint_0 %uint_1
OpGraphSetOutputARM %in %uint_0 %uint_2
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPVENV));
}
TEST_F(ValidateGraph, ValidTensorOutputWholeRuntimeArray) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor_runtime_array %int8tensor_runtime_array
OpGraphEntryPointARM %graph "longname" %var_int8tensor_runtime_array %var_int8tensor_runtime_array
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor_runtime_array %uint_0
OpGraphSetOutputARM %in %uint_0
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPVENV));
}
TEST_F(ValidateGraph, ValidTensorOutputRuntimeArraySingleElement) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor %int8tensor_runtime_array
OpGraphEntryPointARM %graph "longname" %var_int8tensor %var_int8tensor_runtime_array
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor %uint_0
OpGraphSetOutputARM %in %uint_0 %uint_1
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPVENV));
}
TEST_F(ValidateGraph, ValidTensorOutputRuntimeArrayMultipleElements) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor %int8tensor_runtime_array
OpGraphEntryPointARM %graph "longname" %var_int8tensor %var_int8tensor_runtime_array
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor %uint_0
OpGraphSetOutputARM %in %uint_0 %uint_1
OpGraphSetOutputARM %in %uint_0 %uint_2
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPVENV));
}
TEST_F(ValidateGraph, InvalidGraphOutputIndexWrongType) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor %int8tensor
OpGraphEntryPointARM %graph "longname" %var_int8tensor %var_int8tensor
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor %uint_0
OpGraphSetOutputARM %in %float_1
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPVENV));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("GraphSetOutputARM OutputIndex must be a 32-bit integer"));
}
TEST_F(ValidateGraph, InvalidGraphOutputElementIndexWrongType) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor %int8tensor_array3
OpGraphEntryPointARM %graph "longname" %var_int8tensor %var_int8tensor_array3
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor %uint_0
OpGraphSetOutputARM %in %uint_0 %float_1
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPVENV));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("GraphSetOutputARM ElementIndex must be a 32-bit integer"));
}
TEST_F(ValidateGraph, InvalidGraphOutputIndexDuplicate) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor %int8tensor
OpGraphEntryPointARM %graph "longname" %var_int8tensor %var_int8tensor
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor %uint_0
OpGraphSetOutputARM %in %uint_0
OpGraphSetOutputARM %in %uint_0
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPVENV));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Two OpGraphSetOutputARM instructions with the same "
"OutputIndex must not be part of the same "
"graph definition unless ElementIndex is present in "
"both with different values."));
}
TEST_F(ValidateGraph, InvalidGraphOutputAndElementIndexDuplicate) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor %int8tensor_array3
OpGraphEntryPointARM %graph "longname" %var_int8tensor %var_int8tensor_array3
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor %uint_0
OpGraphSetOutputARM %in %uint_0 %uint_1
OpGraphSetOutputARM %in %uint_0 %uint_1
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPVENV));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Two OpGraphSetOutputARM instructions with the same "
"OutputIndex must not be part of the same "
"graph definition unless ElementIndex is present in "
"both with different values."));
}
TEST_F(ValidateGraph,
InvalidGraphOutputIndexDuplicateWithAndWithoutElementIndex) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor_array3 %int8tensor_array3
OpGraphEntryPointARM %graph "longname" %var_int8tensor_array3 %var_int8tensor_array3
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor_array3 %uint_0
%in_single = OpCompositeExtract %int8tensor %in 0
OpGraphSetOutputARM %in %uint_0
OpGraphSetOutputARM %in_single %uint_0 %uint_1
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPVENV));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Two OpGraphSetOutputARM instructions with the same "
"OutputIndex must not be part of the same "
"graph definition unless ElementIndex is present in "
"both with different values."));
}
TEST_F(ValidateGraph, ValidGraphOutputIndexDuplicateWithDifferentElementIndex) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor %int8tensor_runtime_array
OpGraphEntryPointARM %graph "longname" %var_int8tensor %var_int8tensor_runtime_array
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor %uint_0
OpGraphSetOutputARM %in %uint_0 %uint_1
OpGraphSetOutputARM %in %uint_0 %uint_4
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPVENV));
}
TEST_F(ValidateGraph, InvalidGraphOutputElementIndexWithNonArrayOutput) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor %int8tensor
OpGraphEntryPointARM %graph "longname" %var_int8tensor %var_int8tensor
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor %uint_0
OpGraphSetOutputARM %in %uint_0 %uint_0
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPVENV));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("OpGraphSetOutputARM ElementIndex not allowed when the graph "
"output selected by "
"OutputIndex is not an OpTypeArray or OpTypeRuntimeArray"));
}
TEST_F(ValidateGraph, InvalidGraphOutputElementIndexOutOfRange) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor %int8tensor_array3
OpGraphEntryPointARM %graph "longname" %var_int8tensor %var_int8tensor_array3
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor %uint_0
OpGraphSetOutputARM %in %uint_0 %uint_3
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPVENV));
EXPECT_THAT(
getDiagnosticString(),
ContainsRegex("OpGraphSetOutputARM ElementIndex out of range. The "
"type of the graph output being accessed '.*' is an "
"array of 3 elements but ElementIndex is 3.*"));
}
TEST_F(ValidateGraph, InvalidGraphOutputNotBeforeEndOrOutput) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor_array3 %int8tensor_array3 %int8tensor
OpGraphEntryPointARM %graph "longname" %var_int8tensor_array3 %var_int8tensor_array3 %var_int8tensor
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor_array3 %uint_0
OpGraphSetOutputARM %in %uint_0
%val = OpCompositeExtract %int8tensor %in 0
OpGraphSetOutputARM %val %uint_1
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions(SPVENV));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
"CompositeExtract cannot appear after a graph output instruction"));
}
TEST_F(ValidateGraph, InvalidGraphOutputIndexOutOfRange) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor %int8tensor %int8tensor
OpGraphEntryPointARM %graph "longname" %var_int8tensor %var_int8tensor %var_int8tensor
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor %uint_0
OpGraphSetOutputARM %in %uint_2
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPVENV));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("GraphSetOutputARM setting OutputIndex 2 but graph "
"only has 2 outputs."));
}
TEST_F(ValidateGraph, InvalidGraphFirstOutputValueTypeDoesNotMatchOutputType) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int32tensor %int8tensor %int8tensor
OpGraphEntryPointARM %graph "longname" %var_int32tensor %var_int8tensor %var_int8tensor
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int32tensor %uint_0
OpGraphSetOutputARM %in %uint_0
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPVENV));
EXPECT_THAT(
getDiagnosticString(),
ContainsRegex(
"The type '.*' of Value provided to the graph output instruction "
"'.*' does not match the type '.*' of output 0 in the graph type.*"));
}
TEST_F(ValidateGraph, InvalidGraphLastOutputValueTypeDoesNotMatchOutputType) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int32tensor %int32tensor %int8tensor
OpGraphEntryPointARM %graph "longname" %var_int32tensor %var_int32tensor %var_int8tensor
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int32tensor %uint_0
OpGraphSetOutputARM %in %uint_1
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPVENV));
EXPECT_THAT(
getDiagnosticString(),
ContainsRegex(
"The type '.*' of Value provided to the graph output instruction "
"'.*' does not match the type '.*' of output 1 in the graph type.*"));
}
TEST_F(ValidateGraph, InvalidGraphNoSetOuputBeforeEnd) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor %int8tensor
OpGraphEntryPointARM %graph "longname" %var_int8tensor %var_int8tensor
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor %uint_0
OpGraphEndARM
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions(SPVENV));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("GraphEndARM must be preceded by at least one "
"OpGraphSetOutputARM instruction"));
}
//
// End tests
//
TEST_F(ValidateGraph, InvalidGraphNoEnd) {
const std::string src = R"(
%graph_type = OpTypeGraphARM 1 %int8tensor %int8tensor
OpGraphEntryPointARM %graph "longname" %var_int8tensor %var_int8tensor
%graph = OpGraphARM %graph_type
%in = OpGraphInputARM %int8tensor %uint_0
)";
std::string spvasm = GenerateModule(src);
CompileSuccessfully(spvasm, SPVENV);
EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions(SPVENV));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Missing OpGraphEndARM at end of module"));
}
} // namespace
} // namespace val
} // namespace spvtools