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