Add FPEncoding operand type. (#5726)

This patch adds the optional FPEncoding operand that can be added to OpTypeFloat.
At the moment there is no usable operand, so support is limited to adding the entry.

Co-authored-by: Kévin Petit <kevin.petit@arm.com>
Co-authored-by: David Neto <dneto@google.com>
This commit is contained in:
Victor Lomuller 2024-07-03 18:18:40 +01:00 committed by GitHub
parent 973e791a9a
commit 3bc9744d0a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 38 additions and 16 deletions

View File

@ -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

View File

@ -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)) {

View File

@ -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))

View File

@ -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");

View File

@ -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;

View File

@ -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<Instruction>(
context(), spv::Op::OpTypeFloat, 0, id,
std::initializer_list<Operand>{

View File

@ -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};

View File

@ -136,19 +136,25 @@ TEST_F(ImmediateIntTest, IntegerFollowingImmediate) {
}
// Literal floats after !<integer> 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)));
}

View File

@ -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)