annotate mlir/examples/toy/Ch7/toyc.cpp @ 167:e037d1dd7369

...
author anatofuz
date Tue, 24 Mar 2020 17:35:46 +0900
parents 1d019706d866
children 0572611fdcc8
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
150
anatofuz
parents:
diff changeset
1 //===- toyc.cpp - The Toy Compiler ----------------------------------------===//
anatofuz
parents:
diff changeset
2 //
anatofuz
parents:
diff changeset
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
anatofuz
parents:
diff changeset
4 // See https://llvm.org/LICENSE.txt for license information.
anatofuz
parents:
diff changeset
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
anatofuz
parents:
diff changeset
6 //
anatofuz
parents:
diff changeset
7 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
8 //
anatofuz
parents:
diff changeset
9 // This file implements the entry point for the Toy compiler.
anatofuz
parents:
diff changeset
10 //
anatofuz
parents:
diff changeset
11 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
12
anatofuz
parents:
diff changeset
13 #include "toy/Dialect.h"
anatofuz
parents:
diff changeset
14 #include "toy/MLIRGen.h"
anatofuz
parents:
diff changeset
15 #include "toy/Parser.h"
anatofuz
parents:
diff changeset
16 #include "toy/Passes.h"
anatofuz
parents:
diff changeset
17
anatofuz
parents:
diff changeset
18 #include "mlir/Analysis/Verifier.h"
anatofuz
parents:
diff changeset
19 #include "mlir/ExecutionEngine/ExecutionEngine.h"
anatofuz
parents:
diff changeset
20 #include "mlir/ExecutionEngine/OptUtils.h"
anatofuz
parents:
diff changeset
21 #include "mlir/IR/MLIRContext.h"
anatofuz
parents:
diff changeset
22 #include "mlir/IR/Module.h"
anatofuz
parents:
diff changeset
23 #include "mlir/InitAllDialects.h"
anatofuz
parents:
diff changeset
24 #include "mlir/Parser.h"
anatofuz
parents:
diff changeset
25 #include "mlir/Pass/Pass.h"
anatofuz
parents:
diff changeset
26 #include "mlir/Pass/PassManager.h"
anatofuz
parents:
diff changeset
27 #include "mlir/Target/LLVMIR.h"
anatofuz
parents:
diff changeset
28 #include "mlir/Transforms/Passes.h"
anatofuz
parents:
diff changeset
29
anatofuz
parents:
diff changeset
30 #include "llvm/ADT/StringRef.h"
anatofuz
parents:
diff changeset
31 #include "llvm/IR/Module.h"
anatofuz
parents:
diff changeset
32 #include "llvm/Support/CommandLine.h"
anatofuz
parents:
diff changeset
33 #include "llvm/Support/ErrorOr.h"
anatofuz
parents:
diff changeset
34 #include "llvm/Support/MemoryBuffer.h"
anatofuz
parents:
diff changeset
35 #include "llvm/Support/SourceMgr.h"
anatofuz
parents:
diff changeset
36 #include "llvm/Support/TargetSelect.h"
anatofuz
parents:
diff changeset
37 #include "llvm/Support/raw_ostream.h"
anatofuz
parents:
diff changeset
38
anatofuz
parents:
diff changeset
39 using namespace toy;
anatofuz
parents:
diff changeset
40 namespace cl = llvm::cl;
anatofuz
parents:
diff changeset
41
anatofuz
parents:
diff changeset
42 static cl::opt<std::string> inputFilename(cl::Positional,
anatofuz
parents:
diff changeset
43 cl::desc("<input toy file>"),
anatofuz
parents:
diff changeset
44 cl::init("-"),
anatofuz
parents:
diff changeset
45 cl::value_desc("filename"));
anatofuz
parents:
diff changeset
46
anatofuz
parents:
diff changeset
47 namespace {
anatofuz
parents:
diff changeset
48 enum InputType { Toy, MLIR };
anatofuz
parents:
diff changeset
49 }
anatofuz
parents:
diff changeset
50 static cl::opt<enum InputType> inputType(
anatofuz
parents:
diff changeset
51 "x", cl::init(Toy), cl::desc("Decided the kind of output desired"),
anatofuz
parents:
diff changeset
52 cl::values(clEnumValN(Toy, "toy", "load the input file as a Toy source.")),
anatofuz
parents:
diff changeset
53 cl::values(clEnumValN(MLIR, "mlir",
anatofuz
parents:
diff changeset
54 "load the input file as an MLIR file")));
anatofuz
parents:
diff changeset
55
anatofuz
parents:
diff changeset
56 namespace {
anatofuz
parents:
diff changeset
57 enum Action {
anatofuz
parents:
diff changeset
58 None,
anatofuz
parents:
diff changeset
59 DumpAST,
anatofuz
parents:
diff changeset
60 DumpMLIR,
anatofuz
parents:
diff changeset
61 DumpMLIRAffine,
anatofuz
parents:
diff changeset
62 DumpMLIRLLVM,
anatofuz
parents:
diff changeset
63 DumpLLVMIR,
anatofuz
parents:
diff changeset
64 RunJIT
anatofuz
parents:
diff changeset
65 };
anatofuz
parents:
diff changeset
66 }
anatofuz
parents:
diff changeset
67 static cl::opt<enum Action> emitAction(
anatofuz
parents:
diff changeset
68 "emit", cl::desc("Select the kind of output desired"),
anatofuz
parents:
diff changeset
69 cl::values(clEnumValN(DumpAST, "ast", "output the AST dump")),
anatofuz
parents:
diff changeset
70 cl::values(clEnumValN(DumpMLIR, "mlir", "output the MLIR dump")),
anatofuz
parents:
diff changeset
71 cl::values(clEnumValN(DumpMLIRAffine, "mlir-affine",
anatofuz
parents:
diff changeset
72 "output the MLIR dump after affine lowering")),
anatofuz
parents:
diff changeset
73 cl::values(clEnumValN(DumpMLIRLLVM, "mlir-llvm",
anatofuz
parents:
diff changeset
74 "output the MLIR dump after llvm lowering")),
anatofuz
parents:
diff changeset
75 cl::values(clEnumValN(DumpLLVMIR, "llvm", "output the LLVM IR dump")),
anatofuz
parents:
diff changeset
76 cl::values(
anatofuz
parents:
diff changeset
77 clEnumValN(RunJIT, "jit",
anatofuz
parents:
diff changeset
78 "JIT the code and run it by invoking the main function")));
anatofuz
parents:
diff changeset
79
anatofuz
parents:
diff changeset
80 static cl::opt<bool> enableOpt("opt", cl::desc("Enable optimizations"));
anatofuz
parents:
diff changeset
81
anatofuz
parents:
diff changeset
82 /// Returns a Toy AST resulting from parsing the file or a nullptr on error.
anatofuz
parents:
diff changeset
83 std::unique_ptr<toy::ModuleAST> parseInputFile(llvm::StringRef filename) {
anatofuz
parents:
diff changeset
84 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> fileOrErr =
anatofuz
parents:
diff changeset
85 llvm::MemoryBuffer::getFileOrSTDIN(filename);
anatofuz
parents:
diff changeset
86 if (std::error_code ec = fileOrErr.getError()) {
anatofuz
parents:
diff changeset
87 llvm::errs() << "Could not open input file: " << ec.message() << "\n";
anatofuz
parents:
diff changeset
88 return nullptr;
anatofuz
parents:
diff changeset
89 }
anatofuz
parents:
diff changeset
90 auto buffer = fileOrErr.get()->getBuffer();
anatofuz
parents:
diff changeset
91 LexerBuffer lexer(buffer.begin(), buffer.end(), std::string(filename));
anatofuz
parents:
diff changeset
92 Parser parser(lexer);
anatofuz
parents:
diff changeset
93 return parser.parseModule();
anatofuz
parents:
diff changeset
94 }
anatofuz
parents:
diff changeset
95
anatofuz
parents:
diff changeset
96 int loadMLIR(mlir::MLIRContext &context, mlir::OwningModuleRef &module) {
anatofuz
parents:
diff changeset
97 // Handle '.toy' input to the compiler.
anatofuz
parents:
diff changeset
98 if (inputType != InputType::MLIR &&
anatofuz
parents:
diff changeset
99 !llvm::StringRef(inputFilename).endswith(".mlir")) {
anatofuz
parents:
diff changeset
100 auto moduleAST = parseInputFile(inputFilename);
anatofuz
parents:
diff changeset
101 if (!moduleAST)
anatofuz
parents:
diff changeset
102 return 6;
anatofuz
parents:
diff changeset
103 module = mlirGen(context, *moduleAST);
anatofuz
parents:
diff changeset
104 return !module ? 1 : 0;
anatofuz
parents:
diff changeset
105 }
anatofuz
parents:
diff changeset
106
anatofuz
parents:
diff changeset
107 // Otherwise, the input is '.mlir'.
anatofuz
parents:
diff changeset
108 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> fileOrErr =
anatofuz
parents:
diff changeset
109 llvm::MemoryBuffer::getFileOrSTDIN(inputFilename);
anatofuz
parents:
diff changeset
110 if (std::error_code EC = fileOrErr.getError()) {
anatofuz
parents:
diff changeset
111 llvm::errs() << "Could not open input file: " << EC.message() << "\n";
anatofuz
parents:
diff changeset
112 return -1;
anatofuz
parents:
diff changeset
113 }
anatofuz
parents:
diff changeset
114
anatofuz
parents:
diff changeset
115 // Parse the input mlir.
anatofuz
parents:
diff changeset
116 llvm::SourceMgr sourceMgr;
anatofuz
parents:
diff changeset
117 sourceMgr.AddNewSourceBuffer(std::move(*fileOrErr), llvm::SMLoc());
anatofuz
parents:
diff changeset
118 module = mlir::parseSourceFile(sourceMgr, &context);
anatofuz
parents:
diff changeset
119 if (!module) {
anatofuz
parents:
diff changeset
120 llvm::errs() << "Error can't load file " << inputFilename << "\n";
anatofuz
parents:
diff changeset
121 return 3;
anatofuz
parents:
diff changeset
122 }
anatofuz
parents:
diff changeset
123 return 0;
anatofuz
parents:
diff changeset
124 }
anatofuz
parents:
diff changeset
125
anatofuz
parents:
diff changeset
126 int loadAndProcessMLIR(mlir::MLIRContext &context,
anatofuz
parents:
diff changeset
127 mlir::OwningModuleRef &module) {
anatofuz
parents:
diff changeset
128 if (int error = loadMLIR(context, module))
anatofuz
parents:
diff changeset
129 return error;
anatofuz
parents:
diff changeset
130
anatofuz
parents:
diff changeset
131 mlir::PassManager pm(&context);
anatofuz
parents:
diff changeset
132 // Apply any generic pass manager command line options and run the pipeline.
anatofuz
parents:
diff changeset
133 applyPassManagerCLOptions(pm);
anatofuz
parents:
diff changeset
134
anatofuz
parents:
diff changeset
135 // Check to see what granularity of MLIR we are compiling to.
anatofuz
parents:
diff changeset
136 bool isLoweringToAffine = emitAction >= Action::DumpMLIRAffine;
anatofuz
parents:
diff changeset
137 bool isLoweringToLLVM = emitAction >= Action::DumpMLIRLLVM;
anatofuz
parents:
diff changeset
138
anatofuz
parents:
diff changeset
139 if (enableOpt || isLoweringToAffine) {
anatofuz
parents:
diff changeset
140 // Inline all functions into main and then delete them.
anatofuz
parents:
diff changeset
141 pm.addPass(mlir::createInlinerPass());
anatofuz
parents:
diff changeset
142 pm.addPass(mlir::createSymbolDCEPass());
anatofuz
parents:
diff changeset
143
anatofuz
parents:
diff changeset
144 // Now that there is only one function, we can infer the shapes of each of
anatofuz
parents:
diff changeset
145 // the operations.
anatofuz
parents:
diff changeset
146 mlir::OpPassManager &optPM = pm.nest<mlir::FuncOp>();
anatofuz
parents:
diff changeset
147 optPM.addPass(mlir::createCanonicalizerPass());
anatofuz
parents:
diff changeset
148 optPM.addPass(mlir::toy::createShapeInferencePass());
anatofuz
parents:
diff changeset
149 optPM.addPass(mlir::createCanonicalizerPass());
anatofuz
parents:
diff changeset
150 optPM.addPass(mlir::createCSEPass());
anatofuz
parents:
diff changeset
151 }
anatofuz
parents:
diff changeset
152
anatofuz
parents:
diff changeset
153 if (isLoweringToAffine) {
anatofuz
parents:
diff changeset
154 // Partially lower the toy dialect with a few cleanups afterwards.
anatofuz
parents:
diff changeset
155 pm.addPass(mlir::toy::createLowerToAffinePass());
anatofuz
parents:
diff changeset
156
anatofuz
parents:
diff changeset
157 mlir::OpPassManager &optPM = pm.nest<mlir::FuncOp>();
anatofuz
parents:
diff changeset
158 optPM.addPass(mlir::createCanonicalizerPass());
anatofuz
parents:
diff changeset
159 optPM.addPass(mlir::createCSEPass());
anatofuz
parents:
diff changeset
160
anatofuz
parents:
diff changeset
161 // Add optimizations if enabled.
anatofuz
parents:
diff changeset
162 if (enableOpt) {
anatofuz
parents:
diff changeset
163 optPM.addPass(mlir::createLoopFusionPass());
anatofuz
parents:
diff changeset
164 optPM.addPass(mlir::createMemRefDataFlowOptPass());
anatofuz
parents:
diff changeset
165 }
anatofuz
parents:
diff changeset
166 }
anatofuz
parents:
diff changeset
167
anatofuz
parents:
diff changeset
168 if (isLoweringToLLVM) {
anatofuz
parents:
diff changeset
169 // Finish lowering the toy IR to the LLVM dialect.
anatofuz
parents:
diff changeset
170 pm.addPass(mlir::toy::createLowerToLLVMPass());
anatofuz
parents:
diff changeset
171 }
anatofuz
parents:
diff changeset
172
anatofuz
parents:
diff changeset
173 if (mlir::failed(pm.run(*module)))
anatofuz
parents:
diff changeset
174 return 4;
anatofuz
parents:
diff changeset
175 return 0;
anatofuz
parents:
diff changeset
176 }
anatofuz
parents:
diff changeset
177
anatofuz
parents:
diff changeset
178 int dumpAST() {
anatofuz
parents:
diff changeset
179 if (inputType == InputType::MLIR) {
anatofuz
parents:
diff changeset
180 llvm::errs() << "Can't dump a Toy AST when the input is MLIR\n";
anatofuz
parents:
diff changeset
181 return 5;
anatofuz
parents:
diff changeset
182 }
anatofuz
parents:
diff changeset
183
anatofuz
parents:
diff changeset
184 auto moduleAST = parseInputFile(inputFilename);
anatofuz
parents:
diff changeset
185 if (!moduleAST)
anatofuz
parents:
diff changeset
186 return 1;
anatofuz
parents:
diff changeset
187
anatofuz
parents:
diff changeset
188 dump(*moduleAST);
anatofuz
parents:
diff changeset
189 return 0;
anatofuz
parents:
diff changeset
190 }
anatofuz
parents:
diff changeset
191
anatofuz
parents:
diff changeset
192 int dumpLLVMIR(mlir::ModuleOp module) {
anatofuz
parents:
diff changeset
193 auto llvmModule = mlir::translateModuleToLLVMIR(module);
anatofuz
parents:
diff changeset
194 if (!llvmModule) {
anatofuz
parents:
diff changeset
195 llvm::errs() << "Failed to emit LLVM IR\n";
anatofuz
parents:
diff changeset
196 return -1;
anatofuz
parents:
diff changeset
197 }
anatofuz
parents:
diff changeset
198
anatofuz
parents:
diff changeset
199 // Initialize LLVM targets.
anatofuz
parents:
diff changeset
200 llvm::InitializeNativeTarget();
anatofuz
parents:
diff changeset
201 llvm::InitializeNativeTargetAsmPrinter();
anatofuz
parents:
diff changeset
202 mlir::ExecutionEngine::setupTargetTriple(llvmModule.get());
anatofuz
parents:
diff changeset
203
anatofuz
parents:
diff changeset
204 /// Optionally run an optimization pipeline over the llvm module.
anatofuz
parents:
diff changeset
205 auto optPipeline = mlir::makeOptimizingTransformer(
anatofuz
parents:
diff changeset
206 /*optLevel=*/enableOpt ? 3 : 0, /*sizeLevel=*/0,
anatofuz
parents:
diff changeset
207 /*targetMachine=*/nullptr);
anatofuz
parents:
diff changeset
208 if (auto err = optPipeline(llvmModule.get())) {
anatofuz
parents:
diff changeset
209 llvm::errs() << "Failed to optimize LLVM IR " << err << "\n";
anatofuz
parents:
diff changeset
210 return -1;
anatofuz
parents:
diff changeset
211 }
anatofuz
parents:
diff changeset
212 llvm::errs() << *llvmModule << "\n";
anatofuz
parents:
diff changeset
213 return 0;
anatofuz
parents:
diff changeset
214 }
anatofuz
parents:
diff changeset
215
anatofuz
parents:
diff changeset
216 int runJit(mlir::ModuleOp module) {
anatofuz
parents:
diff changeset
217 // Initialize LLVM targets.
anatofuz
parents:
diff changeset
218 llvm::InitializeNativeTarget();
anatofuz
parents:
diff changeset
219 llvm::InitializeNativeTargetAsmPrinter();
anatofuz
parents:
diff changeset
220
anatofuz
parents:
diff changeset
221 // An optimization pipeline to use within the execution engine.
anatofuz
parents:
diff changeset
222 auto optPipeline = mlir::makeOptimizingTransformer(
anatofuz
parents:
diff changeset
223 /*optLevel=*/enableOpt ? 3 : 0, /*sizeLevel=*/0,
anatofuz
parents:
diff changeset
224 /*targetMachine=*/nullptr);
anatofuz
parents:
diff changeset
225
anatofuz
parents:
diff changeset
226 // Create an MLIR execution engine. The execution engine eagerly JIT-compiles
anatofuz
parents:
diff changeset
227 // the module.
anatofuz
parents:
diff changeset
228 auto maybeEngine = mlir::ExecutionEngine::create(module, optPipeline);
anatofuz
parents:
diff changeset
229 assert(maybeEngine && "failed to construct an execution engine");
anatofuz
parents:
diff changeset
230 auto &engine = maybeEngine.get();
anatofuz
parents:
diff changeset
231
anatofuz
parents:
diff changeset
232 // Invoke the JIT-compiled function.
anatofuz
parents:
diff changeset
233 auto invocationResult = engine->invoke("main");
anatofuz
parents:
diff changeset
234 if (invocationResult) {
anatofuz
parents:
diff changeset
235 llvm::errs() << "JIT invocation failed\n";
anatofuz
parents:
diff changeset
236 return -1;
anatofuz
parents:
diff changeset
237 }
anatofuz
parents:
diff changeset
238
anatofuz
parents:
diff changeset
239 return 0;
anatofuz
parents:
diff changeset
240 }
anatofuz
parents:
diff changeset
241
anatofuz
parents:
diff changeset
242 int main(int argc, char **argv) {
anatofuz
parents:
diff changeset
243 mlir::registerAllDialects();
anatofuz
parents:
diff changeset
244 mlir::registerPassManagerCLOptions();
anatofuz
parents:
diff changeset
245 cl::ParseCommandLineOptions(argc, argv, "toy compiler\n");
anatofuz
parents:
diff changeset
246
anatofuz
parents:
diff changeset
247 if (emitAction == Action::DumpAST)
anatofuz
parents:
diff changeset
248 return dumpAST();
anatofuz
parents:
diff changeset
249
anatofuz
parents:
diff changeset
250 // If we aren't dumping the AST, then we are compiling with/to MLIR.
anatofuz
parents:
diff changeset
251
anatofuz
parents:
diff changeset
252 // Register our Dialect with MLIR.
anatofuz
parents:
diff changeset
253 mlir::registerDialect<mlir::toy::ToyDialect>();
anatofuz
parents:
diff changeset
254
anatofuz
parents:
diff changeset
255 mlir::MLIRContext context;
anatofuz
parents:
diff changeset
256 mlir::OwningModuleRef module;
anatofuz
parents:
diff changeset
257 if (int error = loadAndProcessMLIR(context, module))
anatofuz
parents:
diff changeset
258 return error;
anatofuz
parents:
diff changeset
259
anatofuz
parents:
diff changeset
260 // If we aren't exporting to non-mlir, then we are done.
anatofuz
parents:
diff changeset
261 bool isOutputingMLIR = emitAction <= Action::DumpMLIRLLVM;
anatofuz
parents:
diff changeset
262 if (isOutputingMLIR) {
anatofuz
parents:
diff changeset
263 module->dump();
anatofuz
parents:
diff changeset
264 return 0;
anatofuz
parents:
diff changeset
265 }
anatofuz
parents:
diff changeset
266
anatofuz
parents:
diff changeset
267 // Check to see if we are compiling to LLVM IR.
anatofuz
parents:
diff changeset
268 if (emitAction == Action::DumpLLVMIR)
anatofuz
parents:
diff changeset
269 return dumpLLVMIR(*module);
anatofuz
parents:
diff changeset
270
anatofuz
parents:
diff changeset
271 // Otherwise, we must be running the jit.
anatofuz
parents:
diff changeset
272 if (emitAction == Action::RunJIT)
anatofuz
parents:
diff changeset
273 return runJit(*module);
anatofuz
parents:
diff changeset
274
anatofuz
parents:
diff changeset
275 llvm::errs() << "No action specified (parsing only?), use -emit=<action>\n";
anatofuz
parents:
diff changeset
276 return -1;
anatofuz
parents:
diff changeset
277 }