MLIR  18.0.0git
SPIRVDialect.cpp
Go to the documentation of this file.
1 //===- LLVMDialect.cpp - MLIR SPIR-V dialect ------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM
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 SPIR-V dialect in MLIR.
10 //
11 //===----------------------------------------------------------------------===//
12 
14 
15 #include "SPIRVParsingUtils.h"
16 
22 #include "mlir/IR/Builders.h"
23 #include "mlir/IR/BuiltinTypes.h"
25 #include "mlir/IR/MLIRContext.h"
26 #include "mlir/Parser/Parser.h"
28 #include "llvm/ADT/DenseMap.h"
29 #include "llvm/ADT/Sequence.h"
30 #include "llvm/ADT/SetVector.h"
31 #include "llvm/ADT/StringExtras.h"
32 #include "llvm/ADT/StringMap.h"
33 #include "llvm/ADT/TypeSwitch.h"
34 #include "llvm/Support/raw_ostream.h"
35 
36 using namespace mlir;
37 using namespace mlir::spirv;
38 
39 #include "mlir/Dialect/SPIRV/IR/SPIRVOpsDialect.cpp.inc"
40 
41 //===----------------------------------------------------------------------===//
42 // InlinerInterface
43 //===----------------------------------------------------------------------===//
44 
45 /// Returns true if the given region contains spirv.Return or spirv.ReturnValue
46 /// ops.
47 static inline bool containsReturn(Region &region) {
48  return llvm::any_of(region, [](Block &block) {
49  Operation *terminator = block.getTerminator();
50  return isa<spirv::ReturnOp, spirv::ReturnValueOp>(terminator);
51  });
52 }
53 
54 namespace {
55 /// This class defines the interface for inlining within the SPIR-V dialect.
56 struct SPIRVInlinerInterface : public DialectInlinerInterface {
58 
59  /// All call operations within SPIRV can be inlined.
60  bool isLegalToInline(Operation *call, Operation *callable,
61  bool wouldBeCloned) const final {
62  return true;
63  }
64 
65  /// Returns true if the given region 'src' can be inlined into the region
66  /// 'dest' that is attached to an operation registered to the current dialect.
67  bool isLegalToInline(Region *dest, Region *src, bool wouldBeCloned,
68  IRMapping &) const final {
69  // Return true here when inlining into spirv.func, spirv.mlir.selection, and
70  // spirv.mlir.loop operations.
71  auto *op = dest->getParentOp();
72  return isa<spirv::FuncOp, spirv::SelectionOp, spirv::LoopOp>(op);
73  }
74 
75  /// Returns true if the given operation 'op', that is registered to this
76  /// dialect, can be inlined into the region 'dest' that is attached to an
77  /// operation registered to the current dialect.
78  bool isLegalToInline(Operation *op, Region *dest, bool wouldBeCloned,
79  IRMapping &) const final {
80  // TODO: Enable inlining structured control flows with return.
81  if ((isa<spirv::SelectionOp, spirv::LoopOp>(op)) &&
82  containsReturn(op->getRegion(0)))
83  return false;
84  // TODO: we need to filter OpKill here to avoid inlining it to
85  // a loop continue construct:
86  // https://github.com/KhronosGroup/SPIRV-Headers/issues/86
87  // However OpKill is fragment shader specific and we don't support it yet.
88  return true;
89  }
90 
91  /// Handle the given inlined terminator by replacing it with a new operation
92  /// as necessary.
93  void handleTerminator(Operation *op, Block *newDest) const final {
94  if (auto returnOp = dyn_cast<spirv::ReturnOp>(op)) {
95  OpBuilder(op).create<spirv::BranchOp>(op->getLoc(), newDest);
96  op->erase();
97  } else if (auto retValOp = dyn_cast<spirv::ReturnValueOp>(op)) {
98  llvm_unreachable("unimplemented spirv.ReturnValue in inliner");
99  }
100  }
101 
102  /// Handle the given inlined terminator by replacing it with a new operation
103  /// as necessary.
104  void handleTerminator(Operation *op, ValueRange valuesToRepl) const final {
105  // Only spirv.ReturnValue needs to be handled here.
106  auto retValOp = dyn_cast<spirv::ReturnValueOp>(op);
107  if (!retValOp)
108  return;
109 
110  // Replace the values directly with the return operands.
111  assert(valuesToRepl.size() == 1 &&
112  "spirv.ReturnValue expected to only handle one result");
113  valuesToRepl.front().replaceAllUsesWith(retValOp.getValue());
114  }
115 };
116 } // namespace
117 
118 //===----------------------------------------------------------------------===//
119 // SPIR-V Dialect
120 //===----------------------------------------------------------------------===//
121 
122 void SPIRVDialect::initialize() {
123  registerAttributes();
124  registerTypes();
125 
126  // Add SPIR-V ops.
127  addOperations<
128 #define GET_OP_LIST
129 #include "mlir/Dialect/SPIRV/IR/SPIRVOps.cpp.inc"
130  >();
131 
132  addInterfaces<SPIRVInlinerInterface>();
133 
134  // Allow unknown operations because SPIR-V is extensible.
135  allowUnknownOperations();
136  declarePromisedInterface<TargetEnvAttr, gpu::TargetAttrInterface>();
137 }
138 
139 std::string SPIRVDialect::getAttributeName(Decoration decoration) {
140  return llvm::convertToSnakeFromCamelCase(stringifyDecoration(decoration));
141 }
142 
143 //===----------------------------------------------------------------------===//
144 // Type Parsing
145 //===----------------------------------------------------------------------===//
146 
147 // Forward declarations.
148 template <typename ValTy>
149 static std::optional<ValTy> parseAndVerify(SPIRVDialect const &dialect,
150  DialectAsmParser &parser);
151 template <>
152 std::optional<Type> parseAndVerify<Type>(SPIRVDialect const &dialect,
153  DialectAsmParser &parser);
154 
155 template <>
156 std::optional<unsigned> parseAndVerify<unsigned>(SPIRVDialect const &dialect,
157  DialectAsmParser &parser);
158 
159 static Type parseAndVerifyType(SPIRVDialect const &dialect,
160  DialectAsmParser &parser) {
161  Type type;
162  SMLoc typeLoc = parser.getCurrentLocation();
163  if (parser.parseType(type))
164  return Type();
165 
166  // Allow SPIR-V dialect types
167  if (&type.getDialect() == &dialect)
168  return type;
169 
170  // Check other allowed types
171  if (auto t = llvm::dyn_cast<FloatType>(type)) {
172  if (type.isBF16()) {
173  parser.emitError(typeLoc, "cannot use 'bf16' to compose SPIR-V types");
174  return Type();
175  }
176  } else if (auto t = llvm::dyn_cast<IntegerType>(type)) {
177  if (!ScalarType::isValid(t)) {
178  parser.emitError(typeLoc,
179  "only 1/8/16/32/64-bit integer type allowed but found ")
180  << type;
181  return Type();
182  }
183  } else if (auto t = llvm::dyn_cast<VectorType>(type)) {
184  if (t.getRank() != 1) {
185  parser.emitError(typeLoc, "only 1-D vector allowed but found ") << t;
186  return Type();
187  }
188  if (t.getNumElements() > 4) {
189  parser.emitError(
190  typeLoc, "vector length has to be less than or equal to 4 but found ")
191  << t.getNumElements();
192  return Type();
193  }
194  } else {
195  parser.emitError(typeLoc, "cannot use ")
196  << type << " to compose SPIR-V types";
197  return Type();
198  }
199 
200  return type;
201 }
202 
203 static Type parseAndVerifyMatrixType(SPIRVDialect const &dialect,
204  DialectAsmParser &parser) {
205  Type type;
206  SMLoc typeLoc = parser.getCurrentLocation();
207  if (parser.parseType(type))
208  return Type();
209 
210  if (auto t = llvm::dyn_cast<VectorType>(type)) {
211  if (t.getRank() != 1) {
212  parser.emitError(typeLoc, "only 1-D vector allowed but found ") << t;
213  return Type();
214  }
215  if (t.getNumElements() > 4 || t.getNumElements() < 2) {
216  parser.emitError(typeLoc,
217  "matrix columns size has to be less than or equal "
218  "to 4 and greater than or equal 2, but found ")
219  << t.getNumElements();
220  return Type();
221  }
222 
223  if (!llvm::isa<FloatType>(t.getElementType())) {
224  parser.emitError(typeLoc, "matrix columns' elements must be of "
225  "Float type, got ")
226  << t.getElementType();
227  return Type();
228  }
229  } else {
230  parser.emitError(typeLoc, "matrix must be composed using vector "
231  "type, got ")
232  << type;
233  return Type();
234  }
235 
236  return type;
237 }
238 
239 static Type parseAndVerifySampledImageType(SPIRVDialect const &dialect,
240  DialectAsmParser &parser) {
241  Type type;
242  SMLoc typeLoc = parser.getCurrentLocation();
243  if (parser.parseType(type))
244  return Type();
245 
246  if (!llvm::isa<ImageType>(type)) {
247  parser.emitError(typeLoc,
248  "sampled image must be composed using image type, got ")
249  << type;
250  return Type();
251  }
252 
253  return type;
254 }
255 
256 /// Parses an optional `, stride = N` assembly segment. If no parsing failure
257 /// occurs, writes `N` to `stride` if existing and writes 0 to `stride` if
258 /// missing.
259 static LogicalResult parseOptionalArrayStride(const SPIRVDialect &dialect,
260  DialectAsmParser &parser,
261  unsigned &stride) {
262  if (failed(parser.parseOptionalComma())) {
263  stride = 0;
264  return success();
265  }
266 
267  if (parser.parseKeyword("stride") || parser.parseEqual())
268  return failure();
269 
270  SMLoc strideLoc = parser.getCurrentLocation();
271  std::optional<unsigned> optStride = parseAndVerify<unsigned>(dialect, parser);
272  if (!optStride)
273  return failure();
274 
275  if (!(stride = *optStride)) {
276  parser.emitError(strideLoc, "ArrayStride must be greater than zero");
277  return failure();
278  }
279  return success();
280 }
281 
282 // element-type ::= integer-type
283 // | floating-point-type
284 // | vector-type
285 // | spirv-type
286 //
287 // array-type ::= `!spirv.array` `<` integer-literal `x` element-type
288 // (`,` `stride` `=` integer-literal)? `>`
289 static Type parseArrayType(SPIRVDialect const &dialect,
290  DialectAsmParser &parser) {
291  if (parser.parseLess())
292  return Type();
293 
294  SmallVector<int64_t, 1> countDims;
295  SMLoc countLoc = parser.getCurrentLocation();
296  if (parser.parseDimensionList(countDims, /*allowDynamic=*/false))
297  return Type();
298  if (countDims.size() != 1) {
299  parser.emitError(countLoc,
300  "expected single integer for array element count");
301  return Type();
302  }
303 
304  // According to the SPIR-V spec:
305  // "Length is the number of elements in the array. It must be at least 1."
306  int64_t count = countDims[0];
307  if (count == 0) {
308  parser.emitError(countLoc, "expected array length greater than 0");
309  return Type();
310  }
311 
312  Type elementType = parseAndVerifyType(dialect, parser);
313  if (!elementType)
314  return Type();
315 
316  unsigned stride = 0;
317  if (failed(parseOptionalArrayStride(dialect, parser, stride)))
318  return Type();
319 
320  if (parser.parseGreater())
321  return Type();
322  return ArrayType::get(elementType, count, stride);
323 }
324 
325 // cooperative-matrix-type ::=
326 // `!spirv.coopmatrix` `<` rows `x` columns `x` element-type `,`
327 // scope `,` use `>`
328 static Type parseCooperativeMatrixType(SPIRVDialect const &dialect,
329  DialectAsmParser &parser) {
330  if (parser.parseLess())
331  return {};
332 
334  SMLoc countLoc = parser.getCurrentLocation();
335  if (parser.parseDimensionList(dims, /*allowDynamic=*/false))
336  return {};
337 
338  if (dims.size() != 2) {
339  parser.emitError(countLoc, "expected row and column count");
340  return {};
341  }
342 
343  auto elementTy = parseAndVerifyType(dialect, parser);
344  if (!elementTy)
345  return {};
346 
347  Scope scope;
348  if (parser.parseComma() ||
349  spirv::parseEnumKeywordAttr(scope, parser, "scope <id>"))
350  return {};
351 
352  CooperativeMatrixUseKHR use;
353  if (parser.parseComma() ||
354  spirv::parseEnumKeywordAttr(use, parser, "use <id>"))
355  return {};
356 
357  if (parser.parseGreater())
358  return {};
359 
360  return CooperativeMatrixType::get(elementTy, dims[0], dims[1], scope, use);
361 }
362 
363 // nv-cooperative-matrix-type ::=
364 // `!spirv.NV.coopmatrix` `<` rows `x` columns `x` element-type `,` scope `>`
365 static Type parseCooperativeMatrixNVType(SPIRVDialect const &dialect,
366  DialectAsmParser &parser) {
367  if (parser.parseLess())
368  return Type();
369 
371  SMLoc countLoc = parser.getCurrentLocation();
372  if (parser.parseDimensionList(dims, /*allowDynamic=*/false))
373  return Type();
374 
375  if (dims.size() != 2) {
376  parser.emitError(countLoc, "expected rows and columns size");
377  return Type();
378  }
379 
380  auto elementTy = parseAndVerifyType(dialect, parser);
381  if (!elementTy)
382  return Type();
383 
384  Scope scope;
385  if (parser.parseComma() ||
386  spirv::parseEnumKeywordAttr(scope, parser, "scope <id>"))
387  return Type();
388 
389  if (parser.parseGreater())
390  return Type();
391  return CooperativeMatrixNVType::get(elementTy, scope, dims[0], dims[1]);
392 }
393 
394 // joint-matrix-type ::= `!spirv.jointmatrix` `<`rows `x` columns `x`
395 // element-type
396 // `,` layout `,` scope`>`
397 static Type parseJointMatrixType(SPIRVDialect const &dialect,
398  DialectAsmParser &parser) {
399  if (parser.parseLess())
400  return Type();
401 
403  SMLoc countLoc = parser.getCurrentLocation();
404  if (parser.parseDimensionList(dims, /*allowDynamic=*/false))
405  return Type();
406 
407  if (dims.size() != 2) {
408  parser.emitError(countLoc, "expected rows and columns size");
409  return Type();
410  }
411 
412  auto elementTy = parseAndVerifyType(dialect, parser);
413  if (!elementTy)
414  return Type();
415  MatrixLayout matrixLayout;
416  if (parser.parseComma() ||
417  spirv::parseEnumKeywordAttr(matrixLayout, parser, "matrixLayout <id>"))
418  return Type();
419  Scope scope;
420  if (parser.parseComma() ||
421  spirv::parseEnumKeywordAttr(scope, parser, "scope <id>"))
422  return Type();
423  if (parser.parseGreater())
424  return Type();
425  return JointMatrixINTELType::get(elementTy, scope, dims[0], dims[1],
426  matrixLayout);
427 }
428 
429 // TODO: Reorder methods to be utilities first and parse*Type
430 // methods in alphabetical order
431 //
432 // storage-class ::= `UniformConstant`
433 // | `Uniform`
434 // | `Workgroup`
435 // | <and other storage classes...>
436 //
437 // pointer-type ::= `!spirv.ptr<` element-type `,` storage-class `>`
438 static Type parsePointerType(SPIRVDialect const &dialect,
439  DialectAsmParser &parser) {
440  if (parser.parseLess())
441  return Type();
442 
443  auto pointeeType = parseAndVerifyType(dialect, parser);
444  if (!pointeeType)
445  return Type();
446 
447  StringRef storageClassSpec;
448  SMLoc storageClassLoc = parser.getCurrentLocation();
449  if (parser.parseComma() || parser.parseKeyword(&storageClassSpec))
450  return Type();
451 
452  auto storageClass = symbolizeStorageClass(storageClassSpec);
453  if (!storageClass) {
454  parser.emitError(storageClassLoc, "unknown storage class: ")
455  << storageClassSpec;
456  return Type();
457  }
458  if (parser.parseGreater())
459  return Type();
460  return PointerType::get(pointeeType, *storageClass);
461 }
462 
463 // runtime-array-type ::= `!spirv.rtarray` `<` element-type
464 // (`,` `stride` `=` integer-literal)? `>`
465 static Type parseRuntimeArrayType(SPIRVDialect const &dialect,
466  DialectAsmParser &parser) {
467  if (parser.parseLess())
468  return Type();
469 
470  Type elementType = parseAndVerifyType(dialect, parser);
471  if (!elementType)
472  return Type();
473 
474  unsigned stride = 0;
475  if (failed(parseOptionalArrayStride(dialect, parser, stride)))
476  return Type();
477 
478  if (parser.parseGreater())
479  return Type();
480  return RuntimeArrayType::get(elementType, stride);
481 }
482 
483 // matrix-type ::= `!spirv.matrix` `<` integer-literal `x` element-type `>`
484 static Type parseMatrixType(SPIRVDialect const &dialect,
485  DialectAsmParser &parser) {
486  if (parser.parseLess())
487  return Type();
488 
489  SmallVector<int64_t, 1> countDims;
490  SMLoc countLoc = parser.getCurrentLocation();
491  if (parser.parseDimensionList(countDims, /*allowDynamic=*/false))
492  return Type();
493  if (countDims.size() != 1) {
494  parser.emitError(countLoc, "expected single unsigned "
495  "integer for number of columns");
496  return Type();
497  }
498 
499  int64_t columnCount = countDims[0];
500  // According to the specification, Matrices can have 2, 3, or 4 columns
501  if (columnCount < 2 || columnCount > 4) {
502  parser.emitError(countLoc, "matrix is expected to have 2, 3, or 4 "
503  "columns");
504  return Type();
505  }
506 
507  Type columnType = parseAndVerifyMatrixType(dialect, parser);
508  if (!columnType)
509  return Type();
510 
511  if (parser.parseGreater())
512  return Type();
513 
514  return MatrixType::get(columnType, columnCount);
515 }
516 
517 // Specialize this function to parse each of the parameters that define an
518 // ImageType. By default it assumes this is an enum type.
519 template <typename ValTy>
520 static std::optional<ValTy> parseAndVerify(SPIRVDialect const &dialect,
521  DialectAsmParser &parser) {
522  StringRef enumSpec;
523  SMLoc enumLoc = parser.getCurrentLocation();
524  if (parser.parseKeyword(&enumSpec)) {
525  return std::nullopt;
526  }
527 
528  auto val = spirv::symbolizeEnum<ValTy>(enumSpec);
529  if (!val)
530  parser.emitError(enumLoc, "unknown attribute: '") << enumSpec << "'";
531  return val;
532 }
533 
534 template <>
535 std::optional<Type> parseAndVerify<Type>(SPIRVDialect const &dialect,
536  DialectAsmParser &parser) {
537  // TODO: Further verify that the element type can be sampled
538  auto ty = parseAndVerifyType(dialect, parser);
539  if (!ty)
540  return std::nullopt;
541  return ty;
542 }
543 
544 template <typename IntTy>
545 static std::optional<IntTy> parseAndVerifyInteger(SPIRVDialect const &dialect,
546  DialectAsmParser &parser) {
547  IntTy offsetVal = std::numeric_limits<IntTy>::max();
548  if (parser.parseInteger(offsetVal))
549  return std::nullopt;
550  return offsetVal;
551 }
552 
553 template <>
554 std::optional<unsigned> parseAndVerify<unsigned>(SPIRVDialect const &dialect,
555  DialectAsmParser &parser) {
556  return parseAndVerifyInteger<unsigned>(dialect, parser);
557 }
558 
559 namespace {
560 // Functor object to parse a comma separated list of specs. The function
561 // parseAndVerify does the actual parsing and verification of individual
562 // elements. This is a functor since parsing the last element of the list
563 // (termination condition) needs partial specialization.
564 template <typename ParseType, typename... Args>
565 struct ParseCommaSeparatedList {
566  std::optional<std::tuple<ParseType, Args...>>
567  operator()(SPIRVDialect const &dialect, DialectAsmParser &parser) const {
568  auto parseVal = parseAndVerify<ParseType>(dialect, parser);
569  if (!parseVal)
570  return std::nullopt;
571 
572  auto numArgs = std::tuple_size<std::tuple<Args...>>::value;
573  if (numArgs != 0 && failed(parser.parseComma()))
574  return std::nullopt;
575  auto remainingValues = ParseCommaSeparatedList<Args...>{}(dialect, parser);
576  if (!remainingValues)
577  return std::nullopt;
578  return std::tuple_cat(std::tuple<ParseType>(parseVal.value()),
579  remainingValues.value());
580  }
581 };
582 
583 // Partial specialization of the function to parse a comma separated list of
584 // specs to parse the last element of the list.
585 template <typename ParseType>
586 struct ParseCommaSeparatedList<ParseType> {
587  std::optional<std::tuple<ParseType>>
588  operator()(SPIRVDialect const &dialect, DialectAsmParser &parser) const {
589  if (auto value = parseAndVerify<ParseType>(dialect, parser))
590  return std::tuple<ParseType>(*value);
591  return std::nullopt;
592  }
593 };
594 } // namespace
595 
596 // dim ::= `1D` | `2D` | `3D` | `Cube` | <and other SPIR-V Dim specifiers...>
597 //
598 // depth-info ::= `NoDepth` | `IsDepth` | `DepthUnknown`
599 //
600 // arrayed-info ::= `NonArrayed` | `Arrayed`
601 //
602 // sampling-info ::= `SingleSampled` | `MultiSampled`
603 //
604 // sampler-use-info ::= `SamplerUnknown` | `NeedSampler` | `NoSampler`
605 //
606 // format ::= `Unknown` | `Rgba32f` | <and other SPIR-V Image formats...>
607 //
608 // image-type ::= `!spirv.image<` element-type `,` dim `,` depth-info `,`
609 // arrayed-info `,` sampling-info `,`
610 // sampler-use-info `,` format `>`
611 static Type parseImageType(SPIRVDialect const &dialect,
612  DialectAsmParser &parser) {
613  if (parser.parseLess())
614  return Type();
615 
616  auto value =
617  ParseCommaSeparatedList<Type, Dim, ImageDepthInfo, ImageArrayedInfo,
618  ImageSamplingInfo, ImageSamplerUseInfo,
619  ImageFormat>{}(dialect, parser);
620  if (!value)
621  return Type();
622 
623  if (parser.parseGreater())
624  return Type();
625  return ImageType::get(*value);
626 }
627 
628 // sampledImage-type :: = `!spirv.sampledImage<` image-type `>`
629 static Type parseSampledImageType(SPIRVDialect const &dialect,
630  DialectAsmParser &parser) {
631  if (parser.parseLess())
632  return Type();
633 
634  Type parsedType = parseAndVerifySampledImageType(dialect, parser);
635  if (!parsedType)
636  return Type();
637 
638  if (parser.parseGreater())
639  return Type();
640  return SampledImageType::get(parsedType);
641 }
642 
643 // Parse decorations associated with a member.
645  SPIRVDialect const &dialect, DialectAsmParser &parser,
646  ArrayRef<Type> memberTypes,
649 
650  // Check if the first element is offset.
651  SMLoc offsetLoc = parser.getCurrentLocation();
652  StructType::OffsetInfo offset = 0;
653  OptionalParseResult offsetParseResult = parser.parseOptionalInteger(offset);
654  if (offsetParseResult.has_value()) {
655  if (failed(*offsetParseResult))
656  return failure();
657 
658  if (offsetInfo.size() != memberTypes.size() - 1) {
659  return parser.emitError(offsetLoc,
660  "offset specification must be given for "
661  "all members");
662  }
663  offsetInfo.push_back(offset);
664  }
665 
666  // Check for no spirv::Decorations.
667  if (succeeded(parser.parseOptionalRSquare()))
668  return success();
669 
670  // If there was an offset, make sure to parse the comma.
671  if (offsetParseResult.has_value() && parser.parseComma())
672  return failure();
673 
674  // Check for spirv::Decorations.
675  auto parseDecorations = [&]() {
676  auto memberDecoration = parseAndVerify<spirv::Decoration>(dialect, parser);
677  if (!memberDecoration)
678  return failure();
679 
680  // Parse member decoration value if it exists.
681  if (succeeded(parser.parseOptionalEqual())) {
682  auto memberDecorationValue =
683  parseAndVerifyInteger<uint32_t>(dialect, parser);
684 
685  if (!memberDecorationValue)
686  return failure();
687 
688  memberDecorationInfo.emplace_back(
689  static_cast<uint32_t>(memberTypes.size() - 1), 1,
690  memberDecoration.value(), memberDecorationValue.value());
691  } else {
692  memberDecorationInfo.emplace_back(
693  static_cast<uint32_t>(memberTypes.size() - 1), 0,
694  memberDecoration.value(), 0);
695  }
696  return success();
697  };
698  if (failed(parser.parseCommaSeparatedList(parseDecorations)) ||
699  failed(parser.parseRSquare()))
700  return failure();
701 
702  return success();
703 }
704 
705 // struct-member-decoration ::= integer-literal? spirv-decoration*
706 // struct-type ::=
707 // `!spirv.struct<` (id `,`)?
708 // `(`
709 // (spirv-type (`[` struct-member-decoration `]`)?)*
710 // `)>`
711 static Type parseStructType(SPIRVDialect const &dialect,
712  DialectAsmParser &parser) {
713  // TODO: This function is quite lengthy. Break it down into smaller chunks.
714 
715  if (parser.parseLess())
716  return Type();
717 
718  StringRef identifier;
720 
721  // Check if this is an identified struct type.
722  if (succeeded(parser.parseOptionalKeyword(&identifier))) {
723  // Check if this is a possible recursive reference.
724  auto structType =
725  StructType::getIdentified(dialect.getContext(), identifier);
726  cyclicParse = parser.tryStartCyclicParse(structType);
727  if (succeeded(parser.parseOptionalGreater())) {
728  if (succeeded(cyclicParse)) {
729  parser.emitError(
730  parser.getNameLoc(),
731  "recursive struct reference not nested in struct definition");
732 
733  return Type();
734  }
735 
736  return structType;
737  }
738 
739  if (failed(parser.parseComma()))
740  return Type();
741 
742  if (failed(cyclicParse)) {
743  parser.emitError(parser.getNameLoc(),
744  "identifier already used for an enclosing struct");
745  return Type();
746  }
747  }
748 
749  if (failed(parser.parseLParen()))
750  return Type();
751 
752  if (succeeded(parser.parseOptionalRParen()) &&
753  succeeded(parser.parseOptionalGreater())) {
754  return StructType::getEmpty(dialect.getContext(), identifier);
755  }
756 
757  StructType idStructTy;
758 
759  if (!identifier.empty())
760  idStructTy = StructType::getIdentified(dialect.getContext(), identifier);
761 
762  SmallVector<Type, 4> memberTypes;
765 
766  do {
767  Type memberType;
768  if (parser.parseType(memberType))
769  return Type();
770  memberTypes.push_back(memberType);
771 
772  if (succeeded(parser.parseOptionalLSquare()))
773  if (parseStructMemberDecorations(dialect, parser, memberTypes, offsetInfo,
774  memberDecorationInfo))
775  return Type();
776  } while (succeeded(parser.parseOptionalComma()));
777 
778  if (!offsetInfo.empty() && memberTypes.size() != offsetInfo.size()) {
779  parser.emitError(parser.getNameLoc(),
780  "offset specification must be given for all members");
781  return Type();
782  }
783 
784  if (failed(parser.parseRParen()) || failed(parser.parseGreater()))
785  return Type();
786 
787  if (!identifier.empty()) {
788  if (failed(idStructTy.trySetBody(memberTypes, offsetInfo,
789  memberDecorationInfo)))
790  return Type();
791  return idStructTy;
792  }
793 
794  return StructType::get(memberTypes, offsetInfo, memberDecorationInfo);
795 }
796 
797 // spirv-type ::= array-type
798 // | element-type
799 // | image-type
800 // | pointer-type
801 // | runtime-array-type
802 // | sampled-image-type
803 // | struct-type
805  StringRef keyword;
806  if (parser.parseKeyword(&keyword))
807  return Type();
808 
809  if (keyword == "array")
810  return parseArrayType(*this, parser);
811  if (keyword == "coopmatrix")
812  return parseCooperativeMatrixType(*this, parser);
813  if (keyword == "NV.coopmatrix")
814  return parseCooperativeMatrixNVType(*this, parser);
815  if (keyword == "jointmatrix")
816  return parseJointMatrixType(*this, parser);
817  if (keyword == "image")
818  return parseImageType(*this, parser);
819  if (keyword == "ptr")
820  return parsePointerType(*this, parser);
821  if (keyword == "rtarray")
822  return parseRuntimeArrayType(*this, parser);
823  if (keyword == "sampled_image")
824  return parseSampledImageType(*this, parser);
825  if (keyword == "struct")
826  return parseStructType(*this, parser);
827  if (keyword == "matrix")
828  return parseMatrixType(*this, parser);
829  parser.emitError(parser.getNameLoc(), "unknown SPIR-V type: ") << keyword;
830  return Type();
831 }
832 
833 //===----------------------------------------------------------------------===//
834 // Type Printing
835 //===----------------------------------------------------------------------===//
836 
837 static void print(ArrayType type, DialectAsmPrinter &os) {
838  os << "array<" << type.getNumElements() << " x " << type.getElementType();
839  if (unsigned stride = type.getArrayStride())
840  os << ", stride=" << stride;
841  os << ">";
842 }
843 
844 static void print(RuntimeArrayType type, DialectAsmPrinter &os) {
845  os << "rtarray<" << type.getElementType();
846  if (unsigned stride = type.getArrayStride())
847  os << ", stride=" << stride;
848  os << ">";
849 }
850 
851 static void print(PointerType type, DialectAsmPrinter &os) {
852  os << "ptr<" << type.getPointeeType() << ", "
853  << stringifyStorageClass(type.getStorageClass()) << ">";
854 }
855 
856 static void print(ImageType type, DialectAsmPrinter &os) {
857  os << "image<" << type.getElementType() << ", " << stringifyDim(type.getDim())
858  << ", " << stringifyImageDepthInfo(type.getDepthInfo()) << ", "
859  << stringifyImageArrayedInfo(type.getArrayedInfo()) << ", "
860  << stringifyImageSamplingInfo(type.getSamplingInfo()) << ", "
861  << stringifyImageSamplerUseInfo(type.getSamplerUseInfo()) << ", "
862  << stringifyImageFormat(type.getImageFormat()) << ">";
863 }
864 
865 static void print(SampledImageType type, DialectAsmPrinter &os) {
866  os << "sampled_image<" << type.getImageType() << ">";
867 }
868 
869 static void print(StructType type, DialectAsmPrinter &os) {
871 
872  os << "struct<";
873 
874  if (type.isIdentified()) {
875  os << type.getIdentifier();
876 
877  cyclicPrint = os.tryStartCyclicPrint(type);
878  if (failed(cyclicPrint)) {
879  os << ">";
880  return;
881  }
882 
883  os << ", ";
884  }
885 
886  os << "(";
887 
888  auto printMember = [&](unsigned i) {
889  os << type.getElementType(i);
891  type.getMemberDecorations(i, decorations);
892  if (type.hasOffset() || !decorations.empty()) {
893  os << " [";
894  if (type.hasOffset()) {
895  os << type.getMemberOffset(i);
896  if (!decorations.empty())
897  os << ", ";
898  }
899  auto eachFn = [&os](spirv::StructType::MemberDecorationInfo decoration) {
900  os << stringifyDecoration(decoration.decoration);
901  if (decoration.hasValue) {
902  os << "=" << decoration.decorationValue;
903  }
904  };
905  llvm::interleaveComma(decorations, os, eachFn);
906  os << "]";
907  }
908  };
909  llvm::interleaveComma(llvm::seq<unsigned>(0, type.getNumElements()), os,
910  printMember);
911  os << ")>";
912 }
913 
915  os << "coopmatrix<" << type.getRows() << "x" << type.getColumns() << "x"
916  << type.getElementType() << ", " << type.getScope() << ", "
917  << type.getUse() << ">";
918 }
919 
921  os << "NV.coopmatrix<" << type.getRows() << "x" << type.getColumns() << "x";
922  os << type.getElementType() << ", " << stringifyScope(type.getScope());
923  os << ">";
924 }
925 
927  os << "jointmatrix<" << type.getRows() << "x" << type.getColumns() << "x";
928  os << type.getElementType() << ", "
929  << stringifyMatrixLayout(type.getMatrixLayout());
930  os << ", " << stringifyScope(type.getScope()) << ">";
931 }
932 
933 static void print(MatrixType type, DialectAsmPrinter &os) {
934  os << "matrix<" << type.getNumColumns() << " x " << type.getColumnType();
935  os << ">";
936 }
937 
938 void SPIRVDialect::printType(Type type, DialectAsmPrinter &os) const {
939  TypeSwitch<Type>(type)
943  [&](auto type) { print(type, os); })
944  .Default([](Type) { llvm_unreachable("unhandled SPIR-V type"); });
945 }
946 
947 //===----------------------------------------------------------------------===//
948 // Constant
949 //===----------------------------------------------------------------------===//
950 
952  Attribute value, Type type,
953  Location loc) {
954  if (auto poison = dyn_cast<ub::PoisonAttr>(value))
955  return builder.create<ub::PoisonOp>(loc, type, poison);
956 
957  if (!spirv::ConstantOp::isBuildableWith(type))
958  return nullptr;
959 
960  return builder.create<spirv::ConstantOp>(loc, type, value);
961 }
962 
963 //===----------------------------------------------------------------------===//
964 // Shader Interface ABI
965 //===----------------------------------------------------------------------===//
966 
967 LogicalResult SPIRVDialect::verifyOperationAttribute(Operation *op,
968  NamedAttribute attribute) {
969  StringRef symbol = attribute.getName().strref();
970  Attribute attr = attribute.getValue();
971 
972  if (symbol == spirv::getEntryPointABIAttrName()) {
973  if (!llvm::isa<spirv::EntryPointABIAttr>(attr)) {
974  return op->emitError("'")
975  << symbol << "' attribute must be an entry point ABI attribute";
976  }
977  } else if (symbol == spirv::getTargetEnvAttrName()) {
978  if (!llvm::isa<spirv::TargetEnvAttr>(attr))
979  return op->emitError("'") << symbol << "' must be a spirv::TargetEnvAttr";
980  } else {
981  return op->emitError("found unsupported '")
982  << symbol << "' attribute on operation";
983  }
984 
985  return success();
986 }
987 
988 /// Verifies the given SPIR-V `attribute` attached to a value of the given
989 /// `valueType` is valid.
991  NamedAttribute attribute) {
992  StringRef symbol = attribute.getName().strref();
993  Attribute attr = attribute.getValue();
994 
995  if (symbol != spirv::getInterfaceVarABIAttrName())
996  return emitError(loc, "found unsupported '")
997  << symbol << "' attribute on region argument";
998 
999  auto varABIAttr = llvm::dyn_cast<spirv::InterfaceVarABIAttr>(attr);
1000  if (!varABIAttr)
1001  return emitError(loc, "'")
1002  << symbol << "' must be a spirv::InterfaceVarABIAttr";
1003 
1004  if (varABIAttr.getStorageClass() && !valueType.isIntOrIndexOrFloat())
1005  return emitError(loc, "'") << symbol
1006  << "' attribute cannot specify storage class "
1007  "when attaching to a non-scalar value";
1008 
1009  return success();
1010 }
1011 
1012 LogicalResult SPIRVDialect::verifyRegionArgAttribute(Operation *op,
1013  unsigned regionIndex,
1014  unsigned argIndex,
1015  NamedAttribute attribute) {
1016  return verifyRegionAttribute(
1017  op->getLoc(), op->getRegion(regionIndex).getArgument(argIndex).getType(),
1018  attribute);
1019 }
1020 
1021 LogicalResult SPIRVDialect::verifyRegionResultAttribute(
1022  Operation *op, unsigned /*regionIndex*/, unsigned /*resultIndex*/,
1023  NamedAttribute attribute) {
1024  return op->emitError("cannot attach SPIR-V attributes to region result");
1025 }
static Operation * materializeConstant(Dialect *dialect, OpBuilder &builder, Attribute value, Type type, Location loc)
A utility function used to materialize a constant for a given attribute and type.
Definition: FoldUtils.cpp:50
static bool isLegalToInline(InlinerInterface &interface, Region *src, Region *insertRegion, bool shouldCloneInlinedRegion, IRMapping &valueMapping)
Utility to check that all of the operations within 'src' can be inlined.
static Value max(ImplicitLocOpBuilder &builder, Value value, Value bound)
std::optional< unsigned > parseAndVerify< unsigned >(SPIRVDialect const &dialect, DialectAsmParser &parser)
static LogicalResult parseOptionalArrayStride(const SPIRVDialect &dialect, DialectAsmParser &parser, unsigned &stride)
Parses an optional , stride = N assembly segment.
static LogicalResult verifyRegionAttribute(Location loc, Type valueType, NamedAttribute attribute)
Verifies the given SPIR-V attribute attached to a value of the given valueType is valid.
static Type parseJointMatrixType(SPIRVDialect const &dialect, DialectAsmParser &parser)
static void print(ArrayType type, DialectAsmPrinter &os)
static Type parseSampledImageType(SPIRVDialect const &dialect, DialectAsmParser &parser)
static Type parseAndVerifyType(SPIRVDialect const &dialect, DialectAsmParser &parser)
static ParseResult parseStructMemberDecorations(SPIRVDialect const &dialect, DialectAsmParser &parser, ArrayRef< Type > memberTypes, SmallVectorImpl< StructType::OffsetInfo > &offsetInfo, SmallVectorImpl< StructType::MemberDecorationInfo > &memberDecorationInfo)
static Type parseAndVerifySampledImageType(SPIRVDialect const &dialect, DialectAsmParser &parser)
static Type parseCooperativeMatrixType(SPIRVDialect const &dialect, DialectAsmParser &parser)
std::optional< Type > parseAndVerify< Type >(SPIRVDialect const &dialect, DialectAsmParser &parser)
static Type parseAndVerifyMatrixType(SPIRVDialect const &dialect, DialectAsmParser &parser)
static Type parseArrayType(SPIRVDialect const &dialect, DialectAsmParser &parser)
static Type parseCooperativeMatrixNVType(SPIRVDialect const &dialect, DialectAsmParser &parser)
static bool containsReturn(Region &region)
Returns true if the given region contains spirv.Return or spirv.ReturnValue ops.
static Type parseStructType(SPIRVDialect const &dialect, DialectAsmParser &parser)
static Type parseRuntimeArrayType(SPIRVDialect const &dialect, DialectAsmParser &parser)
static std::optional< IntTy > parseAndVerifyInteger(SPIRVDialect const &dialect, DialectAsmParser &parser)
static Type parseMatrixType(SPIRVDialect const &dialect, DialectAsmParser &parser)
static Type parseImageType(SPIRVDialect const &dialect, DialectAsmParser &parser)
static std::optional< ValTy > parseAndVerify(SPIRVDialect const &dialect, DialectAsmParser &parser)
static Type parsePointerType(SPIRVDialect const &dialect, DialectAsmParser &parser)
virtual OptionalParseResult parseOptionalInteger(APInt &result)=0
Parse an optional integer value from the stream.
FailureOr< CyclicParseReset > tryStartCyclicParse(AttrOrTypeT attrOrType)
Attempts to start a cyclic parsing region for attrOrType.
virtual ParseResult parseCommaSeparatedList(Delimiter delimiter, function_ref< ParseResult()> parseElementFn, StringRef contextMessage=StringRef())=0
Parse a list of comma-separated items with an optional delimiter.
virtual ParseResult parseOptionalEqual()=0
Parse a = token if present.
virtual ParseResult parseOptionalKeyword(StringRef keyword)=0
Parse the given keyword if present.
virtual ParseResult parseRParen()=0
Parse a ) token.
virtual InFlightDiagnostic emitError(SMLoc loc, const Twine &message={})=0
Emit a diagnostic at the specified location and return failure.
virtual ParseResult parseRSquare()=0
Parse a ] token.
ParseResult parseInteger(IntT &result)
Parse an integer value from the stream.
virtual ParseResult parseOptionalRParen()=0
Parse a ) token if present.
virtual ParseResult parseLess()=0
Parse a '<' token.
virtual ParseResult parseDimensionList(SmallVectorImpl< int64_t > &dimensions, bool allowDynamic=true, bool withTrailingX=true)=0
Parse a dimension list of a tensor or memref type.
virtual ParseResult parseOptionalGreater()=0
Parse a '>' token if present.
virtual ParseResult parseEqual()=0
Parse a = token.
virtual SMLoc getCurrentLocation()=0
Get the location of the next token and store it into the argument.
virtual ParseResult parseOptionalComma()=0
Parse a , token if present.
virtual SMLoc getNameLoc() const =0
Return the location of the original name token.
virtual ParseResult parseOptionalRSquare()=0
Parse a ] token if present.
virtual ParseResult parseGreater()=0
Parse a '>' token.
virtual ParseResult parseLParen()=0
Parse a ( token.
virtual ParseResult parseType(Type &result)=0
Parse a type.
virtual ParseResult parseComma()=0
Parse a , token.
ParseResult parseKeyword(StringRef keyword)
Parse a given keyword.
virtual ParseResult parseOptionalLSquare()=0
Parse a [ token if present.
FailureOr< CyclicPrintReset > tryStartCyclicPrint(AttrOrTypeT attrOrType)
Attempts to start a cyclic printing region for attrOrType.
Attributes are known-constant values of operations.
Definition: Attributes.h:25
Block represents an ordered list of Operations.
Definition: Block.h:30
Operation * getTerminator()
Get the terminator operation of this block.
Definition: Block.cpp:238
The DialectAsmParser has methods for interacting with the asm parser when parsing attributes and type...
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
This is the interface that must be implemented by the dialects of operations to be inlined.
Definition: InliningUtils.h:44
DialectInlinerInterface(Dialect *dialect)
Definition: InliningUtils.h:46
This class provides support for representing a failure result, or a valid value of type T.
Definition: LogicalResult.h:78
This is a utility class for mapping one set of IR entities to another.
Definition: IRMapping.h:26
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition: Location.h:63
NamedAttribute represents a combination of a name and an Attribute value.
Definition: Attributes.h:198
StringAttr getName() const
Return the name of the attribute.
Definition: Attributes.cpp:49
Attribute getValue() const
Return the value of the attribute.
Definition: Attributes.h:212
This class helps build Operations.
Definition: Builders.h:206
Operation * create(const OperationState &state)
Creates an operation given the fields represented as an OperationState.
Definition: Builders.cpp:446
Operation is the basic unit of execution within MLIR.
Definition: Operation.h:88
Location getLoc()
The source location the operation was defined or derived from.
Definition: Operation.h:223
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
Definition: Operation.h:234
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
Definition: Operation.cpp:267
Region & getRegion(unsigned index)
Returns the region held by this operation at position 'index'.
Definition: Operation.h:665
void erase()
Remove this operation from its parent block and delete it.
Definition: Operation.cpp:538
This class implements Optional functionality for ParseResult.
Definition: OpDefinition.h:39
bool has_value() const
Returns true if we contain a valid ParseResult value.
Definition: OpDefinition.h:49
This class represents success/failure for parsing-like operations that find it important to chain tog...
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition: Region.h:26
BlockArgument getArgument(unsigned i)
Definition: Region.h:124
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition: Types.h:74
Dialect & getDialect() const
Get the dialect this type is registered to.
Definition: Types.h:118
bool isIntOrIndexOrFloat() const
Return true if this is an integer (of any signedness), index, or float type.
Definition: Types.cpp:121
bool isBF16() const
Definition: Types.cpp:48
This class provides an abstraction over the different types of ranges over Values.
Definition: ValueRange.h:378
Type getType() const
Return the type of this value.
Definition: Value.h:125
Type getElementType() const
Definition: SPIRVTypes.cpp:66
unsigned getArrayStride() const
Returns the array stride in bytes.
Definition: SPIRVTypes.cpp:68
unsigned getNumElements() const
Definition: SPIRVTypes.cpp:64
static ArrayType get(Type elementType, unsigned elementCount)
Definition: SPIRVTypes.cpp:52
unsigned getRows() const
Returns the number of rows of the matrix.
Definition: SPIRVTypes.cpp:309
unsigned getColumns() const
Returns the number of columns of the matrix.
Definition: SPIRVTypes.cpp:311
static CooperativeMatrixNVType get(Type elementType, Scope scope, unsigned rows, unsigned columns)
Definition: SPIRVTypes.cpp:297
Scope getScope() const
Returns the scope of the matrix.
Definition: SPIRVTypes.cpp:307
Scope getScope() const
Returns the scope of the matrix.
Definition: SPIRVTypes.cpp:247
uint32_t getRows() const
Returns the number of rows of the matrix.
Definition: SPIRVTypes.cpp:241
uint32_t getColumns() const
Returns the number of columns of the matrix.
Definition: SPIRVTypes.cpp:243
static CooperativeMatrixType get(Type elementType, uint32_t rows, uint32_t columns, Scope scope, CooperativeMatrixUseKHR use)
Definition: SPIRVTypes.cpp:229
CooperativeMatrixUseKHR getUse() const
Returns the use parameter of the cooperative matrix.
Definition: SPIRVTypes.cpp:249
static ImageType get(Type elementType, Dim dim, ImageDepthInfo depth=ImageDepthInfo::DepthUnknown, ImageArrayedInfo arrayed=ImageArrayedInfo::NonArrayed, ImageSamplingInfo samplingInfo=ImageSamplingInfo::SingleSampled, ImageSamplerUseInfo samplerUse=ImageSamplerUseInfo::SamplerUnknown, ImageFormat format=ImageFormat::Unknown)
Definition: SPIRVTypes.h:170
ImageDepthInfo getDepthInfo() const
Definition: SPIRVTypes.cpp:489
ImageArrayedInfo getArrayedInfo() const
Definition: SPIRVTypes.cpp:491
ImageFormat getImageFormat() const
Definition: SPIRVTypes.cpp:503
ImageSamplerUseInfo getSamplerUseInfo() const
Definition: SPIRVTypes.cpp:499
Type getElementType() const
Definition: SPIRVTypes.cpp:485
ImageSamplingInfo getSamplingInfo() const
Definition: SPIRVTypes.cpp:495
Scope getScope() const
Return the scope of the joint matrix.
Definition: SPIRVTypes.cpp:374
unsigned getColumns() const
return the number of columns of the matrix.
Definition: SPIRVTypes.cpp:378
static JointMatrixINTELType get(Type elementType, Scope scope, unsigned rows, unsigned columns, MatrixLayout matrixLayout)
Definition: SPIRVTypes.cpp:363
unsigned getRows() const
return the number of rows of the matrix.
Definition: SPIRVTypes.cpp:376
MatrixLayout getMatrixLayout() const
return the layout of the matrix
Definition: SPIRVTypes.cpp:380
static MatrixType get(Type columnType, uint32_t columnCount)
Type getColumnType() const
unsigned getNumColumns() const
Returns the number of columns.
Type getPointeeType() const
Definition: SPIRVTypes.cpp:550
StorageClass getStorageClass() const
Definition: SPIRVTypes.cpp:552
static PointerType get(Type pointeeType, StorageClass storageClass)
Definition: SPIRVTypes.cpp:546
unsigned getArrayStride() const
Returns the array stride in bytes.
Definition: SPIRVTypes.cpp:613
static RuntimeArrayType get(Type elementType)
Definition: SPIRVTypes.cpp:603
static SampledImageType get(Type imageType)
Definition: SPIRVTypes.cpp:872
static bool isValid(FloatType)
Returns true if the given integer type is valid for the SPIR-V dialect.
Definition: SPIRVTypes.cpp:647
SPIR-V struct type.
Definition: SPIRVTypes.h:294
void getMemberDecorations(SmallVectorImpl< StructType::MemberDecorationInfo > &memberDecorations) const
static StructType getIdentified(MLIRContext *context, StringRef identifier)
Construct an identified StructType.
bool isIdentified() const
Returns true if the StructType is identified.
StringRef getIdentifier() const
For literal structs, return an empty string.
static StructType getEmpty(MLIRContext *context, StringRef identifier="")
Construct a (possibly identified) StructType with no members.
unsigned getNumElements() const
Type getElementType(unsigned) const
LogicalResult trySetBody(ArrayRef< Type > memberTypes, ArrayRef< OffsetInfo > offsetInfo={}, ArrayRef< MemberDecorationInfo > memberDecorations={})
Sets the contents of an incomplete identified StructType.
static StructType get(ArrayRef< Type > memberTypes, ArrayRef< OffsetInfo > offsetInfo={}, ArrayRef< MemberDecorationInfo > memberDecorations={})
Construct a literal StructType with at least one member.
uint64_t getMemberOffset(unsigned) const
void printType(Type type, AsmPrinter &printer)
Prints an LLVM Dialect type.
StringRef getInterfaceVarABIAttrName()
Returns the attribute name for specifying argument ABI information.
ParseResult parseEnumKeywordAttr(EnumClass &value, ParserType &parser, StringRef attrName=spirv::attributeName< EnumClass >())
Parses the next keyword in parser as an enumerant of the given EnumClass.
StringRef getTargetEnvAttrName()
Returns the attribute name for specifying SPIR-V target environment.
StringRef getEntryPointABIAttrName()
Returns the attribute name for specifying entry point information.
Include the generated interface declarations.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:62
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
bool succeeded(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a success value.
Definition: LogicalResult.h:68
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:56
Type parseType(llvm::StringRef typeStr, MLIRContext *context, size_t *numRead=nullptr, bool isKnownNullTerminated=false)
This parses a single MLIR type to an MLIR context if it was valid.
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value.
Definition: LogicalResult.h:72
This class represents an efficient way to signal success or failure.
Definition: LogicalResult.h:26