Validate SpvOpVectorShuffle

This commit is contained in:
Józef Kucia 2017-10-13 21:53:58 +02:00 committed by David Neto
parent 13e6598947
commit 90862fe4b1
3 changed files with 318 additions and 7 deletions

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// Ensures type declarations are unique unless allowed by the specification.
// Performs validation of arithmetic instructions.
#include "validate.h"

View File

@ -1632,12 +1632,87 @@ bool idUsage::isValid<OpVectorInsertDynamic>(
const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
#endif
#if 0
template <>
bool idUsage::isValid<OpVectorShuffle>(const spv_instruction_t *inst,
const spv_opcode_desc opcodeEntry) {
bool idUsage::isValid<SpvOpVectorShuffle>(const spv_instruction_t* inst,
const spv_opcode_desc) {
auto instr_name = [&inst]() {
std::string name =
"Op" + std::string(spvOpcodeString(static_cast<SpvOp>(inst->opcode)));
return name;
};
// Result Type must be an OpTypeVector.
auto resultTypeIndex = 1;
auto resultType = module_.FindDef(inst->words[resultTypeIndex]);
if (!resultType || resultType->opcode() != SpvOpTypeVector) {
DIAG(resultTypeIndex) << "The Result Type of " << instr_name()
<< " must be OpTypeVector. Found Op"
<< spvOpcodeString(
static_cast<SpvOp>(resultType->opcode()))
<< ".";
return false;
}
// The number of components in Result Type must be the same as the number of
// Component operands.
auto componentCount = inst->words.size() - 5;
auto vectorComponentCountIndex = 3;
auto resultVectorDimension = resultType->words()[vectorComponentCountIndex];
if (componentCount != resultVectorDimension) {
DIAG(inst->words.size() - 1)
<< instr_name() << " component literals count does not match "
"Result Type <id> '"
<< resultType->id() << "'s vector component count.";
return false;
}
// Vector 1 and Vector 2 must both have vector types, with the same Component
// Type as Result Type.
auto vector1Index = 3;
auto vector1Object = module_.FindDef(inst->words[vector1Index]);
auto vector1Type = module_.FindDef(vector1Object->type_id());
auto vector2Index = 4;
auto vector2Object = module_.FindDef(inst->words[vector2Index]);
auto vector2Type = module_.FindDef(vector2Object->type_id());
if (!vector1Type || vector1Type->opcode() != SpvOpTypeVector) {
DIAG(vector1Index) << "The type of Vector 1 must be OpTypeVector.";
return false;
}
if (!vector2Type || vector2Type->opcode() != SpvOpTypeVector) {
DIAG(vector2Index) << "The type of Vector 2 must be OpTypeVector.";
return false;
}
auto vectorComponentTypeIndex = 2;
auto resultComponentType = resultType->words()[vectorComponentTypeIndex];
auto vector1ComponentType = vector1Type->words()[vectorComponentTypeIndex];
if (vector1ComponentType != resultComponentType) {
DIAG(vector1Index) << "The Component Type of Vector 1 must be the same "
"as ResultType.";
return false;
}
auto vector2ComponentType = vector2Type->words()[vectorComponentTypeIndex];
if (vector2ComponentType != resultComponentType) {
DIAG(vector2Index) << "The Component Type of Vector 2 must be the same "
"as ResultType.";
return false;
}
// All Component literals must either be FFFFFFFF or in [0, N - 1].
auto vector1ComponentCount = vector1Type->words()[vectorComponentCountIndex];
auto vector2ComponentCount = vector2Type->words()[vectorComponentCountIndex];
auto N = vector1ComponentCount + vector2ComponentCount;
auto firstLiteralIndex = 5;
for (size_t i = firstLiteralIndex; i < inst->words.size(); ++i) {
auto literal = inst->words[i];
if (literal != 0xFFFFFFFF && literal >= N) {
DIAG(i) << "Component literal value " << literal << " is greater than "
<< N - 1 << ".";
return false;
}
}
return true;
}
#endif
#if 0
template <>
@ -2425,7 +2500,7 @@ bool idUsage::isValid(const spv_instruction_t* inst) {
// Conversion opcodes are validated in validate_conversion.cpp.
TODO(OpVectorExtractDynamic)
TODO(OpVectorInsertDynamic)
TODO(OpVectorShuffle)
CASE(OpVectorShuffle)
TODO(OpCompositeConstruct)
CASE(OpCompositeExtract)
CASE(OpCompositeInsert)

View File

@ -3625,7 +3625,243 @@ TEST_F(ValidateIdWithMessage, OpFunctionCallArgumentCountBar) {
// TODO: OpSatConvertUToS
// TODO: OpVectorExtractDynamic
// TODO: OpVectorInsertDynamic
// TODO: OpVectorShuffle
TEST_F(ValidateIdWithMessage, OpVectorShuffleIntGood) {
string spirv = kGLSL450MemoryModel + R"(
%int = OpTypeInt 32 0
%ivec3 = OpTypeVector %int 3
%ivec4 = OpTypeVector %int 4
%ptr_ivec3 = OpTypePointer Function %ivec3
%undef = OpUndef %ivec4
%int_42 = OpConstant %int 42
%int_0 = OpConstant %int 0
%int_2 = OpConstant %int 2
%1 = OpConstantComposite %ivec3 %int_42 %int_0 %int_2
%2 = OpTypeFunction %ivec3
%3 = OpFunction %ivec3 None %2
%4 = OpLabel
%var = OpVariable %ptr_ivec3 Function %1
%5 = OpLoad %ivec3 %var
%6 = OpVectorShuffle %ivec3 %5 %undef 2 1 0
OpReturnValue %6
OpFunctionEnd)";
CompileSuccessfully(spirv.c_str());
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
}
TEST_F(ValidateIdWithMessage, OpVectorShuffleFloatGood) {
string spirv = kGLSL450MemoryModel + R"(
%float = OpTypeFloat 32
%vec2 = OpTypeVector %float 2
%vec3 = OpTypeVector %float 3
%vec4 = OpTypeVector %float 4
%ptr_vec2 = OpTypePointer Function %vec2
%ptr_vec3 = OpTypePointer Function %vec3
%float_1 = OpConstant %float 1
%float_2 = OpConstant %float 2
%1 = OpConstantComposite %vec2 %float_2 %float_1
%2 = OpConstantComposite %vec3 %float_1 %float_2 %float_2
%3 = OpTypeFunction %vec4
%4 = OpFunction %vec4 None %3
%5 = OpLabel
%var = OpVariable %ptr_vec2 Function %1
%var2 = OpVariable %ptr_vec3 Function %2
%6 = OpLoad %vec2 %var
%7 = OpLoad %vec3 %var2
%8 = OpVectorShuffle %vec4 %6 %7 4 3 1 0xffffffff
OpReturnValue %8
OpFunctionEnd)";
CompileSuccessfully(spirv.c_str());
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
}
TEST_F(ValidateIdWithMessage, OpVectorShuffleScalarResultType) {
string spirv = kGLSL450MemoryModel + R"(
%float = OpTypeFloat 32
%vec2 = OpTypeVector %float 2
%ptr_vec2 = OpTypePointer Function %vec2
%float_1 = OpConstant %float 1
%float_2 = OpConstant %float 2
%1 = OpConstantComposite %vec2 %float_2 %float_1
%2 = OpTypeFunction %float
%3 = OpFunction %float None %2
%4 = OpLabel
%var = OpVariable %ptr_vec2 Function %1
%5 = OpLoad %vec2 %var
%6 = OpVectorShuffle %float %5 %5 0
OpReturnValue %6
OpFunctionEnd)";
CompileSuccessfully(spirv.c_str());
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("Result Type of OpVectorShuffle must be OpTypeVector."));
}
TEST_F(ValidateIdWithMessage, OpVectorShuffleComponentCount) {
string spirv = kGLSL450MemoryModel + R"(
%int = OpTypeInt 32 0
%ivec3 = OpTypeVector %int 3
%ptr_ivec3 = OpTypePointer Function %ivec3
%int_42 = OpConstant %int 42
%int_0 = OpConstant %int 0
%int_2 = OpConstant %int 2
%1 = OpConstantComposite %ivec3 %int_42 %int_0 %int_2
%2 = OpTypeFunction %ivec3
%3 = OpFunction %ivec3 None %2
%4 = OpLabel
%var = OpVariable %ptr_ivec3 Function %1
%5 = OpLoad %ivec3 %var
%6 = OpVectorShuffle %ivec3 %5 %5 0 1
OpReturnValue %6
OpFunctionEnd)";
CompileSuccessfully(spirv.c_str());
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("OpVectorShuffle component literals count does not match "
"Result Type <id> '2's vector component count."));
}
TEST_F(ValidateIdWithMessage, OpVectorShuffleVector1Type) {
string spirv = kGLSL450MemoryModel + R"(
%int = OpTypeInt 32 0
%ivec2 = OpTypeVector %int 2
%ptr_int = OpTypePointer Function %int
%undef = OpUndef %ivec2
%int_42 = OpConstant %int 42
%2 = OpTypeFunction %ivec2
%3 = OpFunction %ivec2 None %2
%4 = OpLabel
%var = OpVariable %ptr_int Function %int_42
%5 = OpLoad %int %var
%6 = OpVectorShuffle %ivec2 %5 %undef 0 0
OpReturnValue %6
OpFunctionEnd)";
CompileSuccessfully(spirv.c_str());
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("The type of Vector 1 must be OpTypeVector."));
}
TEST_F(ValidateIdWithMessage, OpVectorShuffleVector2Type) {
string spirv = kGLSL450MemoryModel + R"(
%int = OpTypeInt 32 0
%ivec2 = OpTypeVector %int 2
%ptr_ivec2 = OpTypePointer Function %ivec2
%undef = OpUndef %int
%int_42 = OpConstant %int 42
%1 = OpConstantComposite %ivec2 %int_42 %int_42
%2 = OpTypeFunction %ivec2
%3 = OpFunction %ivec2 None %2
%4 = OpLabel
%var = OpVariable %ptr_ivec2 Function %1
%5 = OpLoad %ivec2 %var
%6 = OpVectorShuffle %ivec2 %5 %undef 0 1
OpReturnValue %6
OpFunctionEnd)";
CompileSuccessfully(spirv.c_str());
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("The type of Vector 2 must be OpTypeVector."));
}
TEST_F(ValidateIdWithMessage, OpVectorShuffleVector1ComponentType) {
string spirv = kGLSL450MemoryModel + R"(
%int = OpTypeInt 32 0
%ivec3 = OpTypeVector %int 3
%ptr_ivec3 = OpTypePointer Function %ivec3
%int_42 = OpConstant %int 42
%int_0 = OpConstant %int 0
%int_2 = OpConstant %int 2
%float = OpTypeFloat 32
%vec3 = OpTypeVector %float 3
%vec4 = OpTypeVector %float 4
%ptr_vec3 = OpTypePointer Function %vec3
%float_1 = OpConstant %float 1
%float_2 = OpConstant %float 2
%1 = OpConstantComposite %ivec3 %int_42 %int_0 %int_2
%2 = OpConstantComposite %vec3 %float_1 %float_2 %float_2
%3 = OpTypeFunction %vec4
%4 = OpFunction %vec4 None %3
%5 = OpLabel
%var = OpVariable %ptr_ivec3 Function %1
%var2 = OpVariable %ptr_vec3 Function %2
%6 = OpLoad %ivec3 %var
%7 = OpLoad %vec3 %var2
%8 = OpVectorShuffle %vec4 %6 %7 4 3 1 0
OpReturnValue %8
OpFunctionEnd)";
CompileSuccessfully(spirv.c_str());
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("The Component Type of Vector 1 must be the same as "
"ResultType."));
}
TEST_F(ValidateIdWithMessage, OpVectorShuffleVector2ComponentType) {
string spirv = kGLSL450MemoryModel + R"(
%int = OpTypeInt 32 0
%ivec3 = OpTypeVector %int 3
%ptr_ivec3 = OpTypePointer Function %ivec3
%int_42 = OpConstant %int 42
%int_0 = OpConstant %int 0
%int_2 = OpConstant %int 2
%float = OpTypeFloat 32
%vec3 = OpTypeVector %float 3
%vec4 = OpTypeVector %float 4
%ptr_vec3 = OpTypePointer Function %vec3
%float_1 = OpConstant %float 1
%float_2 = OpConstant %float 2
%1 = OpConstantComposite %ivec3 %int_42 %int_0 %int_2
%2 = OpConstantComposite %vec3 %float_1 %float_2 %float_2
%3 = OpTypeFunction %vec4
%4 = OpFunction %vec4 None %3
%5 = OpLabel
%var = OpVariable %ptr_ivec3 Function %1
%var2 = OpVariable %ptr_vec3 Function %2
%6 = OpLoad %vec3 %var2
%7 = OpLoad %ivec3 %var
%8 = OpVectorShuffle %vec4 %6 %7 4 3 1 0
OpReturnValue %8
OpFunctionEnd)";
CompileSuccessfully(spirv.c_str());
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("The Component Type of Vector 2 must be the same as "
"ResultType."));
}
TEST_F(ValidateIdWithMessage, OpVectorShuffleLiterals) {
string spirv = kGLSL450MemoryModel + R"(
%float = OpTypeFloat 32
%vec2 = OpTypeVector %float 2
%vec3 = OpTypeVector %float 3
%vec4 = OpTypeVector %float 4
%ptr_vec2 = OpTypePointer Function %vec2
%ptr_vec3 = OpTypePointer Function %vec3
%float_1 = OpConstant %float 1
%float_2 = OpConstant %float 2
%1 = OpConstantComposite %vec2 %float_2 %float_1
%2 = OpConstantComposite %vec3 %float_1 %float_2 %float_2
%3 = OpTypeFunction %vec4
%4 = OpFunction %vec4 None %3
%5 = OpLabel
%var = OpVariable %ptr_vec2 Function %1
%var2 = OpVariable %ptr_vec3 Function %2
%6 = OpLoad %vec2 %var
%7 = OpLoad %vec3 %var2
%8 = OpVectorShuffle %vec4 %6 %7 0 5 2 6
OpReturnValue %8
OpFunctionEnd)";
CompileSuccessfully(spirv.c_str());
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Component literal value 5 is greater than 4."));
}
// TODO: OpCompositeConstruct
// TODO: OpCompositeExtract
// TODO: OpCompositeInsert