From 69e8782c6761d478330d0a0b18d10a3a9302e660 Mon Sep 17 00:00:00 2001 From: Sameer Rahmani Date: Wed, 3 Nov 2021 14:06:45 +0000 Subject: [PATCH] finalize ep 12 --- CMakeLists.txt | 6 +- docs/videos.org | 3 + src/serenec/CMakeLists.txt | 3 +- src/serenec/serenec.cpp | 328 +++++++++++++++++++++---------------- 4 files changed, 192 insertions(+), 148 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index af3c8e0..0de7e07 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -169,10 +169,12 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) # LLVM setup ========================================= find_package(LLVM REQUIRED CONFIG) find_package(MLIR REQUIRED CONFIG) + find_package(LLD REQUIRED CONFIG) message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") message(STATUS "Using MLIRConfig.cmake in: ${MLIR_DIR}") + message(STATUS "Using LLDConfig.cmake in: ${LLD_DIR}") set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/bin) set(LLVM_LIBRARY_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/lib) @@ -180,15 +182,15 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) list(APPEND CMAKE_MODULE_PATH "${MLIR_CMAKE_DIR}") list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") + list(APPEND CMAKE_MODULE_PATH "${LLD_CMAKE_DIR}") include(TableGen) include(AddLLVM) include(AddMLIR) include(HandleLLVMOptions) - - include_directories(SYSTEM ${LLVM_INCLUDE_DIRS}) + separate_arguments(LLVM_DEFINITIONS_LIST NATIVE_COMMAND ${LLVM_DEFINITIONS}) add_definitions(${LLVM_DEFINITIONS_LIST}) diff --git a/docs/videos.org b/docs/videos.org index 940a9ab..93fe62a 100644 --- a/docs/videos.org +++ b/docs/videos.org @@ -517,6 +517,7 @@ This framework allows for transforming a set of illegal operations to a set of l ** Next Step *** Compile to object files *** Link object files to create an executable +** End of wiring for static compilers ** What is an object file? *** Symbols - A pair of a name and a value @@ -558,3 +559,5 @@ and tries to =resolve= *undefined* symbols + write the result to a file as an executable ** AOT vs JIT ** Let's look at some code +** Resources: +- [[https://lwn.net/Articles/276782/][20 part linker essay]] diff --git a/src/serenec/CMakeLists.txt b/src/serenec/CMakeLists.txt index e5307d0..52c095f 100644 --- a/src/serenec/CMakeLists.txt +++ b/src/serenec/CMakeLists.txt @@ -43,7 +43,8 @@ target_link_libraries(serenec LLVMTarget LLVMOption - + lldDriver + lldELF clangDriver clangBasic clangdSupport diff --git a/src/serenec/serenec.cpp b/src/serenec/serenec.cpp index 3ba2b73..f01b6ca 100644 --- a/src/serenec/serenec.cpp +++ b/src/serenec/serenec.cpp @@ -25,6 +25,8 @@ #include "serene/slir/generatable.h" #include "serene/slir/slir.h" +#include + #include #include #include @@ -176,182 +178,218 @@ int dumpAsObject(Namespace &ns) { dest.flush(); if (emitAction == Action::Compile) { - 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"}; + args.push_back("--eh-frame-hdr"); + args.push_back("-m"); + args.push_back("elf_x86_64"); + args.push_back("-dynamic-linker"); + args.push_back("/lib64/ld-linux-x86-64.so.2"); + args.push_back( + "/usr/lib/gcc/x86_64-pc-linux-gnu/11.2.0/../../../../lib64/crt1.o"); + args.push_back( + "/usr/lib/gcc/x86_64-pc-linux-gnu/11.2.0/../../../../lib64/crti.o"); + args.push_back("/usr/lib/gcc/x86_64-pc-linux-gnu/11.2.0/crtbegin.o"); + args.push_back("-L"); + args.push_back("/usr/lib/gcc/x86_64-pc-linux-gnu/11.2.0/"); + args.push_back("-L"); + args.push_back("/usr/lib64/"); + args.push_back(destObjFilePath.c_str()); args.push_back("-o"); args.push_back(destFile.c_str()); + args.push_back("-lgcc"); + args.push_back("--as-needed"); + args.push_back("-lgcc_s"); + args.push_back("--no-as-needed"); + args.push_back("-lc"); + args.push_back("-lgcc"); + args.push_back("--as-needed"); + args.push_back("-lgcc_s"); + args.push_back("--no-as-needed"); + args.push_back("/usr/lib/gcc/x86_64-pc-linux-gnu/11.2.0/crtend.o"); + args.push_back( + "/usr/lib/gcc/x86_64-pc-linux-gnu/11.2.0/../../../../lib64/crtn.o"); - d.setCheckInputsExist(true); + lld::elf::link(args, false, llvm::outs(), llvm::errs()); - std::unique_ptr compilation; - compilation.reset(d.BuildCompilation(args)); + // llvm::IntrusiveRefCntPtr opts = + // new clang::DiagnosticOptions; + // clang::DiagnosticsEngine diags( + // new clang::DiagnosticIDs, opts, + // new clang::TextDiagnosticPrinter(llvm::errs(), opts.get())); - if (!compilation) { - llvm::errs() << "can't create the compilation!\n"; + // clang::driver::Driver d("clang", ctx.targetTriple, diags, + // "Serene compiler"); + // std::vector args = {"serenec"}; + + // args.push_back(destObjFilePath.c_str()); + // args.push_back("-o"); + // args.push_back(destFile.c_str()); + + // d.setCheckInputsExist(true); + + // std::unique_ptr compilation; + // compilation.reset(d.BuildCompilation(args)); + + // if (!compilation) { + // llvm::errs() << "can't create the compilation!\n"; + // return 1; + // } + + // llvm::SmallVector> + // failCommand; + + // d.ExecuteCompilation(*compilation, failCommand); + + // if (failCommand.empty()) { + // llvm::outs() << "Done!\n"; + // } else { + // llvm::errs() << "Linking failed!\n"; + // failCommand.front().second->Print(llvm::errs(), "\n", false); + // } + // } + + return 0; + }; + + int main(int argc, char *argv[]) { + initCompiler(); + registerSereneCLOptions(); + + cl::ParseCommandLineOptions(argc, argv, banner); + + auto ctx = makeSereneContext(); + auto userNS = makeNamespace(*ctx, "user", llvm::None); + + applySereneCLOptions(*ctx); + + // 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 '-b'?\n"; return 1; } - llvm::SmallVector> - failCommand; + switch (emitAction) { - d.ExecuteCompilation(*compilation, failCommand); + case Action::RunJIT: { + // TODO: Replace it by a proper jit configuration + ctx->setOperationPhase(CompilationPhase::NoOptimization); + break; + }; - if (failCommand.empty()) { - llvm::outs() << "Done!\n"; - } else { - llvm::errs() << "Linking failed!\n"; - failCommand.front().second->Print(llvm::errs(), "\n", false); + // Just print out the raw AST + case Action::DumpAST: { + ctx->setOperationPhase(CompilationPhase::Parse); + break; + }; + + case Action::DumpSemantic: { + ctx->setOperationPhase(CompilationPhase::Analysis); + break; + }; + + case Action::DumpSLIR: { + ctx->setOperationPhase(CompilationPhase::SLIR); + break; } - } - return 0; -}; + case Action::DumpMLIR: { + ctx->setOperationPhase(CompilationPhase::MLIR); + break; + } -int main(int argc, char *argv[]) { - initCompiler(); - registerSereneCLOptions(); + case Action::DumpLIR: { + ctx->setOperationPhase(CompilationPhase::LIR); + break; + } - cl::ParseCommandLineOptions(argc, argv, banner); + case Action::DumpIR: { + ctx->setOperationPhase(CompilationPhase::IR); + break; + } - auto ctx = makeSereneContext(); - auto userNS = makeNamespace(*ctx, "user", llvm::None); + case Action::CompileToObject: { + ctx->setOperationPhase(CompilationPhase::NoOptimization); + break; + } - applySereneCLOptions(*ctx); + case Action::Compile: { + ctx->setOperationPhase(CompilationPhase::NoOptimization); + break; + } - // 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 '-b'?\n"; - return 1; - } + default: { + llvm::errs() << "No action specified. TODO: Print out help here\n"; + return 1; + } + } - switch (emitAction) { + auto runLoc = reader::LocationRange::UnknownLocation(inputNS); + auto maybeNS = ctx->sourceManager.readNamespace(*ctx, inputNS, runLoc); - case Action::RunJIT: { - // TODO: Replace it by a proper jit configuration - ctx->setOperationPhase(CompilationPhase::NoOptimization); - break; - }; + if (!maybeNS) { + throwErrors(*ctx, maybeNS.getError()); + return (int)std::errc::no_such_file_or_directory; + } - // Just print out the raw AST - case Action::DumpAST: { - ctx->setOperationPhase(CompilationPhase::Parse); - break; - }; + auto ns = maybeNS.getValue(); - case Action::DumpSemantic: { - ctx->setOperationPhase(CompilationPhase::Analysis); - break; - }; + ctx->insertNS(ns); - case Action::DumpSLIR: { - ctx->setOperationPhase(CompilationPhase::SLIR); - break; - } + switch (emitAction) { + case Action::DumpAST: + case Action::DumpSemantic: { + auto ast = ns->getTree(); + llvm::outs() << exprs::astToString(&ast) << "\n"; + return 0; + } - case Action::DumpMLIR: { - ctx->setOperationPhase(CompilationPhase::MLIR); - break; - } + case Action::DumpSLIR: + case Action::DumpMLIR: + case Action::DumpLIR: { + ns->dump(); + break; + }; + case Action::DumpIR: { + auto maybeModule = ns->compileToLLVM(); - case Action::DumpLIR: { - ctx->setOperationPhase(CompilationPhase::LIR); - break; - } + if (!maybeModule) { + llvm::errs() << "Failed to generate the IR.\n"; + return 1; + } - case Action::DumpIR: { - ctx->setOperationPhase(CompilationPhase::IR); - break; - } + maybeModule.getValue()->dump(); + break; + }; - case Action::CompileToObject: { - ctx->setOperationPhase(CompilationPhase::NoOptimization); - break; - } + case Action::RunJIT: { + auto maybeJIT = JIT::make(*ns); + if (!maybeJIT) { + // TODO: panic in here: "Couldn't creat the JIT!" + return -1; + } + auto jit = std::move(maybeJIT.getValue()); - case Action::Compile: { - ctx->setOperationPhase(CompilationPhase::NoOptimization); - break; - } + if (jit->invoke("main")) { + llvm::errs() << "Faild to invoke the 'main' function.\n"; + return 1; + } + llvm::outs() << "Done!"; + break; + }; - default: { - llvm::errs() << "No action specified. TODO: Print out help here\n"; - return 1; - } - } + case Action::Compile: + case Action::CompileToObject: { + return dumpAsObject(*ns); + }; + default: { + llvm::errs() << "Action is not supported yet!\n"; + }; + } - auto runLoc = reader::LocationRange::UnknownLocation(inputNS); - auto maybeNS = ctx->sourceManager.readNamespace(*ctx, inputNS, runLoc); - - if (!maybeNS) { - throwErrors(*ctx, maybeNS.getError()); - return (int)std::errc::no_such_file_or_directory; - } - - auto ns = maybeNS.getValue(); - - ctx->insertNS(ns); - - switch (emitAction) { - case Action::DumpAST: - case Action::DumpSemantic: { - auto ast = ns->getTree(); - llvm::outs() << exprs::astToString(&ast) << "\n"; return 0; } - - case Action::DumpSLIR: - case Action::DumpMLIR: - case Action::DumpLIR: { - ns->dump(); - break; - }; - case Action::DumpIR: { - auto maybeModule = ns->compileToLLVM(); - - if (!maybeModule) { - llvm::errs() << "Failed to generate the IR.\n"; - return 1; - } - - maybeModule.getValue()->dump(); - break; - }; - - case Action::RunJIT: { - auto maybeJIT = JIT::make(*ns); - if (!maybeJIT) { - // TODO: panic in here: "Couldn't creat the JIT!" - return -1; - } - auto jit = std::move(maybeJIT.getValue()); - - if (jit->invoke("main")) { - llvm::errs() << "Faild to invoke the 'main' function.\n"; - return 1; - } - llvm::outs() << "Done!"; - break; - }; - - case Action::Compile: - case Action::CompileToObject: { - return dumpAsObject(*ns); - }; - default: { - llvm::errs() << "Action is not supported yet!\n"; - }; - } - - return 0; -}