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