MLIR 22.0.0git
LLVMTypeSyntax.cpp
Go to the documentation of this file.
1//===- LLVMTypeSyntax.cpp - Parsing/printing for MLIR LLVM Dialect types --===//
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
10#include "mlir/IR/Builders.h"
12#include "llvm/ADT/StringExtras.h"
13#include "llvm/ADT/TypeSwitch.h"
14
15using namespace mlir;
16using namespace mlir::LLVM;
17
18//===----------------------------------------------------------------------===//
19// Printing.
20//===----------------------------------------------------------------------===//
21
22/// If the given type is compatible with the LLVM dialect, prints it using
23/// internal functions to avoid getting a verbose `!llvm` prefix. Otherwise
24/// prints it as usual.
25static void dispatchPrint(AsmPrinter &printer, Type type) {
26 if (isCompatibleType(type) &&
27 !(llvm::isa<IntegerType, FloatType, VectorType>(type) ||
28 (llvm::isa<PtrLikeTypeInterface>(type) &&
29 !llvm::isa<LLVMPointerType>(type))))
30 return mlir::LLVM::detail::printType(type, printer);
31 printer.printType(type);
32}
33
34/// Returns the keyword to use for the given type.
35static StringRef getTypeKeyword(Type type) {
37 .Case<LLVMVoidType>([&](Type) { return "void"; })
38 .Case<LLVMPPCFP128Type>([&](Type) { return "ppc_fp128"; })
39 .Case<LLVMTokenType>([&](Type) { return "token"; })
40 .Case<LLVMLabelType>([&](Type) { return "label"; })
41 .Case<LLVMMetadataType>([&](Type) { return "metadata"; })
42 .Case<LLVMFunctionType>([&](Type) { return "func"; })
43 .Case<LLVMPointerType>([&](Type) { return "ptr"; })
44 .Case<LLVMArrayType>([&](Type) { return "array"; })
45 .Case<LLVMStructType>([&](Type) { return "struct"; })
46 .Case<LLVMTargetExtType>([&](Type) { return "target"; })
47 .Case<LLVMX86AMXType>([&](Type) { return "x86_amx"; })
48 .DefaultUnreachable("unexpected 'llvm' type kind");
49}
50
51/// Prints a structure type. Keeps track of known struct names to handle self-
52/// or mutually-referring structs without falling into infinite recursion.
53void LLVMStructType::print(AsmPrinter &printer) const {
54 FailureOr<AsmPrinter::CyclicPrintReset> cyclicPrint;
55
56 printer << "<";
57 if (isIdentified()) {
58 cyclicPrint = printer.tryStartCyclicPrint(*this);
59
60 printer << '"';
61 llvm::printEscapedString(getName(), printer.getStream());
62 printer << '"';
63 // If we are printing a reference to one of the enclosing structs, just
64 // print the name and stop to avoid infinitely long output.
65 if (failed(cyclicPrint)) {
66 printer << '>';
67 return;
68 }
69 printer << ", ";
70 }
71
72 if (isIdentified() && isOpaque()) {
73 printer << "opaque>";
74 return;
75 }
76
77 if (isPacked())
78 printer << "packed ";
79
80 // Put the current type on stack to avoid infinite recursion.
81 printer << '(';
82 llvm::interleaveComma(getBody(), printer.getStream(),
83 [&](Type subtype) { dispatchPrint(printer, subtype); });
84 printer << ')';
85 printer << '>';
86}
87
88/// Prints the given LLVM dialect type recursively. This leverages closedness of
89/// the LLVM dialect type system to avoid printing the dialect prefix
90/// repeatedly. For recursive structures, only prints the name of the structure
91/// when printing a self-reference. Note that this does not apply to sibling
92/// references. For example,
93/// struct<"a", (ptr<struct<"a">>)>
94/// struct<"c", (ptr<struct<"b", (ptr<struct<"c">>)>>,
95/// ptr<struct<"b", (ptr<struct<"c">>)>>)>
96/// note that "b" is printed twice.
98 if (!type) {
99 printer << "<<NULL-TYPE>>";
100 return;
101 }
102
103 printer << getTypeKeyword(type);
104
106 .Case<LLVMPointerType, LLVMArrayType, LLVMFunctionType, LLVMTargetExtType,
107 LLVMStructType>([&](auto type) { type.print(printer); });
108}
109
110//===----------------------------------------------------------------------===//
111// Parsing.
112//===----------------------------------------------------------------------===//
113
114static ParseResult dispatchParse(AsmParser &parser, Type &type);
115
116/// Attempts to set the body of an identified structure type. Reports a parsing
117/// error at `subtypesLoc` in case of failure.
118static LLVMStructType trySetStructBody(LLVMStructType type,
119 ArrayRef<Type> subtypes, bool isPacked,
120 AsmParser &parser, SMLoc subtypesLoc) {
121 for (Type t : subtypes) {
122 if (!LLVMStructType::isValidElementType(t)) {
123 parser.emitError(subtypesLoc)
124 << "invalid LLVM structure element type: " << t;
125 return LLVMStructType();
126 }
127 }
128
129 if (succeeded(type.setBody(subtypes, isPacked)))
130 return type;
131
132 parser.emitError(subtypesLoc)
133 << "identified type already used with a different body";
134 return LLVMStructType();
135}
136
137/// Parses an LLVM dialect structure type.
138/// llvm-type ::= `struct<` (string-literal `,`)? `packed`?
139/// `(` llvm-type-list `)` `>`
140/// | `struct<` string-literal `>`
141/// | `struct<` string-literal `, opaque>`
142Type LLVMStructType::parse(AsmParser &parser) {
143 Location loc = parser.getEncodedSourceLoc(parser.getCurrentLocation());
144
145 if (failed(parser.parseLess()))
146 return LLVMStructType();
147
148 // If we are parsing a self-reference to a recursive struct, i.e. the parsing
149 // stack already contains a struct with the same identifier, bail out after
150 // the name.
151 std::string name;
152 bool isIdentified = succeeded(parser.parseOptionalString(&name));
153 if (isIdentified) {
154 SMLoc greaterLoc = parser.getCurrentLocation();
155 if (succeeded(parser.parseOptionalGreater())) {
156 auto type = LLVMStructType::getIdentifiedChecked(
157 [loc] { return emitError(loc); }, loc.getContext(), name);
158 if (succeeded(parser.tryStartCyclicParse(type))) {
159 parser.emitError(
160 greaterLoc,
161 "struct without a body only allowed in a recursive struct");
162 return nullptr;
163 }
164
165 return type;
166 }
167 if (failed(parser.parseComma()))
168 return LLVMStructType();
169 }
170
171 // Handle intentionally opaque structs.
172 SMLoc kwLoc = parser.getCurrentLocation();
173 if (succeeded(parser.parseOptionalKeyword("opaque"))) {
174 if (!isIdentified)
175 return parser.emitError(kwLoc, "only identified structs can be opaque"),
176 LLVMStructType();
177 if (failed(parser.parseGreater()))
178 return LLVMStructType();
179 auto type = LLVMStructType::getOpaqueChecked(
180 [loc] { return emitError(loc); }, loc.getContext(), name);
181 if (!type.isOpaque()) {
182 parser.emitError(kwLoc, "redeclaring defined struct as opaque");
183 return LLVMStructType();
184 }
185 return type;
186 }
187
188 FailureOr<AsmParser::CyclicParseReset> cyclicParse;
189 if (isIdentified) {
190 cyclicParse =
191 parser.tryStartCyclicParse(LLVMStructType::getIdentifiedChecked(
192 [loc] { return emitError(loc); }, loc.getContext(), name));
193 if (failed(cyclicParse)) {
194 parser.emitError(kwLoc,
195 "identifier already used for an enclosing struct");
196 return nullptr;
197 }
198 }
199
200 // Check for packedness.
201 bool isPacked = succeeded(parser.parseOptionalKeyword("packed"));
202 if (failed(parser.parseLParen()))
203 return LLVMStructType();
204
205 // Fast pass for structs with zero subtypes.
206 if (succeeded(parser.parseOptionalRParen())) {
207 if (failed(parser.parseGreater()))
208 return LLVMStructType();
209 if (!isIdentified)
210 return LLVMStructType::getLiteralChecked([loc] { return emitError(loc); },
211 loc.getContext(), {}, isPacked);
212 auto type = LLVMStructType::getIdentifiedChecked(
213 [loc] { return emitError(loc); }, loc.getContext(), name);
214 return trySetStructBody(type, {}, isPacked, parser, kwLoc);
215 }
216
217 // Parse subtypes. For identified structs, put the identifier of the struct on
218 // the stack to support self-references in the recursive calls.
219 SmallVector<Type, 4> subtypes;
220 SMLoc subtypesLoc = parser.getCurrentLocation();
221 do {
222 Type type;
223 if (dispatchParse(parser, type))
224 return LLVMStructType();
225 subtypes.push_back(type);
226 } while (succeeded(parser.parseOptionalComma()));
227
228 if (parser.parseRParen() || parser.parseGreater())
229 return LLVMStructType();
230
231 // Construct the struct with body.
232 if (!isIdentified)
233 return LLVMStructType::getLiteralChecked(
234 [loc] { return emitError(loc); }, loc.getContext(), subtypes, isPacked);
235 auto type = LLVMStructType::getIdentifiedChecked(
236 [loc] { return emitError(loc); }, loc.getContext(), name);
237 return trySetStructBody(type, subtypes, isPacked, parser, subtypesLoc);
238}
239
240/// Parses a type appearing inside another LLVM dialect-compatible type. This
241/// will try to parse any type in full form (including types with the `!llvm`
242/// prefix), and on failure fall back to parsing the short-hand version of the
243/// LLVM dialect types without the `!llvm` prefix.
244static Type dispatchParse(AsmParser &parser, bool allowAny = true) {
245 SMLoc keyLoc = parser.getCurrentLocation();
246
247 // Try parsing any MLIR type.
248 Type type;
250 if (result.has_value()) {
251 if (failed(result.value()))
252 return nullptr;
253 if (!allowAny) {
254 parser.emitError(keyLoc) << "unexpected type, expected keyword";
255 return nullptr;
256 }
257 return type;
258 }
259
260 // If no type found, fallback to the shorthand form.
261 StringRef key;
262 if (failed(parser.parseKeyword(&key)))
263 return Type();
264
265 MLIRContext *ctx = parser.getContext();
266 return StringSwitch<function_ref<Type()>>(key)
267 .Case("void", [&] { return LLVMVoidType::get(ctx); })
268 .Case("ppc_fp128", [&] { return LLVMPPCFP128Type::get(ctx); })
269 .Case("token", [&] { return LLVMTokenType::get(ctx); })
270 .Case("label", [&] { return LLVMLabelType::get(ctx); })
271 .Case("metadata", [&] { return LLVMMetadataType::get(ctx); })
272 .Case("func", [&] { return LLVMFunctionType::parse(parser); })
273 .Case("ptr", [&] { return LLVMPointerType::parse(parser); })
274 .Case("array", [&] { return LLVMArrayType::parse(parser); })
275 .Case("struct", [&] { return LLVMStructType::parse(parser); })
276 .Case("target", [&] { return LLVMTargetExtType::parse(parser); })
277 .Case("x86_amx", [&] { return LLVMX86AMXType::get(ctx); })
278 .Default([&] {
279 parser.emitError(keyLoc) << "unknown LLVM type: " << key;
280 return Type();
281 })();
282}
283
284/// Helper to use in parse lists.
285static ParseResult dispatchParse(AsmParser &parser, Type &type) {
286 type = dispatchParse(parser);
287 return success(type != nullptr);
288}
289
290/// Parses one of the LLVM dialect types.
292 SMLoc loc = parser.getCurrentLocation();
293 Type type = dispatchParse(parser, /*allowAny=*/false);
294 if (!type)
295 return type;
296 if (!isCompatibleOuterType(type)) {
297 parser.emitError(loc) << "unexpected type, expected keyword";
298 return nullptr;
299 }
300 return type;
301}
302
304 return dispatchParse(p, type);
305}
306
308 return dispatchPrint(p, type);
309}
return success()
static ParseResult dispatchParse(AsmParser &parser, Type &type)
Helper to use in parse lists.
static void dispatchPrint(AsmPrinter &printer, Type type)
If the given type is compatible with the LLVM dialect, prints it using internal functions to avoid ge...
static LLVMStructType trySetStructBody(LLVMStructType type, ArrayRef< Type > subtypes, bool isPacked, AsmParser &parser, SMLoc subtypesLoc)
Attempts to set the body of an identified structure type.
static StringRef getTypeKeyword(Type type)
Returns the keyword to use for the given type.
This base class exposes generic asm parser hooks, usable across the various derived parsers.
virtual ParseResult parseOptionalKeyword(StringRef keyword)=0
Parse the given keyword if present.
virtual OptionalParseResult parseOptionalType(Type &result)=0
Parse an optional type.
MLIRContext * getContext() const
virtual Location getEncodedSourceLoc(SMLoc loc)=0
Re-encode the given source location as an MLIR location and return it.
virtual ParseResult parseRParen()=0
Parse a ) token.
virtual InFlightDiagnostic emitError(SMLoc loc, const Twine &message={})=0
Emit a diagnostic at the specified location and return failure.
virtual ParseResult parseOptionalRParen()=0
Parse a ) token if present.
virtual ParseResult parseLess()=0
Parse a '<' token.
virtual ParseResult parseOptionalGreater()=0
Parse a '>' token if present.
virtual SMLoc getCurrentLocation()=0
Get the location of the next token and store it into the argument.
virtual ParseResult parseOptionalComma()=0
Parse a , token if present.
virtual ParseResult parseOptionalString(std::string *string)=0
Parse a quoted string token if present.
FailureOr< CyclicParseReset > tryStartCyclicParse(AttrOrTypeT attrOrType)
Attempts to start a cyclic parsing region for attrOrType.
virtual ParseResult parseGreater()=0
Parse a '>' token.
virtual ParseResult parseLParen()=0
Parse a ( token.
virtual ParseResult parseComma()=0
Parse a , token.
ParseResult parseKeyword(StringRef keyword)
Parse a given keyword.
This base class exposes generic asm printer hooks, usable across the various derived printers.
virtual void printType(Type type)
FailureOr< CyclicPrintReset > tryStartCyclicPrint(AttrOrTypeT attrOrType)
Attempts to start a cyclic printing region for attrOrType.
virtual raw_ostream & getStream() const
Return the raw output stream used by this printer.
The DialectAsmParser has methods for interacting with the asm parser when parsing attributes and type...
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition Location.h:76
MLIRContext * getContext() const
Return the context this location is uniqued in.
Definition Location.h:86
MLIRContext is the top-level object for a collection of MLIR operations.
Definition MLIRContext.h:63
This class implements Optional functionality for ParseResult.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition Types.h:74
void print(raw_ostream &os) const
Print the current type.
void printType(Type type, AsmPrinter &printer)
Prints an LLVM Dialect type.
Type parseType(DialectAsmParser &parser)
Parses an LLVM dialect type.
void printPrettyLLVMType(AsmPrinter &p, Type type)
Print any MLIR type or a concise syntax for LLVM types.
ParseResult parsePrettyLLVMType(AsmParser &p, Type &type)
Parse any MLIR type or a concise syntax for LLVM types.
bool isCompatibleOuterType(Type type)
Returns true if the given outer type is compatible with the LLVM dialect without checking its potenti...
bool isCompatibleType(Type type)
Returns true if the given type is compatible with the LLVM dialect.
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition Remarks.h:561
Include the generated interface declarations.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
llvm::TypeSwitch< T, ResultT > TypeSwitch
Definition LLVM.h:144
llvm::StringSwitch< T, R > StringSwitch
Definition LLVM.h:141
llvm::function_ref< Fn > function_ref
Definition LLVM.h:152