Skip to content

Commit 0f166be

Browse files
committed
Assembler support for OpSpecConstantOp
Adds SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER.
1 parent ce9cef7 commit 0f166be

File tree

7 files changed

+334
-14
lines changed

7 files changed

+334
-14
lines changed

include/libspirv/libspirv.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,10 @@ typedef enum spv_operand_type_t {
182182
// number indicating which instruction to use from an extended instruction
183183
// set.
184184
SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER,
185+
// The Opcode argument to OpSpecConstantOp. It determines the operation
186+
// to be performed on constant operands to compute a specialization constant
187+
// result.
188+
SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER,
185189
// A literal number whose format and size are determined by a previous operand
186190
// in the same instruction. It's a signed integer, an unsigned integer, or a
187191
// floating point number. It also has a specified bit width. The width
@@ -227,11 +231,11 @@ typedef enum spv_operand_type_t {
227231
#undef FIRST_CONCRETE
228232
#undef LAST_CONCRETE
229233

230-
// The remaining operand types are only used internally by the assembler.
231-
// There are two categories:
232-
// Optional : expands to 0 or 1 operand, like ? in regular expressions.
233-
// Variable : expands to 0, 1 or many operands or pairs of operands.
234-
// This is similar to * in regular expressions.
234+
// The remaining operand types are only used internally by the assembler.
235+
// There are two categories:
236+
// Optional : expands to 0 or 1 operand, like ? in regular expressions.
237+
// Variable : expands to 0, 1 or many operands or pairs of operands.
238+
// This is similar to * in regular expressions.
235239

236240
// Macros for defining bounds on optional and variable operand types.
237241
// Any variable operand type is also optional.

source/assembly_grammar.cpp

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,89 @@ spv_ext_inst_table GetDefaultExtInstTable() {
109109
return result;
110110
}
111111

112+
// Associates an opcode with its name.
113+
struct SpecConstantOpcodeEntry {
114+
SpvOp opcode;
115+
const char* name;
116+
};
117+
118+
// All the opcodes allowed as the operation for OpSpecConstantOp.
119+
// The name does not have the usual "Op" prefix. For example opcode SpvOpIAdd
120+
// is associated with the name "IAdd".
121+
//
122+
// clang-format off
123+
#define CASE(NAME) { SpvOp##NAME, #NAME }
124+
const SpecConstantOpcodeEntry kOpSpecConstantOpcodes[] = {
125+
// Conversion
126+
CASE(SConvert),
127+
CASE(FConvert),
128+
CASE(ConvertFToS),
129+
CASE(ConvertSToF),
130+
CASE(ConvertFToU),
131+
CASE(ConvertUToF),
132+
CASE(UConvert),
133+
CASE(ConvertPtrToU),
134+
CASE(ConvertUToPtr),
135+
CASE(PtrCastToGeneric),
136+
CASE(Bitcast),
137+
CASE(QuantizeToF16),
138+
// Arithmetic
139+
CASE(SNegate),
140+
CASE(Not),
141+
CASE(IAdd),
142+
CASE(ISub),
143+
CASE(IMul),
144+
CASE(UDiv),
145+
CASE(SDiv),
146+
CASE(UMod),
147+
CASE(SRem),
148+
CASE(SMod),
149+
CASE(ShiftRightLogical),
150+
CASE(ShiftRightArithmetic),
151+
CASE(ShiftLeftLogical),
152+
CASE(BitwiseOr),
153+
CASE(BitwiseAnd),
154+
CASE(FNegate),
155+
CASE(FAdd),
156+
CASE(FSub),
157+
CASE(FMul),
158+
CASE(FDiv),
159+
CASE(FRem),
160+
CASE(FMod),
161+
// Composite
162+
CASE(VectorShuffle),
163+
CASE(CompositeExtract),
164+
CASE(CompositeInsert),
165+
// Logical
166+
CASE(LogicalOr),
167+
CASE(LogicalAnd),
168+
CASE(LogicalNot),
169+
CASE(LogicalEqual),
170+
CASE(LogicalNotEqual),
171+
CASE(Select),
172+
// Comparison
173+
CASE(IEqual),
174+
CASE(ULessThan),
175+
CASE(SLessThan),
176+
CASE(UGreaterThan),
177+
CASE(SGreaterThan),
178+
CASE(ULessThanEqual),
179+
CASE(SLessThanEqual),
180+
CASE(SLessThanEqual),
181+
CASE(UGreaterThanEqual),
182+
CASE(SGreaterThanEqual),
183+
// Memory
184+
CASE(AccessChain),
185+
CASE(InBoundsAccessChain),
186+
CASE(PtrAccessChain),
187+
CASE(InBoundsPtrAccessChain),
188+
};
189+
#undef CASE
190+
// clang-format on
191+
192+
const size_t kNumOpSpecConstantOpcodes =
193+
sizeof(kOpSpecConstantOpcodes) / sizeof(kOpSpecConstantOpcodes[0]);
194+
112195
} // anonymous namespace
113196

114197
namespace libspirv {
@@ -145,6 +228,19 @@ spv_result_t AssemblyGrammar::lookupOperand(spv_operand_type_t type,
145228
return spvOperandTableValueLookup(operandTable_, type, operand, desc);
146229
}
147230

231+
spv_result_t AssemblyGrammar::lookupSpecConstantOpcode(const char* name,
232+
SpvOp* opcode) const {
233+
const auto* last = kOpSpecConstantOpcodes + kNumOpSpecConstantOpcodes;
234+
const auto* found =
235+
std::find_if(kOpSpecConstantOpcodes, last,
236+
[name](const SpecConstantOpcodeEntry& entry) {
237+
return 0 == strcmp(name, entry.name);
238+
});
239+
if (found == last) return SPV_ERROR_INVALID_LOOKUP;
240+
*opcode = found->opcode;
241+
return SPV_SUCCESS;
242+
}
243+
148244
spv_result_t AssemblyGrammar::parseMaskOperand(const spv_operand_type_t type,
149245
const char* textValue,
150246
uint32_t* pValue) const {

source/assembly_grammar.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,13 @@ class AssemblyGrammar {
7171
spv_result_t lookupOperand(spv_operand_type_t type, uint32_t operand,
7272
spv_operand_desc* desc) const;
7373

74+
// Finds the opcode for the given OpSpecConstantOp opcode name. The name
75+
// should not have the "Op" prefix. For example, "IAdd" corresponds to
76+
// the integer add opcode for OpSpecConstantOp. On success, returns
77+
// SPV_SUCCESS and sends the discovered operation code through the opcode
78+
// parameter. On failure, returns SPV_ERROR_INVALID_LOOKUP.
79+
spv_result_t lookupSpecConstantOpcode(const char* name, SpvOp* opcode) const;
80+
7481
// Parses a mask expression string for the given operand type.
7582
//
7683
// A mask expression is a sequence of one or more terms separated by '|',

source/opcode.cpp

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@ bool opcodeTableInitialized = false;
7575
// Opcode API
7676

7777
// Converts the given operand class enum (from the SPIR-V document generation
78-
// logic) to the operand type required by the parser.
78+
// logic) to the operand type required by the parser. The SPV_OPERAND_TYPE_NONE
79+
// value indicates there is no current operand and no further operands.
7980
// This only applies to logical operands.
8081
spv_operand_type_t convertOperandClassToType(SpvOp opcode,
8182
OperandClass operandClass) {
@@ -113,6 +114,13 @@ spv_operand_type_t convertOperandClassToType(SpvOp opcode,
113114
case OperandOptionalImage:
114115
return SPV_OPERAND_TYPE_OPTIONAL_IMAGE;
115116
case OperandVariableIds:
117+
if (opcode == SpvOpSpecConstantOp) {
118+
// These are the operands to the specialization constant opcode.
119+
// The assembler and binary parser set up the extra Id and literal
120+
// arguments when processing the opcode operand. So don't add
121+
// an operand type for them here.
122+
return SPV_OPERAND_TYPE_NONE;
123+
}
116124
return SPV_OPERAND_TYPE_VARIABLE_ID;
117125
// The spec only uses OptionalLiteral for an optional literal number.
118126
case OperandOptionalLiteral:
@@ -131,6 +139,12 @@ spv_operand_type_t convertOperandClassToType(SpvOp opcode,
131139
// TODO(dneto): Use a function to confirm the assumption, and to verify
132140
// that the index into the operandClass is 1, as expected.
133141
return SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER;
142+
} else if (opcode == SpvOpSpecConstantOp) {
143+
// Use a special operand type for the opcode operand, so we can
144+
// use mnemonic names instead of the numbers. For example, the
145+
// assembler should accept "IAdd" instead of the numeric value of
146+
// SpvOpIAdd.
147+
return SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER;
134148
}
135149
return SPV_OPERAND_TYPE_LITERAL_INTEGER;
136150
case OperandLiteralString:
@@ -245,16 +259,20 @@ void spvOpcodeTableInitialize() {
245259
opcode.numTypes < maxNumOperands && classIndex < maxNumClasses;
246260
classIndex++) {
247261
const OperandClass operandClass = opcode.operandClass[classIndex];
248-
opcode.operandTypes[opcode.numTypes++] =
262+
const auto operandType =
249263
convertOperandClassToType(opcode.opcode, operandClass);
264+
opcode.operandTypes[opcode.numTypes++] = operandType;
250265
// The OperandNone value is not explicitly represented in the .inc file.
251266
// However, it is the zero value, and is created via implicit value
252-
// initialization.
253-
if (operandClass == OperandNone) {
267+
// initialization. It converts to SPV_OPERAND_TYPE_NONE.
268+
// The SPV_OPERAND_TYPE_NONE operand type indicates no current or futher
269+
// operands.
270+
if (operandType == SPV_OPERAND_TYPE_NONE) {
254271
opcode.numTypes--;
255272
break;
256273
}
257274
}
275+
258276
// We should have written the terminating SPV_OPERAND_TYPE_NONE entry, but
259277
// also without overflowing.
260278
assert((opcode.numTypes < maxNumOperands) &&

source/operand.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1191,6 +1191,8 @@ const char* spvOperandTypeStr(spv_operand_type_t type) {
11911191
return "possibly multi-word literal number";
11921192
case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER:
11931193
return "extension instruction number";
1194+
case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER:
1195+
return "OpSpecConstantOp opcode";
11941196
case SPV_OPERAND_TYPE_LITERAL_STRING:
11951197
case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_STRING:
11961198
return "literal string";

source/text.cpp

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,12 @@
3838
#include <unordered_map>
3939
#include <vector>
4040

41+
#include <libspirv/libspirv.h>
4142
#include "assembly_grammar.h"
4243
#include "binary.h"
4344
#include "diagnostic.h"
4445
#include "ext_inst.h"
4546
#include "instruction.h"
46-
#include <libspirv/libspirv.h>
4747
#include "opcode.h"
4848
#include "operand.h"
4949
#include "text_handler.h"
@@ -245,7 +245,6 @@ spv_result_t spvTextEncodeOperand(const libspirv::AssemblyGrammar& grammar,
245245
}
246246
pInst->extInstType = ext_inst_type;
247247
}
248-
249248
} break;
250249

251250
case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER: {
@@ -260,8 +259,30 @@ spv_result_t spvTextEncodeOperand(const libspirv::AssemblyGrammar& grammar,
260259

261260
// Prepare to parse the operands for the extended instructions.
262261
spvPrependOperandTypes(extInst->operandTypes, pExpectedOperands);
262+
} break;
263263

264-
return SPV_SUCCESS;
264+
case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER: {
265+
// The assembler accepts the symbolic name for the opcode, but without
266+
// the "Op" prefix. For example, "IAdd" is accepted. The number
267+
// of the opcode is emitted.
268+
SpvOp opcode;
269+
if (grammar.lookupSpecConstantOpcode(textValue, &opcode)) {
270+
return context->diagnostic() << "Invalid " << spvOperandTypeStr(type)
271+
<< " '" << textValue << "'.";
272+
}
273+
spv_opcode_desc opcodeEntry = nullptr;
274+
if (grammar.lookupOpcode(opcode, &opcodeEntry)) {
275+
return context->diagnostic(SPV_ERROR_INTERNAL)
276+
<< "OpSpecConstant opcode table out of sync";
277+
}
278+
spvInstructionAddWord(pInst, uint32_t(opcodeEntry->opcode));
279+
280+
// Prepare to parse the operands for the opcode. Except skip the
281+
// type Id and result Id, since they've already been processed.
282+
assert(opcodeEntry->hasType);
283+
assert(opcodeEntry->hasResult);
284+
assert(opcodeEntry->numTypes >= 2);
285+
spvPrependOperandTypes(opcodeEntry->operandTypes + 2, pExpectedOperands);
265286
} break;
266287

267288
case SPV_OPERAND_TYPE_LITERAL_INTEGER:
@@ -348,7 +369,8 @@ spv_result_t spvTextEncodeOperand(const libspirv::AssemblyGrammar& grammar,
348369
<< "Invalid extended instruction import '" << literal.value.str
349370
<< "'";
350371
}
351-
if (auto error = context->recordIdAsExtInstImport(pInst->words[1], ext_inst_type))
372+
if (auto error = context->recordIdAsExtInstImport(pInst->words[1],
373+
ext_inst_type))
352374
return error;
353375
}
354376

0 commit comments

Comments
 (0)