diff --git a/bin/serene.cpp b/bin/serene.cpp index 582839b..f17597a 100644 --- a/bin/serene.cpp +++ b/bin/serene.cpp @@ -32,6 +32,10 @@ #include "serene/slir/generatable.h" #include "serene/slir/slir.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringRef.h" + #include #include #include @@ -41,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -62,7 +67,8 @@ enum Action { DumpSemantic, DumpLIR, DumpIR, - CompileToObject + CompileToObject, + Compile, }; } @@ -71,13 +77,16 @@ static cl::opt inputFile(cl::Positional, cl::init("-"), cl::value_desc("filename")); -static cl::opt outputFile("o", - cl::desc("The path to the output file"), - cl::init("-"), - cl::value_desc("filename")); +static cl::opt outputFile( + "o", cl::desc("The relative path to the output file from the build dir"), + cl::init("-"), cl::value_desc("filename")); + +static cl::opt + outputDir("build-dir", cl::desc("The absolute path to the build directory"), + cl::init("-"), cl::value_desc("filename")); static cl::opt emitAction( - "emit", cl::desc("Select what to dump."), cl::init(CompileToObject), + "emit", cl::desc("Select what to dump."), cl::init(Compile), cl::values(clEnumValN(DumpSemantic, "semantic", "Output the AST after one level of analysis only")), cl::values(clEnumValN(DumpIR, "ir", "Output the lowered IR only")), @@ -88,7 +97,9 @@ static cl::opt emitAction( "Output the LIR only (Lowerd to LLVM dialect)")), cl::values(clEnumValN(DumpAST, "ast", "Output the AST only")), cl::values(clEnumValN(CompileToObject, "object", - "Compile to object file. (Default)")) + "Compile to object file.")), + cl::values(clEnumValN(Compile, "target", + "Compile to target code. (Default)")) ); @@ -114,13 +125,13 @@ exprs::Ast readAndAnalyze(SereneContext &ctx) { }; int dumpAsObject(Namespace &ns) { - - auto &module = ns.getLLVMModule(); - auto targetTriple = llvm::sys::getDefaultTargetTriple(); - module.setTargetTriple(targetTriple); + // TODO: Move the compilation process to the Namespace class + auto &module = ns.getLLVMModule(); + auto &ctx = ns.getContext(); + module.setTargetTriple(ctx.targetTriple); std::string Error; - auto target = llvm::TargetRegistry::lookupTarget(targetTriple, Error); + auto target = llvm::TargetRegistry::lookupTarget(ctx.targetTriple, Error); // Print an error and exit if we couldn't find the requested target. // This generally occurs if we've forgotten to initialise the @@ -136,7 +147,7 @@ int dumpAsObject(Namespace &ns) { llvm::TargetOptions opt; auto rm = llvm::Optional(); auto targetMachinePtr = - target->createTargetMachine(targetTriple, cpu, features, opt, rm); + target->createTargetMachine(ctx.targetTriple, cpu, features, opt, rm); auto targetMachine = std::unique_ptr(targetMachinePtr); module.setDataLayout(targetMachine->createDataLayout()); @@ -145,8 +156,10 @@ int dumpAsObject(Namespace &ns) { strcmp(outputFile.c_str(), "-") == 0 ? "output" : outputFile.c_str(); std::error_code ec; - llvm::raw_fd_ostream dest(llvm::formatv("{0}.o", filename).str(), ec, - llvm::sys::fs::OF_None); + llvm::SmallString<256> destFile(outputDir); + llvm::sys::path::append(destFile, filename); + auto destObjFilePath = llvm::formatv("{0}.o", destFile).str(); + llvm::raw_fd_ostream dest(destObjFilePath, ec, llvm::sys::fs::OF_None); if (ec) { llvm::errs() << "Could not open file: " << ec.message(); @@ -164,50 +177,42 @@ int dumpAsObject(Namespace &ns) { pass.run(module); dest.flush(); - llvm::outs() << "Wrote " << filename << "\n"; + if (emitAction == Action::Compile) { + llvm::IntrusiveRefCntPtr opts = + new clang::DiagnosticOptions; + clang::DiagnosticsEngine diags( + new clang::DiagnosticIDs, opts, + new clang::TextDiagnosticPrinter(llvm::errs(), opts.get())); - llvm::IntrusiveRefCntPtr opts = - new clang::DiagnosticOptions; - clang::DiagnosticsEngine diags( - new clang::DiagnosticIDs, opts, - new clang::TextDiagnosticPrinter(llvm::errs(), opts.get())); + clang::driver::Driver d("clang", ctx.targetTriple, diags, + "Serene compiler"); + std::vector args = {"serenec"}; - clang::driver::Driver d("clang", targetTriple, diags, "Serene compiler"); - std::vector args = {"hnt"}; - auto objf = - llvm::formatv("/home/lxsameer/src/serene/serene/build/{0}.o", filename) - .str(); - args.push_back(objf.c_str()); - args.push_back("-o"); - args.push_back(filename); + args.push_back(destObjFilePath.c_str()); + args.push_back("-o"); + args.push_back(destFile.c_str()); - d.setCheckInputsExist(false); + d.setCheckInputsExist(false); - std::unique_ptr compilation; - compilation.reset(d.BuildCompilation(args)); + std::unique_ptr compilation; + compilation.reset(d.BuildCompilation(args)); - if (!compilation) { - return 1; + if (!compilation) { + return 1; + } + + llvm::SmallVector> + failCommand; + // compilation->ExecuteJobs(compilation->getJobs(), failCommand); + + d.ExecuteCompilation(*compilation, failCommand); + if (failCommand.empty()) { + llvm::outs() << "Done!\n"; + } else { + llvm::errs() << "Linking failed!\n"; + } } - llvm::SmallVector> failCommand; - // compilation->ExecuteJobs(compilation->getJobs(), failCommand); - - d.ExecuteCompilation(*compilation, failCommand); - if (failCommand.empty()) { - llvm::outs() << "Done!\n"; - } else { - llvm::errs() << "Linking failed!\n"; - } - // const llvm::opt::ArgStringList *const cc1Args = n - // getCC1Arguments(&diags, compilation.get()); - // if (!cc1Args) - // return 2; - // std::unique_ptr Invocation( - // clang::tooling::newInvocation(&diags, *cc1Args, "hnt")); - // return clang::tooling::runInvocation("hnt", compilation.get(), - // std::move(Invocation), - // std::move(PCHContainerOps)); return 0; }; @@ -227,6 +232,15 @@ int main(int argc, char *argv[]) { auto ns = makeNamespace(*ctx, "user", llvm::None); // TODO: We might want to find a better place for this applyPassManagerCLOptions(ctx->pm); + + // TODO: handle the outputDir by not forcing it. it should be + // default to the current working dir + if (outputDir == "-") { + llvm::errs() << "Error: The build directory is not set. Did you forget to " + "use '-build-dir'?\n"; + return 1; + } + switch (emitAction) { // Just print out the raw AST @@ -267,6 +281,11 @@ int main(int argc, char *argv[]) { break; } + case Action::Compile: { + ctx->setOperationPhase(CompilationPhase::NoOptimization); + break; + } + default: { llvm::errs() << "No action specified. TODO: Print out help here\n"; return 1; diff --git a/include/serene/context.h b/include/serene/context.h index 2129a00..fbdce11 100644 --- a/include/serene/context.h +++ b/include/serene/context.h @@ -31,6 +31,7 @@ #include "serene/slir/dialect.h" #include +#include #include #include #include @@ -65,6 +66,7 @@ public: llvm::LLVMContext llvmContext; mlir::MLIRContext mlirContext; mlir::PassManager pm; + std::string targetTriple; /// Insert the given `ns` into the context. The Context object is /// the owner of all the namespaces. The `ns` will overwrite any @@ -84,7 +86,9 @@ public: : pm(&mlirContext), targetPhase(CompilationPhase::NoOptimization) { mlirContext.getOrLoadDialect(); mlirContext.getOrLoadDialect(); + // TODO: Get the crash report path dynamically from the cli pm.enableCrashReproducerGeneration("/home/lxsameer/mlir.mlir"); + targetTriple = llvm::sys::getDefaultTargetTriple(); }; void setOperationPhase(CompilationPhase phase);