MLIR  22.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 
25 using 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.
34 static inline spirv::Opcode extractOpcode(uint32_t word) {
35  return static_cast<spirv::Opcode>(word & 0xffff);
36 }
37 
38 //===----------------------------------------------------------------------===//
39 // Instruction
40 //===----------------------------------------------------------------------===//
41 
42 Value spirv::Deserializer::getValue(uint32_t id) {
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 =
49  getConstantCompositeReplicate(id)) {
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 =
67  getSpecConstantComposite(id)) {
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 =
74  getSpecConstantCompositeReplicate(id)) {
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)) {
81  return materializeSpecConstantOperation(
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 
99 LogicalResult spirv::Deserializer::sliceInstruction(
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 
128 LogicalResult spirv::Deserializer::processInstruction(
129  spirv::Opcode opcode, ArrayRef<uint32_t> operands, bool deferInstructions) {
130  LLVM_DEBUG(logger.startLine() << "[inst] processing instruction "
131  << spirv::stringifyOpcode(opcode) << "\n");
132 
133  // First dispatch all the instructions whose opcode does not correspond to
134  // those that have a direct mirror in the SPIR-V dialect
135  switch (opcode) {
136  case spirv::Opcode::OpCapability:
137  return processCapability(operands);
138  case spirv::Opcode::OpExtension:
139  return processExtension(operands);
140  case spirv::Opcode::OpExtInst:
141  return processExtInst(operands);
142  case spirv::Opcode::OpExtInstImport:
143  return processExtInstImport(operands);
144  case spirv::Opcode::OpMemberName:
145  return processMemberName(operands);
146  case spirv::Opcode::OpMemoryModel:
147  return processMemoryModel(operands);
148  case spirv::Opcode::OpEntryPoint:
149  case spirv::Opcode::OpExecutionMode:
150  if (deferInstructions) {
151  deferredInstructions.emplace_back(opcode, operands);
152  return success();
153  }
154  break;
155  case spirv::Opcode::OpVariable:
156  if (isa<spirv::ModuleOp>(opBuilder.getBlock()->getParentOp())) {
157  return processGlobalVariable(operands);
158  }
159  break;
160  case spirv::Opcode::OpLine:
161  return processDebugLine(operands);
162  case spirv::Opcode::OpNoLine:
163  clearDebugLine();
164  return success();
165  case spirv::Opcode::OpName:
166  return processName(operands);
167  case spirv::Opcode::OpString:
168  return processDebugString(operands);
169  case spirv::Opcode::OpModuleProcessed:
170  case spirv::Opcode::OpSource:
171  case spirv::Opcode::OpSourceContinued:
172  case spirv::Opcode::OpSourceExtension:
173  // TODO: This is debug information embedded in the binary which should be
174  // translated into the spirv.module.
175  return success();
176  case spirv::Opcode::OpTypeVoid:
177  case spirv::Opcode::OpTypeBool:
178  case spirv::Opcode::OpTypeInt:
179  case spirv::Opcode::OpTypeFloat:
180  case spirv::Opcode::OpTypeVector:
181  case spirv::Opcode::OpTypeMatrix:
182  case spirv::Opcode::OpTypeArray:
183  case spirv::Opcode::OpTypeFunction:
184  case spirv::Opcode::OpTypeImage:
185  case spirv::Opcode::OpTypeSampledImage:
186  case spirv::Opcode::OpTypeRuntimeArray:
187  case spirv::Opcode::OpTypeStruct:
188  case spirv::Opcode::OpTypePointer:
189  case spirv::Opcode::OpTypeTensorARM:
190  case spirv::Opcode::OpTypeGraphARM:
191  case spirv::Opcode::OpTypeCooperativeMatrixKHR:
192  return processType(opcode, operands);
193  case spirv::Opcode::OpTypeForwardPointer:
194  return processTypeForwardPointer(operands);
195  case spirv::Opcode::OpConstant:
196  return processConstant(operands, /*isSpec=*/false);
197  case spirv::Opcode::OpSpecConstant:
198  return processConstant(operands, /*isSpec=*/true);
199  case spirv::Opcode::OpConstantComposite:
200  return processConstantComposite(operands);
201  case spirv::Opcode::OpConstantCompositeReplicateEXT:
202  return processConstantCompositeReplicateEXT(operands);
203  case spirv::Opcode::OpSpecConstantComposite:
204  return processSpecConstantComposite(operands);
205  case spirv::Opcode::OpSpecConstantCompositeReplicateEXT:
206  return processSpecConstantCompositeReplicateEXT(operands);
207  case spirv::Opcode::OpSpecConstantOp:
208  return processSpecConstantOperation(operands);
209  case spirv::Opcode::OpConstantTrue:
210  return processConstantBool(/*isTrue=*/true, operands, /*isSpec=*/false);
211  case spirv::Opcode::OpSpecConstantTrue:
212  return processConstantBool(/*isTrue=*/true, operands, /*isSpec=*/true);
213  case spirv::Opcode::OpConstantFalse:
214  return processConstantBool(/*isTrue=*/false, operands, /*isSpec=*/false);
215  case spirv::Opcode::OpSpecConstantFalse:
216  return processConstantBool(/*isTrue=*/false, operands, /*isSpec=*/true);
217  case spirv::Opcode::OpConstantNull:
218  return processConstantNull(operands);
219  case spirv::Opcode::OpGraphConstantARM:
220  return processGraphConstantARM(operands);
221  case spirv::Opcode::OpDecorate:
222  return processDecoration(operands);
223  case spirv::Opcode::OpMemberDecorate:
224  return processMemberDecoration(operands);
225  case spirv::Opcode::OpFunction:
226  return processFunction(operands);
227  case spirv::Opcode::OpGraphEntryPointARM:
228  if (deferInstructions) {
229  deferredInstructions.emplace_back(opcode, operands);
230  return success();
231  }
232  return processGraphEntryPointARM(operands);
233  case spirv::Opcode::OpGraphARM:
234  return processGraphARM(operands);
235  case spirv::Opcode::OpGraphSetOutputARM:
236  return processOpGraphSetOutputARM(operands);
237  case spirv::Opcode::OpGraphEndARM:
238  return processGraphEndARM(operands);
239  case spirv::Opcode::OpLabel:
240  return processLabel(operands);
241  case spirv::Opcode::OpBranch:
242  return processBranch(operands);
243  case spirv::Opcode::OpBranchConditional:
244  return processBranchConditional(operands);
245  case spirv::Opcode::OpSelectionMerge:
246  return processSelectionMerge(operands);
247  case spirv::Opcode::OpLoopMerge:
248  return processLoopMerge(operands);
249  case spirv::Opcode::OpPhi:
250  return processPhi(operands);
251  case spirv::Opcode::OpUndef:
252  return processUndef(operands);
253  default:
254  break;
255  }
256  return dispatchToAutogenDeserialization(opcode, operands);
257 }
258 
259 LogicalResult spirv::Deserializer::processOpWithoutGrammarAttr(
260  ArrayRef<uint32_t> words, StringRef opName, bool hasResult,
261  unsigned numOperands) {
262  SmallVector<Type, 1> resultTypes;
263  uint32_t valueID = 0;
264 
265  size_t wordIndex = 0;
266  if (hasResult) {
267  if (wordIndex >= words.size())
268  return emitError(unknownLoc,
269  "expected result type <id> while deserializing for ")
270  << opName;
271 
272  // Decode the type <id>
273  auto type = getType(words[wordIndex]);
274  if (!type)
275  return emitError(unknownLoc, "unknown type result <id>: ")
276  << words[wordIndex];
277  resultTypes.push_back(type);
278  ++wordIndex;
279 
280  // Decode the result <id>
281  if (wordIndex >= words.size())
282  return emitError(unknownLoc,
283  "expected result <id> while deserializing for ")
284  << opName;
285  valueID = words[wordIndex];
286  ++wordIndex;
287  }
288 
289  SmallVector<Value, 4> operands;
291 
292  // Decode operands
293  size_t operandIndex = 0;
294  for (; operandIndex < numOperands && wordIndex < words.size();
295  ++operandIndex, ++wordIndex) {
296  auto arg = getValue(words[wordIndex]);
297  if (!arg)
298  return emitError(unknownLoc, "unknown result <id>: ") << words[wordIndex];
299  operands.push_back(arg);
300  }
301  if (operandIndex != numOperands) {
302  return emitError(
303  unknownLoc,
304  "found less operands than expected when deserializing for ")
305  << opName << "; only " << operandIndex << " of " << numOperands
306  << " processed";
307  }
308  if (wordIndex != words.size()) {
309  return emitError(
310  unknownLoc,
311  "found more operands than expected when deserializing for ")
312  << opName << "; only " << wordIndex << " of " << words.size()
313  << " processed";
314  }
315 
316  // Attach attributes from decorations
317  if (decorations.count(valueID)) {
318  auto attrs = decorations[valueID].getAttrs();
319  attributes.append(attrs.begin(), attrs.end());
320  }
321 
322  // Create the op and update bookkeeping maps
323  Location loc = createFileLineColLoc(opBuilder);
324  OperationState opState(loc, opName);
325  opState.addOperands(operands);
326  if (hasResult)
327  opState.addTypes(resultTypes);
328  opState.addAttributes(attributes);
329  Operation *op = opBuilder.create(opState);
330  if (hasResult)
331  valueMap[valueID] = op->getResult(0);
332 
333  if (op->hasTrait<OpTrait::IsTerminator>())
334  clearDebugLine();
335 
336  return success();
337 }
338 
339 LogicalResult spirv::Deserializer::processUndef(ArrayRef<uint32_t> operands) {
340  if (operands.size() != 2) {
341  return emitError(unknownLoc, "OpUndef instruction must have two operands");
342  }
343  auto type = getType(operands[0]);
344  if (!type) {
345  return emitError(unknownLoc, "unknown type <id> with OpUndef instruction");
346  }
347  undefMap[operands[1]] = type;
348  return success();
349 }
350 
351 LogicalResult spirv::Deserializer::processExtInst(ArrayRef<uint32_t> operands) {
352  if (operands.size() < 4) {
353  return emitError(unknownLoc,
354  "OpExtInst must have at least 4 operands, result type "
355  "<id>, result <id>, set <id> and instruction opcode");
356  }
357  if (!extendedInstSets.count(operands[2])) {
358  return emitError(unknownLoc, "undefined set <id> in OpExtInst");
359  }
360  SmallVector<uint32_t, 4> slicedOperands;
361  slicedOperands.append(operands.begin(), std::next(operands.begin(), 2));
362  slicedOperands.append(std::next(operands.begin(), 4), operands.end());
363  return dispatchToExtensionSetAutogenDeserialization(
364  extendedInstSets[operands[2]], operands[3], slicedOperands);
365 }
366 
367 namespace mlir {
368 namespace spirv {
369 
370 template <>
371 LogicalResult
372 Deserializer::processOp<spirv::EntryPointOp>(ArrayRef<uint32_t> words) {
373  unsigned wordIndex = 0;
374  if (wordIndex >= words.size()) {
375  return emitError(unknownLoc,
376  "missing Execution Model specification in OpEntryPoint");
377  }
378  auto execModel = spirv::ExecutionModelAttr::get(
379  context, static_cast<spirv::ExecutionModel>(words[wordIndex++]));
380  if (wordIndex >= words.size()) {
381  return emitError(unknownLoc, "missing <id> in OpEntryPoint");
382  }
383  // Get the function <id>
384  auto fnID = words[wordIndex++];
385  // Get the function name
386  auto fnName = decodeStringLiteral(words, wordIndex);
387  // Verify that the function <id> matches the fnName
388  auto parsedFunc = getFunction(fnID);
389  if (!parsedFunc) {
390  return emitError(unknownLoc, "no function matching <id> ") << fnID;
391  }
392  if (parsedFunc.getName() != fnName) {
393  // The deserializer uses "spirv_fn_<id>" as the function name if the input
394  // SPIR-V blob does not contain a name for it. We should use a more clear
395  // indication for such case rather than relying on naming details.
396  if (!parsedFunc.getName().starts_with("spirv_fn_"))
397  return emitError(unknownLoc,
398  "function name mismatch between OpEntryPoint "
399  "and OpFunction with <id> ")
400  << fnID << ": " << fnName << " vs. " << parsedFunc.getName();
401  parsedFunc.setName(fnName);
402  }
403  SmallVector<Attribute, 4> interface;
404  while (wordIndex < words.size()) {
405  auto arg = getGlobalVariable(words[wordIndex]);
406  if (!arg) {
407  return emitError(unknownLoc, "undefined result <id> ")
408  << words[wordIndex] << " while decoding OpEntryPoint";
409  }
410  interface.push_back(SymbolRefAttr::get(arg.getOperation()));
411  wordIndex++;
412  }
413  spirv::EntryPointOp::create(
414  opBuilder, unknownLoc, execModel,
415  SymbolRefAttr::get(opBuilder.getContext(), fnName),
416  opBuilder.getArrayAttr(interface));
417  return success();
418 }
419 
420 template <>
421 LogicalResult
422 Deserializer::processOp<spirv::ExecutionModeOp>(ArrayRef<uint32_t> words) {
423  unsigned wordIndex = 0;
424  if (wordIndex >= words.size()) {
425  return emitError(unknownLoc,
426  "missing function result <id> in OpExecutionMode");
427  }
428  // Get the function <id> to get the name of the function
429  auto fnID = words[wordIndex++];
430  auto fn = getFunction(fnID);
431  if (!fn) {
432  return emitError(unknownLoc, "no function matching <id> ") << fnID;
433  }
434  // Get the Execution mode
435  if (wordIndex >= words.size()) {
436  return emitError(unknownLoc, "missing Execution Mode in OpExecutionMode");
437  }
438  auto execMode = spirv::ExecutionModeAttr::get(
439  context, static_cast<spirv::ExecutionMode>(words[wordIndex++]));
440 
441  // Get the values
442  SmallVector<Attribute, 4> attrListElems;
443  while (wordIndex < words.size()) {
444  attrListElems.push_back(opBuilder.getI32IntegerAttr(words[wordIndex++]));
445  }
446  auto values = opBuilder.getArrayAttr(attrListElems);
447  spirv::ExecutionModeOp::create(
448  opBuilder, unknownLoc,
449  SymbolRefAttr::get(opBuilder.getContext(), fn.getName()), execMode,
450  values);
451  return success();
452 }
453 
454 template <>
455 LogicalResult
456 Deserializer::processOp<spirv::FunctionCallOp>(ArrayRef<uint32_t> operands) {
457  if (operands.size() < 3) {
458  return emitError(unknownLoc,
459  "OpFunctionCall must have at least 3 operands");
460  }
461 
462  Type resultType = getType(operands[0]);
463  if (!resultType) {
464  return emitError(unknownLoc, "undefined result type from <id> ")
465  << operands[0];
466  }
467 
468  // Use null type to mean no result type.
469  if (isVoidType(resultType))
470  resultType = nullptr;
471 
472  auto resultID = operands[1];
473  auto functionID = operands[2];
474 
475  auto functionName = getFunctionSymbol(functionID);
476 
477  SmallVector<Value, 4> arguments;
478  for (auto operand : llvm::drop_begin(operands, 3)) {
479  auto value = getValue(operand);
480  if (!value) {
481  return emitError(unknownLoc, "unknown <id> ")
482  << operand << " used by OpFunctionCall";
483  }
484  arguments.push_back(value);
485  }
486 
487  auto opFunctionCall = spirv::FunctionCallOp::create(
488  opBuilder, unknownLoc, resultType,
489  SymbolRefAttr::get(opBuilder.getContext(), functionName), arguments);
490 
491  if (resultType)
492  valueMap[resultID] = opFunctionCall.getResult(0);
493  return success();
494 }
495 
496 template <>
497 LogicalResult
498 Deserializer::processOp<spirv::CopyMemoryOp>(ArrayRef<uint32_t> words) {
499  SmallVector<Type, 1> resultTypes;
500  size_t wordIndex = 0;
501  SmallVector<Value, 4> operands;
503 
504  if (wordIndex < words.size()) {
505  auto arg = getValue(words[wordIndex]);
506 
507  if (!arg) {
508  return emitError(unknownLoc, "unknown result <id> : ")
509  << words[wordIndex];
510  }
511 
512  operands.push_back(arg);
513  wordIndex++;
514  }
515 
516  if (wordIndex < words.size()) {
517  auto arg = getValue(words[wordIndex]);
518 
519  if (!arg) {
520  return emitError(unknownLoc, "unknown result <id> : ")
521  << words[wordIndex];
522  }
523 
524  operands.push_back(arg);
525  wordIndex++;
526  }
527 
528  bool isAlignedAttr = false;
529 
530  if (wordIndex < words.size()) {
531  auto attrValue = words[wordIndex++];
532  auto attr = opBuilder.getAttr<spirv::MemoryAccessAttr>(
533  static_cast<spirv::MemoryAccess>(attrValue));
534  attributes.push_back(
535  opBuilder.getNamedAttr(attributeName<MemoryAccess>(), attr));
536  isAlignedAttr = (attrValue == 2);
537  }
538 
539  if (isAlignedAttr && wordIndex < words.size()) {
540  attributes.push_back(opBuilder.getNamedAttr(
541  "alignment", opBuilder.getI32IntegerAttr(words[wordIndex++])));
542  }
543 
544  if (wordIndex < words.size()) {
545  auto attrValue = words[wordIndex++];
546  auto attr = opBuilder.getAttr<spirv::MemoryAccessAttr>(
547  static_cast<spirv::MemoryAccess>(attrValue));
548  attributes.push_back(opBuilder.getNamedAttr("source_memory_access", attr));
549  }
550 
551  if (wordIndex < words.size()) {
552  attributes.push_back(opBuilder.getNamedAttr(
553  "source_alignment", opBuilder.getI32IntegerAttr(words[wordIndex++])));
554  }
555 
556  if (wordIndex != words.size()) {
557  return emitError(unknownLoc,
558  "found more operands than expected when deserializing "
559  "spirv::CopyMemoryOp, only ")
560  << wordIndex << " of " << words.size() << " processed";
561  }
562 
563  Location loc = createFileLineColLoc(opBuilder);
564  spirv::CopyMemoryOp::create(opBuilder, loc, resultTypes, operands,
565  attributes);
566 
567  return success();
568 }
569 
570 template <>
571 LogicalResult Deserializer::processOp<spirv::GenericCastToPtrExplicitOp>(
572  ArrayRef<uint32_t> words) {
573  if (words.size() != 4) {
574  return emitError(unknownLoc,
575  "expected 4 words in GenericCastToPtrExplicitOp"
576  " but got : ")
577  << words.size();
578  }
579  SmallVector<Type, 1> resultTypes;
580  SmallVector<Value, 4> operands;
581  uint32_t valueID = 0;
582  auto type = getType(words[0]);
583 
584  if (!type)
585  return emitError(unknownLoc, "unknown type result <id> : ") << words[0];
586  resultTypes.push_back(type);
587 
588  valueID = words[1];
589 
590  auto arg = getValue(words[2]);
591  if (!arg)
592  return emitError(unknownLoc, "unknown result <id> : ") << words[2];
593  operands.push_back(arg);
594 
595  Location loc = createFileLineColLoc(opBuilder);
596  Operation *op = spirv::GenericCastToPtrExplicitOp::create(
597  opBuilder, loc, resultTypes, operands);
598  valueMap[valueID] = op->getResult(0);
599  return success();
600 }
601 
602 // Pull in auto-generated Deserializer::dispatchToAutogenDeserialization() and
603 // various Deserializer::processOp<...>() specializations.
604 #define GET_DESERIALIZATION_FNS
605 #include "mlir/Dialect/SPIRV/IR/SPIRVSerialization.inc"
606 
607 } // namespace spirv
608 } // namespace mlir
static spirv::Opcode extractOpcode(uint32_t word)
Extracts the opcode from the given first word of a SPIR-V instruction.
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.
Definition: OpDefinition.h:773
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:749
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Definition: Operation.h:407
static Operation * create(Location location, OperationName name, TypeRange resultTypes, ValueRange operands, NamedAttrList &&attributes, OpaqueProperties properties, BlockRange successors, unsigned numRegions)
Create a new Operation with the specific fields.
Definition: Operation.cpp:67
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
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:304
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
This represents an operation in an abstracted form, suitable for use with the builder APIs.