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 
15 using namespace mlir;
16 using 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.
25 static 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.
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  .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.
53 void 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.
97 void mlir::LLVM::detail::printType(Type type, AsmPrinter &printer) {
98  if (!type) {
99  printer << "<<NULL-TYPE>>";
100  return;
101  }
102 
103  printer << getTypeKeyword(type);
104 
105  llvm::TypeSwitch<Type>(type)
106  .Case<LLVMPointerType, LLVMArrayType, LLVMFunctionType, LLVMTargetExtType,
107  LLVMStructType>([&](auto type) { type.print(printer); });
108 }
109 
110 //===----------------------------------------------------------------------===//
111 // Parsing.
112 //===----------------------------------------------------------------------===//
113 
114 static 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.
118 static 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>`
142 Type 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.
244 static Type dispatchParse(AsmParser &parser, bool allowAny = true) {
245  SMLoc keyLoc = parser.getCurrentLocation();
246 
247  // Try parsing any MLIR type.
248  Type type;
249  OptionalParseResult result = parser.parseOptionalType(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.
285 static 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.
291 Type mlir::LLVM::detail::parseType(DialectAsmParser &parser) {
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 
303 ParseResult LLVM::parsePrettyLLVMType(AsmParser &p, Type &type) {
304  return dispatchParse(p, type);
305 }
306 
307 void LLVM::printPrettyLLVMType(AsmPrinter &p, Type type) {
308  return dispatchPrint(p, type);
309 }
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:809
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition: Remarks.h:561
Include the generated interface declarations.