From c42ad11bd03a48d6b001a3cb662f6a991e920684 Mon Sep 17 00:00:00 2001 From: Sameer Rahmani Date: Mon, 13 Jun 2022 22:18:58 +0100 Subject: [PATCH] Move over SereneContext and remove the old bits --- .pre-commit-config.yaml | 2 +- CMakeLists.txt | 2 + core/lib/CMakeLists.txt | 4 +- libserene/include/serene/context.h | 142 ++++++++++++++++++ libserene/include/serene/source_mgr.h | 182 ++++++++++++++++++++++++ libserene/lib/CMakeLists.txt | 11 +- libserene/lib/context.cpp | 99 +++++++++++++ serene-tblgen/main.cpp | 19 +-- serene-tblgen/serene/errors-backend.cpp | 18 ++- serene-tblgen/serene/errors-backend.h | 6 +- 10 files changed, 461 insertions(+), 24 deletions(-) create mode 100644 libserene/include/serene/context.h create mode 100644 libserene/include/serene/source_mgr.h create mode 100644 libserene/lib/context.cpp diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 608fd69..2c9c098 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -30,9 +30,9 @@ repos: rev: v1.3.5 hooks: - id: clang-format + args: ['-i'] - id: cppcheck args: ['--project=compile_commands.json'] - - id: include-what-you-use - repo: https://github.com/detailyang/pre-commit-shell rev: 1.0.5 hooks: diff --git a/CMakeLists.txt b/CMakeLists.txt index 2d27332..2fce99b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,6 +65,8 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) find_program(CLANG_TIDY_PATH NAMES clang-tidy REQUIRED) endif() + find_program(iwyu NAMES include-what-you-use iwyu REQUIRED) + set(iwyu_path ${iwyu}) # Let's ensure -std=c++xx instead of -std=g++xx set(CMAKE_CXX_EXTENSIONS OFF) diff --git a/core/lib/CMakeLists.txt b/core/lib/CMakeLists.txt index 3c41559..50763c4 100644 --- a/core/lib/CMakeLists.txt +++ b/core/lib/CMakeLists.txt @@ -37,8 +37,8 @@ set_target_properties(core PROPERTIES CMAKE_PKG_NAME SereneCore # Warn on unused libs LINK_WHAT_YOU_USE TRUE - CXX_INCLUDE_WHAT_YOU_USE "include-what-you-use" - + CXX_INCLUDE_WHAT_YOU_USE "${iwyu_path}" + C_INCLUDE_WHAT_YOU_USE "${iwyu_path}" # LTO support INTERPROCEDURAL_OPTIMIZATION TRUE) diff --git a/libserene/include/serene/context.h b/libserene/include/serene/context.h new file mode 100644 index 0000000..e675d78 --- /dev/null +++ b/libserene/include/serene/context.h @@ -0,0 +1,142 @@ +/* -*- C++ -*- + * Serene Programming Language + * + * Copyright (c) 2019-2022 Sameer Rahmani + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef SERENE_CONTEXT_H +#define SERENE_CONTEXT_H + +#include "serene/export.h" // for SERENE_EXPORT +#include "serene/source_mgr.h" // for SourceMgr + +#include // for Triple +#include // for Twine +#include // for LLVMContext +#include // for getDefaultTargetTriple + +#include // for function +#include // for make_unique, unique_ptr + +#define DEFAULT_NS_NAME "serene.user" +#define INTERNAL_NS "serene.internal" + +namespace serene { +class SereneContext; + +/// This enum describes the different operational phases for the compiler +/// in order. Anything below `NoOptimization` is considered only for debugging +enum class CompilationPhase { + Parse, + Analysis, + SLIR, + MLIR, // Lowered slir to other dialects + LIR, // Lowered to the llvm ir dialect + IR, // Lowered to the LLVMIR itself + NoOptimization, + O1, + O2, + O3, +}; + +/// Terminates the serene compiler process in a thread safe manner +/// This function is only meant to be used in the compiler context +/// if you want to terminate the process in context of a serene program +/// via the JIT use an appropriate function in the `serene.core` ns. +SERENE_EXPORT void terminate(SereneContext &ctx, int exitCode); + +/// Options describes the compiler options that can be passed to the +/// compiler via command line. Anything that user should be able to +/// tweak about the compiler has to end up here regardless of the +/// different subsystem that might use it. +struct SERENE_EXPORT Options { + + /// Whether to use colors for the output or not + bool withColors = true; + + // JIT related flags + bool JITenableObjectCache = true; + bool JITenableGDBNotificationListener = true; + bool JITenablePerfNotificationListener = true; + bool JITLazy = false; + + Options() = default; +}; + +class SERENE_EXPORT SereneContext { + +public: + template + using CurrentNSFn = std::function; + + /// The source manager is responsible for loading files and practically + /// managing the source code in form of memory buffers. + SourceMgr sourceManager; + + /// The set of options to change the compilers behaivoirs + Options opts; + + const llvm::Triple triple; + + explicit SereneContext(Options &options) + : opts(options), triple(llvm::sys::getDefaultTargetTriple()), + targetPhase(CompilationPhase::NoOptimization){}; + + /// Set the target compilation phase of the compiler. The compilation + /// phase dictates the behavior and the output type of the compiler. + void setOperationPhase(CompilationPhase phase); + + CompilationPhase getTargetPhase() { return targetPhase; }; + int getOptimizatioLevel(); + + static std::unique_ptr genLLVMContext() { + return std::make_unique(); + }; + + // JIT JITDylib related functions --- + + // TODO: For Dylib related functions, make sure that the namespace in questoin + // is aleady registered in the context + + /// Return a pointer to the most registered JITDylib of the given \p ns + ////name + // llvm::orc::JITDylib *getLatestJITDylib(Namespace &ns); + + // /// Register the given pointer to a `JITDylib` \p l, with the give \p ns. + // void pushJITDylib(Namespace &ns, llvm::orc::JITDylib *l); + + // /// Returns the number of registered `JITDylib` for the given \p ns. + // size_t getNumberOfJITDylibs(Namespace &ns); + +private: + CompilationPhase targetPhase; + + /// A vector of pointers to all the jitDylibs for namespaces. Usually + /// There will be only one pre NS but in case of forceful reloads of a + /// namespace there will be more. + // llvm::StringMap> jitDylibs; +}; + +/// Creates a new context object. Contexts are used through out the compilation +/// process to store the state. +/// +/// \p opts is an instance of \c Options that can be used to set options of +/// of the compiler. +SERENE_EXPORT std::unique_ptr +makeSereneContext(Options opts = Options()); + +} // namespace serene + +#endif diff --git a/libserene/include/serene/source_mgr.h b/libserene/include/serene/source_mgr.h new file mode 100644 index 0000000..9aa14d6 --- /dev/null +++ b/libserene/include/serene/source_mgr.h @@ -0,0 +1,182 @@ +/* -*- C++ -*- + * Serene Programming Language + * + * Copyright (c) 2019-2022 Sameer Rahmani + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef SERENE_SOURCE_MGR_H +#define SERENE_SOURCE_MGR_H + +#include "serene/export.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define SMGR_LOG(...) \ + DEBUG_WITH_TYPE("sourcemgr", llvm::dbgs() \ + << "[SMGR]: " << __VA_ARGS__ << "\n"); + +namespace serene { +namespace reader { +class LocationRange; +} // namespace reader + +class SereneContext; + +/// This class is quite similar to the `llvm::SourceMgr` in functionality. We +/// even borrowed some of the code from the original implementation but removed +/// a lot of code that were irrelevant to us. +/// +/// SouceMgr is responsible for finding a namespace in the `loadPaths` and read +/// the content of the `.srn` (or any of the `DEFAULT_SUFFIX`) into a +/// `llvm::MemoryBuffer` embedded in a `SrcBuffer` object as the owner of the +/// source files and then it will call the `reader` on the buffer to parse it +/// and create the actual `Namespace` object from the parsed AST. +/// +/// Later on, whenever we need to refer to the source file of a namespace for +/// diagnosis purposes or any other purpose we can use the functions in this +/// class to get hold of a pointer to a specific `reader::Location` of the +/// buffer. +/// +/// Note: Unlike the original version, SourceMgr does not handle the diagnostics +/// and it uses the Serene's `DiagnosticEngine` for that matter. +class SERENE_EXPORT SourceMgr { + +public: + // TODO: Make it a vector of supported suffixes + std::string DEFAULT_SUFFIX = "srn"; + +private: + struct SrcBuffer { + /// The memory buffer for the file. + std::unique_ptr buffer; + + /// Vector of offsets into Buffer at which there are line-endings + /// (lazily populated). Once populated, the '\n' that marks the end of + /// line number N from [1..] is at Buffer[OffsetCache[N-1]]. Since + /// these offsets are in sorted (ascending) order, they can be + /// binary-searched for the first one after any given offset (eg. an + /// offset corresponding to a particular SMLoc). + /// + /// Since we're storing offsets into relatively small files (often smaller + /// than 2^8 or 2^16 bytes), we select the offset vector element type + /// dynamically based on the size of Buffer. + mutable void *offsetCache = nullptr; + + /// Look up a given \p ptr in in the buffer, determining which line it came + /// from. + unsigned getLineNumber(const char *ptr) const; + template + unsigned getLineNumberSpecialized(const char *ptr) const; + + /// Return a pointer to the first character of the specified line number or + /// null if the line number is invalid. + const char *getPointerForLineNumber(unsigned lineNo) const; + + template + const char *getPointerForLineNumberSpecialized(unsigned lineNo) const; + + /// This is the location of the parent import or unknown location if it is + /// the main namespace + // reader::LocationRange importLoc; + + SrcBuffer() = default; + SrcBuffer(SrcBuffer &&) noexcept; + SrcBuffer(const SrcBuffer &) = delete; + SrcBuffer &operator=(const SrcBuffer &) = delete; + ~SrcBuffer(); + }; + using MemBufPtr = std::unique_ptr; + + /// This is all of the buffers that we are reading from. + std::vector buffers; + + /// A hashtable that works as an index from namespace names to the buffer + /// position it the `buffer` + llvm::StringMap nsTable; + + // This is the list of directories we should search for include files in. + std::vector loadPaths; + + // Find a namespace file with the given \p name in the load path and \r retuns + // a unique pointer to the memory buffer containing the content or an error. + // In the success case it will put the path of the file into the \p + // importedFile. + MemBufPtr findFileInLoadPath(const std::string &name, + std::string &importedFile); + + bool isValidBufferID(unsigned i) const; + + /// Converts the ns name to a partial path by replacing the dots with slashes + static std::string convertNamespaceToPath(std::string ns_name); + +public: + SourceMgr() = default; + SourceMgr(const SourceMgr &) = delete; + SourceMgr &operator=(const SourceMgr &) = delete; + SourceMgr(SourceMgr &&) = default; + SourceMgr &operator=(SourceMgr &&) = default; + ~SourceMgr() = default; + + /// Set the `loadPaths` to the given \p dirs. `loadPaths` is a vector of + /// directories that Serene will look in order to find a file that constains a + /// namespace which it is looking for. + void setLoadPaths(std::vector &dirs) { loadPaths.swap(dirs); } + + /// Return a reference to a `SrcBuffer` with the given ID \p i. + const SrcBuffer &getBufferInfo(unsigned i) const { + assert(isValidBufferID(i)); + return buffers[i - 1]; + } + + /// Return a reference to a `SrcBuffer` with the given namspace name \p ns. + const SrcBuffer &getBufferInfo(llvm::StringRef ns) const { + auto bufferId = nsTable.lookup(ns); + + if (bufferId == 0) { + // No such namespace + llvm_unreachable("couldn't find the src buffer for a namespace. It " + "should never happen."); + } + + return buffers[bufferId - 1]; + } + + /// Return a pointer to the internal `llvm::MemoryBuffer` of the `SrcBuffer` + /// with the given ID \p i. + const llvm::MemoryBuffer *getMemoryBuffer(unsigned i) const { + assert(isValidBufferID(i)); + return buffers[i - 1].buffer.get(); + } + + unsigned getNumBuffers() const { return buffers.size(); } + + /// Add a new source buffer to this source manager. This takes ownership of + /// the memory buffer. + unsigned AddNewSourceBuffer(std::unique_ptr f, + reader::LocationRange includeLoc); +}; + +}; // namespace serene + +#endif diff --git a/libserene/lib/CMakeLists.txt b/libserene/lib/CMakeLists.txt index 7a77f12..847e61f 100644 --- a/libserene/lib/CMakeLists.txt +++ b/libserene/lib/CMakeLists.txt @@ -23,7 +23,8 @@ if(NOT APPLE) endif() add_library(serene - serene.cpp) + serene.cpp + context.cpp) # Create an ALIAS target. This way if we mess up the name # there will be an cmake error inseat of a linker error which is harder @@ -36,8 +37,8 @@ set_target_properties(serene PROPERTIES SOVERSION ${PROJECT_VERSION_MAJOR} # Warn on unused libs LINK_WHAT_YOU_USE TRUE - CXX_INCLUDE_WHAT_YOU_USE "include-what-you-use" - C_INCLUDE_WHAT_YOU_USE "include-what-you-use" + CXX_INCLUDE_WHAT_YOU_USE "${iwyu_path}" + C_INCLUDE_WHAT_YOU_USE "${iwyu_path}" # LTO support INTERPROCEDURAL_OPTIMIZATION TRUE) @@ -84,5 +85,5 @@ target_compile_definitions( serene PUBLIC "$<$>:SERENE_STATIC_DEFINE>") -# target_link_libraries(serene PRIVATE -# ${llvm_libs}) +target_link_libraries(serene PRIVATE + ${llvm_libs}) diff --git a/libserene/lib/context.cpp b/libserene/lib/context.cpp new file mode 100644 index 0000000..50be8b4 --- /dev/null +++ b/libserene/lib/context.cpp @@ -0,0 +1,99 @@ +/* -*- C++ -*- + * Serene Programming Language + * + * Copyright (c) 2019-2022 Sameer Rahmani + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "serene/context.h" + +#include // for exit + +namespace serene { + +// void SereneContext::setOperationPhase(CompilationPhase phase) { +// this->targetPhase = phase; + +// if (phase == CompilationPhase::SLIR) { +// return; +// } + +// if (phase >= CompilationPhase::MLIR) { +// pm.addPass(serene::passes::createSLIRLowerToMLIRPass()); +// } + +// if (phase >= CompilationPhase::LIR) { +// pm.addPass(serene::passes::createSLIRLowerToLLVMDialectPass()); +// } +// }; + +// int SereneContext::getOptimizatioLevel() { +// if (targetPhase <= CompilationPhase::NoOptimization) { +// return 0; +// } + +// if (targetPhase == CompilationPhase::O1) { +// return 1; +// } +// if (targetPhase == CompilationPhase::O2) { +// return 2; +// } +// return 3; +// } + +// llvm::orc::JITDylib *SereneContext::getLatestJITDylib(Namespace &ns) { + +// if (jitDylibs.count(ns.name) == 0) { +// return nullptr; +// } + +// auto vec = jitDylibs[ns.name]; +// // TODO: Make sure that the returning Dylib still exists in the JIT +// // by calling jit->engine->getJITDylibByName(dylib_name); +// return vec.empty() ? nullptr : vec.back(); +// }; + +// void SereneContext::pushJITDylib(Namespace &ns, llvm::orc::JITDylib *l) { +// if (jitDylibs.count(ns.name) == 0) { +// llvm::SmallVector vec{l}; +// jitDylibs[ns.name] = vec; +// return; +// } +// auto vec = jitDylibs[ns.name]; +// vec.push_back(l); +// jitDylibs[ns.name] = vec; +// } + +// size_t SereneContext::getNumberOfJITDylibs(Namespace &ns) { +// if (jitDylibs.count(ns.name) == 0) { +// return 0; +// } +// auto vec = jitDylibs[ns.name]; +// return vec.size(); +// }; + +void terminate(SereneContext &ctx, int exitCode) { + (void)ctx; + // TODO: Since we are running in a single thread for now using exit is fine + // but we need to adjust and change it to a thread safe termination + // process later on. + // NOLINTNEXTLINE(concurrency-mt-unsafe) + std::exit(exitCode); +} + +std::unique_ptr makeSereneContext(Options opts) { + return std::make_unique(opts); +}; + +}; // namespace serene diff --git a/serene-tblgen/main.cpp b/serene-tblgen/main.cpp index 91e518d..1a2f23e 100644 --- a/serene-tblgen/main.cpp +++ b/serene-tblgen/main.cpp @@ -23,14 +23,16 @@ * instances. */ -#include "serene/errors-backend.h" +#include "serene/errors-backend.h" // for emitErrors -#include -#include -#include -#include -#include -#include +#include // for SmallVector +#include // for StringRef +#include // for opt, ParseCommandLineOptions +#include // for LLVM_ATTRIBUTE_USED +#include // for InitLLVM +#include // for raw_ostream +#include // for TableGenMain +#include // for operator<<, RecordKeeper (ptr ... namespace cl = llvm::cl; @@ -73,7 +75,8 @@ int main(int argc, char **argv) { #if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) || \ __has_feature(leak_sanitizer) -#include +#include // for __lsan_is_turned_off + // Disable LeakSanitizer for this binary as it has too many leaks that are not // very interesting to fix. See compiler-rt/include/sanitizer/lsan_interface.h LLVM_ATTRIBUTE_USED int __lsan_is_turned_off() { return 1; } diff --git a/serene-tblgen/serene/errors-backend.cpp b/serene-tblgen/serene/errors-backend.cpp index 3df92ca..33762b3 100644 --- a/serene-tblgen/serene/errors-backend.cpp +++ b/serene-tblgen/serene/errors-backend.cpp @@ -27,12 +27,18 @@ // The "serene/" part is due to a convention that we use in the project #include "serene/errors-backend.h" -#include -#include -#include -#include -#include -#include +#include // for StringRef +#include // for operator+ +#include // for dyn_cast +#include // for line_iterator +#include // for MemoryBufferRef +#include // for raw_ostream +#include // for PrintError +#include // for ListInit, Record, RecordK... +#include // for emitSourceFileHeader + +#include // for function +#include // for size_t #define DEBUG_TYPE "errors-backend" #define INSTANCE_SUFFIX "Instance" diff --git a/serene-tblgen/serene/errors-backend.h b/serene-tblgen/serene/errors-backend.h index 0feebbb..f0ab54f 100644 --- a/serene-tblgen/serene/errors-backend.h +++ b/serene-tblgen/serene/errors-backend.h @@ -16,8 +16,10 @@ * along with this program. If not, see . */ -#include -#include +namespace llvm { +class RecordKeeper; +class raw_ostream; +} // namespace llvm #define DEBUG_TYPE "errors-backend"