Bug Summary

File:build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/mlir/lib/Dialect/Quant/IR/TypeParser.cpp
Warning:line 90, column 22
The left operand of '>' is a garbage value

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name TypeParser.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/build-llvm/tools/clang/stage2-bins -resource-dir /usr/lib/llvm-15/lib/clang/15.0.0 -D MLIR_CUDA_CONVERSIONS_ENABLED=1 -D MLIR_ROCM_CONVERSIONS_ENABLED=1 -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I tools/mlir/lib/Dialect/Quant/IR -I /build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/mlir/lib/Dialect/Quant/IR -I include -I /build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/llvm/include -I /build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/mlir/include -I tools/mlir/include -D _FORTIFY_SOURCE=2 -D NDEBUG -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -internal-isystem /usr/lib/llvm-15/lib/clang/15.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fmacro-prefix-map=/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/= -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/= -O3 -Wno-unused-command-line-argument -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wno-comment -std=c++14 -fdeprecated-macro -fdebug-compilation-dir=/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/= -ferror-limit 19 -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2022-04-20-140412-16051-1 -x c++ /build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/mlir/lib/Dialect/Quant/IR/TypeParser.cpp

/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/mlir/lib/Dialect/Quant/IR/TypeParser.cpp

1//===- TypeParser.h - Quantization Type Parser ------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "mlir/Dialect/Quant/QuantOps.h"
10#include "mlir/Dialect/Quant/QuantTypes.h"
11#include "mlir/IR/BuiltinTypes.h"
12#include "mlir/IR/DialectImplementation.h"
13#include "mlir/IR/Location.h"
14#include "mlir/IR/Types.h"
15#include "llvm/ADT/APFloat.h"
16#include "llvm/ADT/StringSwitch.h"
17#include "llvm/Support/Format.h"
18#include "llvm/Support/MathExtras.h"
19#include "llvm/Support/SourceMgr.h"
20#include "llvm/Support/raw_ostream.h"
21
22using namespace mlir;
23using namespace quant;
24
25static IntegerType parseStorageType(DialectAsmParser &parser, bool &isSigned) {
26 auto typeLoc = parser.getCurrentLocation();
27 IntegerType type;
28
29 // Parse storage type (alpha_ident, integer_literal).
30 StringRef identifier;
31 unsigned storageTypeWidth = 0;
32 OptionalParseResult result = parser.parseOptionalType(type);
33 if (result.hasValue()) {
34 if (!succeeded(*result)) {
35 parser.parseType(type);
36 return nullptr;
37 }
38 isSigned = !type.isUnsigned();
39 storageTypeWidth = type.getWidth();
40 } else if (succeeded(parser.parseKeyword(&identifier))) {
41 // Otherwise, this must be an unsigned integer (`u` integer-literal).
42 if (!identifier.consume_front("u")) {
43 parser.emitError(typeLoc, "illegal storage type prefix");
44 return nullptr;
45 }
46 if (identifier.getAsInteger(10, storageTypeWidth)) {
47 parser.emitError(typeLoc, "expected storage type width");
48 return nullptr;
49 }
50 isSigned = false;
51 type = parser.getBuilder().getIntegerType(storageTypeWidth);
52 } else {
53 return nullptr;
54 }
55
56 if (storageTypeWidth == 0 ||
57 storageTypeWidth > QuantizedType::MaxStorageBits) {
58 parser.emitError(typeLoc, "illegal storage type size: ")
59 << storageTypeWidth;
60 return nullptr;
61 }
62
63 return type;
64}
65
66static ParseResult parseStorageRange(DialectAsmParser &parser,
67 IntegerType storageType, bool isSigned,
68 int64_t &storageTypeMin,
69 int64_t &storageTypeMax) {
70 int64_t defaultIntegerMin = QuantizedType::getDefaultMinimumForInteger(
71 isSigned, storageType.getWidth());
72 int64_t defaultIntegerMax = QuantizedType::getDefaultMaximumForInteger(
73 isSigned, storageType.getWidth());
74 if (failed(parser.parseOptionalLess())) {
11
Taking false branch
75 storageTypeMin = defaultIntegerMin;
76 storageTypeMax = defaultIntegerMax;
77 return success();
78 }
79
80 // Explicit storage min and storage max.
81 SMLoc minLoc = parser.getCurrentLocation(), maxLoc;
82 if (parser.parseInteger(storageTypeMin) || parser.parseColon() ||
21
Taking false branch
83 parser.getCurrentLocation(&maxLoc) ||
84 parser.parseInteger(storageTypeMax) || parser.parseGreater())
12
Calling 'AsmParser::parseInteger'
20
Returning from 'AsmParser::parseInteger'
85 return failure();
86 if (storageTypeMin
21.1
'storageTypeMin' is >= 'defaultIntegerMin'
21.1
'storageTypeMin' is >= 'defaultIntegerMin'
< defaultIntegerMin) {
22
Taking false branch
87 return parser.emitError(minLoc, "illegal storage type minimum: ")
88 << storageTypeMin;
89 }
90 if (storageTypeMax > defaultIntegerMax) {
23
The left operand of '>' is a garbage value
91 return parser.emitError(maxLoc, "illegal storage type maximum: ")
92 << storageTypeMax;
93 }
94 return success();
95}
96
97static FloatType parseExpressedTypeAndRange(DialectAsmParser &parser,
98 double &min, double &max) {
99 auto typeLoc = parser.getCurrentLocation();
100 FloatType type;
101
102 if (failed(parser.parseType(type))) {
103 parser.emitError(typeLoc, "expecting float expressed type");
104 return nullptr;
105 }
106
107 // Calibrated min and max values.
108 if (parser.parseLess() || parser.parseFloat(min) || parser.parseColon() ||
109 parser.parseFloat(max) || parser.parseGreater()) {
110 parser.emitError(typeLoc, "calibrated values must be present");
111 return nullptr;
112 }
113 return type;
114}
115
116/// Parses an AnyQuantizedType.
117///
118/// any ::= `any<` storage-spec (expressed-type-spec)?`>`
119/// storage-spec ::= storage-type (`<` storage-range `>`)?
120/// storage-range ::= integer-literal `:` integer-literal
121/// storage-type ::= (`i` | `u`) integer-literal
122/// expressed-type-spec ::= `:` `f` integer-literal
123static Type parseAnyType(DialectAsmParser &parser) {
124 IntegerType storageType;
125 FloatType expressedType;
126 unsigned typeFlags = 0;
127 int64_t storageTypeMin;
128 int64_t storageTypeMax;
129
130 // Type specification.
131 if (parser.parseLess())
132 return nullptr;
133
134 // Storage type.
135 bool isSigned = false;
136 storageType = parseStorageType(parser, isSigned);
137 if (!storageType) {
138 return nullptr;
139 }
140 if (isSigned) {
141 typeFlags |= QuantizationFlags::Signed;
142 }
143
144 // Storage type range.
145 if (parseStorageRange(parser, storageType, isSigned, storageTypeMin,
146 storageTypeMax)) {
147 return nullptr;
148 }
149
150 // Optional expressed type.
151 if (succeeded(parser.parseOptionalColon())) {
152 if (parser.parseType(expressedType)) {
153 return nullptr;
154 }
155 }
156
157 if (parser.parseGreater()) {
158 return nullptr;
159 }
160
161 return parser.getChecked<AnyQuantizedType>(
162 typeFlags, storageType, expressedType, storageTypeMin, storageTypeMax);
163}
164
165static ParseResult parseQuantParams(DialectAsmParser &parser, double &scale,
166 int64_t &zeroPoint) {
167 // scale[:zeroPoint]?
168 // scale.
169 if (parser.parseFloat(scale))
170 return failure();
171
172 // zero point.
173 zeroPoint = 0;
174 if (failed(parser.parseOptionalColon())) {
175 // Default zero point.
176 return success();
177 }
178
179 return parser.parseInteger(zeroPoint);
180}
181
182/// Parses a UniformQuantizedType.
183///
184/// uniform_type ::= uniform_per_layer
185/// | uniform_per_axis
186/// uniform_per_layer ::= `uniform<` storage-spec expressed-type-spec
187/// `,` scale-zero `>`
188/// uniform_per_axis ::= `uniform<` storage-spec expressed-type-spec
189/// axis-spec `,` scale-zero-list `>`
190/// storage-spec ::= storage-type (`<` storage-range `>`)?
191/// storage-range ::= integer-literal `:` integer-literal
192/// storage-type ::= (`i` | `u`) integer-literal
193/// expressed-type-spec ::= `:` `f` integer-literal
194/// axis-spec ::= `:` integer-literal
195/// scale-zero ::= float-literal `:` integer-literal
196/// scale-zero-list ::= `{` scale-zero (`,` scale-zero)* `}`
197static Type parseUniformType(DialectAsmParser &parser) {
198 IntegerType storageType;
199 FloatType expressedType;
200 unsigned typeFlags = 0;
201 int64_t storageTypeMin;
202 int64_t storageTypeMax;
5
'storageTypeMax' declared without an initial value
203 bool isPerAxis = false;
204 int32_t quantizedDimension;
205 SmallVector<double, 1> scales;
206 SmallVector<int64_t, 1> zeroPoints;
207
208 // Type specification.
209 if (parser.parseLess()) {
6
Taking false branch
210 return nullptr;
211 }
212
213 // Storage type.
214 bool isSigned = false;
215 storageType = parseStorageType(parser, isSigned);
216 if (!storageType) {
7
Taking false branch
217 return nullptr;
218 }
219 if (isSigned
7.1
'isSigned' is false
7.1
'isSigned' is false
) {
8
Taking false branch
220 typeFlags |= QuantizationFlags::Signed;
221 }
222
223 // Storage type range.
224 if (parseStorageRange(parser, storageType, isSigned, storageTypeMin,
10
Calling 'parseStorageRange'
225 storageTypeMax)) {
9
Passing value via 5th parameter 'storageTypeMax'
226 return nullptr;
227 }
228
229 // Expressed type.
230 if (parser.parseColon() || parser.parseType(expressedType)) {
231 return nullptr;
232 }
233
234 // Optionally parse quantized dimension for per-axis quantization.
235 if (succeeded(parser.parseOptionalColon())) {
236 if (parser.parseInteger(quantizedDimension))
237 return nullptr;
238 isPerAxis = true;
239 }
240
241 // Comma leading into range_spec.
242 if (parser.parseComma()) {
243 return nullptr;
244 }
245
246 // Parameter specification.
247 // For per-axis, ranges are in a {} delimitted list.
248 if (isPerAxis) {
249 if (parser.parseLBrace()) {
250 return nullptr;
251 }
252 }
253
254 // Parse scales/zeroPoints.
255 SMLoc scaleZPLoc = parser.getCurrentLocation();
256 do {
257 scales.resize(scales.size() + 1);
258 zeroPoints.resize(zeroPoints.size() + 1);
259 if (parseQuantParams(parser, scales.back(), zeroPoints.back())) {
260 return nullptr;
261 }
262 } while (isPerAxis && succeeded(parser.parseOptionalComma()));
263
264 if (isPerAxis) {
265 if (parser.parseRBrace()) {
266 return nullptr;
267 }
268 }
269
270 if (parser.parseGreater()) {
271 return nullptr;
272 }
273
274 if (!isPerAxis && scales.size() > 1) {
275 return (parser.emitError(scaleZPLoc,
276 "multiple scales/zeroPoints provided, but "
277 "quantizedDimension wasn't specified"),
278 nullptr);
279 }
280
281 if (isPerAxis) {
282 ArrayRef<double> scalesRef(scales.begin(), scales.end());
283 ArrayRef<int64_t> zeroPointsRef(zeroPoints.begin(), zeroPoints.end());
284 return parser.getChecked<UniformQuantizedPerAxisType>(
285 typeFlags, storageType, expressedType, scalesRef, zeroPointsRef,
286 quantizedDimension, storageTypeMin, storageTypeMax);
287 }
288
289 return parser.getChecked<UniformQuantizedType>(
290 typeFlags, storageType, expressedType, scales.front(), zeroPoints.front(),
291 storageTypeMin, storageTypeMax);
292}
293
294/// Parses an CalibratedQuantizedType.
295///
296/// calibrated ::= `calibrated<` expressed-spec `>`
297/// expressed-spec ::= expressed-type `<` calibrated-range `>`
298/// expressed-type ::= `f` integer-literal
299/// calibrated-range ::= float-literal `:` float-literal
300static Type parseCalibratedType(DialectAsmParser &parser) {
301 FloatType expressedType;
302 double min;
303 double max;
304
305 // Type specification.
306 if (parser.parseLess())
307 return nullptr;
308
309 // Expressed type.
310 expressedType = parseExpressedTypeAndRange(parser, min, max);
311 if (!expressedType) {
312 return nullptr;
313 }
314
315 if (parser.parseGreater()) {
316 return nullptr;
317 }
318
319 return parser.getChecked<CalibratedQuantizedType>(expressedType, min, max);
320}
321
322/// Parse a type registered to this dialect.
323Type QuantizationDialect::parseType(DialectAsmParser &parser) const {
324 // All types start with an identifier that we switch on.
325 StringRef typeNameSpelling;
326 if (failed(parser.parseKeyword(&typeNameSpelling)))
1
Taking false branch
327 return nullptr;
328
329 if (typeNameSpelling == "uniform")
2
Assuming the condition is true
3
Taking true branch
330 return parseUniformType(parser);
4
Calling 'parseUniformType'
331 if (typeNameSpelling == "any")
332 return parseAnyType(parser);
333 if (typeNameSpelling == "calibrated")
334 return parseCalibratedType(parser);
335
336 parser.emitError(parser.getNameLoc(),
337 "unknown quantized type " + typeNameSpelling);
338 return nullptr;
339}
340
341static void printStorageType(QuantizedType type, DialectAsmPrinter &out) {
342 // storage type
343 unsigned storageWidth = type.getStorageTypeIntegralWidth();
344 bool isSigned = type.isSigned();
345 if (isSigned) {
346 out << "i" << storageWidth;
347 } else {
348 out << "u" << storageWidth;
349 }
350
351 // storageTypeMin and storageTypeMax if not default.
352 int64_t defaultIntegerMin =
353 QuantizedType::getDefaultMinimumForInteger(isSigned, storageWidth);
354 int64_t defaultIntegerMax =
355 QuantizedType::getDefaultMaximumForInteger(isSigned, storageWidth);
356 if (defaultIntegerMin != type.getStorageTypeMin() ||
357 defaultIntegerMax != type.getStorageTypeMax()) {
358 out << "<" << type.getStorageTypeMin() << ":" << type.getStorageTypeMax()
359 << ">";
360 }
361}
362
363static void printQuantParams(double scale, int64_t zeroPoint,
364 DialectAsmPrinter &out) {
365 out << scale;
366 if (zeroPoint != 0) {
367 out << ":" << zeroPoint;
368 }
369}
370
371/// Helper that prints a AnyQuantizedType.
372static void printAnyQuantizedType(AnyQuantizedType type,
373 DialectAsmPrinter &out) {
374 out << "any<";
375 printStorageType(type, out);
376 if (Type expressedType = type.getExpressedType()) {
377 out << ":" << expressedType;
378 }
379 out << ">";
380}
381
382/// Helper that prints a UniformQuantizedType.
383static void printUniformQuantizedType(UniformQuantizedType type,
384 DialectAsmPrinter &out) {
385 out << "uniform<";
386 printStorageType(type, out);
387 out << ":" << type.getExpressedType() << ", ";
388
389 // scheme specific parameters
390 printQuantParams(type.getScale(), type.getZeroPoint(), out);
391 out << ">";
392}
393
394/// Helper that prints a UniformQuantizedPerAxisType.
395static void printUniformQuantizedPerAxisType(UniformQuantizedPerAxisType type,
396 DialectAsmPrinter &out) {
397 out << "uniform<";
398 printStorageType(type, out);
399 out << ":" << type.getExpressedType() << ":";
400 out << type.getQuantizedDimension();
401 out << ", ";
402
403 // scheme specific parameters
404 ArrayRef<double> scales = type.getScales();
405 ArrayRef<int64_t> zeroPoints = type.getZeroPoints();
406 out << "{";
407 llvm::interleave(
408 llvm::seq<size_t>(0, scales.size()), out,
409 [&](size_t index) {
410 printQuantParams(scales[index], zeroPoints[index], out);
411 },
412 ",");
413 out << "}>";
414}
415
416/// Helper that prints a CalibratedQuantizedType.
417static void printCalibratedQuantizedType(CalibratedQuantizedType type,
418 DialectAsmPrinter &out) {
419 out << "calibrated<" << type.getExpressedType();
420 out << "<" << type.getMin() << ":" << type.getMax() << ">";
421 out << ">";
422}
423
424/// Print a type registered to this dialect.
425void QuantizationDialect::printType(Type type, DialectAsmPrinter &os) const {
426 if (auto anyType = type.dyn_cast<AnyQuantizedType>())
427 printAnyQuantizedType(anyType, os);
428 else if (auto uniformType = type.dyn_cast<UniformQuantizedType>())
429 printUniformQuantizedType(uniformType, os);
430 else if (auto perAxisType = type.dyn_cast<UniformQuantizedPerAxisType>())
431 printUniformQuantizedPerAxisType(perAxisType, os);
432 else if (auto calibratedType = type.dyn_cast<CalibratedQuantizedType>())
433 printCalibratedQuantizedType(calibratedType, os);
434 else
435 llvm_unreachable("Unhandled quantized type")::llvm::llvm_unreachable_internal("Unhandled quantized type",
"mlir/lib/Dialect/Quant/IR/TypeParser.cpp", 435)
;
436}

