171 lines · cpp
1//===- toyc.cpp - The Toy Compiler ----------------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the entry point for the Toy compiler.10//11//===----------------------------------------------------------------------===//12 13#include "mlir/IR/Diagnostics.h"14#include "toy/AST.h"15#include "toy/Dialect.h"16#include "toy/Lexer.h"17#include "toy/MLIRGen.h"18#include "toy/Parser.h"19 20#include "mlir/IR/AsmState.h"21#include "mlir/IR/BuiltinOps.h"22#include "mlir/IR/MLIRContext.h"23#include "mlir/IR/Verifier.h"24#include "mlir/Parser/Parser.h"25#include "mlir/Pass/PassManager.h"26#include "mlir/Transforms/Passes.h"27 28#include "llvm/ADT/StringRef.h"29#include "llvm/Support/CommandLine.h"30#include "llvm/Support/ErrorOr.h"31#include "llvm/Support/MemoryBuffer.h"32#include "llvm/Support/SourceMgr.h"33#include "llvm/Support/raw_ostream.h"34#include <memory>35#include <string>36#include <system_error>37#include <utility>38 39using namespace toy;40namespace cl = llvm::cl;41 42static cl::opt<std::string> inputFilename(cl::Positional,43 cl::desc("<input toy file>"),44 cl::init("-"),45 cl::value_desc("filename"));46 47namespace {48enum InputType { Toy, MLIR };49} // namespace50static cl::opt<enum InputType> inputType(51 "x", cl::init(Toy), cl::desc("Decided the kind of output desired"),52 cl::values(clEnumValN(Toy, "toy", "load the input file as a Toy source.")),53 cl::values(clEnumValN(MLIR, "mlir",54 "load the input file as an MLIR file")));55 56namespace {57enum Action { None, DumpAST, DumpMLIR };58} // namespace59static cl::opt<enum Action> emitAction(60 "emit", cl::desc("Select the kind of output desired"),61 cl::values(clEnumValN(DumpAST, "ast", "output the AST dump")),62 cl::values(clEnumValN(DumpMLIR, "mlir", "output the MLIR dump")));63 64static cl::opt<bool> enableOpt("opt", cl::desc("Enable optimizations"));65 66/// Returns a Toy AST resulting from parsing the file or a nullptr on error.67static std::unique_ptr<toy::ModuleAST>68parseInputFile(llvm::StringRef filename) {69 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> fileOrErr =70 llvm::MemoryBuffer::getFileOrSTDIN(filename);71 if (std::error_code ec = fileOrErr.getError()) {72 llvm::errs() << "Could not open input file: " << ec.message() << "\n";73 return nullptr;74 }75 auto buffer = fileOrErr.get()->getBuffer();76 LexerBuffer lexer(buffer.begin(), buffer.end(), std::string(filename));77 Parser parser(lexer);78 return parser.parseModule();79}80 81static int loadMLIR(llvm::SourceMgr &sourceMgr, mlir::MLIRContext &context,82 mlir::OwningOpRef<mlir::ModuleOp> &module) {83 // Handle '.toy' input to the compiler.84 if (inputType != InputType::MLIR &&85 !llvm::StringRef(inputFilename).ends_with(".mlir")) {86 auto moduleAST = parseInputFile(inputFilename);87 if (!moduleAST)88 return 6;89 module = mlirGen(context, *moduleAST);90 return !module ? 1 : 0;91 }92 93 // Otherwise, the input is '.mlir'.94 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> fileOrErr =95 llvm::MemoryBuffer::getFileOrSTDIN(inputFilename);96 if (std::error_code ec = fileOrErr.getError()) {97 llvm::errs() << "Could not open input file: " << ec.message() << "\n";98 return -1;99 }100 101 // Parse the input mlir.102 sourceMgr.AddNewSourceBuffer(std::move(*fileOrErr), llvm::SMLoc());103 module = mlir::parseSourceFile<mlir::ModuleOp>(sourceMgr, &context);104 if (!module) {105 llvm::errs() << "Error can't load file " << inputFilename << "\n";106 return 3;107 }108 return 0;109}110 111static int dumpMLIR() {112 mlir::MLIRContext context;113 // Load our Dialect in this MLIR Context.114 context.getOrLoadDialect<mlir::toy::ToyDialect>();115 116 mlir::OwningOpRef<mlir::ModuleOp> module;117 llvm::SourceMgr sourceMgr;118 mlir::SourceMgrDiagnosticHandler sourceMgrHandler(sourceMgr, &context);119 if (int error = loadMLIR(sourceMgr, context, module))120 return error;121 122 if (enableOpt) {123 mlir::PassManager pm(module.get()->getName());124 // Apply any generic pass manager command line options and run the pipeline.125 if (mlir::failed(mlir::applyPassManagerCLOptions(pm)))126 return 4;127 128 // Add a run of the canonicalizer to optimize the mlir module.129 pm.addNestedPass<mlir::toy::FuncOp>(mlir::createCanonicalizerPass());130 if (mlir::failed(pm.run(*module)))131 return 4;132 }133 134 module->dump();135 return 0;136}137 138static int dumpAST() {139 if (inputType == InputType::MLIR) {140 llvm::errs() << "Can't dump a Toy AST when the input is MLIR\n";141 return 5;142 }143 144 auto moduleAST = parseInputFile(inputFilename);145 if (!moduleAST)146 return 1;147 148 dump(*moduleAST);149 return 0;150}151 152int main(int argc, char **argv) {153 // Register any command line options.154 mlir::registerAsmPrinterCLOptions();155 mlir::registerMLIRContextCLOptions();156 mlir::registerPassManagerCLOptions();157 158 cl::ParseCommandLineOptions(argc, argv, "toy compiler\n");159 160 switch (emitAction) {161 case Action::DumpAST:162 return dumpAST();163 case Action::DumpMLIR:164 return dumpMLIR();165 default:166 llvm::errs() << "No action specified (parsing only?), use -emit=<action>\n";167 }168 169 return 0;170}171