1//===- Parser.h - MLIR Parser Library Interface -----------------*- C++ -*-===//
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//
9// This file is contains a unified interface for parsing serialized MLIR.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef MLIR_PARSER_PARSER_H
14#define MLIR_PARSER_PARSER_H
15
16#include "mlir/IR/AsmState.h"
17#include "mlir/IR/Builders.h"
18#include "mlir/IR/OwningOpRef.h"
19#include <cstddef>
20
21namespace llvm {
22class SourceMgr;
23class SMDiagnostic;
24class StringRef;
25} // namespace llvm
26
27namespace mlir {
28namespace detail {
29
30/// Given a block containing operations that have just been parsed, if the block
31/// contains a single operation of `ContainerOpT` type then remove it from the
32/// block and return it. If the block does not contain just that operation,
33/// create a new operation instance of `ContainerOpT` and move all of the
34/// operations within `parsedBlock` into the first block of the first region.
35/// `ContainerOpT` is required to have a single region containing a single
36/// block, and must implement the `SingleBlockImplicitTerminator` trait.
37template <typename ContainerOpT>
38inline OwningOpRef<ContainerOpT> constructContainerOpForParserIfNecessary(
39 Block *parsedBlock, MLIRContext *context, Location sourceFileLoc) {
40
41 // Check to see if we parsed a single instance of this operation.
42 if (llvm::hasSingleElement(C&: *parsedBlock)) {
43 if (ContainerOpT op = dyn_cast<ContainerOpT>(&parsedBlock->front())) {
44 op->remove();
45 return op;
46 }
47 }
48
49 // If not, then build a new top-level op if a concrete operation type was
50 // specified.
51 if constexpr (std::is_same_v<ContainerOpT, Operation *>) {
52 (void)context;
53 return emitError(loc: sourceFileLoc)
54 << "source must contain a single top-level operation, found: "
55 << parsedBlock->getOperations().size(),
56 nullptr;
57 } else {
58 static_assert(
59 ContainerOpT::template hasTrait<OpTrait::OneRegion>() &&
60 (ContainerOpT::template hasTrait<OpTrait::NoTerminator>() ||
61 OpTrait::template hasSingleBlockImplicitTerminator<
62 ContainerOpT>::value),
63 "Expected `ContainerOpT` to have a single region with a single "
64 "block that has an implicit terminator or does not require one");
65
66 OpBuilder builder(context);
67 ContainerOpT op = builder.create<ContainerOpT>(sourceFileLoc);
68 OwningOpRef<ContainerOpT> opRef(op);
69 assert(op->getNumRegions() == 1 &&
70 llvm::hasSingleElement(op->getRegion(0)) &&
71 "expected generated operation to have a single region with a single "
72 "block");
73 Block *opBlock = &op->getRegion(0).front();
74 opBlock->getOperations().splice(where: opBlock->begin(),
75 L2&: parsedBlock->getOperations());
76
77 // After splicing, verify just this operation to ensure it can properly
78 // contain the operations inside of it.
79 if (failed(op.verifyInvariants()))
80 return OwningOpRef<ContainerOpT>();
81 return opRef;
82 }
83}
84} // namespace detail
85
86/// This parses the file specified by the indicated SourceMgr and appends parsed
87/// operations to the given block. If the block is non-empty, the operations are
88/// placed before the current terminator. If parsing is successful, success is
89/// returned. Otherwise, an error message is emitted through the error handler
90/// registered in the context, and failure is returned. If `sourceFileLoc` is
91/// non-null, it is populated with a file location representing the start of the
92/// source file that is being parsed.
93LogicalResult parseSourceFile(const llvm::SourceMgr &sourceMgr, Block *block,
94 const ParserConfig &config,
95 LocationAttr *sourceFileLoc = nullptr);
96/// An overload with a source manager that may have references taken during the
97/// parsing process, and whose lifetime can be freely extended (such that the
98/// source manager is not destroyed before the parsed IR). This is useful, for
99/// example, to avoid copying some large resources into the MLIRContext and
100/// instead referencing the data directly from the input buffers.
101LogicalResult parseSourceFile(const std::shared_ptr<llvm::SourceMgr> &sourceMgr,
102 Block *block, const ParserConfig &config,
103 LocationAttr *sourceFileLoc = nullptr);
104
105/// This parses the file specified by the indicated filename and appends parsed
106/// operations to the given block. If the block is non-empty, the operations are
107/// placed before the current terminator. If parsing is successful, success is
108/// returned. Otherwise, an error message is emitted through the error handler
109/// registered in the context, and failure is returned. If `sourceFileLoc` is
110/// non-null, it is populated with a file location representing the start of the
111/// source file that is being parsed.
112LogicalResult parseSourceFile(llvm::StringRef filename, Block *block,
113 const ParserConfig &config,
114 LocationAttr *sourceFileLoc = nullptr);
115
116/// This parses the file specified by the indicated filename using the provided
117/// SourceMgr and appends parsed operations to the given block. If the block is
118/// non-empty, the operations are placed before the current terminator. If
119/// parsing is successful, success is returned. Otherwise, an error message is
120/// emitted through the error handler registered in the context, and failure is
121/// returned. If `sourceFileLoc` is non-null, it is populated with a file
122/// location representing the start of the source file that is being parsed.
123LogicalResult parseSourceFile(llvm::StringRef filename,
124 llvm::SourceMgr &sourceMgr, Block *block,
125 const ParserConfig &config,
126 LocationAttr *sourceFileLoc = nullptr);
127/// An overload with a source manager that may have references taken during the
128/// parsing process, and whose lifetime can be freely extended (such that the
129/// source manager is not destroyed before the parsed IR). This is useful, for
130/// example, to avoid copying some large resources into the MLIRContext and
131/// instead referencing the data directly from the input buffers.
132LogicalResult parseSourceFile(llvm::StringRef filename,
133 const std::shared_ptr<llvm::SourceMgr> &sourceMgr,
134 Block *block, const ParserConfig &config,
135 LocationAttr *sourceFileLoc = nullptr);
136
137/// This parses the IR string and appends parsed operations to the given block.
138/// If the block is non-empty, the operations are placed before the current
139/// terminator. If parsing is successful, success is returned. Otherwise, an
140/// error message is emitted through the error handler registered in the
141/// context, and failure is returned.
142/// `sourceName` is used as the file name of the source; any IR without
143/// locations will get a `FileLineColLoc` location with `sourceName` as the file
144/// name. If `sourceFileLoc` is non-null, it is populated with a file location
145/// representing the start of the source file that is being parsed.
146LogicalResult parseSourceString(llvm::StringRef sourceStr, Block *block,
147 const ParserConfig &config,
148 StringRef sourceName = "",
149 LocationAttr *sourceFileLoc = nullptr);
150
151namespace detail {
152/// The internal implementation of the templated `parseSourceFile` methods
153/// below, that simply forwards to the non-templated version.
154template <typename ContainerOpT, typename... ParserArgs>
155inline OwningOpRef<ContainerOpT> parseSourceFile(const ParserConfig &config,
156 ParserArgs &&...args) {
157 LocationAttr sourceFileLoc;
158 Block block;
159 if (failed(parseSourceFile(std::forward<ParserArgs>(args)..., &block, config,
160 &sourceFileLoc)))
161 return OwningOpRef<ContainerOpT>();
162 return detail::constructContainerOpForParserIfNecessary<ContainerOpT>(
163 &block, config.getContext(), sourceFileLoc);
164}
165} // namespace detail
166
167/// This parses the file specified by the indicated SourceMgr. If the source IR
168/// contained a single instance of `ContainerOpT`, it is returned. Otherwise, a
169/// new instance of `ContainerOpT` is constructed containing all of the parsed
170/// operations. If parsing was not successful, null is returned and an error
171/// message is emitted through the error handler registered in the context, and
172/// failure is returned. `ContainerOpT` is required to have a single region
173/// containing a single block, and must implement the
174/// `SingleBlockImplicitTerminator` trait.
175template <typename ContainerOpT = Operation *>
176inline OwningOpRef<ContainerOpT>
177parseSourceFile(const llvm::SourceMgr &sourceMgr, const ParserConfig &config) {
178 return detail::parseSourceFile<ContainerOpT>(config, sourceMgr);
179}
180/// An overload with a source manager that may have references taken during the
181/// parsing process, and whose lifetime can be freely extended (such that the
182/// source manager is not destroyed before the parsed IR). This is useful, for
183/// example, to avoid copying some large resources into the MLIRContext and
184/// instead referencing the data directly from the input buffers.
185template <typename ContainerOpT = Operation *>
186inline OwningOpRef<ContainerOpT>
187parseSourceFile(const std::shared_ptr<llvm::SourceMgr> &sourceMgr,
188 const ParserConfig &config) {
189 return detail::parseSourceFile<ContainerOpT>(config, sourceMgr);
190}
191
192/// This parses the file specified by the indicated filename. If the source IR
193/// contained a single instance of `ContainerOpT`, it is returned. Otherwise, a
194/// new instance of `ContainerOpT` is constructed containing all of the parsed
195/// operations. If parsing was not successful, null is returned and an error
196/// message is emitted through the error handler registered in the context, and
197/// failure is returned. `ContainerOpT` is required to have a single region
198/// containing a single block, and must implement the
199/// `SingleBlockImplicitTerminator` trait.
200template <typename ContainerOpT = Operation *>
201inline OwningOpRef<ContainerOpT> parseSourceFile(StringRef filename,
202 const ParserConfig &config) {
203 return detail::parseSourceFile<ContainerOpT>(config, filename);
204}
205
206/// This parses the file specified by the indicated filename using the provided
207/// SourceMgr. If the source IR contained a single instance of `ContainerOpT`,
208/// it is returned. Otherwise, a new instance of `ContainerOpT` is constructed
209/// containing all of the parsed operations. If parsing was not successful, null
210/// is returned and an error message is emitted through the error handler
211/// registered in the context, and failure is returned. `ContainerOpT` is
212/// required to have a single region containing a single block, and must
213/// implement the `SingleBlockImplicitTerminator` trait.
214template <typename ContainerOpT = Operation *>
215inline OwningOpRef<ContainerOpT> parseSourceFile(llvm::StringRef filename,
216 llvm::SourceMgr &sourceMgr,
217 const ParserConfig &config) {
218 return detail::parseSourceFile<ContainerOpT>(config, filename, sourceMgr);
219}
220/// An overload with a source manager that may have references taken during the
221/// parsing process, and whose lifetime can be freely extended (such that the
222/// source manager is not destroyed before the parsed IR). This is useful, for
223/// example, to avoid copying some large resources into the MLIRContext and
224/// instead referencing the data directly from the input buffers.
225template <typename ContainerOpT = Operation *>
226inline OwningOpRef<ContainerOpT>
227parseSourceFile(llvm::StringRef filename,
228 const std::shared_ptr<llvm::SourceMgr> &sourceMgr,
229 const ParserConfig &config) {
230 return detail::parseSourceFile<ContainerOpT>(config, filename, sourceMgr);
231}
232
233/// This parses the provided string containing MLIR. If the source IR contained
234/// a single instance of `ContainerOpT`, it is returned. Otherwise, a new
235/// instance of `ContainerOpT` is constructed containing all of the parsed
236/// operations. If parsing was not successful, null is returned and an error
237/// message is emitted through the error handler registered in the context, and
238/// failure is returned. `ContainerOpT` is required to have a single region
239/// containing a single block, and must implement the
240/// `SingleBlockImplicitTerminator` trait.
241/// `sourceName` is used as the file name of the source; any IR without
242/// locations will get a `FileLineColLoc` location with `sourceName` as the file
243/// name.
244template <typename ContainerOpT = Operation *>
245inline OwningOpRef<ContainerOpT> parseSourceString(llvm::StringRef sourceStr,
246 const ParserConfig &config,
247 StringRef sourceName = "") {
248 LocationAttr sourceFileLoc;
249 Block block;
250 if (failed(result: parseSourceString(sourceStr, block: &block, config, sourceName,
251 sourceFileLoc: &sourceFileLoc)))
252 return OwningOpRef<ContainerOpT>();
253 return detail::constructContainerOpForParserIfNecessary<ContainerOpT>(
254 &block, config.getContext(), sourceFileLoc);
255}
256
257} // namespace mlir
258
259#endif // MLIR_PARSER_PARSER_H
260

source code of mlir/include/mlir/Parser/Parser.h