diff --git a/include/spirv-tools/libspirv.h b/include/spirv-tools/libspirv.h index 162553d89..1a21ccef0 100644 --- a/include/spirv-tools/libspirv.h +++ b/include/spirv-tools/libspirv.h @@ -175,6 +175,7 @@ typedef enum spv_operand_type_t { SPV_OPERAND_TYPE_KERNEL_ENQ_FLAGS, // SPIR-V Sec 3.29 SPV_OPERAND_TYPE_KERNEL_PROFILING_INFO, // SPIR-V Sec 3.30 SPV_OPERAND_TYPE_CAPABILITY, // SPIR-V Sec 3.31 + SPV_OPERAND_TYPE_FPENCODING, // SPIR-V Sec 3.51 // NOTE: New concrete enum values should be added at the end. @@ -236,6 +237,8 @@ typedef enum spv_operand_type_t { // assemble regardless of where they occur -- literals, IDs, immediate // integers, etc. SPV_OPERAND_TYPE_OPTIONAL_CIV, + // An optional floating point encoding enum + SPV_OPERAND_TYPE_OPTIONAL_FPENCODING, // A variable operand represents zero or more logical operands. // In an instruction definition, this may only appear at the end of the diff --git a/source/binary.cpp b/source/binary.cpp index a39bcf06b..f0dd070b1 100644 --- a/source/binary.cpp +++ b/source/binary.cpp @@ -671,6 +671,8 @@ spv_result_t Parser::parseOperand(size_t inst_offset, case SPV_OPERAND_TYPE_OVERFLOW_MODES: case SPV_OPERAND_TYPE_PACKED_VECTOR_FORMAT: case SPV_OPERAND_TYPE_OPTIONAL_PACKED_VECTOR_FORMAT: + case SPV_OPERAND_TYPE_FPENCODING: + case SPV_OPERAND_TYPE_OPTIONAL_FPENCODING: case SPV_OPERAND_TYPE_NAMED_MAXIMUM_NUMBER_OF_REGISTERS: { // A single word that is a plain enum value. @@ -679,6 +681,8 @@ spv_result_t Parser::parseOperand(size_t inst_offset, parsed_operand.type = SPV_OPERAND_TYPE_ACCESS_QUALIFIER; if (type == SPV_OPERAND_TYPE_OPTIONAL_PACKED_VECTOR_FORMAT) parsed_operand.type = SPV_OPERAND_TYPE_PACKED_VECTOR_FORMAT; + if (type == SPV_OPERAND_TYPE_OPTIONAL_FPENCODING) + parsed_operand.type = SPV_OPERAND_TYPE_FPENCODING; spv_operand_desc entry; if (grammar_.lookupOperand(type, word, &entry)) { diff --git a/source/disassemble.cpp b/source/disassemble.cpp index 0add26009..db99151a9 100644 --- a/source/disassemble.cpp +++ b/source/disassemble.cpp @@ -944,6 +944,7 @@ void InstructionDisassembler::EmitOperand(std::ostream& stream, case SPV_OPERAND_TYPE_FPDENORM_MODE: case SPV_OPERAND_TYPE_FPOPERATION_MODE: case SPV_OPERAND_TYPE_QUANTIZATION_MODES: + case SPV_OPERAND_TYPE_FPENCODING: case SPV_OPERAND_TYPE_OVERFLOW_MODES: { spv_operand_desc entry; if (grammar_.lookupOperand(operand.type, word, &entry)) diff --git a/source/name_mapper.cpp b/source/name_mapper.cpp index b2d0f4452..bc18b7f1b 100644 --- a/source/name_mapper.cpp +++ b/source/name_mapper.cpp @@ -218,6 +218,7 @@ spv_result_t FriendlyNameMapper::ParseInstruction( } break; case spv::Op::OpTypeFloat: { const auto bit_width = inst.words[2]; + // TODO: Handle optional fpencoding enum once actually used. switch (bit_width) { case 16: SaveName(result_id, "half"); diff --git a/source/operand.cpp b/source/operand.cpp index e15004541..508a5d1d0 100644 --- a/source/operand.cpp +++ b/source/operand.cpp @@ -252,6 +252,9 @@ const char* spvOperandTypeStr(spv_operand_type_t type) { return "OpenCL.DebugInfo.100 debug operation"; case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_IMPORTED_ENTITY: return "OpenCL.DebugInfo.100 debug imported entity"; + case SPV_OPERAND_TYPE_FPENCODING: + case SPV_OPERAND_TYPE_OPTIONAL_FPENCODING: + return "FP encoding"; // The next values are for values returned from an instruction, not actually // an operand. So the specific strings don't matter. But let's add them @@ -366,6 +369,7 @@ bool spvOperandIsConcrete(spv_operand_type_t type) { case SPV_OPERAND_TYPE_LOAD_CACHE_CONTROL: case SPV_OPERAND_TYPE_STORE_CACHE_CONTROL: case SPV_OPERAND_TYPE_NAMED_MAXIMUM_NUMBER_OF_REGISTERS: + case SPV_OPERAND_TYPE_FPENCODING: return true; default: break; @@ -407,6 +411,7 @@ bool spvOperandIsOptional(spv_operand_type_t type) { case SPV_OPERAND_TYPE_OPTIONAL_COOPERATIVE_MATRIX_OPERANDS: case SPV_OPERAND_TYPE_OPTIONAL_CIV: case SPV_OPERAND_TYPE_OPTIONAL_RAW_ACCESS_CHAIN_OPERANDS: + case SPV_OPERAND_TYPE_OPTIONAL_FPENCODING: return true; default: break; diff --git a/source/opt/type_manager.cpp b/source/opt/type_manager.cpp index 62f93698f..79648ad49 100644 --- a/source/opt/type_manager.cpp +++ b/source/opt/type_manager.cpp @@ -245,6 +245,7 @@ uint32_t TypeManager::GetTypeInstruction(const Type* type) { {(type->AsInteger()->IsSigned() ? 1u : 0u)}}}); break; case Type::kFloat: + // TODO: Handle FP encoding enums once actually used. typeInst = MakeUnique( context(), spv::Op::OpTypeFloat, 0, id, std::initializer_list{ diff --git a/source/text_handler.cpp b/source/text_handler.cpp index 35c4b83c1..a778c2c14 100644 --- a/source/text_handler.cpp +++ b/source/text_handler.cpp @@ -329,8 +329,9 @@ spv_result_t AssemblyContext::recordTypeDefinition( types_[value] = {pInst->words[2], pInst->words[3] != 0, IdTypeClass::kScalarIntegerType}; } else if (pInst->opcode == spv::Op::OpTypeFloat) { - if (pInst->words.size() != 3) + if ((pInst->words.size() != 3) && (pInst->words.size() != 4)) return diagnostic() << "Invalid OpTypeFloat instruction"; + // TODO(kpet) Do we need to record the FP Encoding here? types_[value] = {pInst->words[2], false, IdTypeClass::kScalarFloatType}; } else { types_[value] = {0, false, IdTypeClass::kOtherType}; diff --git a/test/immediate_int_test.cpp b/test/immediate_int_test.cpp index 8e7a8fd30..44f96e21a 100644 --- a/test/immediate_int_test.cpp +++ b/test/immediate_int_test.cpp @@ -136,19 +136,25 @@ TEST_F(ImmediateIntTest, IntegerFollowingImmediate) { } // Literal floats after ! are handled correctly. +// Insert OpNop to avoid reading the immediate value as the extra FP encoding +// operand to OpTypeFloat. TEST_F(ImmediateIntTest, FloatFollowingImmediate) { - EXPECT_EQ( - CompiledInstructions("%1 = OpTypeFloat 32\n%2 = OpConstant %1 0.123"), - CompiledInstructions("%1 = OpTypeFloat 32\n!0x0004002b %1 !2 0.123")); - EXPECT_EQ( - CompiledInstructions("%1 = OpTypeFloat 32\n%2 = OpConstant %1 -0.5"), - CompiledInstructions("%1 = OpTypeFloat 32\n!0x0004002b %1 !2 -0.5")); - EXPECT_EQ( - CompiledInstructions("%1 = OpTypeFloat 32\n%2 = OpConstant %1 0.123"), - CompiledInstructions("%1 = OpTypeFloat 32\n!0x0004002b %1 %2 0.123")); - EXPECT_EQ( - CompiledInstructions("%1 = OpTypeFloat 32\n%2 = OpConstant %1 -0.5"), - CompiledInstructions("%1 = OpTypeFloat 32\n!0x0004002b %1 %2 -0.5")); + EXPECT_EQ(CompiledInstructions( + "%1 = OpTypeFloat 32\nOpNop %2 = OpConstant %1 0.123"), + CompiledInstructions( + "%1 = OpTypeFloat 32\nOpNop !0x0004002b %1 !2 0.123")); + EXPECT_EQ(CompiledInstructions( + "%1 = OpTypeFloat 32\nOpNop %2 = OpConstant %1 -0.5"), + CompiledInstructions( + "%1 = OpTypeFloat 32\nOpNop !0x0004002b %1 !2 -0.5")); + EXPECT_EQ(CompiledInstructions( + "%1 = OpTypeFloat 32\nOpNop %2 = OpConstant %1 0.123"), + CompiledInstructions( + "%1 = OpTypeFloat 32\nOpNop !0x0004002b %1 %2 0.123")); + EXPECT_EQ(CompiledInstructions( + "%1 = OpTypeFloat 32\nOpNop %2 = OpConstant %1 -0.5"), + CompiledInstructions( + "%1 = OpTypeFloat 32\nOpNop !0x0004002b %1 %2 -0.5")); EXPECT_EQ(Concatenate({ MakeInstruction(spv::Op::OpTypeInt, {1, 64, 0}), @@ -203,9 +209,9 @@ TEST_F(ImmediateIntTest, InvalidStatement) { TEST_F(ImmediateIntTest, InvalidStatementBetweenValidOnes) { EXPECT_THAT(Subvector(CompileSuccessfully( - "%10 = OpTypeFloat 32 !5 !6 !7 OpEmitVertex"), + "%10 = OpTypeInt 32 0 !5 !6 !7 OpEmitVertex"), kFirstInstruction), - ElementsAre(spvOpcodeMake(3, spv::Op::OpTypeFloat), 1, 32, 5, 6, + ElementsAre(spvOpcodeMake(4, spv::Op::OpTypeInt), 1, 32, 0, 5, 6, 7, spvOpcodeMake(1, spv::Op::OpEmitVertex))); } diff --git a/utils/generate_grammar_tables.py b/utils/generate_grammar_tables.py index 88534ffed..cb168b6db 100755 --- a/utils/generate_grammar_tables.py +++ b/utils/generate_grammar_tables.py @@ -540,7 +540,7 @@ def generate_operand_kind_table(enums): # We have a few operand kinds that require their optional counterpart to # exist in the operand info table. - optional_enums = ['ImageOperands', 'AccessQualifier', 'MemoryAccess', 'PackedVectorFormat', 'CooperativeMatrixOperands', 'RawAccessChainOperands'] + optional_enums = ['ImageOperands', 'AccessQualifier', 'MemoryAccess', 'PackedVectorFormat', 'CooperativeMatrixOperands', 'RawAccessChainOperands', 'FPEncoding'] optional_enums = [e for e in enums if e[0] in optional_enums] enums.extend(optional_enums)