Disassembler support for OpSpecConstantOp

Document the fact that we use names for extended instructions
and OpSpecConstantOp opcode operands.
This commit is contained in:
David Neto 2015-11-11 02:45:45 -05:00
parent 0f166be68d
commit 2119694775
7 changed files with 60 additions and 0 deletions

View File

@ -25,6 +25,9 @@ The validator is incomplete. See the Future Work section for more information.
## CHANGES (for tools hackers)
* Support `OpSpecConstantOp`.
The opcode operand uses the opcode name, but without the `Op` prefix.
2015-11-10
* Refactored the SPIR-V binary parser:
* The binary parser issues callbacks to a parser client.

View File

@ -241,6 +241,17 @@ spv_result_t AssemblyGrammar::lookupSpecConstantOpcode(const char* name,
return SPV_SUCCESS;
}
spv_result_t AssemblyGrammar::lookupSpecConstantOpcode(SpvOp opcode) const {
const auto* last = kOpSpecConstantOpcodes + kNumOpSpecConstantOpcodes;
const auto* found =
std::find_if(kOpSpecConstantOpcodes, last,
[opcode](const SpecConstantOpcodeEntry& entry) {
return opcode == entry.opcode;
});
if (found == last) return SPV_ERROR_INVALID_LOOKUP;
return SPV_SUCCESS;
}
spv_result_t AssemblyGrammar::parseMaskOperand(const spv_operand_type_t type,
const char* textValue,
uint32_t* pValue) const {

View File

@ -78,6 +78,10 @@ class AssemblyGrammar {
// parameter. On failure, returns SPV_ERROR_INVALID_LOOKUP.
spv_result_t lookupSpecConstantOpcode(const char* name, SpvOp* opcode) const;
// Returns SPV_SUCCESS if the given opcode is valid as the opcode operand
// to OpSpecConstantOp.
spv_result_t lookupSpecConstantOpcode(SpvOp opcode) const;
// Parses a mask expression string for the given operand type.
//
// A mask expression is a sequence of one or more terms separated by '|',

View File

@ -439,6 +439,26 @@ spv_result_t Parser::parseOperand(spv_parsed_instruction_t* inst,
spvPrependOperandTypes(ext_inst->operandTypes, expected_operands);
} break;
case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER: {
assert(SpvOpSpecConstantOp == inst->opcode);
if (grammar_.lookupSpecConstantOpcode(SpvOp(word))) {
return diagnostic() << "Invalid " << spvOperandTypeStr(type) << ": "
<< word;
}
spv_opcode_desc opcode_entry = nullptr;
if (grammar_.lookupOpcode(SpvOp(word), &opcode_entry)) {
return diagnostic(SPV_ERROR_INTERNAL)
<< "OpSpecConstant opcode table out of sync";
}
// OpSpecConstant opcodes must have a type and result. We've already
// processed them, so skip them when preparing to parse the other
// operants for the opcode.
assert(opcode_entry->hasType);
assert(opcode_entry->hasResult);
assert(opcode_entry->numTypes >= 2);
spvPrependOperandTypes(opcode_entry->operandTypes + 2, expected_operands);
} break;
case SPV_OPERAND_TYPE_LITERAL_INTEGER:
case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER:
// These are regular single-word literal integer operands.

View File

@ -183,6 +183,13 @@ void Disassembler::EmitOperand(const spv_parsed_instruction_t& inst,
SetRed();
stream_ << ext_inst->name;
} break;
case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER: {
spv_opcode_desc opcode_desc;
if (grammar_.lookupOpcode(SpvOp(word), &opcode_desc))
assert(false && "should have caught this earlier");
SetRed();
stream_ << opcode_desc->name;
} break;
case SPV_OPERAND_TYPE_LITERAL_INTEGER:
case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER: {
SetRed();

View File

@ -55,6 +55,12 @@ the SPIR-V specification. An operand is one of:
which is the combination of the `NotNaN`, `NotInf`, and `NSZ` flags.
* an injected immediate integer: `!<integer>`. See [below](#immediate).
* an ID, e.g. `%foo`. See [below](#id).
* the name of an extended instruction. For example, `sqrt` in an extended
instruction such as `%f = OpExtInst %f32 %OpenCLImport sqrt %arg`
* the name of an opcode for OpSpecConstantOp, but where the `Op` prefix
is removed. For example, the following indicates the use of an integer
addition in a specialization constant computation:
`%sum = OpSpecConstantOp %i32 IAdd %a %b`
## ID Definitions & Usage
<a name="id"></a>

View File

@ -487,6 +487,9 @@ TEST_P(OpSpecConstantOpTestWithIds, Assembly) {
Eq(MakeInstruction(SpvOpSpecConstantOp,
{1, 2, uint32_t(GetParam().value())},
GetParam().operands())));
// Check the disassembler as well.
EXPECT_THAT(EncodeAndDecodeSuccessfully(input.str()), input.str());
}
// clang-format off
@ -594,6 +597,9 @@ TEST_P(OpSpecConstantOpTestWithTwoIdsThenLiteralNumbers, Assembly) {
Eq(MakeInstruction(SpvOpSpecConstantOp,
{1, 2, uint32_t(GetParam().value()), 3, 4},
GetParam().operands())));
// Check the disassembler as well.
EXPECT_THAT(EncodeAndDecodeSuccessfully(input.str()), input.str());
}
#define CASE(NAME) SpvOp##NAME, #NAME
@ -629,6 +635,9 @@ TEST_P(OpSpecConstantOpTestWithOneIdThenLiteralNumbers, Assembly) {
Eq(MakeInstruction(SpvOpSpecConstantOp,
{1, 2, uint32_t(GetParam().value()), 3},
GetParam().operands())));
// Check the disassembler as well.
EXPECT_THAT(EncodeAndDecodeSuccessfully(input.str()), input.str());
}
#define CASE(NAME) SpvOp##NAME, #NAME