Compare commits

...

2 Commits
master ... ep13

4 changed files with 170 additions and 146 deletions

View File

@ -509,7 +509,8 @@ This framework allows for transforming a set of illegal operations to a set of l
*** Rewrite Patterns *** Rewrite Patterns
*** Type Converter *** Type Converter
** Full vs Partial Conversion ** Full vs Partial Conversion
* Episode 12 - Target code generation * DONE Episode 12 - Target code generation
CLOSED: [2021-11-04 Thu 00:57]
** Updates: ** Updates:
*** JIT work *** JIT work
*** Emacs dev mode *** Emacs dev mode
@ -561,3 +562,23 @@ and tries to =resolve= *undefined* symbols
** Let's look at some code ** Let's look at some code
** Resources: ** Resources:
- [[https://lwn.net/Articles/276782/][20 part linker essay]] - [[https://lwn.net/Articles/276782/][20 part linker essay]]
* Episode 13 - Source Managers
** FAQ:
- What tools are you using?
** Updates:
- Still JIT
- We're going to start the JIT discussion from next EP
** Forgot to show case the code generation
I didn't show it in action
** What is a source manager
- It owns and manages are the source buffers
- All of our interactions with source files will happen though Source manager
- Including reading files
- Loading namespaces
- Including namespaces
- ...
- LLVM provides a =SourceMgr= class that we're not using it

View File

@ -42,7 +42,7 @@ class SereneContext;
/// This class is quite similar to the `llvm::SourceMgr` in functionality. We /// This class is quite similar to the `llvm::SourceMgr` in functionality. We
/// even borrowed some of the code from the original implementation but removed /// even borrowed some of the code from the original implementation but removed
/// a lot of code that ar irrelevant to us. /// a lot of code that were irrelevant to us.
/// ///
/// SouceMgr is responsible for finding a namespace in the `loadPaths` and read /// 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 /// the content of the `.srn` (or any of the `DEFAULT_SUFFIX`) into a
@ -80,7 +80,7 @@ private:
/// dynamically based on the size of Buffer. /// dynamically based on the size of Buffer.
mutable void *offsetCache = nullptr; mutable void *offsetCache = nullptr;
/// Look up a given \p Ptr in in the buffer, determining which line it came /// Look up a given \p ptr in in the buffer, determining which line it came
/// from. /// from.
unsigned getLineNumber(const char *ptr) const; unsigned getLineNumber(const char *ptr) const;
template <typename T> template <typename T>
@ -103,7 +103,7 @@ private:
SrcBuffer &operator=(const SrcBuffer &) = delete; SrcBuffer &operator=(const SrcBuffer &) = delete;
~SrcBuffer(); ~SrcBuffer();
}; };
using ErrorOrMemBufPtr = llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>; using MemBufPtr = std::unique_ptr<llvm::MemoryBuffer>;
/// This is all of the buffers that we are reading from. /// This is all of the buffers that we are reading from.
std::vector<SrcBuffer> buffers; std::vector<SrcBuffer> buffers;
@ -119,8 +119,8 @@ private:
// a unique pointer to the memory buffer containing the content or an error. // 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 // In the success case it will put the path of the file into the \p
// importedFile. // importedFile.
ErrorOrMemBufPtr findFileInLoadPath(const std::string &name, MemBufPtr findFileInLoadPath(const std::string &name,
std::string &importedFile); std::string &importedFile);
bool isValidBufferID(unsigned i) const; bool isValidBufferID(unsigned i) const;
@ -138,7 +138,7 @@ public:
/// Set the `loadPaths` to the given \p dirs. `loadPaths` is a vector of /// 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 /// directories that Serene will look in order to find a file that constains a
/// namespace which it is looking for. /// namespace which it is looking for.
void setLoadPaths(const std::vector<std::string> &dirs) { loadPaths = dirs; } void setLoadPaths(std::vector<std::string> &dirs) { loadPaths.swap(dirs); }
/// Return a reference to a `SrcBuffer` with the given ID \p i. /// Return a reference to a `SrcBuffer` with the given ID \p i.
const SrcBuffer &getBufferInfo(unsigned i) const { const SrcBuffer &getBufferInfo(unsigned i) const {

View File

@ -28,15 +28,16 @@
#include "serene/namespace.h" #include "serene/namespace.h"
#include "serene/reader/location.h" #include "serene/reader/location.h"
#include "serene/reader/reader.h" #include "serene/reader/reader.h"
#include "serene/reader/semantics.h"
#include "serene/utils.h" #include "serene/utils.h"
#include <system_error> #include <system_error>
#include <llvm/Support/Error.h>
#include <llvm/Support/FormatVariadic.h> #include <llvm/Support/FormatVariadic.h>
#include <llvm/Support/Locale.h> #include <llvm/Support/Locale.h>
#include <llvm/Support/MemoryBufferRef.h> #include <llvm/Support/MemoryBufferRef.h>
#include <llvm/Support/Path.h> #include <llvm/Support/Path.h>
#include <llvm/Support/raw_ostream.h>
#include <mlir/Support/LogicalResult.h> #include <mlir/Support/LogicalResult.h>
namespace serene { namespace serene {
@ -55,27 +56,30 @@ bool SourceMgr::isValidBufferID(unsigned i) const {
return i != 0 && i <= buffers.size(); return i != 0 && i <= buffers.size();
}; };
SourceMgr::ErrorOrMemBufPtr SourceMgr::MemBufPtr SourceMgr::findFileInLoadPath(const std::string &name,
SourceMgr::findFileInLoadPath(const std::string &name, std::string &importedFile) {
std::string &importedFile) {
auto path = convertNamespaceToPath(name); auto path = convertNamespaceToPath(name);
// TODO: Fix this to enqueue a proper error instead
ErrorOrMemBufPtr newBufOrErr(
std::make_error_code(std::errc::no_such_file_or_directory));
// If the file didn't exist directly, see if it's in an include path. // If the file didn't exist directly, see if it's in an include path.
for (unsigned i = 0, e = loadPaths.size(); i != e && !newBufOrErr; ++i) { for (unsigned i = 0, e = loadPaths.size(); i != e; ++i) {
// TODO: Ugh, Udgly, fix this using llvm::sys::path functions // TODO: Ugh, Udgly, fix this using llvm::sys::path functions
importedFile = loadPaths[i] + llvm::sys::path::get_separator().data() + importedFile = loadPaths[i] + llvm::sys::path::get_separator().data() +
path + "." + DEFAULT_SUFFIX; path + "." + DEFAULT_SUFFIX;
SMGR_LOG("Try to load the ns from: " + importedFile); SMGR_LOG("Try to load the ns from: " + importedFile);
newBufOrErr = llvm::MemoryBuffer::getFile(importedFile); auto newBufOrErr = llvm::MemoryBuffer::getFile(importedFile);
if (auto err = newBufOrErr.getError()) {
llvm::consumeError(llvm::errorCodeToError(err));
continue;
}
return std::move(*newBufOrErr);
} }
return newBufOrErr; return nullptr;
}; };
MaybeNS SourceMgr::readNamespace(SereneContext &ctx, std::string name, MaybeNS SourceMgr::readNamespace(SereneContext &ctx, std::string name,
@ -83,16 +87,16 @@ MaybeNS SourceMgr::readNamespace(SereneContext &ctx, std::string name,
std::string importedFile; std::string importedFile;
SMGR_LOG("Attempt to load namespace: " + name); SMGR_LOG("Attempt to load namespace: " + name);
ErrorOrMemBufPtr newBufOrErr(findFileInLoadPath(name, importedFile)); MemBufPtr newBufOrErr(findFileInLoadPath(name, importedFile));
if (!newBufOrErr) { if (newBufOrErr == nullptr) {
auto msg = llvm::formatv("Couldn't find namespace '{0}'", name); auto msg = llvm::formatv("Couldn't find namespace '{0}'", name);
auto err = errors::makeErrorTree(importLoc, errors::NSLoadError, auto err = errors::makeErrorTree(importLoc, errors::NSLoadError,
llvm::StringRef(msg)); llvm::StringRef(msg));
return MaybeNS::error(err); return MaybeNS::error(err);
} }
auto bufferId = AddNewSourceBuffer(std::move(*newBufOrErr), importLoc); auto bufferId = AddNewSourceBuffer(std::move(newBufOrErr), importLoc);
UNUSED(nsTable.insert_or_assign(name, bufferId)); UNUSED(nsTable.insert_or_assign(name, bufferId));

View File

@ -249,147 +249,146 @@ int dumpAsObject(Namespace &ns) {
// failCommand.front().second->Print(llvm::errs(), "\n", false); // failCommand.front().second->Print(llvm::errs(), "\n", false);
// } // }
// } // }
}
return 0;
};
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;
}
switch (emitAction) {
case Action::RunJIT: {
// TODO: Replace it by a proper jit configuration
ctx->setOperationPhase(CompilationPhase::NoOptimization);
break;
}; };
int main(int argc, char *argv[]) { // Just print out the raw AST
initCompiler(); case Action::DumpAST: {
registerSereneCLOptions(); ctx->setOperationPhase(CompilationPhase::Parse);
break;
};
cl::ParseCommandLineOptions(argc, argv, banner); case Action::DumpSemantic: {
ctx->setOperationPhase(CompilationPhase::Analysis);
break;
};
auto ctx = makeSereneContext(); case Action::DumpSLIR: {
auto userNS = makeNamespace(*ctx, "user", llvm::None); ctx->setOperationPhase(CompilationPhase::SLIR);
break;
}
applySereneCLOptions(*ctx); case Action::DumpMLIR: {
ctx->setOperationPhase(CompilationPhase::MLIR);
break;
}
// TODO: handle the outputDir by not forcing it. it should be case Action::DumpLIR: {
// default to the current working dir ctx->setOperationPhase(CompilationPhase::LIR);
if (outputDir == "-") { break;
llvm::errs() }
<< "Error: The build directory is not set. Did you forget to "
"use '-b'?\n";
return 1;
}
switch (emitAction) { case Action::DumpIR: {
ctx->setOperationPhase(CompilationPhase::IR);
break;
}
case Action::RunJIT: { case Action::CompileToObject: {
// TODO: Replace it by a proper jit configuration ctx->setOperationPhase(CompilationPhase::NoOptimization);
ctx->setOperationPhase(CompilationPhase::NoOptimization); break;
break; }
};
// Just print out the raw AST case Action::Compile: {
case Action::DumpAST: { ctx->setOperationPhase(CompilationPhase::NoOptimization);
ctx->setOperationPhase(CompilationPhase::Parse); break;
break; }
};
case Action::DumpSemantic: { default: {
ctx->setOperationPhase(CompilationPhase::Analysis); llvm::errs() << "No action specified. TODO: Print out help here\n";
break; return 1;
}; }
}
case Action::DumpSLIR: { auto runLoc = reader::LocationRange::UnknownLocation(inputNS);
ctx->setOperationPhase(CompilationPhase::SLIR); auto maybeNS = ctx->sourceManager.readNamespace(*ctx, inputNS, runLoc);
break;
}
case Action::DumpMLIR: { if (!maybeNS) {
ctx->setOperationPhase(CompilationPhase::MLIR); throwErrors(*ctx, maybeNS.getError());
break; return (int)std::errc::no_such_file_or_directory;
} }
case Action::DumpLIR: { auto ns = maybeNS.getValue();
ctx->setOperationPhase(CompilationPhase::LIR);
break;
}
case Action::DumpIR: { ctx->insertNS(ns);
ctx->setOperationPhase(CompilationPhase::IR);
break;
}
case Action::CompileToObject: {
ctx->setOperationPhase(CompilationPhase::NoOptimization);
break;
}
case Action::Compile: {
ctx->setOperationPhase(CompilationPhase::NoOptimization);
break;
}
default: {
llvm::errs() << "No action specified. TODO: Print out help here\n";
return 1;
}
}
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";
};
}
switch (emitAction) {
case Action::DumpAST:
case Action::DumpSemantic: {
auto ast = ns->getTree();
llvm::outs() << exprs::astToString(&ast) << "\n";
return 0; 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;
}