Bug Summary

File:build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/mlir/include/mlir/IR/OpImplementation.h
Warning:line 803, column 12
6th function call argument is an uninitialized 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~++20221003111214+1fa2019828ca/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~++20221003111214+1fa2019828ca/mlir/lib/Dialect/Quant/IR -I include -I /build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/llvm/include -I /build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/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~++20221003111214+1fa2019828ca/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fmacro-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/= -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/= -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~++20221003111214+1fa2019828ca/build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/= -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-10-03-140002-15933-1 -x c++ /build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/mlir/lib/Dialect/Quant/IR/TypeParser.cpp

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

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