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