1//===- mlir-pdll.cpp - MLIR PDLL frontend -----------------------*- 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#include "mlir/IR/BuiltinOps.h"
10#include "mlir/Support/FileUtilities.h"
11#include "mlir/Support/ToolUtilities.h"
12#include "mlir/Tools/PDLL/AST/Context.h"
13#include "mlir/Tools/PDLL/AST/Nodes.h"
14#include "mlir/Tools/PDLL/CodeGen/CPPGen.h"
15#include "mlir/Tools/PDLL/CodeGen/MLIRGen.h"
16#include "mlir/Tools/PDLL/ODS/Context.h"
17#include "mlir/Tools/PDLL/Parser/Parser.h"
18#include "llvm/Support/CommandLine.h"
19#include "llvm/Support/InitLLVM.h"
20#include "llvm/Support/SourceMgr.h"
21#include "llvm/Support/ToolOutputFile.h"
22#include <set>
23
24using namespace mlir;
25using namespace mlir::pdll;
26
27//===----------------------------------------------------------------------===//
28// main
29//===----------------------------------------------------------------------===//
30
31/// The desired output type.
32enum class OutputType {
33 AST,
34 MLIR,
35 CPP,
36};
37
38static LogicalResult
39processBuffer(raw_ostream &os, std::unique_ptr<llvm::MemoryBuffer> chunkBuffer,
40 OutputType outputType, std::vector<std::string> &includeDirs,
41 bool dumpODS, std::set<std::string> *includedFiles) {
42 llvm::SourceMgr sourceMgr;
43 sourceMgr.setIncludeDirs(includeDirs);
44 sourceMgr.AddNewSourceBuffer(F: std::move(chunkBuffer), IncludeLoc: SMLoc());
45
46 // If we are dumping ODS information, also enable documentation to ensure the
47 // summary and description information is imported as well.
48 bool enableDocumentation = dumpODS;
49
50 ods::Context odsContext;
51 ast::Context astContext(odsContext);
52 FailureOr<ast::Module *> module =
53 parsePDLLAST(ctx&: astContext, sourceMgr, enableDocumentation);
54 if (failed(Result: module))
55 return failure();
56
57 // Add the files that were included to the set.
58 if (includedFiles) {
59 for (unsigned i = 1, e = sourceMgr.getNumBuffers(); i < e; ++i) {
60 includedFiles->insert(
61 x: sourceMgr.getMemoryBuffer(i: i + 1)->getBufferIdentifier().str());
62 }
63 }
64
65 // Print out the ODS information if requested.
66 if (dumpODS)
67 odsContext.print(os&: llvm::errs());
68
69 // Generate the output.
70 if (outputType == OutputType::AST) {
71 (*module)->print(os);
72 return success();
73 }
74
75 MLIRContext mlirContext;
76 OwningOpRef<ModuleOp> pdlModule =
77 codegenPDLLToMLIR(&mlirContext, astContext, sourceMgr, **module);
78 if (!pdlModule)
79 return failure();
80
81 if (outputType == OutputType::MLIR) {
82 pdlModule->print(os, OpPrintingFlags().enableDebugInfo());
83 return success();
84 }
85 codegenPDLLToCPP(**module, *pdlModule, os);
86 return success();
87}
88
89/// Create a dependency file for `-d` option.
90///
91/// This functionality is generally only for the benefit of the build system,
92/// and is modeled after the same option in TableGen.
93static LogicalResult
94createDependencyFile(StringRef outputFilename, StringRef dependencyFile,
95 std::set<std::string> &includedFiles) {
96 if (outputFilename == "-") {
97 llvm::errs() << "error: the option -d must be used together with -o\n";
98 return failure();
99 }
100
101 std::string errorMessage;
102 std::unique_ptr<llvm::ToolOutputFile> outputFile =
103 openOutputFile(outputFilename: dependencyFile, errorMessage: &errorMessage);
104 if (!outputFile) {
105 llvm::errs() << errorMessage << "\n";
106 return failure();
107 }
108
109 outputFile->os() << outputFilename << ":";
110 for (const auto &includeFile : includedFiles)
111 outputFile->os() << ' ' << includeFile;
112 outputFile->os() << "\n";
113 outputFile->keep();
114 return success();
115}
116
117int main(int argc, char **argv) {
118 // FIXME: This is necessary because we link in TableGen, which defines its
119 // options as static variables.. some of which overlap with our options.
120 llvm::cl::ResetCommandLineParser();
121
122 llvm::cl::opt<std::string> inputFilename(
123 llvm::cl::Positional, llvm::cl::desc("<input file>"), llvm::cl::init(Val: "-"),
124 llvm::cl::value_desc("filename"));
125
126 llvm::cl::opt<std::string> outputFilename(
127 "o", llvm::cl::desc("Output filename"), llvm::cl::value_desc("filename"),
128 llvm::cl::init(Val: "-"));
129
130 llvm::cl::list<std::string> includeDirs(
131 "I", llvm::cl::desc("Directory of include files"),
132 llvm::cl::value_desc("directory"), llvm::cl::Prefix);
133
134 llvm::cl::opt<bool> dumpODS(
135 "dump-ods",
136 llvm::cl::desc(
137 "Print out the parsed ODS information from the input file"),
138 llvm::cl::init(Val: false));
139 llvm::cl::opt<std::string> inputSplitMarker{
140 "split-input-file", llvm::cl::ValueOptional,
141 llvm::cl::callback(CB: [&](const std::string &str) {
142 // Implicit value: use default marker if flag was used without value.
143 if (str.empty())
144 inputSplitMarker.setValue(V: kDefaultSplitMarker);
145 }),
146 llvm::cl::desc("Split the input file into chunks using the given or "
147 "default marker and process each chunk independently"),
148 llvm::cl::init(Val: "")};
149 llvm::cl::opt<std::string> outputSplitMarker(
150 "output-split-marker",
151 llvm::cl::desc("Split marker to use for merging the ouput"),
152 llvm::cl::init(Val: kDefaultSplitMarker));
153 llvm::cl::opt<enum OutputType> outputType(
154 "x", llvm::cl::init(Val: OutputType::AST),
155 llvm::cl::desc("The type of output desired"),
156 llvm::cl::values(clEnumValN(OutputType::AST, "ast",
157 "generate the AST for the input file"),
158 clEnumValN(OutputType::MLIR, "mlir",
159 "generate the PDL MLIR for the input file"),
160 clEnumValN(OutputType::CPP, "cpp",
161 "generate a C++ source file containing the "
162 "patterns for the input file")));
163 llvm::cl::opt<std::string> dependencyFilename(
164 "d", llvm::cl::desc("Dependency filename"),
165 llvm::cl::value_desc("filename"), llvm::cl::init(Val: ""));
166 llvm::cl::opt<bool> writeIfChanged(
167 "write-if-changed",
168 llvm::cl::desc("Only write to the output file if it changed"));
169
170 // `ResetCommandLineParser` at the above unregistered the "D" option
171 // of `llvm-tblgen`, which causes tblgen usage to fail due to
172 // "Unknnown command line argument '-D...`" when a macros name is
173 // present. The following is a workaround to re-register it again.
174 llvm::cl::list<std::string> macroNames(
175 "D",
176 llvm::cl::desc("Name of the macro to be defined -- ignored by mlir-pdll"),
177 llvm::cl::value_desc("macro name"), llvm::cl::Prefix);
178
179 llvm::InitLLVM y(argc, argv);
180 llvm::cl::ParseCommandLineOptions(argc, argv, Overview: "PDLL Frontend");
181
182 // Set up the input file.
183 std::string errorMessage;
184 std::unique_ptr<llvm::MemoryBuffer> inputFile =
185 openInputFile(inputFilename, errorMessage: &errorMessage);
186 if (!inputFile) {
187 llvm::errs() << errorMessage << "\n";
188 return 1;
189 }
190
191 // If we are creating a dependency file, we'll also need to track what files
192 // get included during processing.
193 std::set<std::string> includedFilesStorage;
194 std::set<std::string> *includedFiles = nullptr;
195 if (!dependencyFilename.empty())
196 includedFiles = &includedFilesStorage;
197
198 // The split-input-file mode is a very specific mode that slices the file
199 // up into small pieces and checks each independently.
200 std::string outputStr;
201 llvm::raw_string_ostream outputStrOS(outputStr);
202 auto processFn = [&](std::unique_ptr<llvm::MemoryBuffer> chunkBuffer,
203 raw_ostream &os) {
204 return processBuffer(os, chunkBuffer: std::move(chunkBuffer), outputType, includeDirs,
205 dumpODS, includedFiles);
206 };
207 if (failed(Result: splitAndProcessBuffer(originalBuffer: std::move(inputFile), processChunkBuffer: processFn, os&: outputStrOS,
208 inputSplitMarker, outputSplitMarker)))
209 return 1;
210
211 // Write the output.
212 bool shouldWriteOutput = true;
213 if (writeIfChanged) {
214 // Only update the real output file if there are any differences. This
215 // prevents recompilation of all the files depending on it if there aren't
216 // any.
217 if (auto existingOrErr =
218 llvm::MemoryBuffer::getFile(Filename: outputFilename, /*IsText=*/true))
219 if (std::move(existingOrErr.get())->getBuffer() == outputStr)
220 shouldWriteOutput = false;
221 }
222
223 // Populate the output file if necessary.
224 if (shouldWriteOutput) {
225 std::unique_ptr<llvm::ToolOutputFile> outputFile =
226 openOutputFile(outputFilename, errorMessage: &errorMessage);
227 if (!outputFile) {
228 llvm::errs() << errorMessage << "\n";
229 return 1;
230 }
231 outputFile->os() << outputStr;
232 outputFile->keep();
233 }
234
235 // Always write the depfile, even if the main output hasn't changed. If it's
236 // missing, Ninja considers the output dirty.
237 if (!dependencyFilename.empty()) {
238 if (failed(Result: createDependencyFile(outputFilename, dependencyFile: dependencyFilename,
239 includedFiles&: includedFilesStorage)))
240 return 1;
241 }
242
243 return 0;
244}
245

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of mlir/tools/mlir-pdll/mlir-pdll.cpp