Bug Summary

File:build/llvm-toolchain-snapshot-16~++20220904122748+c444af1c20b3/mlir/lib/Dialect/Quant/IR/TypeParser.cpp
Warning:line 88, 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-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-16~++20220904122748+c444af1c20b3/build-llvm/tools/clang/stage2-bins -resource-dir /usr/lib/llvm-16/lib/clang/16.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-16~++20220904122748+c444af1c20b3/mlir/lib/Dialect/Quant/IR -I include -I /build/llvm-toolchain-snapshot-16~++20220904122748+c444af1c20b3/llvm/include -I /build/llvm-toolchain-snapshot-16~++20220904122748+c444af1c20b3/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-16/lib/clang/16.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-16~++20220904122748+c444af1c20b3/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fmacro-prefix-map=/build/llvm-toolchain-snapshot-16~++20220904122748+c444af1c20b3/= -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-16~++20220904122748+c444af1c20b3/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-16~++20220904122748+c444af1c20b3/= -O2 -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 -Wno-misleading-indentation -std=c++17 -fdeprecated-macro -fdebug-compilation-dir=/build/llvm-toolchain-snapshot-16~++20220904122748+c444af1c20b3/build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/llvm-toolchain-snapshot-16~++20220904122748+c444af1c20b3/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/llvm-toolchain-snapshot-16~++20220904122748+c444af1c20b3/= -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-09-04-125545-48738-1 -x c++ /build/llvm-toolchain-snapshot-16~++20220904122748+c444af1c20b3/mlir/lib/Dialect/Quant/IR/TypeParser.cpp

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

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