MLIR 23.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<LLVMLabelType>([&](Type) { return "label"; })
40 .Case<LLVMMetadataType>([&](Type) { return "metadata"; })
41 .Case<LLVMFunctionType>([&](Type) { return "func"; })
42 .Case<LLVMPointerType>([&](Type) { return "ptr"; })
43 .Case<LLVMArrayType>([&](Type) { return "array"; })
44 .Case<LLVMByteType>([&](Type) { return "byte"; })
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, LLVMByteType, LLVMFunctionType,
107 LLVMTargetExtType, LLVMStructType>(
108 [&](auto type) { type.print(printer); });
109}
110
111//===----------------------------------------------------------------------===//
112// Parsing.
113//===----------------------------------------------------------------------===//
114
115static ParseResult dispatchParse(AsmParser &parser, Type &type);
116
117/// Attempts to set the body of an identified structure type. Reports a parsing
118/// error at `subtypesLoc` in case of failure.
119static LLVMStructType trySetStructBody(LLVMStructType type,
120 ArrayRef<Type> subtypes, bool isPacked,
121 AsmParser &parser, SMLoc subtypesLoc) {
122 for (Type t : subtypes) {
123 if (!LLVMStructType::isValidElementType(t)) {
124 parser.emitError(subtypesLoc)
125 << "invalid LLVM structure element type: " << t;
126 return LLVMStructType();
127 }
128 }
129
130 if (succeeded(type.setBody(subtypes, isPacked)))
131 return type;
132
133 parser.emitError(subtypesLoc)
134 << "identified type already used with a different body";
135 return LLVMStructType();
136}
137
138/// Parses an LLVM dialect structure type.
139/// llvm-type ::= `struct<` (string-literal `,`)? `packed`?
140/// `(` llvm-type-list `)` `>`
141/// | `struct<` string-literal `>`
142/// | `struct<` string-literal `, opaque>`
143Type LLVMStructType::parse(AsmParser &parser) {
144 Location loc = parser.getEncodedSourceLoc(parser.getCurrentLocation());
145
146 if (failed(parser.parseLess()))
147 return LLVMStructType();
148
149 // If we are parsing a self-reference to a recursive struct, i.e. the parsing
150 // stack already contains a struct with the same identifier, bail out after
151 // the name.
152 std::string name;
153 bool isIdentified = succeeded(parser.parseOptionalString(&name));
154 if (isIdentified) {
155 SMLoc greaterLoc = parser.getCurrentLocation();
156 if (succeeded(parser.parseOptionalGreater())) {
157 auto type = LLVMStructType::getIdentifiedChecked(
158 [loc] { return emitError(loc); }, loc.getContext(), name);
159 if (succeeded(parser.tryStartCyclicParse(type))) {
160 parser.emitError(
161 greaterLoc,
162 "struct without a body only allowed in a recursive struct");
163 return nullptr;
164 }
165
166 return type;
167 }
168 if (failed(parser.parseComma()))
169 return LLVMStructType();
170 }
171
172 // Handle intentionally opaque structs.
173 SMLoc kwLoc = parser.getCurrentLocation();
174 if (succeeded(parser.parseOptionalKeyword("opaque"))) {
175 if (!isIdentified)
176 return parser.emitError(kwLoc, "only identified structs can be opaque"),
177 LLVMStructType();
178 if (failed(parser.parseGreater()))
179 return LLVMStructType();
180 auto type = LLVMStructType::getOpaqueChecked(
181 [loc] { return emitError(loc); }, loc.getContext(), name);
182 if (!type.isOpaque()) {
183 parser.emitError(kwLoc, "redeclaring defined struct as opaque");
184 return LLVMStructType();
185 }
186 return type;
187 }
188
189 FailureOr<AsmParser::CyclicParseReset> cyclicParse;
190 if (isIdentified) {
191 cyclicParse =
192 parser.tryStartCyclicParse(LLVMStructType::getIdentifiedChecked(
193 [loc] { return emitError(loc); }, loc.getContext(), name));
194 if (failed(cyclicParse)) {
195 parser.emitError(kwLoc,
196 "identifier already used for an enclosing struct");
197 return nullptr;
198 }
199 }
200
201 // Check for packedness.
202 bool isPacked = succeeded(parser.parseOptionalKeyword("packed"));
203 if (failed(parser.parseLParen()))
204 return LLVMStructType();
205
206 // Fast pass for structs with zero subtypes.
207 if (succeeded(parser.parseOptionalRParen())) {
208 if (failed(parser.parseGreater()))
209 return LLVMStructType();
210 if (!isIdentified)
211 return LLVMStructType::getLiteralChecked([loc] { return emitError(loc); },
212 loc.getContext(), {}, isPacked);
213 auto type = LLVMStructType::getIdentifiedChecked(
214 [loc] { return emitError(loc); }, loc.getContext(), name);
215 return trySetStructBody(type, {}, isPacked, parser, kwLoc);
216 }
217
218 // Parse subtypes. For identified structs, put the identifier of the struct on
219 // the stack to support self-references in the recursive calls.
220 SmallVector<Type, 4> subtypes;
221 SMLoc subtypesLoc = parser.getCurrentLocation();
222 do {
223 Type type;
224 if (dispatchParse(parser, type))
225 return LLVMStructType();
226 subtypes.push_back(type);
227 } while (succeeded(parser.parseOptionalComma()));
228
229 if (parser.parseRParen() || parser.parseGreater())
230 return LLVMStructType();
231
232 // Construct the struct with body.
233 if (!isIdentified)
234 return LLVMStructType::getLiteralChecked(
235 [loc] { return emitError(loc); }, loc.getContext(), subtypes, isPacked);
236 auto type = LLVMStructType::getIdentifiedChecked(
237 [loc] { return emitError(loc); }, loc.getContext(), name);
238 return trySetStructBody(type, subtypes, isPacked, parser, subtypesLoc);
239}
240
241/// Parses a type appearing inside another LLVM dialect-compatible type. This
242/// will try to parse any type in full form (including types with the `!llvm`
243/// prefix), and on failure fall back to parsing the short-hand version of the
244/// LLVM dialect types without the `!llvm` prefix.
245static Type dispatchParse(AsmParser &parser, bool allowAny = true) {
246 SMLoc keyLoc = parser.getCurrentLocation();
247
248 // Try parsing any MLIR type.
249 Type type;
251 if (result.has_value()) {
252 if (failed(result.value()))
253 return nullptr;
254 if (!allowAny) {
255 parser.emitError(keyLoc) << "unexpected type, expected keyword";
256 return nullptr;
257 }
258 return type;
259 }
260
261 // If no type found, fallback to the shorthand form.
262 StringRef key;
263 if (failed(parser.parseKeyword(&key)))
264 return Type();
265
266 MLIRContext *ctx = parser.getContext();
267 return StringSwitch<function_ref<Type()>>(key)
268 .Case("void", [&] { return LLVMVoidType::get(ctx); })
269 .Case("ppc_fp128", [&] { return LLVMPPCFP128Type::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("byte", [&] { return LLVMByteType::parse(parser); })
276 .Case("struct", [&] { return LLVMStructType::parse(parser); })
277 .Case("target", [&] { return LLVMTargetExtType::parse(parser); })
278 .Case("x86_amx", [&] { return LLVMX86AMXType::get(ctx); })
279 .Default([&] {
280 parser.emitError(keyLoc) << "unknown LLVM type: " << key;
281 return Type();
282 })();
283}
284
285/// Helper to use in parse lists.
286static ParseResult dispatchParse(AsmParser &parser, Type &type) {
287 type = dispatchParse(parser);
288 return success(type != nullptr);
289}
290
291/// Parses one of the LLVM dialect types.
293 SMLoc loc = parser.getCurrentLocation();
294 Type type = dispatchParse(parser, /*allowAny=*/false);
295 if (!type)
296 return type;
297 if (!isCompatibleOuterType(type)) {
298 parser.emitError(loc) << "unexpected type, expected keyword";
299 return nullptr;
300 }
301 return type;
302}
303
305 return dispatchParse(p, type);
306}
307
309 return dispatchPrint(p, type);
310}
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:717
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:139
llvm::StringSwitch< T, R > StringSwitch
Definition LLVM.h:136
llvm::function_ref< Fn > function_ref
Definition LLVM.h:147