From 90862fe4b1c6763b32ce683d2d32c2f281f577cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B3zef=20Kucia?= Date: Fri, 13 Oct 2017 21:53:58 +0200 Subject: [PATCH] Validate SpvOpVectorShuffle --- source/validate_arithmetics.cpp | 2 +- source/validate_id.cpp | 85 +++++++++++- test/val/val_id_test.cpp | 238 +++++++++++++++++++++++++++++++- 3 files changed, 318 insertions(+), 7 deletions(-) diff --git a/source/validate_arithmetics.cpp b/source/validate_arithmetics.cpp index e0714fb0e..a2d3fbcec 100644 --- a/source/validate_arithmetics.cpp +++ b/source/validate_arithmetics.cpp @@ -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" diff --git a/source/validate_id.cpp b/source/validate_id.cpp index 987b67b0e..e898b2319 100644 --- a/source/validate_id.cpp +++ b/source/validate_id.cpp @@ -1632,12 +1632,87 @@ bool idUsage::isValid( const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {} #endif -#if 0 template <> -bool idUsage::isValid(const spv_instruction_t *inst, - const spv_opcode_desc opcodeEntry) { +bool idUsage::isValid(const spv_instruction_t* inst, + const spv_opcode_desc) { + auto instr_name = [&inst]() { + std::string name = + "Op" + std::string(spvOpcodeString(static_cast(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(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 '" + << 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) diff --git a/test/val/val_id_test.cpp b/test/val/val_id_test.cpp index da997a31a..9cd32f9fb 100644 --- a/test/val/val_id_test.cpp +++ b/test/val/val_id_test.cpp @@ -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 '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