Disassembler support for OpSpecConstantOp
Document the fact that we use names for extended instructions and OpSpecConstantOp opcode operands.
This commit is contained in:
Родитель
0f166be68d
Коммит
2119694775
|
@ -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.
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 '|',
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче