Move over SereneContext and remove the old bits

This commit is contained in:
Sameer Rahmani 2022-06-13 22:18:58 +01:00
parent c0ad467c87
commit c42ad11bd0
10 changed files with 461 additions and 24 deletions

View File

@ -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:

View File

@ -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)

View File

@ -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)

View File

@ -0,0 +1,142 @@
/* -*- C++ -*-
* Serene Programming Language
*
* Copyright (c) 2019-2022 Sameer Rahmani <lxsameer@gnu.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef SERENE_CONTEXT_H
#define SERENE_CONTEXT_H
#include "serene/export.h" // for SERENE_EXPORT
#include "serene/source_mgr.h" // for SourceMgr
#include <llvm/ADT/Triple.h> // for Triple
#include <llvm/ADT/Twine.h> // for Twine
#include <llvm/IR/LLVMContext.h> // for LLVMContext
#include <llvm/Support/Host.h> // for getDefaultTargetTriple
#include <functional> // for function
#include <memory> // 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 <typename T>
using CurrentNSFn = std::function<T()>;
/// 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<llvm::LLVMContext> genLLVMContext() {
return std::make_unique<llvm::LLVMContext>();
};
// 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<llvm::SmallVector<llvm::orc::JITDylib *, 1>> 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<SereneContext>
makeSereneContext(Options opts = Options());
} // namespace serene
#endif

View File

@ -0,0 +1,182 @@
/* -*- C++ -*-
* Serene Programming Language
*
* Copyright (c) 2019-2022 Sameer Rahmani <lxsameer@gnu.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef SERENE_SOURCE_MGR_H
#define SERENE_SOURCE_MGR_H
#include "serene/export.h"
#include <llvm/ADT/SmallVector.h>
#include <llvm/ADT/StringMap.h>
#include <llvm/Support/ErrorHandling.h>
#include <llvm/Support/ErrorOr.h>
#include <llvm/Support/MemoryBuffer.h>
#include <llvm/Support/SourceMgr.h>
#include <mlir/IR/Diagnostics.h>
#include <mlir/Support/Timing.h>
#include <memory>
#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<llvm::MemoryBuffer> 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 <typename T>
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 <typename T>
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<llvm::MemoryBuffer>;
/// This is all of the buffers that we are reading from.
std::vector<SrcBuffer> buffers;
/// A hashtable that works as an index from namespace names to the buffer
/// position it the `buffer`
llvm::StringMap<unsigned> nsTable;
// This is the list of directories we should search for include files in.
std::vector<std::string> 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<std::string> &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<llvm::MemoryBuffer> f,
reader::LocationRange includeLoc);
};
}; // namespace serene
#endif

View File

@ -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 "$<$<NOT:$<BOOL:${BUILD_SHARED_LIBS}>>:SERENE_STATIC_DEFINE>")
# target_link_libraries(serene PRIVATE
# ${llvm_libs})
target_link_libraries(serene PRIVATE
${llvm_libs})

99
libserene/lib/context.cpp Normal file
View File

@ -0,0 +1,99 @@
/* -*- C++ -*-
* Serene Programming Language
*
* Copyright (c) 2019-2022 Sameer Rahmani <lxsameer@gnu.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "serene/context.h"
#include <cstdlib> // 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<llvm::orc::JITDylib *, 1> 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<SereneContext> makeSereneContext(Options opts) {
return std::make_unique<SereneContext>(opts);
};
}; // namespace serene

View File

@ -23,14 +23,16 @@
* instances.
*/
#include "serene/errors-backend.h"
#include "serene/errors-backend.h" // for emitErrors
#include <llvm/Support/CommandLine.h>
#include <llvm/Support/InitLLVM.h>
#include <llvm/Support/raw_ostream.h>
#include <llvm/TableGen/Main.h>
#include <llvm/TableGen/Record.h>
#include <llvm/TableGen/SetTheory.h>
#include <llvm/ADT/SmallVector.h> // for SmallVector
#include <llvm/ADT/StringRef.h> // for StringRef
#include <llvm/Support/CommandLine.h> // for opt, ParseCommandLineOptions
#include <llvm/Support/Compiler.h> // for LLVM_ATTRIBUTE_USED
#include <llvm/Support/InitLLVM.h> // for InitLLVM
#include <llvm/Support/raw_ostream.h> // for raw_ostream
#include <llvm/TableGen/Main.h> // for TableGenMain
#include <llvm/TableGen/Record.h> // 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 <sanitizer/lsan_interface.h>
#include <sanitizer/lsan_interface.h> // 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; }

View File

@ -27,12 +27,18 @@
// The "serene/" part is due to a convention that we use in the project
#include "serene/errors-backend.h"
#include <llvm/Support/Casting.h>
#include <llvm/Support/Format.h>
#include <llvm/Support/LineIterator.h>
#include <llvm/Support/MemoryBufferRef.h>
#include <llvm/TableGen/Error.h>
#include <llvm/TableGen/Record.h>
#include <llvm/ADT/StringRef.h> // for StringRef
#include <llvm/ADT/Twine.h> // for operator+
#include <llvm/Support/Casting.h> // for dyn_cast
#include <llvm/Support/LineIterator.h> // for line_iterator
#include <llvm/Support/MemoryBufferRef.h> // for MemoryBufferRef
#include <llvm/Support/raw_ostream.h> // for raw_ostream
#include <llvm/TableGen/Error.h> // for PrintError
#include <llvm/TableGen/Record.h> // for ListInit, Record, RecordK...
#include <llvm/TableGen/TableGenBackend.h> // for emitSourceFileHeader
#include <functional> // for function
#include <stddef.h> // for size_t
#define DEBUG_TYPE "errors-backend"
#define INSTANCE_SUFFIX "Instance"

View File

@ -16,8 +16,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <llvm/TableGen/Record.h>
#include <llvm/TableGen/TableGenBackend.h>
namespace llvm {
class RecordKeeper;
class raw_ostream;
} // namespace llvm
#define DEBUG_TYPE "errors-backend"