/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/mlir/include/mlir/IR/OpImplementation.h

1//===- OpImplementation.h - Classes for implementing Op types ---*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This classes used by the implementation details of Op types.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef MLIR_IR_OPIMPLEMENTATION_H
14#define MLIR_IR_OPIMPLEMENTATION_H
15
16#include "mlir/IR/BuiltinTypes.h"
17#include "mlir/IR/DialectInterface.h"
18#include "mlir/IR/OpDefinition.h"
19#include "llvm/ADT/Twine.h"
20#include "llvm/Support/SMLoc.h"
21
22namespace mlir {
23
24class Builder;
25
26//===----------------------------------------------------------------------===//
27// AsmPrinter
28//===----------------------------------------------------------------------===//
29
30/// This base class exposes generic asm printer hooks, usable across the various
31/// derived printers.
32class AsmPrinter {
33public:
34 /// This class contains the internal default implementation of the base
35 /// printer methods.
36 class Impl;
37
38 /// Initialize the printer with the given internal implementation.
39 AsmPrinter(Impl &impl) : impl(&impl) {}
40 virtual ~AsmPrinter();
41
42 /// Return the raw output stream used by this printer.
43 virtual raw_ostream &getStream() const;
44
45 /// Print the given floating point value in a stabilized form that can be
46 /// roundtripped through the IR. This is the companion to the 'parseFloat'
47 /// hook on the AsmParser.
48 virtual void printFloat(const APFloat &value);
49
50 virtual void printType(Type type);
51 virtual void printAttribute(Attribute attr);
52
53 /// Trait to check if `AttrType` provides a `print` method.
54 template <typename AttrOrType>
55 using has_print_method =
56 decltype(std::declval<AttrOrType>().print(std::declval<AsmPrinter &>()));
57 template <typename AttrOrType>
58 using detect_has_print_method =
59 llvm::is_detected<has_print_method, AttrOrType>;
60
61 /// Print the provided attribute in the context of an operation custom
62 /// printer/parser: this will invoke directly the print method on the
63 /// attribute class and skip the `#dialect.mnemonic` prefix in most cases.
64 template <typename AttrOrType,
65 std::enable_if_t<detect_has_print_method<AttrOrType>::value>
66 *sfinae = nullptr>
67 void printStrippedAttrOrType(AttrOrType attrOrType) {
68 if (succeeded(printAlias(attrOrType)))
69 return;
70 attrOrType.print(*this);
71 }
72
73 /// SFINAE for printing the provided attribute in the context of an operation
74 /// custom printer in the case where the attribute does not define a print
75 /// method.
76 template <typename AttrOrType,
77 std::enable_if_t<!detect_has_print_method<AttrOrType>::value>
78 *sfinae = nullptr>
79 void printStrippedAttrOrType(AttrOrType attrOrType) {
80 *this << attrOrType;
81 }
82
83 /// Print the given attribute without its type. The corresponding parser must
84 /// provide a valid type for the attribute.
85 virtual void printAttributeWithoutType(Attribute attr);
86
87 /// Print the given string as a keyword, or a quoted and escaped string if it
88 /// has any special or non-printable characters in it.
89 virtual void printKeywordOrString(StringRef keyword);
90
91 /// Print the given string as a symbol reference, i.e. a form representable by
92 /// a SymbolRefAttr. A symbol reference is represented as a string prefixed
93 /// with '@'. The reference is surrounded with ""'s and escaped if it has any
94 /// special or non-printable characters in it.
95 virtual void printSymbolName(StringRef symbolRef);
96
97 /// Print an optional arrow followed by a type list.
98 template <typename TypeRange>
99 void printOptionalArrowTypeList(TypeRange &&types) {
100 if (types.begin() != types.end())
101 printArrowTypeList(types);
102 }
103 template <typename TypeRange>
104 void printArrowTypeList(TypeRange &&types) {
105 auto &os = getStream() << " -> ";
106
107 bool wrapped = !llvm::hasSingleElement(types) ||
108 (*types.begin()).template isa<FunctionType>();
109 if (wrapped)
110 os << '(';
111 llvm::interleaveComma(types, *this);
112 if (wrapped)
113 os << ')';
114 }
115
116 /// Print the two given type ranges in a functional form.
117 template <typename InputRangeT, typename ResultRangeT>
118 void printFunctionalType(InputRangeT &&inputs, ResultRangeT &&results) {
119 auto &os = getStream();
120 os << '(';
121 llvm::interleaveComma(inputs, *this);
122 os << ')';
123 printArrowTypeList(results);
124 }
125
126protected:
127 /// Initialize the printer with no internal implementation. In this case, all
128 /// virtual methods of this class must be overriden.
129 AsmPrinter() {}
130
131private:
132 AsmPrinter(const AsmPrinter &) = delete;
133 void operator=(const AsmPrinter &) = delete;
134
135 /// Print the alias for the given attribute, return failure if no alias could
136 /// be printed.
137 virtual LogicalResult printAlias(Attribute attr);
138
139 /// Print the alias for the given type, return failure if no alias could
140 /// be printed.
141 virtual LogicalResult printAlias(Type type);
142
143 /// The internal implementation of the printer.
144 Impl *impl{nullptr};
145};
146
147template <typename AsmPrinterT>
148inline std::enable_if_t<std::is_base_of<AsmPrinter, AsmPrinterT>::value,
149 AsmPrinterT &>
150operator<<(AsmPrinterT &p, Type type) {
151 p.printType(type);
152 return p;
153}
154
155template <typename AsmPrinterT>
156inline std::enable_if_t<std::is_base_of<AsmPrinter, AsmPrinterT>::value,
157 AsmPrinterT &>
158operator<<(AsmPrinterT &p, Attribute attr) {
159 p.printAttribute(attr);
160 return p;
161}
162
163template <typename AsmPrinterT>
164inline std::enable_if_t<std::is_base_of<AsmPrinter, AsmPrinterT>::value,
165 AsmPrinterT &>
166operator<<(AsmPrinterT &p, const APFloat &value) {
167 p.printFloat(value);
168 return p;
169}
170template <typename AsmPrinterT>
171inline std::enable_if_t<std::is_base_of<AsmPrinter, AsmPrinterT>::value,
172 AsmPrinterT &>
173operator<<(AsmPrinterT &p, float value) {
174 return p << APFloat(value);
175}
176template <typename AsmPrinterT>
177inline std::enable_if_t<std::is_base_of<AsmPrinter, AsmPrinterT>::value,
178 AsmPrinterT &>
179operator<<(AsmPrinterT &p, double value) {
180 return p << APFloat(value);
181}
182
183// Support printing anything that isn't convertible to one of the other
184// streamable types, even if it isn't exactly one of them. For example, we want
185// to print FunctionType with the Type version above, not have it match this.
186template <
187 typename AsmPrinterT, typename T,
188 typename std::enable_if<!std::is_convertible<T &, Value &>::value &&
189 !std::is_convertible<T &, Type &>::value &&
190 !std::is_convertible<T &, Attribute &>::value &&
191 !std::is_convertible<T &, ValueRange>::value &&
192 !std::is_convertible<T &, APFloat &>::value &&
193 !llvm::is_one_of<T, bool, float, double>::value,
194 T>::type * = nullptr>
195inline std::enable_if_t<std::is_base_of<AsmPrinter, AsmPrinterT>::value,
196 AsmPrinterT &>
197operator<<(AsmPrinterT &p, const T &other) {
198 p.getStream() << other;
199 return p;
200}
201
202template <typename AsmPrinterT>
203inline std::enable_if_t<std::is_base_of<AsmPrinter, AsmPrinterT>::value,
204 AsmPrinterT &>
205operator<<(AsmPrinterT &p, bool value) {
206 return p << (value ? StringRef("true") : "false");
207}
208
209template <typename AsmPrinterT, typename ValueRangeT>
210inline std::enable_if_t<std::is_base_of<AsmPrinter, AsmPrinterT>::value,
211 AsmPrinterT &>
212operator<<(AsmPrinterT &p, const ValueTypeRange<ValueRangeT> &types) {
213 llvm::interleaveComma(types, p);
214 return p;
215}
216template <typename AsmPrinterT>
217inline std::enable_if_t<std::is_base_of<AsmPrinter, AsmPrinterT>::value,
218 AsmPrinterT &>
219operator<<(AsmPrinterT &p, const TypeRange &types) {
220 llvm::interleaveComma(types, p);
221 return p;
222}
223template <typename AsmPrinterT, typename ElementT>
224inline std::enable_if_t<std::is_base_of<AsmPrinter, AsmPrinterT>::value,
225 AsmPrinterT &>
226operator<<(AsmPrinterT &p, ArrayRef<ElementT> types) {
227 llvm::interleaveComma(types, p);
228 return p;
229}
230
231//===----------------------------------------------------------------------===//
232// OpAsmPrinter
233//===----------------------------------------------------------------------===//
234
235/// This is a pure-virtual base class that exposes the asmprinter hooks
236/// necessary to implement a custom print() method.
237class OpAsmPrinter : public AsmPrinter {
238public:
239 using AsmPrinter::AsmPrinter;
240 ~OpAsmPrinter() override;
241
242 /// Print a newline and indent the printer to the start of the current
243 /// operation.
244 virtual void printNewline() = 0;
245
246 /// Print a block argument in the usual format of:
247 /// %ssaName : type {attr1=42} loc("here")
248 /// where location printing is controlled by the standard internal option.
249 /// You may pass omitType=true to not print a type, and pass an empty
250 /// attribute list if you don't care for attributes.
251 virtual void printRegionArgument(BlockArgument arg,
252 ArrayRef<NamedAttribute> argAttrs = {},
253 bool omitType = false) = 0;
254
255 /// Print implementations for various things an operation contains.
256 virtual void printOperand(Value value) = 0;
257 virtual void printOperand(Value value, raw_ostream &os) = 0;
258
259 /// Print a comma separated list of operands.
260 template <typename ContainerType>
261 void printOperands(const ContainerType &container) {
262 printOperands(container.begin(), container.end());
263 }
264
265 /// Print a comma separated list of operands.
266 template <typename IteratorType>
267 void printOperands(IteratorType it, IteratorType end) {
268 if (it == end)
269 return;
270 printOperand(*it);
271 for (++it; it != end; ++it) {
272 getStream() << ", ";
273 printOperand(*it);
274 }
275 }
276
277 /// Print the given successor.
278 virtual void printSuccessor(Block *successor) = 0;
279
280 /// Print the successor and its operands.
281 virtual void printSuccessorAndUseList(Block *successor,
282 ValueRange succOperands) = 0;
283
284 /// If the specified operation has attributes, print out an attribute
285 /// dictionary with their values. elidedAttrs allows the client to ignore
286 /// specific well known attributes, commonly used if the attribute value is
287 /// printed some other way (like as a fixed operand).
288 virtual void printOptionalAttrDict(ArrayRef<NamedAttribute> attrs,
289 ArrayRef<StringRef> elidedAttrs = {}) = 0;
290
291 /// If the specified operation has attributes, print out an attribute
292 /// dictionary prefixed with 'attributes'.
293 virtual void
294 printOptionalAttrDictWithKeyword(ArrayRef<NamedAttribute> attrs,
295 ArrayRef<StringRef> elidedAttrs = {}) = 0;
296
297 /// Print the entire operation with the default generic assembly form.
298 /// If `printOpName` is true, then the operation name is printed (the default)
299 /// otherwise it is omitted and the print will start with the operand list.
300 virtual void printGenericOp(Operation *op, bool printOpName = true) = 0;
301
302 /// Prints a region.
303 /// If 'printEntryBlockArgs' is false, the arguments of the
304 /// block are not printed. If 'printBlockTerminator' is false, the terminator
305 /// operation of the block is not printed. If printEmptyBlock is true, then
306 /// the block header is printed even if the block is empty.
307 virtual void printRegion(Region &blocks, bool printEntryBlockArgs = true,
308 bool printBlockTerminators = true,
309 bool printEmptyBlock = false) = 0;
310
311 /// Renumber the arguments for the specified region to the same names as the
312 /// SSA values in namesToUse. This may only be used for IsolatedFromAbove
313 /// operations. If any entry in namesToUse is null, the corresponding
314 /// argument name is left alone.
315 virtual void shadowRegionArgs(Region &region, ValueRange namesToUse) = 0;
316
317 /// Prints an affine map of SSA ids, where SSA id names are used in place
318 /// of dims/symbols.
319 /// Operand values must come from single-result sources, and be valid
320 /// dimensions/symbol identifiers according to mlir::isValidDim/Symbol.
321 virtual void printAffineMapOfSSAIds(AffineMapAttr mapAttr,
322 ValueRange operands) = 0;
323
324 /// Prints an affine expression of SSA ids with SSA id names used instead of
325 /// dims and symbols.
326 /// Operand values must come from single-result sources, and be valid
327 /// dimensions/symbol identifiers according to mlir::isValidDim/Symbol.
328 virtual void printAffineExprOfSSAIds(AffineExpr expr, ValueRange dimOperands,
329 ValueRange symOperands) = 0;
330
331 /// Print the complete type of an operation in functional form.
332 void printFunctionalType(Operation *op);
333 using AsmPrinter::printFunctionalType;
334};
335
336// Make the implementations convenient to use.
337inline OpAsmPrinter &operator<<(OpAsmPrinter &p, Value value) {
338 p.printOperand(value);
339 return p;
340}
341
342template <typename T,
343 typename std::enable_if<std::is_convertible<T &, ValueRange>::value &&
344 !std::is_convertible<T &, Value &>::value,
345 T>::type * = nullptr>
346inline OpAsmPrinter &operator<<(OpAsmPrinter &p, const T &values) {
347 p.printOperands(values);
348 return p;
349}
350
351inline OpAsmPrinter &operator<<(OpAsmPrinter &p, Block *value) {
352 p.printSuccessor(value);
353 return p;
354}
355
356//===----------------------------------------------------------------------===//
357// AsmParser
358//===----------------------------------------------------------------------===//
359
360/// This base class exposes generic asm parser hooks, usable across the various
361/// derived parsers.
362class AsmParser {
363public:
364 AsmParser() = default;
365 virtual ~AsmParser();
366
367 MLIRContext *getContext() const;
368
369 /// Return the location of the original name token.
370 virtual SMLoc getNameLoc() const = 0;
371
372 //===--------------------------------------------------------------------===//
373 // Utilities
374 //===--------------------------------------------------------------------===//
375
376 /// Emit a diagnostic at the specified location and return failure.
377 virtual InFlightDiagnostic emitError(SMLoc loc,
378 const Twine &message = {}) = 0;
379
380 /// Return a builder which provides useful access to MLIRContext, global
381 /// objects like types and attributes.
382 virtual Builder &getBuilder() const = 0;
383
384 /// Get the location of the next token and store it into the argument. This
385 /// always succeeds.
386 virtual SMLoc getCurrentLocation() = 0;
387 ParseResult getCurrentLocation(SMLoc *loc) {
388 *loc = getCurrentLocation();
389 return success();
390 }
391
392 /// Re-encode the given source location as an MLIR location and return it.
393 /// Note: This method should only be used when a `Location` is necessary, as
394 /// the encoding process is not efficient.
395 virtual Location getEncodedSourceLoc(SMLoc loc) = 0;
396
397 //===--------------------------------------------------------------------===//
398 // Token Parsing
399 //===--------------------------------------------------------------------===//
400
401 /// Parse a '->' token.
402 virtual ParseResult parseArrow() = 0;
403
404 /// Parse a '->' token if present
405 virtual ParseResult parseOptionalArrow() = 0;
406
407 /// Parse a `{` token.
408 virtual ParseResult parseLBrace() = 0;
409
410 /// Parse a `{` token if present.
411 virtual ParseResult parseOptionalLBrace() = 0;
412
413 /// Parse a `}` token.
414 virtual ParseResult parseRBrace() = 0;
415
416 /// Parse a `}` token if present.
417 virtual ParseResult parseOptionalRBrace() = 0;
418
419 /// Parse a `:` token.
420 virtual ParseResult parseColon() = 0;
421
422 /// Parse a `:` token if present.
423 virtual ParseResult parseOptionalColon() = 0;
424
425 /// Parse a `,` token.
426 virtual ParseResult parseComma() = 0;
427
428 /// Parse a `,` token if present.
429 virtual ParseResult parseOptionalComma() = 0;
430
431 /// Parse a `=` token.
432 virtual ParseResult parseEqual() = 0;
433
434 /// Parse a `=` token if present.
435 virtual ParseResult parseOptionalEqual() = 0;
436
437 /// Parse a '<' token.
438 virtual ParseResult parseLess() = 0;
439
440 /// Parse a '<' token if present.
441 virtual ParseResult parseOptionalLess() = 0;
442
443 /// Parse a '>' token.
444 virtual ParseResult parseGreater() = 0;
445
446 /// Parse a '>' token if present.
447 virtual ParseResult parseOptionalGreater() = 0;
448
449 /// Parse a '?' token.
450 virtual ParseResult parseQuestion() = 0;
451
452 /// Parse a '?' token if present.
453 virtual ParseResult parseOptionalQuestion() = 0;
454
455 /// Parse a '+' token.
456 virtual ParseResult parsePlus() = 0;
457
458 /// Parse a '+' token if present.
459 virtual ParseResult parseOptionalPlus() = 0;
460
461 /// Parse a '*' token.
462 virtual ParseResult parseStar() = 0;
463
464 /// Parse a '*' token if present.
465 virtual ParseResult parseOptionalStar() = 0;
466
467 /// Parse a quoted string token.
468 ParseResult parseString(std::string *string) {
469 auto loc = getCurrentLocation();
470 if (parseOptionalString(string))
471 return emitError(loc, "expected string");
472 return success();
473 }
474
475 /// Parse a quoted string token if present.
476 virtual ParseResult parseOptionalString(std::string *string) = 0;
477
478 /// Parse a given keyword.
479 ParseResult parseKeyword(StringRef keyword, const Twine &msg = "") {
480 auto loc = getCurrentLocation();
481 if (parseOptionalKeyword(keyword))
482 return emitError(loc, "expected '") << keyword << "'" << msg;
483 return success();
484 }
485
486 /// Parse a keyword into 'keyword'.
487 ParseResult parseKeyword(StringRef *keyword) {
488 auto loc = getCurrentLocation();
489 if (parseOptionalKeyword(keyword))
490 return emitError(loc, "expected valid keyword");
491 return success();
492 }
493
494 /// Parse the given keyword if present.
495 virtual ParseResult parseOptionalKeyword(StringRef keyword) = 0;
496
497 /// Parse a keyword, if present, into 'keyword'.
498 virtual ParseResult parseOptionalKeyword(StringRef *keyword) = 0;
499
500 /// Parse a keyword, if present, and if one of the 'allowedValues',
501 /// into 'keyword'
502 virtual ParseResult
503 parseOptionalKeyword(StringRef *keyword,
504 ArrayRef<StringRef> allowedValues) = 0;
505
506 /// Parse a keyword or a quoted string.
507 ParseResult parseKeywordOrString(std::string *result) {
508 if (failed(parseOptionalKeywordOrString(result)))
509 return emitError(getCurrentLocation())
510 << "expected valid keyword or string";
511 return success();
512 }
513
514 /// Parse an optional keyword or string.
515 virtual ParseResult parseOptionalKeywordOrString(std::string *result) = 0;
516
517 /// Parse a `(` token.
518 virtual ParseResult parseLParen() = 0;
519
520 /// Parse a `(` token if present.
521 virtual ParseResult parseOptionalLParen() = 0;
522
523 /// Parse a `)` token.
524 virtual ParseResult parseRParen() = 0;
525
526 /// Parse a `)` token if present.
527 virtual ParseResult parseOptionalRParen() = 0;
528
529 /// Parse a `[` token.
530 virtual ParseResult parseLSquare() = 0;
531
532 /// Parse a `[` token if present.
533 virtual ParseResult parseOptionalLSquare() = 0;
534
535 /// Parse a `]` token.
536 virtual ParseResult parseRSquare() = 0;
537
538 /// Parse a `]` token if present.
539 virtual ParseResult parseOptionalRSquare() = 0;
540
541 /// Parse a `...` token if present;
542 virtual ParseResult parseOptionalEllipsis() = 0;
543
544 /// Parse a floating point value from the stream.
545 virtual ParseResult parseFloat(double &result) = 0;
546
547 /// Parse an integer value from the stream.
548 template <typename IntT>
549 ParseResult parseInteger(IntT &result) {
550 auto loc = getCurrentLocation();
551 OptionalParseResult parseResult = parseOptionalInteger(result);
13
Calling 'AsmParser::parseOptionalInteger'
17
Returning from 'AsmParser::parseOptionalInteger'
552 if (!parseResult.hasValue())
18
Taking false branch
553 return emitError(loc, "expected integer value");
554 return *parseResult;
19
Returning without writing to 'result'
555 }
556
557 /// Parse an optional integer value from the stream.
558 virtual OptionalParseResult parseOptionalInteger(APInt &result) = 0;
559
560 template <typename IntT>
561 OptionalParseResult parseOptionalInteger(IntT &result) {
562 auto loc = getCurrentLocation();
563
564 // Parse the unsigned variant.
565 APInt uintResult;
566 OptionalParseResult parseResult = parseOptionalInteger(uintResult);
567 if (!parseResult.hasValue() || failed(*parseResult))
14
Assuming the condition is false
15
Taking true branch
568 return parseResult;
16
Returning without writing to 'result'
569
570 // Try to convert to the provided integer type. sextOrTrunc is correct even
571 // for unsigned types because parseOptionalInteger ensures the sign bit is
572 // zero for non-negated integers.
573 result =
574 (IntT)uintResult.sextOrTrunc(sizeof(IntT) * CHAR_BIT8).getLimitedValue();
575 if (APInt(uintResult.getBitWidth(), result) != uintResult)
576 return emitError(loc, "integer value too large");
577 return success();
578 }
579
580 /// These are the supported delimiters around operand lists and region
581 /// argument lists, used by parseOperandList and parseRegionArgumentList.
582 enum class Delimiter {
583 /// Zero or more operands with no delimiters.
584 None,
585 /// Parens surrounding zero or more operands.
586 Paren,
587 /// Square brackets surrounding zero or more operands.
588 Square,
589 /// <> brackets surrounding zero or more operands.
590 LessGreater,
591 /// {} brackets surrounding zero or more operands.
592 Braces,
593 /// Parens supporting zero or more operands, or nothing.
594 OptionalParen,
595 /// Square brackets supporting zero or more ops, or nothing.
596 OptionalSquare,
597 /// <> brackets supporting zero or more ops, or nothing.
598 OptionalLessGreater,
599 /// {} brackets surrounding zero or more operands, or nothing.
600 OptionalBraces,
601 };
602
603 /// Parse a list of comma-separated items with an optional delimiter. If a
604 /// delimiter is provided, then an empty list is allowed. If not, then at
605 /// least one element will be parsed.
606 ///
607 /// contextMessage is an optional message appended to "expected '('" sorts of
608 /// diagnostics when parsing the delimeters.
609 virtual ParseResult
610 parseCommaSeparatedList(Delimiter delimiter,
611 function_ref<ParseResult()> parseElementFn,
612 StringRef contextMessage = StringRef()) = 0;
613
614 /// Parse a comma separated list of elements that must have at least one entry
615 /// in it.
616 ParseResult
617 parseCommaSeparatedList(function_ref<ParseResult()> parseElementFn) {
618 return parseCommaSeparatedList(Delimiter::None, parseElementFn);
619 }
620
621 //===--------------------------------------------------------------------===//
622 // Attribute/Type Parsing
623 //===--------------------------------------------------------------------===//
624
625 /// Invoke the `getChecked` method of the given Attribute or Type class, using
626 /// the provided location to emit errors in the case of failure. Note that
627 /// unlike `OpBuilder::getType`, this method does not implicitly insert a
628 /// context parameter.
629 template <typename T, typename... ParamsT>
630 T getChecked(SMLoc loc, ParamsT &&... params) {
631 return T::getChecked([&] { return emitError(loc); },
632 std::forward<ParamsT>(params)...);
633 }
634 /// A variant of `getChecked` that uses the result of `getNameLoc` to emit
635 /// errors.
636 template <typename T, typename... ParamsT>
637 T getChecked(ParamsT &&... params) {
638 return T::getChecked([&] { return emitError(getNameLoc()); },
639 std::forward<ParamsT>(params)...);
640 }
641
642 //===--------------------------------------------------------------------===//
643 // Attribute Parsing
644 //===--------------------------------------------------------------------===//
645
646 /// Parse an arbitrary attribute of a given type and return it in result.
647 virtual ParseResult parseAttribute(Attribute &result, Type type = {}) = 0;
648
649 /// Parse a custom attribute with the provided callback, unless the next
650 /// token is `#`, in which case the generic parser is invoked.
651 virtual ParseResult parseCustomAttributeWithFallback(
652 Attribute &result, Type type,
653 function_ref<ParseResult(Attribute &result, Type type)>
654 parseAttribute) = 0;
655
656 /// Parse an attribute of a specific kind and type.
657 template <typename AttrType>
658 ParseResult parseAttribute(AttrType &result, Type type = {}) {
659 SMLoc loc = getCurrentLocation();
660
661 // Parse any kind of attribute.
662 Attribute attr;
663 if (parseAttribute(attr, type))
664 return failure();
665
666 // Check for the right kind of attribute.
667 if (!(result = attr.dyn_cast<AttrType>()))
668 return emitError(loc, "invalid kind of attribute specified");
669
670 return success();
671 }
672
673 /// Parse an arbitrary attribute and return it in result. This also adds the
674 /// attribute to the specified attribute list with the specified name.
675 ParseResult parseAttribute(Attribute &result, StringRef attrName,
676 NamedAttrList &attrs) {
677 return parseAttribute(result, Type(), attrName, attrs);
678 }
679
680 /// Parse an attribute of a specific kind and type.
681 template <typename AttrType>
682 ParseResult parseAttribute(AttrType &result, StringRef attrName,
683 NamedAttrList &attrs) {
684 return parseAttribute(result, Type(), attrName, attrs);
685 }
686
687 /// Parse an arbitrary attribute of a given type and populate it in `result`.
688 /// This also adds the attribute to the specified attribute list with the
689 /// specified name.
690 template <typename AttrType>
691 ParseResult parseAttribute(AttrType &result, Type type, StringRef attrName,
692 NamedAttrList &attrs) {
693 SMLoc loc = getCurrentLocation();
694
695 // Parse any kind of attribute.
696 Attribute attr;
697 if (parseAttribute(attr, type))
698 return failure();
699
700 // Check for the right kind of attribute.
701 result = attr.dyn_cast<AttrType>();
702 if (!result)
703 return emitError(loc, "invalid kind of attribute specified");
704
705 attrs.append(attrName, result);
706 return success();
707 }
708
709 /// Trait to check if `AttrType` provides a `parse` method.
710 template <typename AttrType>
711 using has_parse_method = decltype(AttrType::parse(std::declval<AsmParser &>(),
712 std::declval<Type>()));
713 template <typename AttrType>
714 using detect_has_parse_method = llvm::is_detected<has_parse_method, AttrType>;
715
716 /// Parse a custom attribute of a given type unless the next token is `#`, in
717 /// which case the generic parser is invoked. The parsed attribute is
718 /// populated in `result` and also added to the specified attribute list with
719 /// the specified name.
720 template <typename AttrType>
721 std::enable_if_t<detect_has_parse_method<AttrType>::value, ParseResult>
722 parseCustomAttributeWithFallback(AttrType &result, Type type,
723 StringRef attrName, NamedAttrList &attrs) {
724 SMLoc loc = getCurrentLocation();
725
726 // Parse any kind of attribute.
727 Attribute attr;
728 if (parseCustomAttributeWithFallback(
729 attr, type, [&](Attribute &result, Type type) -> ParseResult {
730 result = AttrType::parse(*this, type);
731 if (!result)
732 return failure();
733 return success();
734 }))
735 return failure();
736
737 // Check for the right kind of attribute.
738 result = attr.dyn_cast<AttrType>();
739 if (!result)
740 return emitError(loc, "invalid kind of attribute specified");
741
742 attrs.append(attrName, result);
743 return success();
744 }
745
746 /// SFINAE parsing method for Attribute that don't implement a parse method.
747 template <typename AttrType>
748 std::enable_if_t<!detect_has_parse_method<AttrType>::value, ParseResult>
749 parseCustomAttributeWithFallback(AttrType &result, Type type,
750 StringRef attrName, NamedAttrList &attrs) {
751 return parseAttribute(result, type, attrName, attrs);
752 }
753
754 /// Parse a custom attribute of a given type unless the next token is `#`, in
755 /// which case the generic parser is invoked. The parsed attribute is
756 /// populated in `result`.
757 template <typename AttrType>
758 std::enable_if_t<detect_has_parse_method<AttrType>::value, ParseResult>
759 parseCustomAttributeWithFallback(AttrType &result) {
760 SMLoc loc = getCurrentLocation();
761
762 // Parse any kind of attribute.
763 Attribute attr;
764 if (parseCustomAttributeWithFallback(
765 attr, {}, [&](Attribute &result, Type type) -> ParseResult {
766 result = AttrType::parse(*this, type);
767 return success(!!result);
768 }))
769 return failure();
770
771 // Check for the right kind of attribute.
772 result = attr.dyn_cast<AttrType>();
773 if (!result)
774 return emitError(loc, "invalid kind of attribute specified");
775 return success();
776 }
777
778 /// SFINAE parsing method for Attribute that don't implement a parse method.
779 template <typename AttrType>
780 std::enable_if_t<!detect_has_parse_method<AttrType>::value, ParseResult>
781 parseCustomAttributeWithFallback(AttrType &result) {
782 return parseAttribute(result);
783 }
784
785 /// Parse an arbitrary optional attribute of a given type and return it in
786 /// result.
787 virtual OptionalParseResult parseOptionalAttribute(Attribute &result,
788 Type type = {}) = 0;
789
790 /// Parse an optional array attribute and return it in result.
791 virtual OptionalParseResult parseOptionalAttribute(ArrayAttr &result,
792 Type type = {}) = 0;
793
794 /// Parse an optional string attribute and return it in result.
795 virtual OptionalParseResult parseOptionalAttribute(StringAttr &result,
796 Type type = {}) = 0;
797
798 /// Parse an optional attribute of a specific type and add it to the list with
799 /// the specified name.
800 template <typename AttrType>
801 OptionalParseResult parseOptionalAttribute(AttrType &result,
802 StringRef attrName,
803 NamedAttrList &attrs) {
804 return parseOptionalAttribute(result, Type(), attrName, attrs);
805 }
806
807 /// Parse an optional attribute of a specific type and add it to the list with
808 /// the specified name.
809 template <typename AttrType>
810 OptionalParseResult parseOptionalAttribute(AttrType &result, Type type,
811 StringRef attrName,
812 NamedAttrList &attrs) {
813 OptionalParseResult parseResult = parseOptionalAttribute(result, type);
814 if (parseResult.hasValue() && succeeded(*parseResult))
815 attrs.append(attrName, result);
816 return parseResult;
817 }
818
819 /// Parse a named dictionary into 'result' if it is present.
820 virtual ParseResult parseOptionalAttrDict(NamedAttrList &result) = 0;
821
822 /// Parse a named dictionary into 'result' if the `attributes` keyword is
823 /// present.
824 virtual ParseResult
825 parseOptionalAttrDictWithKeyword(NamedAttrList &result) = 0;
826
827 /// Parse an affine map instance into 'map'.
828 virtual ParseResult parseAffineMap(AffineMap &map) = 0;
829
830 /// Parse an integer set instance into 'set'.
831 virtual ParseResult printIntegerSet(IntegerSet &set) = 0;
832
833 //===--------------------------------------------------------------------===//
834 // Identifier Parsing
835 //===--------------------------------------------------------------------===//
836
837 /// Parse an @-identifier and store it (without the '@' symbol) in a string
838 /// attribute named 'attrName'.
839 ParseResult parseSymbolName(StringAttr &result, StringRef attrName,
840 NamedAttrList &attrs) {
841 if (failed(parseOptionalSymbolName(result, attrName, attrs)))
842 return emitError(getCurrentLocation())
843 << "expected valid '@'-identifier for symbol name";
844 return success();
845 }
846
847 /// Parse an optional @-identifier and store it (without the '@' symbol) in a
848 /// string attribute named 'attrName'.
849 virtual ParseResult parseOptionalSymbolName(StringAttr &result,
850 StringRef attrName,
851 NamedAttrList &attrs) = 0;
852
853 //===--------------------------------------------------------------------===//
854 // Type Parsing
855 //===--------------------------------------------------------------------===//
856
857 /// Parse a type.
858 virtual ParseResult parseType(Type &result) = 0;
859
860 /// Parse a custom type with the provided callback, unless the next
861 /// token is `#`, in which case the generic parser is invoked.
862 virtual ParseResult parseCustomTypeWithFallback(
863 Type &result, function_ref<ParseResult(Type &result)> parseType) = 0;
864
865 /// Parse an optional type.
866 virtual OptionalParseResult parseOptionalType(Type &result) = 0;
867
868 /// Parse a type of a specific type.
869 template <typename TypeT>
870 ParseResult parseType(TypeT &result) {
871 SMLoc loc = getCurrentLocation();
872
873 // Parse any kind of type.
874 Type type;
875 if (parseType(type))
876 return failure();
877
878 // Check for the right kind of type.
879 result = type.dyn_cast<TypeT>();
880 if (!result)
881 return emitError(loc, "invalid kind of type specified");
882
883 return success();
884 }
885
886 /// Trait to check if `TypeT` provides a `parse` method.
887 template <typename TypeT>
888 using type_has_parse_method =
889 decltype(TypeT::parse(std::declval<AsmParser &>()));
890 template <typename TypeT>
891 using detect_type_has_parse_method =
892 llvm::is_detected<type_has_parse_method, TypeT>;
893
894 /// Parse a custom Type of a given type unless the next token is `#`, in
895 /// which case the generic parser is invoked. The parsed Type is
896 /// populated in `result`.
897 template <typename TypeT>
898 std::enable_if_t<detect_type_has_parse_method<TypeT>::value, ParseResult>
899 parseCustomTypeWithFallback(TypeT &result) {
900 SMLoc loc = getCurrentLocation();
901
902 // Parse any kind of Type.
903 Type type;
904 if (parseCustomTypeWithFallback(type, [&](Type &result) -> ParseResult {
905 result = TypeT::parse(*this);
906 return success(!!result);
907 }))
908 return failure();
909
910 // Check for the right kind of Type.
911 result = type.dyn_cast<TypeT>();
912 if (!result)
913 return emitError(loc, "invalid kind of Type specified");
914 return success();
915 }
916
917 /// SFINAE parsing method for Type that don't implement a parse method.
918 template <typename TypeT>
919 std::enable_if_t<!detect_type_has_parse_method<TypeT>::value, ParseResult>
920 parseCustomTypeWithFallback(TypeT &result) {
921 return parseType(result);
922 }
923
924 /// Parse a type list.
925 ParseResult parseTypeList(SmallVectorImpl<Type> &result) {
926 do {
927 Type type;
928 if (parseType(type))
929 return failure();
930 result.push_back(type);
931 } while (succeeded(parseOptionalComma()));
932 return success();
933 }
934
935 /// Parse an arrow followed by a type list.
936 virtual ParseResult parseArrowTypeList(SmallVectorImpl<Type> &result) = 0;
937
938 /// Parse an optional arrow followed by a type list.
939 virtual ParseResult
940 parseOptionalArrowTypeList(SmallVectorImpl<Type> &result) = 0;
941
942 /// Parse a colon followed by a type.
943 virtual ParseResult parseColonType(Type &result) = 0;
944
945 /// Parse a colon followed by a type of a specific kind, e.g. a FunctionType.
946 template <typename TypeType>
947 ParseResult parseColonType(TypeType &result) {
948 SMLoc loc = getCurrentLocation();
949
950 // Parse any kind of type.
951 Type type;
952 if (parseColonType(type))
953 return failure();
954
955 // Check for the right kind of type.
956 result = type.dyn_cast<TypeType>();
957 if (!result)
958 return emitError(loc, "invalid kind of type specified");
959
960 return success();
961 }
962
963 /// Parse a colon followed by a type list, which must have at least one type.
964 virtual ParseResult parseColonTypeList(SmallVectorImpl<Type> &result) = 0;
965
966 /// Parse an optional colon followed by a type list, which if present must
967 /// have at least one type.
968 virtual ParseResult
969 parseOptionalColonTypeList(SmallVectorImpl<Type> &result) = 0;
970
971 /// Parse a keyword followed by a type.
972 ParseResult parseKeywordType(const char *keyword, Type &result) {
973 return failure(parseKeyword(keyword) || parseType(result));
974 }
975
976 /// Add the specified type to the end of the specified type list and return
977 /// success. This is a helper designed to allow parse methods to be simple
978 /// and chain through || operators.
979 ParseResult addTypeToList(Type type, SmallVectorImpl<Type> &result) {
980 result.push_back(type);
981 return success();
982 }
983
984 /// Add the specified types to the end of the specified type list and return
985 /// success. This is a helper designed to allow parse methods to be simple
986 /// and chain through || operators.
987 ParseResult addTypesToList(ArrayRef<Type> types,
988 SmallVectorImpl<Type> &result) {
989 result.append(types.begin(), types.end());
990 return success();
991 }
992
993 /// Parse a 'x' separated dimension list. This populates the dimension list,
994 /// using -1 for the `?` dimensions if `allowDynamic` is set and errors out on
995 /// `?` otherwise.
996 ///
997 /// dimension-list ::= (dimension `x`)*
998 /// dimension ::= `?` | integer
999 ///
1000 /// When `allowDynamic` is not set, this is used to parse:
1001 ///
1002 /// static-dimension-list ::= (integer `x`)*
1003 virtual ParseResult parseDimensionList(SmallVectorImpl<int64_t> &dimensions,
1004 bool allowDynamic = true) = 0;
1005
1006 /// Parse an 'x' token in a dimension list, handling the case where the x is
1007 /// juxtaposed with an element type, as in "xf32", leaving the "f32" as the
1008 /// next token.
1009 virtual ParseResult parseXInDimensionList() = 0;
1010
1011private:
1012 AsmParser(const AsmParser &) = delete;
1013 void operator=(const AsmParser &) = delete;
1014};
1015
1016//===----------------------------------------------------------------------===//
1017// OpAsmParser
1018//===----------------------------------------------------------------------===//
1019
1020/// The OpAsmParser has methods for interacting with the asm parser: parsing
1021/// things from it, emitting errors etc. It has an intentionally high-level API
1022/// that is designed to reduce/constrain syntax innovation in individual
1023/// operations.
1024///
1025/// For example, consider an op like this:
1026///
1027/// %x = load %p[%1, %2] : memref<...>
1028///
1029/// The "%x = load" tokens are already parsed and therefore invisible to the
1030/// custom op parser. This can be supported by calling `parseOperandList` to
1031/// parse the %p, then calling `parseOperandList` with a `SquareDelimiter` to
1032/// parse the indices, then calling `parseColonTypeList` to parse the result
1033/// type.
1034///
1035class OpAsmParser : public AsmParser {
1036public:
1037 using AsmParser::AsmParser;
1038 ~OpAsmParser() override;
1039
1040 /// Parse a loc(...) specifier if present, filling in result if so.
1041 /// Location for BlockArgument and Operation may be deferred with an alias, in
1042 /// which case an OpaqueLoc is set and will be resolved when parsing
1043 /// completes.
1044 virtual ParseResult
1045 parseOptionalLocationSpecifier(Optional<Location> &result) = 0;
1046
1047 /// Return the name of the specified result in the specified syntax, as well
1048 /// as the sub-element in the name. It returns an empty string and ~0U for
1049 /// invalid result numbers. For example, in this operation:
1050 ///
1051 /// %x, %y:2, %z = foo.op
1052 ///
1053 /// getResultName(0) == {"x", 0 }
1054 /// getResultName(1) == {"y", 0 }
1055 /// getResultName(2) == {"y", 1 }
1056 /// getResultName(3) == {"z", 0 }
1057 /// getResultName(4) == {"", ~0U }
1058 virtual std::pair<StringRef, unsigned>
1059 getResultName(unsigned resultNo) const = 0;
1060
1061 /// Return the number of declared SSA results. This returns 4 for the foo.op
1062 /// example in the comment for `getResultName`.
1063 virtual size_t getNumResults() const = 0;
1064
1065 // These methods emit an error and return failure or success. This allows
1066 // these to be chained together into a linear sequence of || expressions in
1067 // many cases.
1068
1069 /// Parse an operation in its generic form.
1070 /// The parsed operation is parsed in the current context and inserted in the
1071 /// provided block and insertion point. The results produced by this operation
1072 /// aren't mapped to any named value in the parser. Returns nullptr on
1073 /// failure.
1074 virtual Operation *parseGenericOperation(Block *insertBlock,
1075 Block::iterator insertPt) = 0;
1076
1077 /// Parse the name of an operation, in the custom form. On success, return a
1078 /// an object of type 'OperationName'. Otherwise, failure is returned.
1079 virtual FailureOr<OperationName> parseCustomOperationName() = 0;
1080
1081 //===--------------------------------------------------------------------===//
1082 // Operand Parsing
1083 //===--------------------------------------------------------------------===//
1084
1085 /// This is the representation of an operand reference.
1086 struct UnresolvedOperand {
1087 SMLoc location; // Location of the token.
1088 StringRef name; // Value name, e.g. %42 or %abc
1089 unsigned number; // Number, e.g. 12 for an operand like %xyz#12
1090 };
1091
1092 /// Parse different components, viz., use-info of operand(s), successor(s),
1093 /// region(s), attribute(s) and function-type, of the generic form of an
1094 /// operation instance and populate the input operation-state 'result' with
1095 /// those components. If any of the components is explicitly provided, then
1096 /// skip parsing that component.
1097 virtual ParseResult parseGenericOperationAfterOpName(
1098 OperationState &result,
1099 Optional<ArrayRef<UnresolvedOperand>> parsedOperandType = llvm::None,
1100 Optional<ArrayRef<Block *>> parsedSuccessors = llvm::None,
1101 Optional<MutableArrayRef<std::unique_ptr<Region>>> parsedRegions =
1102 llvm::None,
1103 Optional<ArrayRef<NamedAttribute>> parsedAttributes = llvm::None,
1104 Optional<FunctionType> parsedFnType = llvm::None) = 0;
1105
1106 /// Parse a single operand.
1107 virtual ParseResult parseOperand(UnresolvedOperand &result) = 0;
1108
1109 /// Parse a single operand if present.
1110 virtual OptionalParseResult
1111 parseOptionalOperand(UnresolvedOperand &result) = 0;
1112
1113 /// Parse zero or more SSA comma-separated operand references with a specified
1114 /// surrounding delimiter, and an optional required operand count.
1115 virtual ParseResult
1116 parseOperandList(SmallVectorImpl<UnresolvedOperand> &result,
1117 int requiredOperandCount = -1,
1118 Delimiter delimiter = Delimiter::None) = 0;
1119 ParseResult parseOperandList(SmallVectorImpl<UnresolvedOperand> &result,
1120 Delimiter delimiter) {
1121 return parseOperandList(result, /*requiredOperandCount=*/-1, delimiter);
1122 }
1123
1124 /// Parse zero or more trailing SSA comma-separated trailing operand
1125 /// references with a specified surrounding delimiter, and an optional
1126 /// required operand count. A leading comma is expected before the operands.
1127 virtual ParseResult
1128 parseTrailingOperandList(SmallVectorImpl<UnresolvedOperand> &result,
1129 int requiredOperandCount = -1,
1130 Delimiter delimiter = Delimiter::None) = 0;
1131 ParseResult
1132 parseTrailingOperandList(SmallVectorImpl<UnresolvedOperand> &result,
1133 Delimiter delimiter) {
1134 return parseTrailingOperandList(result, /*requiredOperandCount=*/-1,
1135 delimiter);
1136 }
1137
1138 /// Resolve an operand to an SSA value, emitting an error on failure.
1139 virtual ParseResult resolveOperand(const UnresolvedOperand &operand,
1140 Type type,
1141 SmallVectorImpl<Value> &result) = 0;
1142
1143 /// Resolve a list of operands to SSA values, emitting an error on failure, or
1144 /// appending the results to the list on success. This method should be used
1145 /// when all operands have the same type.
1146 ParseResult resolveOperands(ArrayRef<UnresolvedOperand> operands, Type type,
1147 SmallVectorImpl<Value> &result) {
1148 for (auto elt : operands)
1149 if (resolveOperand(elt, type, result))
1150 return failure();
1151 return success();
1152 }
1153
1154 /// Resolve a list of operands and a list of operand types to SSA values,
1155 /// emitting an error and returning failure, or appending the results
1156 /// to the list on success.
1157 ParseResult resolveOperands(ArrayRef<UnresolvedOperand> operands,
1158 ArrayRef<Type> types, SMLoc loc,
1159 SmallVectorImpl<Value> &result) {
1160 if (operands.size() != types.size())
1161 return emitError(loc)
1162 << operands.size() << " operands present, but expected "
1163 << types.size();
1164
1165 for (unsigned i = 0, e = operands.size(); i != e; ++i)
1166 if (resolveOperand(operands[i], types[i], result))
1167 return failure();
1168 return success();
1169 }
1170 template <typename Operands>
1171 ParseResult resolveOperands(Operands &&operands, Type type, SMLoc loc,
1172 SmallVectorImpl<Value> &result) {
1173 return resolveOperands(std::forward<Operands>(operands),
1174 ArrayRef<Type>(type), loc, result);
1175 }
1176 template <typename Operands, typename Types>
1177 std::enable_if_t<!std::is_convertible<Types, Type>::value, ParseResult>
1178 resolveOperands(Operands &&operands, Types &&types, SMLoc loc,
1179 SmallVectorImpl<Value> &result) {
1180 size_t operandSize = std::distance(operands.begin(), operands.end());
1181 size_t typeSize = std::distance(types.begin(), types.end());
1182 if (operandSize != typeSize)
1183 return emitError(loc)
1184 << operandSize << " operands present, but expected " << typeSize;
1185
1186 for (auto it : llvm::zip(operands, types))
1187 if (resolveOperand(std::get<0>(it), std::get<1>(it), result))
1188 return failure();
1189 return success();
1190 }
1191
1192 /// Parses an affine map attribute where dims and symbols are SSA operands.
1193 /// Operand values must come from single-result sources, and be valid
1194 /// dimensions/symbol identifiers according to mlir::isValidDim/Symbol.
1195 virtual ParseResult
1196 parseAffineMapOfSSAIds(SmallVectorImpl<UnresolvedOperand> &operands,
1197 Attribute &map, StringRef attrName,
1198 NamedAttrList &attrs,
1199 Delimiter delimiter = Delimiter::Square) = 0;
1200
1201 /// Parses an affine expression where dims and symbols are SSA operands.
1202 /// Operand values must come from single-result sources, and be valid
1203 /// dimensions/symbol identifiers according to mlir::isValidDim/Symbol.
1204 virtual ParseResult
1205 parseAffineExprOfSSAIds(SmallVectorImpl<UnresolvedOperand> &dimOperands,
1206 SmallVectorImpl<UnresolvedOperand> &symbOperands,
1207 AffineExpr &expr) = 0;
1208
1209 //===--------------------------------------------------------------------===//
1210 // Region Parsing
1211 //===--------------------------------------------------------------------===//
1212
1213 /// Parses a region. Any parsed blocks are appended to 'region' and must be
1214 /// moved to the op regions after the op is created. The first block of the
1215 /// region takes 'arguments' of types 'argTypes'. If `argLocations` is
1216 /// non-empty it contains a location to be attached to each argument. If
1217 /// 'enableNameShadowing' is set to true, the argument names are allowed to
1218 /// shadow the names of other existing SSA values defined above the region
1219 /// scope. 'enableNameShadowing' can only be set to true for regions attached
1220 /// to operations that are 'IsolatedFromAbove'.
1221 virtual ParseResult parseRegion(Region &region,
1222 ArrayRef<UnresolvedOperand> arguments = {},
1223 ArrayRef<Type> argTypes = {},
1224 ArrayRef<Location> argLocations = {},
1225 bool enableNameShadowing = false) = 0;
1226
1227 /// Parses a region if present.
1228 virtual OptionalParseResult parseOptionalRegion(
1229 Region &region, ArrayRef<UnresolvedOperand> arguments = {},
1230 ArrayRef<Type> argTypes = {}, ArrayRef<Location> argLocations = {},
1231 bool enableNameShadowing = false) = 0;
1232
1233 /// Parses a region if present. If the region is present, a new region is
1234 /// allocated and placed in `region`. If no region is present or on failure,
1235 /// `region` remains untouched.
1236 virtual OptionalParseResult
1237 parseOptionalRegion(std::unique_ptr<Region> &region,
1238 ArrayRef<UnresolvedOperand> arguments = {},
1239 ArrayRef<Type> argTypes = {},
1240 bool enableNameShadowing = false) = 0;
1241
1242 /// Parse a region argument, this argument is resolved when calling
1243 /// 'parseRegion'.
1244 virtual ParseResult parseRegionArgument(UnresolvedOperand &argument) = 0;
1245
1246 /// Parse zero or more region arguments with a specified surrounding
1247 /// delimiter, and an optional required argument count. Region arguments
1248 /// define new values; so this also checks if values with the same names have
1249 /// not been defined yet.
1250 virtual ParseResult
1251 parseRegionArgumentList(SmallVectorImpl<UnresolvedOperand> &result,
1252 int requiredOperandCount = -1,
1253 Delimiter delimiter = Delimiter::None) = 0;
1254 virtual ParseResult
1255 parseRegionArgumentList(SmallVectorImpl<UnresolvedOperand> &result,
1256 Delimiter delimiter) {
1257 return parseRegionArgumentList(result, /*requiredOperandCount=*/-1,
1258 delimiter);
1259 }
1260
1261 /// Parse a region argument if present.
1262 virtual ParseResult
1263 parseOptionalRegionArgument(UnresolvedOperand &argument) = 0;
1264
1265 //===--------------------------------------------------------------------===//
1266 // Successor Parsing
1267 //===--------------------------------------------------------------------===//
1268
1269 /// Parse a single operation successor.
1270 virtual ParseResult parseSuccessor(Block *&dest) = 0;
1271
1272 /// Parse an optional operation successor.
1273 virtual OptionalParseResult parseOptionalSuccessor(Block *&dest) = 0;
1274
1275 /// Parse a single operation successor and its operand list.
1276 virtual ParseResult
1277 parseSuccessorAndUseList(Block *&dest, SmallVectorImpl<Value> &operands) = 0;
1278
1279 //===--------------------------------------------------------------------===//
1280 // Type Parsing
1281 //===--------------------------------------------------------------------===//
1282
1283 /// Parse a list of assignments of the form
1284 /// (%x1 = %y1, %x2 = %y2, ...)
1285 ParseResult parseAssignmentList(SmallVectorImpl<UnresolvedOperand> &lhs,
1286 SmallVectorImpl<UnresolvedOperand> &rhs) {
1287 OptionalParseResult result = parseOptionalAssignmentList(lhs, rhs);
1288 if (!result.hasValue())
1289 return emitError(getCurrentLocation(), "expected '('");
1290 return result.getValue();
1291 }
1292
1293 virtual OptionalParseResult
1294 parseOptionalAssignmentList(SmallVectorImpl<UnresolvedOperand> &lhs,
1295 SmallVectorImpl<UnresolvedOperand> &rhs) = 0;
1296
1297 /// Parse a list of assignments of the form
1298 /// (%x1 = %y1 : type1, %x2 = %y2 : type2, ...)
1299 ParseResult
1300 parseAssignmentListWithTypes(SmallVectorImpl<UnresolvedOperand> &lhs,
1301 SmallVectorImpl<UnresolvedOperand> &rhs,
1302 SmallVectorImpl<Type> &types) {
1303 OptionalParseResult result =
1304 parseOptionalAssignmentListWithTypes(lhs, rhs, types);
1305 if (!result.hasValue())
1306 return emitError(getCurrentLocation(), "expected '('");
1307 return result.getValue();
1308 }
1309
1310 virtual OptionalParseResult
1311 parseOptionalAssignmentListWithTypes(SmallVectorImpl<UnresolvedOperand> &lhs,
1312 SmallVectorImpl<UnresolvedOperand> &rhs,
1313 SmallVectorImpl<Type> &types) = 0;
1314
1315private:
1316 /// Parse either an operand list or a region argument list depending on
1317 /// whether isOperandList is true.
1318 ParseResult
1319 parseOperandOrRegionArgList(SmallVectorImpl<UnresolvedOperand> &result,
1320 bool isOperandList, int requiredOperandCount,
1321 Delimiter delimiter);
1322};
1323
1324//===--------------------------------------------------------------------===//
1325// Dialect OpAsm interface.
1326//===--------------------------------------------------------------------===//
1327
1328/// A functor used to set the name of the start of a result group of an
1329/// operation. See 'getAsmResultNames' below for more details.
1330using OpAsmSetValueNameFn = function_ref<void(Value, StringRef)>;
1331
1332/// A functor used to set the name of blocks in regions directly nested under
1333/// an operation.
1334using OpAsmSetBlockNameFn = function_ref<void(Block *, StringRef)>;
1335
1336class OpAsmDialectInterface
1337 : public DialectInterface::Base<OpAsmDialectInterface> {
1338public:
1339 /// Holds the result of `getAlias` hook call.
1340 enum class AliasResult {
1341 /// The object (type or attribute) is not supported by the hook
1342 /// and an alias was not provided.
1343 NoAlias,
1344 /// An alias was provided, but it might be overriden by other hook.
1345 OverridableAlias,
1346 /// An alias was provided and it should be used
1347 /// (no other hooks will be checked).
1348 FinalAlias
1349 };
1350
1351 OpAsmDialectInterface(Dialect *dialect) : Base(dialect) {}
1352
1353 /// Hooks for getting an alias identifier alias for a given symbol, that is
1354 /// not necessarily a part of this dialect. The identifier is used in place of
1355 /// the symbol when printing textual IR. These aliases must not contain `.` or
1356 /// end with a numeric digit([0-9]+).
1357 virtual AliasResult getAlias(Attribute attr, raw_ostream &os) const {
1358 return AliasResult::NoAlias;
1359 }
1360 virtual AliasResult getAlias(Type type, raw_ostream &os) const {
1361 return AliasResult::NoAlias;
1362 }
1363
1364};
1365} // namespace mlir
1366
1367//===--------------------------------------------------------------------===//
1368// Operation OpAsm interface.
1369//===--------------------------------------------------------------------===//
1370
1371/// The OpAsmOpInterface, see OpAsmInterface.td for more details.
1372#include "mlir/IR/OpAsmInterface.h.inc"
1373
1374#endif