MLIR 24.0.0git
DialectImplementation.h
Go to the documentation of this file.
1//===- DialectImplementation.h ----------------------------------*- 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 utilities classes for implementing dialect attributes and
10// types.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef MLIR_IR_DIALECTIMPLEMENTATION_H
15#define MLIR_IR_DIALECTIMPLEMENTATION_H
16
18#include <type_traits>
19
20namespace {
21
22// reference https://stackoverflow.com/a/16000226
23template <typename T, typename = void>
24struct HasStaticDialectName : std::false_type {};
25
26template <typename T>
27struct HasStaticDialectName<
28 T, typename std::enable_if<
29 std::is_same<::llvm::StringLiteral,
30 std::decay_t<decltype(T::dialectName)>>::value,
31 void>::type> : std::true_type {};
32
33} // namespace
34
35namespace mlir {
36
37//===----------------------------------------------------------------------===//
38// DialectAsmPrinter
39//===----------------------------------------------------------------------===//
40
41/// This is a pure-virtual base class that exposes the asmprinter hooks
42/// necessary to implement a custom printAttribute/printType() method on a
43/// dialect.
45public:
48};
49
50//===----------------------------------------------------------------------===//
51// DialectAsmParser
52//===----------------------------------------------------------------------===//
53
54/// The DialectAsmParser has methods for interacting with the asm parser when
55/// parsing attributes and types.
57public:
60
61 /// Returns the full specification of the symbol being parsed. This allows for
62 /// using a separate parser if necessary.
63 virtual StringRef getFullSymbolSpec() const = 0;
64};
65
66//===----------------------------------------------------------------------===//
67// Parse Fields
68//===----------------------------------------------------------------------===//
69
70/// Provide a template class that can be specialized by users to dispatch to
71/// parsers. Auto-generated parsers generate calls to `FieldParser<T>::parse`,
72/// where `T` is the parameter storage type, to parse custom types.
73///
74/// A parser is key-value compositional only if it consumes exactly one value
75/// and leaves the comma separating the next key unconsumed. For example, an
76/// undelimited array parser for `values = 1, 2, next = 9` cannot distinguish
77/// its element commas from the comma before `next` and may try to parse `next`
78/// as another element. Marking it non-compositional lets a keyed property list
79/// use a self-delimiting attribute such as `array<i64: 1, 2>` instead.
80/// Specializations with this behavior, or that may succeed without consuming a
81/// token, should define `isKeyValueCompositional` as false.
82template <typename T, typename = T>
84
85/// Parse an attribute.
86template <typename AttributeT>
88 AttributeT, std::enable_if_t<std::is_base_of<Attribute, AttributeT>::value,
89 AttributeT>> {
90 static FailureOr<AttributeT> parse(AsmParser &parser) {
91 if constexpr (HasStaticDialectName<AttributeT>::value) {
92 parser.getContext()->getOrLoadDialect(AttributeT::dialectName);
93 }
94 AttributeT value;
95 if (parser.parseCustomAttributeWithFallback(value))
96 return failure();
97 return value;
98 }
99};
100
101/// Parse a type.
102template <typename TypeT>
104 TypeT, std::enable_if_t<std::is_base_of<Type, TypeT>::value, TypeT>> {
105 static FailureOr<TypeT> parse(AsmParser &parser) {
106 TypeT value;
107 if (parser.parseCustomTypeWithFallback(value))
108 return failure();
109 return value;
110 }
111};
112
113/// Parse any integer.
114template <typename IntT>
115struct FieldParser<IntT, std::enable_if_t<(std::is_integral<IntT>::value ||
116 std::is_same_v<IntT, llvm::APInt>),
117 IntT>> {
118 static FailureOr<IntT> parse(AsmParser &parser) {
119 IntT value{};
120 if (parser.parseInteger(value))
121 return failure();
122 return value;
123 }
124};
125
126/// Parse a string.
127template <>
128struct FieldParser<std::string> {
129 static FailureOr<std::string> parse(AsmParser &parser) {
130 std::string value;
131 if (parser.parseString(&value))
132 return failure();
133 return value;
134 }
135};
136
137/// Parse an Optional attribute.
138template <typename AttributeT>
140 std::optional<AttributeT>,
141 std::enable_if_t<std::is_base_of<Attribute, AttributeT>::value,
142 std::optional<AttributeT>>> {
143 static constexpr bool isKeyValueCompositional = false;
144
145 static FailureOr<std::optional<AttributeT>> parse(AsmParser &parser) {
146 if constexpr (HasStaticDialectName<AttributeT>::value) {
147 parser.getContext()->getOrLoadDialect(AttributeT::dialectName);
148 }
149 AttributeT attr;
151 if (result.has_value()) {
152 if (succeeded(*result))
153 return {std::optional<AttributeT>(attr)};
154 return failure();
155 }
156 return {std::nullopt};
157 }
158};
159
160/// Parse an Optional integer.
161template <typename IntT>
163 std::optional<IntT>,
164 std::enable_if_t<std::is_integral<IntT>::value, std::optional<IntT>>> {
165 static constexpr bool isKeyValueCompositional = false;
166
167 static FailureOr<std::optional<IntT>> parse(AsmParser &parser) {
168 IntT value;
170 if (result.has_value()) {
171 if (succeeded(*result))
172 return {std::optional<IntT>(value)};
173 return failure();
174 }
175 return {std::nullopt};
176 }
177};
178
179namespace detail {
180template <typename T>
181using has_push_back_t = decltype(std::declval<T>().push_back(
182 std::declval<typename T::value_type &&>()));
183
184template <typename StorageType, typename = void>
185struct HasFieldParser : std::false_type {};
186
187template <typename StorageType>
188struct HasFieldParser<StorageType,
189 std::void_t<decltype(sizeof(FieldParser<StorageType>)),
190 decltype(FieldParser<StorageType>::parse(
191 std::declval<OpAsmParser &>()))>>
192 : std::true_type {};
193
194template <typename ContainerT, typename = void>
195struct HasFieldParserContainer : std::false_type {};
196
197template <typename ContainerT>
198struct HasFieldParserContainer<ContainerT,
199 std::void_t<has_push_back_t<ContainerT>>>
200 : HasFieldParser<typename ContainerT::value_type> {};
201
202template <typename Parser, typename = void>
203struct IsKeyValueCompositional : std::true_type {};
204
205template <typename Parser>
207 Parser, std::void_t<decltype(Parser::isKeyValueCompositional)>>
208 : std::bool_constant<Parser::isKeyValueCompositional> {};
209
210/// Whether the selected FieldParser consumes exactly one value in a keyed
211/// property list. Parser specializations may set isKeyValueCompositional to
212/// false if they can succeed without consuming a token or consume an
213/// undelimited comma-separated list.
214template <typename StorageType>
216 : std::conjunction<HasFieldParser<StorageType>,
217 IsKeyValueCompositional<FieldParser<StorageType>>> {};
218} // namespace detail
219
220/// Parse any container that supports back insertion as a list.
221template <typename ContainerT>
223 ContainerT,
224 std::enable_if_t<detail::HasFieldParserContainer<ContainerT>::value,
225 ContainerT>> {
226 static constexpr bool isKeyValueCompositional = false;
227
228 using ElementT = typename ContainerT::value_type;
229 static FailureOr<ContainerT> parse(AsmParser &parser) {
230 ContainerT elements;
231 auto elementParser = [&]() {
232 auto element = FieldParser<ElementT>::parse(parser);
233 if (failed(element))
234 return failure();
235 elements.push_back(std::move(*element));
236 return success();
237 };
238 if (parser.parseCommaSeparatedList(elementParser))
239 return failure();
240 return elements;
241 }
242};
243
244/// Parse an affine map.
245template <>
247 static FailureOr<AffineMap> parse(AsmParser &parser) {
248 AffineMap map;
249 if (failed(parser.parseAffineMap(map)))
250 return failure();
251 return map;
252 }
253};
254
255namespace detail {
256/// Parse a property with its FieldParser when one is available, otherwise
257/// fall back to the property's attribute conversion.
258template <typename StorageType, typename ConvertFromAttribute>
259ParseResult
260parsePropertyWithFallback(OpAsmParser &parser, StorageType &storage,
261 ConvertFromAttribute convertFromAttribute) {
263 auto value = FieldParser<StorageType>::parse(parser);
264 if (failed(value))
265 return failure();
266 storage = std::move(*value);
267 return success();
268 } else {
269 Attribute attr;
270 if (parser.parseAttribute(attr))
271 return failure();
272 return convertFromAttribute(storage, attr);
273 }
274}
275} // namespace detail
276
277} // namespace mlir
278
279#endif // MLIR_IR_DIALECTIMPLEMENTATION_H
return success()
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
Definition AffineMap.h:46
This base class exposes generic asm parser hooks, usable across the various derived parsers.
virtual OptionalParseResult parseOptionalInteger(APInt &result)=0
Parse an optional integer value from the stream.
AsmParser()=default
virtual ParseResult parseCommaSeparatedList(Delimiter delimiter, function_ref< ParseResult()> parseElementFn, StringRef contextMessage=StringRef())=0
Parse a list of comma-separated items with an optional delimiter.
MLIRContext * getContext() const
ParseResult parseInteger(IntT &result)
Parse an integer value from the stream.
virtual ParseResult parseAffineMap(AffineMap &map)=0
Parse an affine map instance into 'map'.
virtual ParseResult parseCustomAttributeWithFallback(Attribute &result, Type type, function_ref< ParseResult(Attribute &result, Type type)> parseAttribute)=0
Parse a custom attribute with the provided callback, unless the next token is #, in which case the ge...
ParseResult parseString(std::string *string)
Parse a quoted string token.
virtual ParseResult parseCustomTypeWithFallback(Type &result, function_ref< ParseResult(Type &result)> parseType)=0
Parse a custom type with the provided callback, unless the next token is #, in which case the generic...
virtual OptionalParseResult parseOptionalAttribute(Attribute &result, Type type={})=0
Parse an arbitrary optional attribute of a given type and return it in result.
virtual ParseResult parseAttribute(Attribute &result, Type type={})=0
Parse an arbitrary attribute of a given type and return it in result.
AsmPrinter(Impl &impl)
Initialize the printer with the given internal implementation.
Attributes are known-constant values of operations.
Definition Attributes.h:25
The DialectAsmParser has methods for interacting with the asm parser when parsing attributes and type...
virtual StringRef getFullSymbolSpec() const =0
Returns the full specification of the symbol being parsed.
~DialectAsmParser() override
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
~DialectAsmPrinter() override
AsmPrinter(Impl &impl)
Initialize the printer with the given internal implementation.
T * getOrLoadDialect()
Get (or create) a dialect for the given derived dialect type.
The OpAsmParser has methods for interacting with the asm parser: parsing things from it,...
This class implements Optional functionality for ParseResult.
This class implement support for parsing global entities like attributes and types.
Definition Parser.h:27
decltype(std::declval< T >().push_back( std::declval< typename T::value_type && >())) has_push_back_t
ParseResult parsePropertyWithFallback(OpAsmParser &parser, StorageType &storage, ConvertFromAttribute convertFromAttribute)
Parse a property with its FieldParser when one is available, otherwise fall back to the property's at...
Include the generated interface declarations.
LogicalResult convertFromAttribute(int64_t &storage, Attribute attr, function_ref< InFlightDiagnostic()> emitError)
Convert an IntegerAttr attribute to an int64_t, or return an error if the attribute isn't an IntegerA...
static FailureOr< AffineMap > parse(AsmParser &parser)
static FailureOr< std::string > parse(AsmParser &parser)
Provide a template class that can be specialized by users to dispatch to parsers.
Whether the selected FieldParser consumes exactly one value in a keyed property list.