Bug Summary

File:build/source/mlir/test/lib/Dialect/Test/TestAttributes.cpp
Warning:line 70, column 5
1st 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 TestAttributes.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/source/build-llvm/tools/clang/stage2-bins -resource-dir /usr/lib/llvm-17/lib/clang/17 -I tools/mlir/test/lib/Dialect/Test -I /build/source/mlir/test/lib/Dialect/Test -I include -I /build/source/llvm/include -I /build/source/mlir/include -I tools/mlir/include -D MLIR_CUDA_CONVERSIONS_ENABLED=1 -D MLIR_INCLUDE_TESTS -D MLIR_ROCM_CONVERSIONS_ENABLED=1 -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -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-17/lib/clang/17/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/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fmacro-prefix-map=/build/source/= -fcoverage-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fcoverage-prefix-map=/build/source/= -source-date-epoch 1675721604 -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/source/build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/source/= -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-2023-02-07-030702-17298-1 -x c++ /build/source/mlir/test/lib/Dialect/Test/TestAttributes.cpp

/build/source/mlir/test/lib/Dialect/Test/TestAttributes.cpp

1//===- TestAttributes.cpp - MLIR Test Dialect Attributes --------*- 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 file contains attributes defined by the TestDialect for testing various
10// features of MLIR.
11//
12//===----------------------------------------------------------------------===//
13
14#include "TestAttributes.h"
15#include "TestDialect.h"
16#include "mlir/IR/Builders.h"
17#include "mlir/IR/DialectImplementation.h"
18#include "mlir/IR/ExtensibleDialect.h"
19#include "mlir/IR/Types.h"
20#include "mlir/Support/LogicalResult.h"
21#include "llvm/ADT/Hashing.h"
22#include "llvm/ADT/TypeSwitch.h"
23#include "llvm/ADT/bit.h"
24#include "llvm/Support/ErrorHandling.h"
25
26using namespace mlir;
27using namespace test;
28
29//===----------------------------------------------------------------------===//
30// CompoundAAttr
31//===----------------------------------------------------------------------===//
32
33Attribute CompoundAAttr::parse(AsmParser &parser, Type type) {
34 int widthOfSomething;
35 Type oneType;
36 SmallVector<int, 4> arrayOfInts;
37 if (parser.parseLess() || parser.parseInteger(widthOfSomething) ||
38 parser.parseComma() || parser.parseType(oneType) || parser.parseComma() ||
39 parser.parseLSquare())
40 return Attribute();
41
42 int intVal;
43 while (!*parser.parseOptionalInteger(intVal)) {
44 arrayOfInts.push_back(intVal);
45 if (parser.parseOptionalComma())
46 break;
47 }
48
49 if (parser.parseRSquare() || parser.parseGreater())
50 return Attribute();
51 return get(parser.getContext(), widthOfSomething, oneType, arrayOfInts);
52}
53
54void CompoundAAttr::print(AsmPrinter &printer) const {
55 printer << "<" << getWidthOfSomething() << ", " << getOneType() << ", [";
56 llvm::interleaveComma(getArrayOfInts(), printer);
57 printer << "]>";
58}
59
60//===----------------------------------------------------------------------===//
61// CompoundAAttr
62//===----------------------------------------------------------------------===//
63
64Attribute TestI64ElementsAttr::parse(AsmParser &parser, Type type) {
65 SmallVector<uint64_t> elements;
66 if (parser.parseLess() || parser.parseLSquare())
1
Taking false branch
67 return Attribute();
68 uint64_t intVal;
2
'intVal' declared without an initial value
69 while (succeeded(*parser.parseOptionalInteger(intVal))) {
3
Calling 'AsmParser::parseOptionalInteger'
7
Returning from 'AsmParser::parseOptionalInteger'
8
Loop condition is true. Entering loop body
70 elements.push_back(intVal);
9
1st function call argument is an uninitialized value
71 if (parser.parseOptionalComma())
72 break;
73 }
74
75 if (parser.parseRSquare() || parser.parseGreater())
76 return Attribute();
77 return parser.getChecked<TestI64ElementsAttr>(
78 parser.getContext(), type.cast<ShapedType>(), elements);
79}
80
81void TestI64ElementsAttr::print(AsmPrinter &printer) const {
82 printer << "<[";
83 llvm::interleaveComma(getElements(), printer);
84 printer << "] : " << getType() << ">";
85}
86
87LogicalResult
88TestI64ElementsAttr::verify(function_ref<InFlightDiagnostic()> emitError,
89 ShapedType type, ArrayRef<uint64_t> elements) {
90 if (type.getNumElements() != static_cast<int64_t>(elements.size())) {
91 return emitError()
92 << "number of elements does not match the provided shape type, got: "
93 << elements.size() << ", but expected: " << type.getNumElements();
94 }
95 if (type.getRank() != 1 || !type.getElementType().isSignlessInteger(64))
96 return emitError() << "expected single rank 64-bit shape type, but got: "
97 << type;
98 return success();
99}
100
101LogicalResult
102TestAttrWithFormatAttr::verify(function_ref<InFlightDiagnostic()> emitError,
103 int64_t one, std::string two, IntegerAttr three,
104 ArrayRef<int> four, uint64_t five,
105 ArrayRef<AttrWithTypeBuilderAttr> arrayOfAttrs) {
106 if (four.size() != static_cast<unsigned>(one))
107 return emitError() << "expected 'one' to equal 'four.size()'";
108 return success();
109}
110
111//===----------------------------------------------------------------------===//
112// Utility Functions for Generated Attributes
113//===----------------------------------------------------------------------===//
114
115static FailureOr<SmallVector<int>> parseIntArray(AsmParser &parser) {
116 SmallVector<int> ints;
117 if (parser.parseLSquare() || parser.parseCommaSeparatedList([&]() {
118 ints.push_back(0);
119 return parser.parseInteger(ints.back());
120 }) ||
121 parser.parseRSquare())
122 return failure();
123 return ints;
124}
125
126static void printIntArray(AsmPrinter &printer, ArrayRef<int> ints) {
127 printer << '[';
128 llvm::interleaveComma(ints, printer);
129 printer << ']';
130}
131
132//===----------------------------------------------------------------------===//
133// TestSubElementsAccessAttr
134//===----------------------------------------------------------------------===//
135
136Attribute TestSubElementsAccessAttr::parse(::mlir::AsmParser &parser,
137 ::mlir::Type type) {
138 Attribute first, second, third;
139 if (parser.parseLess() || parser.parseAttribute(first) ||
140 parser.parseComma() || parser.parseAttribute(second) ||
141 parser.parseComma() || parser.parseAttribute(third) ||
142 parser.parseGreater()) {
143 return {};
144 }
145 return get(parser.getContext(), first, second, third);
146}
147
148void TestSubElementsAccessAttr::print(::mlir::AsmPrinter &printer) const {
149 printer << "<" << getFirst() << ", " << getSecond() << ", " << getThird()
150 << ">";
151}
152
153//===----------------------------------------------------------------------===//
154// TestExtern1DI64ElementsAttr
155//===----------------------------------------------------------------------===//
156
157ArrayRef<uint64_t> TestExtern1DI64ElementsAttr::getElements() const {
158 if (auto *blob = getHandle().getBlob())
159 return blob->getDataAs<uint64_t>();
160 return std::nullopt;
161}
162
163//===----------------------------------------------------------------------===//
164// TestCustomAnchorAttr
165//===----------------------------------------------------------------------===//
166
167static ParseResult parseTrueFalse(AsmParser &p, std::optional<int> &result) {
168 bool b;
169 if (p.parseInteger(b))
170 return failure();
171 result = b;
172 return success();
173}
174
175static void printTrueFalse(AsmPrinter &p, std::optional<int> result) {
176 p << (*result ? "true" : "false");
177}
178
179//===----------------------------------------------------------------------===//
180// Tablegen Generated Definitions
181//===----------------------------------------------------------------------===//
182
183#include "TestAttrInterfaces.cpp.inc"
184
185#define GET_ATTRDEF_CLASSES
186#include "TestAttrDefs.cpp.inc"
187
188//===----------------------------------------------------------------------===//
189// Dynamic Attributes
190//===----------------------------------------------------------------------===//
191
192/// Define a singleton dynamic attribute.
193static std::unique_ptr<DynamicAttrDefinition>
194getDynamicSingletonAttr(TestDialect *testDialect) {
195 return DynamicAttrDefinition::get(
196 "dynamic_singleton", testDialect,
197 [](function_ref<InFlightDiagnostic()> emitError,
198 ArrayRef<Attribute> args) {
199 if (!args.empty()) {
200 emitError() << "expected 0 attribute arguments, but had "
201 << args.size();
202 return failure();
203 }
204 return success();
205 });
206}
207
208/// Define a dynamic attribute representing a pair or attributes.
209static std::unique_ptr<DynamicAttrDefinition>
210getDynamicPairAttr(TestDialect *testDialect) {
211 return DynamicAttrDefinition::get(
212 "dynamic_pair", testDialect,
213 [](function_ref<InFlightDiagnostic()> emitError,
214 ArrayRef<Attribute> args) {
215 if (args.size() != 2) {
216 emitError() << "expected 2 attribute arguments, but had "
217 << args.size();
218 return failure();
219 }
220 return success();
221 });
222}
223
224static std::unique_ptr<DynamicAttrDefinition>
225getDynamicCustomAssemblyFormatAttr(TestDialect *testDialect) {
226 auto verifier = [](function_ref<InFlightDiagnostic()> emitError,
227 ArrayRef<Attribute> args) {
228 if (args.size() != 2) {
229 emitError() << "expected 2 attribute arguments, but had " << args.size();
230 return failure();
231 }
232 return success();
233 };
234
235 auto parser = [](AsmParser &parser,
236 llvm::SmallVectorImpl<Attribute> &parsedParams) {
237 Attribute leftAttr, rightAttr;
238 if (parser.parseLess() || parser.parseAttribute(leftAttr) ||
239 parser.parseColon() || parser.parseAttribute(rightAttr) ||
240 parser.parseGreater())
241 return failure();
242 parsedParams.push_back(leftAttr);
243 parsedParams.push_back(rightAttr);
244 return success();
245 };
246
247 auto printer = [](AsmPrinter &printer, ArrayRef<Attribute> params) {
248 printer << "<" << params[0] << ":" << params[1] << ">";
249 };
250
251 return DynamicAttrDefinition::get("dynamic_custom_assembly_format",
252 testDialect, std::move(verifier),
253 std::move(parser), std::move(printer));
254}
255
256//===----------------------------------------------------------------------===//
257// TestDialect
258//===----------------------------------------------------------------------===//
259
260void TestDialect::registerAttributes() {
261 addAttributes<
262#define GET_ATTRDEF_LIST
263#include "TestAttrDefs.cpp.inc"
264 >();
265 registerDynamicAttr(getDynamicSingletonAttr(this));
266 registerDynamicAttr(getDynamicPairAttr(this));
267 registerDynamicAttr(getDynamicCustomAssemblyFormatAttr(this));
268}

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