Disassembler support for OpSpecConstantOp
Document the fact that we use names for extended instructions
and OpSpecConstantOp opcode operands.
diff --git a/readme.md b/readme.md
index ba7cc54..9d9018a 100644
--- a/readme.md
+++ b/readme.md
@@ -25,6 +25,9 @@
## 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.
diff --git a/source/assembly_grammar.cpp b/source/assembly_grammar.cpp
index 5e18f94..a437fb3 100644
--- a/source/assembly_grammar.cpp
+++ b/source/assembly_grammar.cpp
@@ -241,6 +241,17 @@
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 {
diff --git a/source/assembly_grammar.h b/source/assembly_grammar.h
index 636e952..197d8f7 100644
--- a/source/assembly_grammar.h
+++ b/source/assembly_grammar.h
@@ -78,6 +78,10 @@
// 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 '|',
diff --git a/source/binary.cpp b/source/binary.cpp
index 94e51a2..699f6b0 100644
--- a/source/binary.cpp
+++ b/source/binary.cpp
@@ -439,6 +439,26 @@
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.
diff --git a/source/disassemble.cpp b/source/disassemble.cpp
index a439b01..4ee6f35 100644
--- a/source/disassemble.cpp
+++ b/source/disassemble.cpp
@@ -183,6 +183,13 @@
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();
diff --git a/syntax.md b/syntax.md
index 5cf3ef4..be3a5d5 100644
--- a/syntax.md
+++ b/syntax.md
@@ -55,6 +55,12 @@
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>
diff --git a/test/TextToBinary.Constant.cpp b/test/TextToBinary.Constant.cpp
index ba76832..c98c7ef 100644
--- a/test/TextToBinary.Constant.cpp
+++ b/test/TextToBinary.Constant.cpp
@@ -487,6 +487,9 @@
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 @@
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 @@
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