MLIR 23.0.0git
DeserializeOps.cpp
Go to the documentation of this file.
1//===- DeserializeOps.cpp - MLIR SPIR-V Deserialization (Ops) -------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines the Deserializer methods for SPIR-V binary instructions.
10//
11//===----------------------------------------------------------------------===//
12
13#include "Deserializer.h"
14
17#include "mlir/IR/Builders.h"
18#include "mlir/IR/Location.h"
20#include "llvm/ADT/STLExtras.h"
21#include "llvm/ADT/SmallVector.h"
22#include "llvm/Support/Debug.h"
23#include <optional>
24
25using namespace mlir;
26
27#define DEBUG_TYPE "spirv-deserialization"
28
29//===----------------------------------------------------------------------===//
30// Utility Functions
31//===----------------------------------------------------------------------===//
32
33/// Extracts the opcode from the given first word of a SPIR-V instruction.
34static inline spirv::Opcode extractOpcode(uint32_t word) {
35 return static_cast<spirv::Opcode>(word & 0xffff);
36}
37
38//===----------------------------------------------------------------------===//
39// Instruction
40//===----------------------------------------------------------------------===//
41
43 if (auto constInfo = getConstant(id)) {
44 // Materialize a `spirv.Constant` op at every use site.
45 return spirv::ConstantOp::create(opBuilder, unknownLoc, constInfo->second,
46 constInfo->first);
47 }
48 if (std::optional<std::pair<Attribute, Type>> constCompositeReplicateInfo =
50 return spirv::EXTConstantCompositeReplicateOp::create(
51 opBuilder, unknownLoc, constCompositeReplicateInfo->second,
52 constCompositeReplicateInfo->first);
53 }
54 if (auto varOp = getGlobalVariable(id)) {
55 auto addressOfOp =
56 spirv::AddressOfOp::create(opBuilder, unknownLoc, varOp.getType(),
57 SymbolRefAttr::get(varOp.getOperation()));
58 return addressOfOp.getPointer();
59 }
60 if (auto constOp = getSpecConstant(id)) {
61 auto referenceOfOp = spirv::ReferenceOfOp::create(
62 opBuilder, unknownLoc, constOp.getDefaultValue().getType(),
63 SymbolRefAttr::get(constOp.getOperation()));
64 return referenceOfOp.getReference();
65 }
66 if (SpecConstantCompositeOp specConstCompositeOp =
68 auto referenceOfOp = spirv::ReferenceOfOp::create(
69 opBuilder, unknownLoc, specConstCompositeOp.getType(),
70 SymbolRefAttr::get(specConstCompositeOp.getOperation()));
71 return referenceOfOp.getReference();
72 }
73 if (auto specConstCompositeReplicateOp =
75 auto referenceOfOp = spirv::ReferenceOfOp::create(
76 opBuilder, unknownLoc, specConstCompositeReplicateOp.getType(),
77 SymbolRefAttr::get(specConstCompositeReplicateOp.getOperation()));
78 return referenceOfOp.getReference();
79 }
80 if (auto specConstOperationInfo = getSpecConstantOperation(id)) {
82 id, specConstOperationInfo->enclodesOpcode,
83 specConstOperationInfo->resultTypeID,
84 specConstOperationInfo->enclosedOpOperands);
85 }
86 if (auto undef = getUndefType(id)) {
87 return spirv::UndefOp::create(opBuilder, unknownLoc, undef);
88 }
89 if (std::optional<spirv::GraphConstantARMOpMaterializationInfo>
90 graphConstantARMInfo = getGraphConstantARM(id)) {
91 IntegerAttr graphConstantID = graphConstantARMInfo->graphConstantID;
92 Type resultType = graphConstantARMInfo->resultType;
93 return spirv::GraphConstantARMOp::create(opBuilder, unknownLoc, resultType,
94 graphConstantID);
95 }
96 return valueMap.lookup(id);
97}
98
100 spirv::Opcode &opcode, ArrayRef<uint32_t> &operands,
101 std::optional<spirv::Opcode> expectedOpcode) {
102 auto binarySize = binary.size();
103 if (curOffset >= binarySize) {
104 return emitError(unknownLoc, "expected ")
105 << (expectedOpcode ? spirv::stringifyOpcode(*expectedOpcode)
106 : "more")
107 << " instruction";
108 }
109
110 // For each instruction, get its word count from the first word to slice it
111 // from the stream properly, and then dispatch to the instruction handler.
112
113 uint32_t wordCount = binary[curOffset] >> 16;
114
115 if (wordCount == 0)
116 return emitError(unknownLoc, "word count cannot be zero");
117
118 uint32_t nextOffset = curOffset + wordCount;
119 if (nextOffset > binarySize)
120 return emitError(unknownLoc, "insufficient words for the last instruction");
121
122 opcode = extractOpcode(binary[curOffset]);
123 operands = binary.slice(curOffset + 1, wordCount - 1);
124 curOffset = nextOffset;
125 return success();
126}
127
129 spirv::Opcode opcode, ArrayRef<uint32_t> &operands,
130 SmallVectorImpl<uint32_t> &mergedStorage) {
131 std::optional<spirv::Opcode> continuationOp = getContinuationOpcode(opcode);
132 if (!continuationOp)
133 return;
134
135 size_t binarySize = binary.size();
136 auto isNextContinuation = [&]() {
137 if (curOffset >= binarySize)
138 return false;
139 uint32_t wordCount = binary[curOffset] >> 16;
140 if (wordCount == 0 || curOffset + wordCount > binarySize)
141 return false;
142 return extractOpcode(binary[curOffset]) == *continuationOp;
143 };
144
145 if (!isNextContinuation())
146 return;
147
148 mergedStorage.assign(operands);
149 do {
150 spirv::Opcode contOpcode;
151 ArrayRef<uint32_t> contOperands;
152 if (failed(sliceInstruction(contOpcode, contOperands, *continuationOp)))
153 return;
154 llvm::append_range(mergedStorage, contOperands);
155 } while (isNextContinuation());
156 operands = mergedStorage;
157}
158
160 spirv::Opcode opcode, ArrayRef<uint32_t> operands, bool deferInstructions) {
161 LLVM_DEBUG(logger.startLine() << "[inst] processing instruction "
162 << spirv::stringifyOpcode(opcode) << "\n");
163
164 SmallVector<uint32_t, 0> mergedStorage;
165 mergeLongCompositeContinuations(opcode, operands, mergedStorage);
166
167 // First dispatch all the instructions whose opcode does not correspond to
168 // those that have a direct mirror in the SPIR-V dialect
169 switch (opcode) {
170 case spirv::Opcode::OpCapability:
171 return processCapability(operands);
172 case spirv::Opcode::OpExtension:
173 return processExtension(operands);
174 case spirv::Opcode::OpExtInst:
175 return processExtInst(operands);
176 case spirv::Opcode::OpExtInstImport:
177 return processExtInstImport(operands);
178 case spirv::Opcode::OpMemberName:
179 return processMemberName(operands);
180 case spirv::Opcode::OpMemoryModel:
181 return processMemoryModel(operands);
182 case spirv::Opcode::OpEntryPoint:
183 case spirv::Opcode::OpExecutionMode:
184 case spirv::Opcode::OpExecutionModeId:
185 if (deferInstructions) {
186 deferredInstructions.emplace_back(opcode, operands);
187 return success();
188 }
189 break;
190 case spirv::Opcode::OpVariable:
191 if (isa<spirv::ModuleOp>(opBuilder.getBlock()->getParentOp())) {
192 return processGlobalVariable(operands);
193 }
194 break;
195 case spirv::Opcode::OpLine:
196 return processDebugLine(operands);
197 case spirv::Opcode::OpNoLine:
199 return success();
200 case spirv::Opcode::OpName:
201 return processName(operands);
202 case spirv::Opcode::OpString:
203 return processDebugString(operands);
204 case spirv::Opcode::OpModuleProcessed:
205 case spirv::Opcode::OpSource:
206 case spirv::Opcode::OpSourceContinued:
207 case spirv::Opcode::OpSourceExtension:
208 // TODO: This is debug information embedded in the binary which should be
209 // translated into the spirv.module.
210 return success();
211 case spirv::Opcode::OpTypeVoid:
212 case spirv::Opcode::OpTypeBool:
213 case spirv::Opcode::OpTypeInt:
214 case spirv::Opcode::OpTypeFloat:
215 case spirv::Opcode::OpTypeVector:
216 case spirv::Opcode::OpTypeMatrix:
217 case spirv::Opcode::OpTypeArray:
218 case spirv::Opcode::OpTypeFunction:
219 case spirv::Opcode::OpTypeImage:
220 case spirv::Opcode::OpTypeSampler:
221 case spirv::Opcode::OpTypeNamedBarrier:
222 case spirv::Opcode::OpTypeSampledImage:
223 case spirv::Opcode::OpTypeRuntimeArray:
224 case spirv::Opcode::OpTypeStruct:
225 case spirv::Opcode::OpTypePointer:
226 case spirv::Opcode::OpTypeTensorARM:
227 case spirv::Opcode::OpTypeGraphARM:
228 case spirv::Opcode::OpTypeCooperativeMatrixKHR:
229 return processType(opcode, operands);
230 case spirv::Opcode::OpTypeForwardPointer:
231 return processTypeForwardPointer(operands);
232 case spirv::Opcode::OpConstant:
233 return processConstant(operands, /*isSpec=*/false);
234 case spirv::Opcode::OpSpecConstant:
235 return processConstant(operands, /*isSpec=*/true);
236 case spirv::Opcode::OpConstantComposite:
237 return processConstantComposite(operands);
238 case spirv::Opcode::OpConstantCompositeReplicateEXT:
240 case spirv::Opcode::OpSpecConstantComposite:
241 return processSpecConstantComposite(operands);
242 case spirv::Opcode::OpSpecConstantCompositeReplicateEXT:
244 case spirv::Opcode::OpSpecConstantOp:
245 return processSpecConstantOperation(operands);
246 case spirv::Opcode::OpConstantTrue:
247 return processConstantBool(/*isTrue=*/true, operands, /*isSpec=*/false);
248 case spirv::Opcode::OpSpecConstantTrue:
249 return processConstantBool(/*isTrue=*/true, operands, /*isSpec=*/true);
250 case spirv::Opcode::OpConstantFalse:
251 return processConstantBool(/*isTrue=*/false, operands, /*isSpec=*/false);
252 case spirv::Opcode::OpSpecConstantFalse:
253 return processConstantBool(/*isTrue=*/false, operands, /*isSpec=*/true);
254 case spirv::Opcode::OpConstantNull:
255 return processConstantNull(operands);
256 case spirv::Opcode::OpGraphConstantARM:
257 return processGraphConstantARM(operands);
258 case spirv::Opcode::OpDecorate:
259 case spirv::Opcode::OpDecorateId:
260 return processDecoration(operands);
261 case spirv::Opcode::OpMemberDecorate:
262 return processMemberDecoration(operands);
263 case spirv::Opcode::OpFunction:
264 return processFunction(operands);
265 case spirv::Opcode::OpGraphEntryPointARM:
266 if (deferInstructions) {
267 deferredInstructions.emplace_back(opcode, operands);
268 return success();
269 }
270 return processGraphEntryPointARM(operands);
271 case spirv::Opcode::OpGraphARM:
272 return processGraphARM(operands);
273 case spirv::Opcode::OpGraphSetOutputARM:
274 return processOpGraphSetOutputARM(operands);
275 case spirv::Opcode::OpGraphEndARM:
276 return processGraphEndARM(operands);
277 case spirv::Opcode::OpLabel:
278 return processLabel(operands);
279 case spirv::Opcode::OpBranch:
280 return processBranch(operands);
281 case spirv::Opcode::OpBranchConditional:
282 return processBranchConditional(operands);
283 case spirv::Opcode::OpSelectionMerge:
284 return processSelectionMerge(operands);
285 case spirv::Opcode::OpLoopMerge:
286 return processLoopMerge(operands);
287 case spirv::Opcode::OpPhi:
288 return processPhi(operands);
289 case spirv::Opcode::OpSwitch:
290 return processSwitch(operands);
291 case spirv::Opcode::OpUndef:
292 return processUndef(operands);
293 default:
294 break;
295 }
296 return dispatchToAutogenDeserialization(opcode, operands);
297}
298
300 ArrayRef<uint32_t> words, StringRef opName, bool hasResult,
301 unsigned numOperands) {
302 SmallVector<Type, 1> resultTypes;
303 uint32_t valueID = 0;
304
305 size_t wordIndex = 0;
306 if (hasResult) {
307 if (wordIndex >= words.size())
308 return emitError(unknownLoc,
309 "expected result type <id> while deserializing for ")
310 << opName;
311
312 // Decode the type <id>
313 auto type = getType(words[wordIndex]);
314 if (!type)
315 return emitError(unknownLoc, "unknown type result <id>: ")
316 << words[wordIndex];
317 resultTypes.push_back(type);
318 ++wordIndex;
319
320 // Decode the result <id>
321 if (wordIndex >= words.size())
322 return emitError(unknownLoc,
323 "expected result <id> while deserializing for ")
324 << opName;
325 valueID = words[wordIndex];
326 ++wordIndex;
327 }
328
329 SmallVector<Value, 4> operands;
331
332 // Decode operands
333 size_t operandIndex = 0;
334 for (; operandIndex < numOperands && wordIndex < words.size();
335 ++operandIndex, ++wordIndex) {
336 auto arg = getValue(words[wordIndex]);
337 if (!arg)
338 return emitError(unknownLoc, "unknown result <id>: ") << words[wordIndex];
339 operands.push_back(arg);
340 }
341 if (operandIndex != numOperands) {
342 return emitError(
343 unknownLoc,
344 "found less operands than expected when deserializing for ")
345 << opName << "; only " << operandIndex << " of " << numOperands
346 << " processed";
347 }
348 if (wordIndex != words.size()) {
349 return emitError(
350 unknownLoc,
351 "found more operands than expected when deserializing for ")
352 << opName << "; only " << wordIndex << " of " << words.size()
353 << " processed";
354 }
355
356 // Attach attributes from decorations
357 if (decorations.count(valueID)) {
358 auto attrs = decorations[valueID].getAttrs();
359 attributes.append(attrs.begin(), attrs.end());
360 }
361
362 // Create the op and update bookkeeping maps
363 Location loc = createFileLineColLoc(opBuilder);
364 OperationState opState(loc, opName);
365 opState.addOperands(operands);
366 if (hasResult)
367 opState.addTypes(resultTypes);
368 opState.addAttributes(attributes);
369 Operation *op = opBuilder.create(opState);
370 if (hasResult)
371 valueMap[valueID] = op->getResult(0);
372
375
376 return success();
377}
378
380 if (operands.size() != 2) {
381 return emitError(unknownLoc, "OpUndef instruction must have two operands");
382 }
383 auto type = getType(operands[0]);
384 if (!type) {
385 return emitError(unknownLoc, "unknown type <id> with OpUndef instruction");
386 }
387 undefMap[operands[1]] = type;
388 return success();
389}
390
392 if (operands.size() < 4) {
393 return emitError(unknownLoc,
394 "OpExtInst must have at least 4 operands, result type "
395 "<id>, result <id>, set <id> and instruction opcode");
396 }
397 if (!extendedInstSets.count(operands[2])) {
398 return emitError(unknownLoc, "undefined set <id> in OpExtInst");
399 }
400 SmallVector<uint32_t, 4> slicedOperands;
401 slicedOperands.append(operands.begin(), std::next(operands.begin(), 2));
402 slicedOperands.append(std::next(operands.begin(), 4), operands.end());
404 extendedInstSets[operands[2]], operands[3], slicedOperands);
405}
406
407namespace mlir {
408namespace spirv {
409
410template <>
411LogicalResult
413 unsigned wordIndex = 0;
414 if (wordIndex >= words.size()) {
415 return emitError(unknownLoc,
416 "missing Execution Model specification in OpEntryPoint");
417 }
418 auto execModel = spirv::ExecutionModelAttr::get(
419 context, static_cast<spirv::ExecutionModel>(words[wordIndex++]));
420 if (wordIndex >= words.size()) {
421 return emitError(unknownLoc, "missing <id> in OpEntryPoint");
422 }
423 // Get the function <id>
424 auto fnID = words[wordIndex++];
425 // Get the function name
426 auto fnName = decodeStringLiteral(words, wordIndex);
427 // Verify that the function <id> matches the fnName
428 auto parsedFunc = getFunction(fnID);
429 if (!parsedFunc) {
430 return emitError(unknownLoc, "no function matching <id> ") << fnID;
431 }
432 if (parsedFunc.getName() != fnName) {
433 // The deserializer uses "spirv_fn_<id>" as the function name if the input
434 // SPIR-V blob does not contain a name for it. We should use a more clear
435 // indication for such case rather than relying on naming details.
436 if (!parsedFunc.getName().starts_with("spirv_fn_"))
437 return emitError(unknownLoc,
438 "function name mismatch between OpEntryPoint "
439 "and OpFunction with <id> ")
440 << fnID << ": " << fnName << " vs. " << parsedFunc.getName();
441 parsedFunc.setName(fnName);
442 }
444 while (wordIndex < words.size()) {
445 auto arg = getGlobalVariable(words[wordIndex]);
446 if (!arg) {
447 return emitError(unknownLoc, "undefined result <id> ")
448 << words[wordIndex] << " while decoding OpEntryPoint";
449 }
450 interface.push_back(SymbolRefAttr::get(arg.getOperation()));
451 wordIndex++;
452 }
453 spirv::EntryPointOp::create(
454 opBuilder, unknownLoc, execModel,
455 SymbolRefAttr::get(opBuilder.getContext(), fnName),
456 opBuilder.getArrayAttr(interface));
457 return success();
458}
459
460template <>
461LogicalResult
463 unsigned wordIndex = 0;
464 if (wordIndex >= words.size()) {
465 return emitError(unknownLoc,
466 "missing function result <id> in OpExecutionMode");
467 }
468 // Get the function <id> to get the name of the function
469 auto fnID = words[wordIndex++];
470 auto fn = getFunction(fnID);
471 if (!fn) {
472 return emitError(unknownLoc, "no function matching <id> ") << fnID;
473 }
474 // Get the Execution mode
475 if (wordIndex >= words.size()) {
476 return emitError(unknownLoc, "missing Execution Mode in OpExecutionMode");
477 }
478 auto execMode = spirv::ExecutionModeAttr::get(
479 context, static_cast<spirv::ExecutionMode>(words[wordIndex++]));
480
481 // Get the values
482 SmallVector<Attribute, 4> attrListElems;
483 while (wordIndex < words.size()) {
484 attrListElems.push_back(opBuilder.getI32IntegerAttr(words[wordIndex++]));
485 }
486 auto values = opBuilder.getArrayAttr(attrListElems);
487 spirv::ExecutionModeOp::create(
488 opBuilder, unknownLoc,
489 SymbolRefAttr::get(opBuilder.getContext(), fn.getName()), execMode,
490 values);
491 return success();
492}
493
494template <>
495LogicalResult
497 unsigned wordIndex = 0;
498 unsigned const wordsSize = words.size();
499 if (wordIndex >= wordsSize)
500 return emitError(unknownLoc,
501 "missing function result <id> in OpExecutionModeId");
502
503 // Get the function <id> to get the name of the function.
504 uint32_t fnID = words[wordIndex++];
505 FuncOp fn = getFunction(fnID);
506 if (!fn)
507 return emitError(unknownLoc, "no function matching <id> ") << fnID;
508
509 // Get the Execution mode.
510 if (wordIndex >= wordsSize)
511 return emitError(unknownLoc, "missing Execution Mode in OpExecutionModeId");
512
513 ExecutionModeAttr execMode = spirv::ExecutionModeAttr::get(
514 context, static_cast<spirv::ExecutionMode>(words[wordIndex++]));
515
516 // Get the values.
517 SmallVector<Attribute, 4> attrListElems;
518 while (wordIndex < words.size()) {
519 std::string id = getSpecConstantSymbol(words[wordIndex++]);
520 attrListElems.push_back(FlatSymbolRefAttr::get(context, id));
521 }
522 ArrayAttr values = opBuilder.getArrayAttr(attrListElems);
523 spirv::ExecutionModeIdOp::create(
524 opBuilder, unknownLoc,
525 SymbolRefAttr::get(opBuilder.getContext(), fn.getName()), execMode,
526 values);
527 return success();
528}
529
530template <>
531LogicalResult
533 if (operands.size() < 3) {
534 return emitError(unknownLoc,
535 "OpFunctionCall must have at least 3 operands");
536 }
537
538 Type resultType = getType(operands[0]);
539 if (!resultType) {
540 return emitError(unknownLoc, "undefined result type from <id> ")
541 << operands[0];
542 }
543
544 // Use null type to mean no result type.
545 if (isVoidType(resultType))
546 resultType = nullptr;
547
548 auto resultID = operands[1];
549 auto functionID = operands[2];
550
551 auto functionName = getFunctionSymbol(functionID);
552
553 SmallVector<Value, 4> arguments;
554 for (auto operand : llvm::drop_begin(operands, 3)) {
555 auto value = getValue(operand);
556 if (!value) {
557 return emitError(unknownLoc, "unknown <id> ")
558 << operand << " used by OpFunctionCall";
559 }
560 arguments.push_back(value);
561 }
562
563 auto opFunctionCall = spirv::FunctionCallOp::create(
564 opBuilder, unknownLoc, resultType,
565 SymbolRefAttr::get(opBuilder.getContext(), functionName), arguments);
566
567 if (resultType)
568 valueMap[resultID] = opFunctionCall.getResult(0);
569 return success();
570}
571
572template <>
573LogicalResult
575 SmallVector<Type, 1> resultTypes;
576 size_t wordIndex = 0;
577 SmallVector<Value, 4> operands;
579
580 if (wordIndex < words.size()) {
581 auto arg = getValue(words[wordIndex]);
582
583 if (!arg) {
584 return emitError(unknownLoc, "unknown result <id> : ")
585 << words[wordIndex];
586 }
587
588 operands.push_back(arg);
589 wordIndex++;
590 }
591
592 if (wordIndex < words.size()) {
593 auto arg = getValue(words[wordIndex]);
594
595 if (!arg) {
596 return emitError(unknownLoc, "unknown result <id> : ")
597 << words[wordIndex];
598 }
599
600 operands.push_back(arg);
601 wordIndex++;
602 }
603
604 bool isAlignedAttr = false;
605
606 if (wordIndex < words.size()) {
607 auto attrValue = words[wordIndex++];
608 auto attr = opBuilder.getAttr<spirv::MemoryAccessAttr>(
609 static_cast<spirv::MemoryAccess>(attrValue));
610 attributes.push_back(
611 opBuilder.getNamedAttr(attributeName<MemoryAccess>(), attr));
612 isAlignedAttr = (attrValue == 2);
613 }
614
615 if (isAlignedAttr && wordIndex < words.size()) {
616 attributes.push_back(opBuilder.getNamedAttr(
617 "alignment", opBuilder.getI32IntegerAttr(words[wordIndex++])));
618 }
619
620 if (wordIndex < words.size()) {
621 auto attrValue = words[wordIndex++];
622 auto attr = opBuilder.getAttr<spirv::MemoryAccessAttr>(
623 static_cast<spirv::MemoryAccess>(attrValue));
624 attributes.push_back(opBuilder.getNamedAttr("source_memory_access", attr));
625 }
626
627 if (wordIndex < words.size()) {
628 attributes.push_back(opBuilder.getNamedAttr(
629 "source_alignment", opBuilder.getI32IntegerAttr(words[wordIndex++])));
630 }
631
632 if (wordIndex != words.size()) {
633 return emitError(unknownLoc,
634 "found more operands than expected when deserializing "
635 "spirv::CopyMemoryOp, only ")
636 << wordIndex << " of " << words.size() << " processed";
637 }
638
639 Location loc = createFileLineColLoc(opBuilder);
640 spirv::CopyMemoryOp::create(opBuilder, loc, resultTypes, operands,
641 attributes);
642
643 return success();
644}
645
646template <>
648 ArrayRef<uint32_t> words) {
649 if (words.size() != 4) {
650 return emitError(unknownLoc,
651 "expected 4 words in GenericCastToPtrExplicitOp"
652 " but got : ")
653 << words.size();
654 }
655 SmallVector<Type, 1> resultTypes;
656 SmallVector<Value, 4> operands;
657 uint32_t valueID = 0;
658 auto type = getType(words[0]);
659
660 if (!type)
661 return emitError(unknownLoc, "unknown type result <id> : ") << words[0];
662 resultTypes.push_back(type);
663
664 valueID = words[1];
665
666 auto arg = getValue(words[2]);
667 if (!arg)
668 return emitError(unknownLoc, "unknown result <id> : ") << words[2];
669 operands.push_back(arg);
670
671 Location loc = createFileLineColLoc(opBuilder);
672 Operation *op = spirv::GenericCastToPtrExplicitOp::create(
673 opBuilder, loc, resultTypes, operands);
674 valueMap[valueID] = op->getResult(0);
675 return success();
676}
677
678// Pull in auto-generated Deserializer::dispatchToAutogenDeserialization() and
679// various Deserializer::processOp<...>() specializations.
680#define GET_DESERIALIZATION_FNS
681#include "mlir/Dialect/SPIRV/IR/SPIRVSerialization.inc"
682
683} // namespace spirv
684} // namespace mlir
return success()
static spirv::Opcode extractOpcode(uint32_t word)
Extracts the opcode from the given first word of a SPIR-V instruction.
static FlatSymbolRefAttr get(StringAttr value)
Construct a symbol reference for the given value name.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition Location.h:76
This class provides the API for ops that are known to be terminators.
Operation is the basic unit of execution within MLIR.
Definition Operation.h:88
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
Definition Operation.h:775
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Definition Operation.h:433
static Operation * create(Location location, OperationName name, TypeRange resultTypes, ValueRange operands, NamedAttrList &&attributes, PropertyRef properties, BlockRange successors, unsigned numRegions)
Create a new Operation with the specific fields.
Definition Operation.cpp:66
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition Types.h:74
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition Value.h:96
Value materializeSpecConstantOperation(uint32_t resultID, spirv::Opcode enclosedOpcode, uint32_t resultTypeID, ArrayRef< uint32_t > enclosedOpOperands)
Materializes/emits an OpSpecConstantOp instruction.
Value getValue(uint32_t id)
Get the Value associated with a result <id>.
LogicalResult processGlobalVariable(ArrayRef< uint32_t > operands)
Processes the OpVariable instructions at current offset into binary.
std::optional< SpecConstOperationMaterializationInfo > getSpecConstantOperation(uint32_t id)
Gets the info needed to materialize the spec constant operation op associated with the given <id>.
LogicalResult processConstantNull(ArrayRef< uint32_t > operands)
Processes a SPIR-V OpConstantNull instruction with the given operands.
LogicalResult processSpecConstantComposite(ArrayRef< uint32_t > operands)
Processes a SPIR-V OpSpecConstantComposite instruction with the given operands.
LogicalResult processInstruction(spirv::Opcode opcode, ArrayRef< uint32_t > operands, bool deferInstructions=true)
Processes a SPIR-V instruction with the given opcode and operands.
LogicalResult processBranchConditional(ArrayRef< uint32_t > operands)
spirv::GlobalVariableOp getGlobalVariable(uint32_t id)
Gets the global variable associated with a result <id> of OpVariable.
LogicalResult processGraphARM(ArrayRef< uint32_t > operands)
LogicalResult processLabel(ArrayRef< uint32_t > operands)
Processes a SPIR-V OpLabel instruction with the given operands.
LogicalResult processExtInst(ArrayRef< uint32_t > operands)
Processes a SPIR-V OpExtInst with given operands.
std::optional< spirv::GraphConstantARMOpMaterializationInfo > getGraphConstantARM(uint32_t id)
Gets the GraphConstantARM ID attribute and result type with the given result <id>.
std::optional< std::pair< Attribute, Type > > getConstant(uint32_t id)
Gets the constant's attribute and type associated with the given <id>.
LogicalResult processType(spirv::Opcode opcode, ArrayRef< uint32_t > operands)
Processes a SPIR-V type instruction with given opcode and operands and registers the type into module...
LogicalResult processLoopMerge(ArrayRef< uint32_t > operands)
Processes a SPIR-V OpLoopMerge instruction with the given operands.
LogicalResult dispatchToExtensionSetAutogenDeserialization(StringRef extensionSetName, uint32_t instructionID, ArrayRef< uint32_t > words)
Dispatches the deserialization of extended instruction set operation based on the extended instructio...
LogicalResult sliceInstruction(spirv::Opcode &opcode, ArrayRef< uint32_t > &operands, std::optional< spirv::Opcode > expectedOpcode=std::nullopt)
Slices the first instruction out of binary and returns its opcode and operands via opcode and operand...
spirv::SpecConstantCompositeOp getSpecConstantComposite(uint32_t id)
Gets the composite specialization constant with the given result <id>.
spirv::EXTSpecConstantCompositeReplicateOp getSpecConstantCompositeReplicate(uint32_t id)
Gets the replicated composite specialization constant with the given result <id>.
LogicalResult processOp(ArrayRef< uint32_t > words)
Method to deserialize an operation in the SPIR-V dialect that is a mirror of an instruction in the SP...
Type getUndefType(uint32_t id)
Get the type associated with the result <id> of an OpUndef.
LogicalResult processSpecConstantCompositeReplicateEXT(ArrayRef< uint32_t > operands)
Processes a SPIR-V OpSpecConstantCompositeReplicateEXT instruction with the given operands.
LogicalResult processGraphEntryPointARM(ArrayRef< uint32_t > operands)
LogicalResult processFunction(ArrayRef< uint32_t > operands)
Creates a deserializer for the given SPIR-V binary module.
LogicalResult processDebugString(ArrayRef< uint32_t > operands)
Processes a SPIR-V OpString instruction with the given operands.
LogicalResult processPhi(ArrayRef< uint32_t > operands)
Processes a SPIR-V OpPhi instruction with the given operands.
void clearDebugLine()
Discontinues any source-level location information that might be active from a previous OpLine instru...
void mergeLongCompositeContinuations(spirv::Opcode opcode, ArrayRef< uint32_t > &operands, SmallVectorImpl< uint32_t > &mergedStorage)
If opcode is a SPV_INTEL_long_composites splittable opcode and the next binary instruction(s) are mat...
LogicalResult processTypeForwardPointer(ArrayRef< uint32_t > operands)
LogicalResult processSwitch(ArrayRef< uint32_t > operands)
Processes a SPIR-V OpSwitch instruction with the given operands.
LogicalResult dispatchToAutogenDeserialization(spirv::Opcode opcode, ArrayRef< uint32_t > words)
Method to dispatch to the specialized deserialization function for an operation in SPIR-V dialect tha...
LogicalResult processOpWithoutGrammarAttr(ArrayRef< uint32_t > words, StringRef opName, bool hasResult, unsigned numOperands)
Processes a SPIR-V instruction from the given operands.
LogicalResult processGraphEndARM(ArrayRef< uint32_t > operands)
LogicalResult processConstantComposite(ArrayRef< uint32_t > operands)
Processes a SPIR-V OpConstantComposite instruction with the given operands.
LogicalResult processBranch(ArrayRef< uint32_t > operands)
std::optional< std::pair< Attribute, Type > > getConstantCompositeReplicate(uint32_t id)
Gets the replicated composite constant's attribute and type associated with the given <id>.
LogicalResult processUndef(ArrayRef< uint32_t > operands)
Processes a OpUndef instruction.
LogicalResult processSpecConstantOperation(ArrayRef< uint32_t > operands)
Processes a SPIR-V OpSpecConstantOp instruction with the given operands.
LogicalResult processConstant(ArrayRef< uint32_t > operands, bool isSpec)
Processes a SPIR-V Op{|Spec}Constant instruction with the given operands.
Location createFileLineColLoc(OpBuilder opBuilder)
Creates a FileLineColLoc with the OpLine location information.
LogicalResult processGraphConstantARM(ArrayRef< uint32_t > operands)
Processes a SPIR-V OpGraphConstantARM instruction with the given operands.
LogicalResult processConstantBool(bool isTrue, ArrayRef< uint32_t > operands, bool isSpec)
Processes a SPIR-V Op{|Spec}Constant{True|False} instruction with the given operands.
spirv::SpecConstantOp getSpecConstant(uint32_t id)
Gets the specialization constant with the given result <id>.
LogicalResult processConstantCompositeReplicateEXT(ArrayRef< uint32_t > operands)
Processes a SPIR-V OpConstantCompositeReplicateEXT instruction with the given operands.
LogicalResult processSelectionMerge(ArrayRef< uint32_t > operands)
Processes a SPIR-V OpSelectionMerge instruction with the given operands.
LogicalResult processOpGraphSetOutputARM(ArrayRef< uint32_t > operands)
LogicalResult processDebugLine(ArrayRef< uint32_t > operands)
Processes a SPIR-V OpLine instruction with the given operands.
std::optional< spirv::Opcode > getContinuationOpcode(spirv::Opcode parent)
Returns the SPV_INTEL_long_composites continuation opcode that may follow parent, or std::nullopt if ...
constexpr StringRef attributeName()
StringRef decodeStringLiteral(ArrayRef< uint32_t > words, unsigned &wordIndex)
Decodes a string literal in words starting at wordIndex.
Include the generated interface declarations.
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
Definition Utils.cpp:307
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
This represents an operation in an abstracted form, suitable for use with the builder APIs.
void addOperands(ValueRange newOperands)
void addAttributes(ArrayRef< NamedAttribute > newAttributes)
Add an array of named attributes.
void addTypes(ArrayRef< Type > newTypes)