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