Add Basic setup for lowering the llvm dialect to the LLVMIR
This commit is contained in:
parent
bd4dc2301c
commit
7f7f49d3ac
|
@ -132,6 +132,11 @@ int main(int argc, char *argv[]) {
|
|||
break;
|
||||
}
|
||||
|
||||
case Action::DumpIR: {
|
||||
ctx->setOperationPhase(CompilationPhase::IR);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
llvm::errs() << "No action specified. TODO: Print out help here\n";
|
||||
return 1;
|
||||
|
@ -143,6 +148,10 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
if (isSet.succeeded()) {
|
||||
ctx->insertNS(ns);
|
||||
if (mlir::failed(serene::slir::generate<Namespace>(*ns))) {
|
||||
llvm::errs() << "IR generation faild\n";
|
||||
return 1;
|
||||
}
|
||||
serene::slir::dump<Namespace>(*ns);
|
||||
} else {
|
||||
llvm::outs() << "Can't set the tree of the namespace!\n";
|
||||
|
|
4
dev.org
4
dev.org
|
@ -102,6 +102,9 @@ on ADF
|
|||
|
||||
* TODOs
|
||||
** Bootstrap
|
||||
*** TODO Replace =llvm::outs()= with debug statements
|
||||
*** TODO Error handling
|
||||
Create proper error handling for the internal infra
|
||||
*** TODO Language Spec :DOCS:
|
||||
*** TODO A proper List implementation
|
||||
*** TODO Vector implementation
|
||||
|
@ -120,7 +123,6 @@ on ADF
|
|||
*** TODO Enum implementation
|
||||
*** TODO Protocol
|
||||
*** TODO Struct implementation
|
||||
*** TODO Error handling
|
||||
*** TODO Multi arity functions
|
||||
*** TODO QuasiQuotation
|
||||
*** TODO Linter :Misc:
|
||||
|
|
|
@ -1 +1 @@
|
|||
4 80
|
||||
4
|
||||
|
|
|
@ -47,19 +47,24 @@ enum class CompilationPhase {
|
|||
MLIR, // Lowered slir to other dialects
|
||||
LIR, // Lowered to the llvm ir dialect
|
||||
IR, // Lowered to the LLVMIR itself
|
||||
O1
|
||||
NoOptimization,
|
||||
O1,
|
||||
O2,
|
||||
O3,
|
||||
};
|
||||
|
||||
class SereneContext {
|
||||
std::map<std::string, std::shared_ptr<Namespace>> namespaces;
|
||||
|
||||
// Why string vs pointer? We might rewrite the namespace and
|
||||
// holding a pointer means that it might point to the old version
|
||||
std::string current_ns;
|
||||
|
||||
public:
|
||||
// --------------------------------------------------------------------------
|
||||
// IMPORTANT:
|
||||
// These two contextes have to be the very first members of the class in
|
||||
// order to destroy last. DO NOT change the order or add anything before
|
||||
// them
|
||||
// --------------------------------------------------------------------------
|
||||
llvm::LLVMContext llvmContext;
|
||||
mlir::MLIRContext mlirContext;
|
||||
mlir::PassManager pm;
|
||||
|
||||
/// Insert the given `ns` into the context. The Context object is
|
||||
/// the owner of all the namespaces. The `ns` will overwrite any
|
||||
/// namespace with the same name.
|
||||
|
@ -74,11 +79,23 @@ public:
|
|||
|
||||
std::shared_ptr<Namespace> getNS(llvm::StringRef ns_name);
|
||||
|
||||
SereneContext() : pm(&mlirContext) {
|
||||
SereneContext()
|
||||
: pm(&mlirContext), targetPhase(CompilationPhase::NoOptimization) {
|
||||
mlirContext.getOrLoadDialect<serene::slir::SereneDialect>();
|
||||
pm.enableCrashReproducerGeneration("/home/lxsameer/mlir.mlir");
|
||||
};
|
||||
|
||||
void setOperationPhase(CompilationPhase phase);
|
||||
CompilationPhase getTargetPhase() { return targetPhase; };
|
||||
int getOptimizatioLevel();
|
||||
|
||||
private:
|
||||
CompilationPhase targetPhase;
|
||||
std::map<std::string, std::shared_ptr<Namespace>> namespaces;
|
||||
|
||||
// Why string vs pointer? We might rewrite the namespace and
|
||||
// holding a pointer means that it might point to the old version
|
||||
std::string current_ns;
|
||||
};
|
||||
|
||||
/// Creates a new context object. Contexts are used through out the compilation
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "serene/traits.h"
|
||||
#include "serene/utils.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <llvm/ADT/SmallString.h>
|
||||
#include <llvm/ADT/StringRef.h>
|
||||
|
@ -62,11 +63,12 @@ private:
|
|||
bool initialized = false;
|
||||
std::atomic<uint> fn_counter = 0;
|
||||
exprs::Ast tree;
|
||||
std::unique_ptr<llvm::Module> llvmModule;
|
||||
mlir::ModuleOp module;
|
||||
|
||||
public:
|
||||
mlir::StringRef name;
|
||||
llvm::Optional<std::string> filename;
|
||||
mlir::ModuleOp module;
|
||||
|
||||
/// The root environment of the namespace on the semantic analysis phase.
|
||||
/// Which is a mapping from names to AST nodes ( no evaluation ).
|
||||
|
@ -82,11 +84,13 @@ public:
|
|||
|
||||
mlir::ModuleOp &getModule();
|
||||
SereneContext &getContext();
|
||||
void setLLVMModule(std::unique_ptr<llvm::Module>);
|
||||
llvm::Module &getLLVMModule();
|
||||
|
||||
// Generatable Trait
|
||||
|
||||
/// Generate the IR of the namespace with respect to the compilation phase
|
||||
mlir::ModuleOp &generate();
|
||||
mlir::LogicalResult generate();
|
||||
mlir::LogicalResult runPasses();
|
||||
|
||||
/// Dumps the namespace with respect to the compilation phase
|
||||
|
|
|
@ -25,17 +25,27 @@
|
|||
#ifndef SERENE_SLIR_GENERATABLE_H
|
||||
#define SERENE_SLIR_GENERATABLE_H
|
||||
|
||||
#include "mlir/IR/Builders.h"
|
||||
#include "mlir/IR/BuiltinOps.h"
|
||||
#include "mlir/IR/Identifier.h"
|
||||
#include "serene/reader/location.h"
|
||||
#include "serene/slir/dialect.h"
|
||||
#include "serene/traits.h"
|
||||
|
||||
#include <llvm/ADT/STLExtras.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
#include <llvm/Support/Casting.h>
|
||||
#include <llvm/Support/TargetSelect.h>
|
||||
#include <mlir/ExecutionEngine/ExecutionEngine.h>
|
||||
#include <mlir/ExecutionEngine/OptUtils.h>
|
||||
#include <mlir/IR/BuiltinOps.h>
|
||||
#include <mlir/IR/MLIRContext.h>
|
||||
#include <mlir/Support/LogicalResult.h>
|
||||
#include <mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.h>
|
||||
#include <mlir/Target/LLVMIR/ModuleTranslation.h>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
namespace serene {
|
||||
class Namespace;
|
||||
}
|
||||
class SereneContext;
|
||||
} // namespace serene
|
||||
|
||||
namespace serene::slir {
|
||||
|
||||
|
@ -58,12 +68,52 @@ public:
|
|||
Generatable(){};
|
||||
Generatable(const Generatable &) = delete;
|
||||
|
||||
mlir::ModuleOp &generate();
|
||||
mlir::LogicalResult runPasses();
|
||||
mlir::LogicalResult generate() { return this->Object().generate(); };
|
||||
mlir::LogicalResult runPasses() { return this->Object().runPasses(); };
|
||||
|
||||
mlir::ModuleOp &getModule() { return this->Object().getModule(); };
|
||||
serene::SereneContext &getContext() { return this->Object().getContext(); };
|
||||
|
||||
void dump() { this->Object().dump(); };
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
mlir::LogicalResult generate(Generatable<T> &t) {
|
||||
return t.generate();
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
std::unique_ptr<llvm::Module> toLLVMIR(Generatable<T> &t) {
|
||||
auto &module = t.getModule();
|
||||
auto &ctx = t.getContext();
|
||||
// Register the translation to LLVM IR with the MLIR context.
|
||||
mlir::registerLLVMDialectTranslation(ctx.mlirContext);
|
||||
|
||||
// Convert the module to LLVM IR in a new LLVM IR context.
|
||||
auto llvmModule = mlir::translateModuleToLLVMIR(module, ctx.llvmContext);
|
||||
if (!llvmModule) {
|
||||
// TODO: Return a Result type instead
|
||||
llvm::errs() << "Failed to emit LLVM IR\n";
|
||||
throw std::runtime_error("Failed to emit LLVM IR\n");
|
||||
}
|
||||
|
||||
// Initialize LLVM targets.
|
||||
llvm::InitializeNativeTarget();
|
||||
llvm::InitializeNativeTargetAsmPrinter();
|
||||
mlir::ExecutionEngine::setupTargetTriple(llvmModule.get());
|
||||
|
||||
/// Optionally run an optimization pipeline over the llvm module.
|
||||
auto optPipeline = mlir::makeOptimizingTransformer(
|
||||
/*optLevel=*/ctx.getOptimizatioLevel(), /*sizeLevel=*/0,
|
||||
/*targetMachine=*/nullptr);
|
||||
if (auto err = optPipeline(llvmModule.get())) {
|
||||
llvm::errs() << "Failed to optimize LLVM IR " << err << "\n";
|
||||
throw std::runtime_error("Failed to optimize LLVM IR");
|
||||
}
|
||||
|
||||
return std::move(llvmModule);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void dump(Generatable<T> &t) {
|
||||
t.dump();
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include "serene/namespace.h"
|
||||
#include "serene/passes.h"
|
||||
#include "serene/slir/generatable.h"
|
||||
|
||||
namespace serene {
|
||||
|
||||
|
@ -61,6 +62,8 @@ std::shared_ptr<Namespace> SereneContext::getCurrentNS() {
|
|||
};
|
||||
|
||||
void SereneContext::setOperationPhase(CompilationPhase phase) {
|
||||
this->targetPhase = phase;
|
||||
|
||||
if (phase == CompilationPhase::SLIR) {
|
||||
return;
|
||||
}
|
||||
|
@ -74,6 +77,20 @@ void SereneContext::setOperationPhase(CompilationPhase phase) {
|
|||
}
|
||||
};
|
||||
|
||||
int SereneContext::getOptimizatioLevel() {
|
||||
if (targetPhase <= CompilationPhase::NoOptimization) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (targetPhase == CompilationPhase::O1) {
|
||||
return 1;
|
||||
}
|
||||
if (targetPhase == CompilationPhase::O2) {
|
||||
return 2;
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
std::unique_ptr<SereneContext> makeSereneContext() {
|
||||
return std::make_unique<SereneContext>();
|
||||
};
|
||||
|
|
|
@ -83,8 +83,16 @@ uint Namespace::nextFnCounter() { return fn_counter++; };
|
|||
|
||||
mlir::ModuleOp &Namespace::getModule() { return this->module; };
|
||||
SereneContext &Namespace::getContext() { return this->ctx; };
|
||||
void Namespace::setLLVMModule(std::unique_ptr<llvm::Module> m) {
|
||||
this->llvmModule = std::move(m);
|
||||
};
|
||||
|
||||
mlir::ModuleOp &Namespace::generate() {
|
||||
llvm::Module &Namespace::getLLVMModule() {
|
||||
// TODO: check the llvm module to make sure it is initialized
|
||||
return *llvmModule;
|
||||
};
|
||||
|
||||
mlir::LogicalResult Namespace::generate() {
|
||||
for (auto &x : getTree()) {
|
||||
x->generateIR(*this);
|
||||
}
|
||||
|
@ -92,19 +100,30 @@ mlir::ModuleOp &Namespace::generate() {
|
|||
if (mlir::failed(runPasses())) {
|
||||
// TODO: throw a proper errer
|
||||
module.emitError("Failure in passes!");
|
||||
return mlir::failure();
|
||||
}
|
||||
|
||||
return module;
|
||||
if (ctx.getTargetPhase() >= CompilationPhase::IR) {
|
||||
auto llvmTmpModule = slir::toLLVMIR<Namespace>(*this);
|
||||
this->llvmModule = std::move(llvmTmpModule);
|
||||
}
|
||||
|
||||
return mlir::success();
|
||||
}
|
||||
|
||||
mlir::LogicalResult Namespace::runPasses() { return ctx.pm.run(module); };
|
||||
|
||||
void Namespace::dump() {
|
||||
// We don't want this module just yet
|
||||
mlir::ModuleOp &m = generate();
|
||||
m->dump();
|
||||
llvm::outs() << "\nMLIR: \n";
|
||||
module->dump();
|
||||
if (llvmModule) {
|
||||
llvm::outs() << "\nLLVM IR: \n";
|
||||
llvmModule->dump();
|
||||
}
|
||||
};
|
||||
|
||||
Namespace::~Namespace() { this->module.erase(); }
|
||||
|
||||
namespace slir {
|
||||
template class Generatable<Namespace>;
|
||||
}
|
||||
} // namespace serene
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#include "serene/passes.h"
|
||||
#include "serene/slir/dialect.h"
|
||||
|
||||
#include "llvm/Support/Casting.h"
|
||||
|
||||
#include <mlir/Dialect/Affine/IR/AffineOps.h>
|
||||
#include <mlir/Dialect/LLVMIR/LLVMDialect.h>
|
||||
#include <mlir/Dialect/MemRef/IR/MemRef.h>
|
||||
|
@ -49,12 +51,29 @@ ValueOpLowering::matchAndRewrite(serene::slir::ValueOp op,
|
|||
auto value = op.value();
|
||||
mlir::Location loc = op.getLoc();
|
||||
|
||||
// auto std_const =
|
||||
rewriter.create<mlir::ConstantIntOp>(loc, (int64_t)value,
|
||||
rewriter.getI64Type());
|
||||
// rewriter.replaceOpWithNewOp<typename OpTy>(Operation *op, Args &&args...)
|
||||
// Replace this operation with the generated alloc.
|
||||
// rewriter.replaceOp(op, alloc);
|
||||
llvm::SmallVector<mlir::Type, 4> arg_types(0);
|
||||
auto func_type = rewriter.getFunctionType(arg_types, rewriter.getI64Type());
|
||||
auto fn = rewriter.create<mlir::FuncOp>(loc, "randomname", func_type);
|
||||
if (!fn) {
|
||||
llvm::outs() << "Value Rewrite fn is null\n";
|
||||
return mlir::failure();
|
||||
}
|
||||
|
||||
auto &entryBlock = *fn.addEntryBlock();
|
||||
rewriter.setInsertionPointToStart(&entryBlock);
|
||||
auto retVal = rewriter
|
||||
.create<mlir::ConstantIntOp>(loc, (int64_t)value,
|
||||
rewriter.getI64Type())
|
||||
.getResult();
|
||||
|
||||
mlir::ReturnOp returnOp = rewriter.create<mlir::ReturnOp>(loc, retVal);
|
||||
|
||||
if (!returnOp) {
|
||||
llvm::outs() << "Value Rewrite returnOp is null\n";
|
||||
return mlir::failure();
|
||||
}
|
||||
|
||||
fn.setPrivate();
|
||||
rewriter.eraseOp(op);
|
||||
return mlir::success();
|
||||
}
|
||||
|
@ -99,6 +118,7 @@ void SLIRToAffinePass::runOnModule() {
|
|||
// to lower, `toy.print`, as `legal`.
|
||||
target.addIllegalDialect<serene::slir::SereneDialect>();
|
||||
// target.addLegalOp<serene::slir::PrintOp>();
|
||||
target.addLegalOp<mlir::FuncOp>();
|
||||
|
||||
// Now that the conversion target has been defined, we just need to provide
|
||||
// the set of patterns that will lower the Toy operations.
|
||||
|
|
|
@ -24,35 +24,24 @@
|
|||
|
||||
#include "serene/slir/generatable.h"
|
||||
|
||||
#include "mlir/IR/Builders.h"
|
||||
#include "mlir/IR/BuiltinOps.h"
|
||||
#include "mlir/IR/Identifier.h"
|
||||
#include "mlir/IR/MLIRContext.h"
|
||||
#include "mlir/IR/Value.h"
|
||||
#include "mlir/Support/LogicalResult.h"
|
||||
#include "serene/exprs/traits.h"
|
||||
#include "serene/namespace.h"
|
||||
#include "serene/slir/dialect.h"
|
||||
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/ScopedHashTable.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <llvm/ADT/STLExtras.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
#include <llvm/Support/Casting.h>
|
||||
#include <llvm/Support/TargetSelect.h>
|
||||
#include <mlir/ExecutionEngine/ExecutionEngine.h>
|
||||
#include <mlir/ExecutionEngine/OptUtils.h>
|
||||
#include <mlir/IR/BuiltinOps.h>
|
||||
#include <mlir/Support/LogicalResult.h>
|
||||
#include <mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.h>
|
||||
#include <mlir/Target/LLVMIR/ModuleTranslation.h>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
namespace serene {
|
||||
namespace slir {
|
||||
|
||||
template <typename T>
|
||||
mlir::ModuleOp &Generatable<T>::generate() {
|
||||
return this->Object().generate();
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
mlir::LogicalResult Generatable<T>::runPasses() {
|
||||
return this->Object().runPasses();
|
||||
};
|
||||
|
||||
// mlir::Operation *Generatable::generate(exprs::Expression *x) {
|
||||
// switch (x->getType()) {
|
||||
// case SereneType::Number: {
|
||||
|
|
Loading…
Reference in New Issue