Add the IR generation facilities to Namespace and Expression

This commit is contained in:
Sameer Rahmani 2021-06-13 22:40:58 +01:00
parent 7e319ece13
commit 65b6aa4020
28 changed files with 253 additions and 803 deletions

1
.ignore_sanitize Normal file
View File

@ -0,0 +1 @@
#leak:mlir::Region::emplaceBlock

View File

@ -27,6 +27,7 @@
#include "serene/namespace.h"
#include "serene/reader/reader.h"
#include "serene/reader/semantics.h"
#include "serene/slir/generatable.h"
#include "serene/slir/slir.h"
#include <iostream>
#include <llvm/Support/CommandLine.h>
@ -37,7 +38,7 @@ using namespace serene;
namespace cl = llvm::cl;
namespace {
enum Action { None, DumpAST, DumpIR, DumpSemantic };
enum Action { None, DumpAST, DumpIR, DumpSLIR, DumpSemantic };
}
static cl::opt<std::string> inputFile(cl::Positional,
@ -49,7 +50,8 @@ static cl::opt<enum Action> emitAction(
"emit", cl::desc("Select what to dump."),
cl::values(clEnumValN(DumpSemantic, "ast1",
"Output the AST after one level of analysis only")),
cl::values(clEnumValN(DumpIR, "slir", "Output the SLIR only")),
cl::values(clEnumValN(DumpIR, "ir", "Output the lowered IR only")),
cl::values(clEnumValN(DumpSLIR, "slir", "Output the SLIR only")),
cl::values(clEnumValN(DumpAST, "ast", "Output the AST only"))
);
@ -112,7 +114,12 @@ int main(int argc, char *argv[]) {
if (isSet.succeeded()) {
ctx->insertNS(ns);
serene::slir::dumpSLIR(*ctx, ns->name);
serene::slir::dumpIR<Namespace>(*ns);
// if (mlir::failed(ns->generateIR(*ctx))) {
// // TODO: Replace with an actual error
// llvm::outs() << "Can't generate IR for namespace\n";
// }
// serene::slir::dumpSLIR(*ctx, ns->name);
} else {
llvm::outs() << "Can't set the tree of the namespace!\n";
}

View File

@ -6,6 +6,9 @@ command=$1
export CC=$(which clang)
export CXX=$(which clang++)
export LDFLAGS="-fuse-ld=lld"
export ASAN_OPTIONS=check_initialization_order=1
export LSAN_OPTIONS=suppressions=`pwd`/.ignore_sanitize
ROOT_DIR=`pwd`
BUILD_DIR=$ROOT_DIR/build
@ -21,7 +24,7 @@ function popd_build() {
function compile() {
pushed_build
ninja
ninja -j `nproc`
popd_build
}

View File

@ -55,6 +55,7 @@ public:
ExprType getType() const;
std::string toString() const;
MaybeNode analyze(SereneContext &);
void generateIR(serene::Namespace &){};
static bool classof(const Expression *e);

View File

@ -54,6 +54,7 @@ public:
ExprType getType() const;
std::string toString() const;
MaybeNode analyze(SereneContext &);
void generateIR(serene::Namespace &){};
static bool classof(const Expression *e);

View File

@ -34,10 +34,6 @@
namespace serene {
namespace reader {
class SereneContext;
}
/// Contains all the builtin AST expressions including those which do not appear
/// in the syntax directly. Like function definitions.
namespace exprs {
@ -82,6 +78,8 @@ public:
///
/// \param ctx is the context object of the semantic analyzer.
virtual MaybeNode analyze(SereneContext &ctx) = 0;
virtual void generateIR(serene::Namespace &ns) = 0;
};
/// Create a new `node` of type `T` and forwards any given parameter

View File

@ -58,6 +58,7 @@ public:
ExprType getType() const;
std::string toString() const;
MaybeNode analyze(SereneContext &);
void generateIR(serene::Namespace &){};
static bool classof(const Expression *e);

View File

@ -67,6 +67,7 @@ public:
std::vector<Node>::iterator end();
MaybeNode analyze(SereneContext &);
void generateIR(serene::Namespace &){};
static bool classof(const Expression *e);

View File

@ -27,6 +27,7 @@
#include "serene/context.h"
#include "serene/exprs/expression.h"
#include "serene/namespace.h"
#include "llvm/Support/FormatVariadic.h"
namespace serene {
@ -57,6 +58,7 @@ struct Number : public Expression {
// TODO: This is horrible, we need to fix it after the mvp
int toI64();
void generateIR(serene::Namespace &);
~Number() = default;
};

View File

@ -52,6 +52,7 @@ public:
static bool classof(const Expression *e);
MaybeNode analyze(SereneContext &);
void generateIR(serene::Namespace &){};
~Symbol() = default;
};

View File

@ -22,16 +22,20 @@
* SOFTWARE.
*/
#ifndef NAMESPACE_H
#define NAMESPACE_H
#ifndef SERENE_NAMESPACE_H
#define SERENE_NAMESPACE_H
#include "serene/environment.h"
#include "serene/slir/generatable.h"
#include "serene/traits.h"
#include "serene/utils.h"
#include "llvm/ADT/SmallString.h"
#include <atomic>
#include <llvm/ADT/SmallString.h>
#include <llvm/ADT/StringRef.h>
#include <llvm/IR/Module.h>
#include <memory>
#include <mlir/IR/Builders.h>
#include <mlir/IR/BuiltinOps.h>
#include <mlir/IR/Value.h>
#include <mlir/Support/LogicalResult.h>
#include <string>
@ -51,26 +55,41 @@ using Ast = std::vector<Node>;
/// Serene's namespaces are the unit of compilation. Any code that needs to be
/// compiled has to be in a namespace. The official way to create a new
/// namespace is to use the `makeNamespace` function.
class Namespace {
class Namespace : public WithTrait<Namespace, slir::Generatable> {
private:
SereneContext &ctx;
bool initialized = false;
std::atomic<uint> fn_counter = 0;
exprs::Ast tree;
mlir::OpBuilder builder;
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 ).
Environment<std::string, exprs::Node> semanticEnv;
Environment<llvm::StringRef, mlir::Value> symbolTable;
Namespace(llvm::StringRef ns_name, llvm::Optional<llvm::StringRef> filename);
Namespace(SereneContext &ctx, llvm::StringRef ns_name,
llvm::Optional<llvm::StringRef> filename);
exprs::Ast &getTree();
mlir::LogicalResult setTree(exprs::Ast &);
uint nextFnCounter();
mlir::OpBuilder &getBuilder();
mlir::ModuleOp &getModule();
SereneContext &getContext();
// Generatable Trait
mlir::ModuleOp &generate();
mlir::LogicalResult runPasses();
void dumpSLIR();
void dumpToIR();
~Namespace();
};

View File

@ -1,5 +0,0 @@
set(LLVM_TARGET_DEFINITIONS dialect.td)
mlir_tablegen(ops.hpp.inc -gen-op-decls)
mlir_tablegen(ops.cpp.inc -gen-op-defs)
mlir_tablegen(dialect.hpp.inc -gen-dialect-decls)
add_public_tablegen_target(SereneDialectGen)

View File

@ -1,104 +0,0 @@
#ifndef SERENE_DIALECT
#define SERENE_DIALECT
include "mlir/IR/OpBase.td"
include "mlir/Interfaces/SideEffectInterfaces.td"
// Dialect definition. It will directly generate the SereneDialect class
def Serene_Dialect : Dialect {
let name = "serene";
let cppNamespace = "::serene::sir";
let summary = "Primary IR of serene language.";
let description = [{
This dialect tries to map the special forms of a lisp into
IR level operations.
}];
}
// Base class for Serene dialect operations. This operation inherits from the base
// `Op` class in OpBase.td, and provides:
// * The parent dialect of the operation.
// * The mnemonic for the operation, or the name without the dialect prefix.
// * A list of traits for the operation.
class Serene_Op<string mnemonic, list<OpTrait> traits = []> :
Op<Serene_Dialect, mnemonic, traits>;
// All of the types will extend this class.
class Serene_Type<string name> : TypeDef<Serene_Dialect, name> { }
// def SymbolType : Serene_Type<"Symbol"> {
// let mnemonic = "symbol";
// let summary = "A typical Lisp symbol";
// let description = [{
// A symbol is just a name and nothing more. Just a name
// to give to a value or to use it as it is.
// }];
// // let cppNamespace = "::serene::sir";
// let parameters = (ins "std::string":$name);
// // We define the printer inline.
// let printer = [{
// $_printer << "Symbol<" << getImpl()->name << ">";
// }];
// // The parser is defined here also.
// let parser = [{
// if ($_parser.parseLess())
// return Type();
// std::string name;
// if ($_parser.parseInteger(name))
// return Type();
// return get($_ctxt, name);
// }];
// }
def ValueOp: Serene_Op<"value"> {
let summary = "This operation represent a value";
let description = [{
some description
}];
let arguments = (ins I64Attr:$value);
let results = (outs I64);
// let verifier = [{ return serene::sir::verify(*this); }];
let builders = [
OpBuilder<(ins "int":$value), [{
// Build from fix 64 bit int
build(odsBuilder, odsState, odsBuilder.getI64Type(), (uint64_t) value);
}]>,
];
}
def FnIdOp: Serene_Op<"fn_id"> {
let summary = "This operation is just a place holder for an anonymouse function";
let description = [{
A place holder for an anonymous function. For example consider an expression
like `(def a (fn (x) x))`, in this case we don't immediately create an anonymous
function since we need to set the name and create the function later.
}];
let arguments = (ins StrAttr:$name);
let results = (outs NoneType);
let builders = [
OpBuilder<(ins "std::string":$name), [{
// Build from fix 64 bit int
build(odsBuilder, odsState, odsBuilder.getNoneType(), odsBuilder.getStringAttr(name));
}]>,
];
}
#endif // SERENE_DIALECT

View File

@ -1,79 +0,0 @@
/**
* Serene programming language.
*
* Copyright (c) 2020 Sameer Rahmani <lxsameer@gnu.org>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef GENERATOR_H
#define GENERATOR_H
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/Identifier.h"
#include "mlir/IR/MLIRContext.h"
#include "serene/expr.hpp"
#include "serene/list.hpp"
#include "serene/namespace.h"
#include "serene/number.hpp"
#include "serene/symbol.hpp"
#include "llvm/ADT/ScopedHashTable.h"
#include <atomic>
#include <memory>
#include <utility>
namespace serene {
namespace sir {
using FnIdPair = std::pair<mlir::Identifier, mlir::FuncOp>;
class Generator {
private:
::mlir::OpBuilder builder;
::mlir::ModuleOp module;
std::unique_ptr<::serene::Namespace> ns;
std::atomic_int anonymousFnCounter{1};
llvm::DenseMap<mlir::Identifier, mlir::FuncOp> anonymousFunctions;
llvm::ScopedHashTable<llvm::StringRef, mlir::Value> symbolTable;
// TODO: Should we use builder here? maybe there is a better option
::mlir::Location toMLIRLocation(serene::reader::Location *);
// mlir::FuncOp generateFn(serene::reader::Location, std::string, List *,
// List *);
public:
Generator(mlir::MLIRContext &context, ::serene::Namespace *ns)
: builder(&context),
module(mlir::ModuleOp::create(builder.getUnknownLoc(), ns->name)) {
this->ns.reset(ns);
}
mlir::Operation *generate(Number *);
mlir::Operation *generate(AExpr *);
mlir::Value generate(List *);
mlir::ModuleOp generate();
~Generator();
};
} // namespace sir
} // namespace serene
#endif

View File

@ -22,50 +22,50 @@
* SOFTWARE.
*/
#ifndef GENERATOR_H
#define GENERATOR_H
#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/context.h"
#include "serene/exprs/expression.h"
#include "serene/exprs/list.h"
#include "serene/exprs/number.h"
#include "serene/exprs/symbol.h"
#include "serene/namespace.h"
#include "llvm/ADT/ScopedHashTable.h"
#include <memory>
#include "serene/reader/location.h"
#include "serene/traits.h"
#include <utility>
namespace serene {
class Namespace;
}
namespace serene::slir {
class Generator {
private:
serene::SereneContext &ctx;
mlir::OpBuilder builder;
mlir::ModuleOp module;
std::shared_ptr<serene::Namespace> ns;
// TODO: Should we use builder here? maybe there is a better option
mlir::Location toMLIRLocation(serene::reader::Location &);
template <typename T>
class GeneratableUnit : public TraitBase<T, GeneratableUnit> {
public:
Generator(serene::SereneContext &ctx, llvm::StringRef ns_name)
: ctx(ctx), builder(&ctx.mlirContext),
module(mlir::ModuleOp::create(builder.getUnknownLoc(), ns_name)) {
this->ns = ctx.getNS(ns_name);
GeneratableUnit(){};
GeneratableUnit(const GeneratableUnit &) = delete;
void generate(serene::Namespace &ns) {
// TODO: should we return any status or possible error here or
// should we just populate them in a ns wide state?
this->Object().generateIR(ns);
};
void generate(exprs::Number &);
mlir::Operation *generate(exprs::Expression *);
mlir::Value generate(exprs::List *);
mlir::ModuleOp generate();
serene::Namespace &getNs();
~Generator();
};
template <typename T> class Generatable : public TraitBase<T, Generatable> {
public:
Generatable(){};
Generatable(const Generatable &) = delete;
mlir::ModuleOp &generate();
mlir::LogicalResult runPasses();
void dumpSLIR();
void dumpIR() { this->Object().dumpToIR(); };
};
template <typename T> void dumpIR(Generatable<T> &t) { t.dumpIR(); };
template <typename T> void dumpSLIR(Generatable<T> &t) { t.dumpSLIR(); };
} // namespace serene::slir
#endif

View File

@ -27,28 +27,11 @@
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/MLIRContext.h"
#include "serene/exprs/expression.h"
#include "serene/namespace.h"
#include "serene/slir/generator.h"
#include "serene/slir/generatable.h"
#include <memory>
namespace serene {
namespace slir {
class SLIR {
private:
serene::SereneContext &context;
public:
SLIR(serene::SereneContext &ctx);
mlir::OwningModuleRef generate(llvm::StringRef ns_name);
~SLIR();
};
void dumpSLIR(serene::SereneContext &ctx, llvm::StringRef ns_name);
} // namespace slir
namespace slir {} // namespace slir
} // namespace serene

View File

@ -1,7 +1,7 @@
/**
/* -*- C++ -*-
* Serene programming language.
*
* Copyright (c) 2020 Sameer Rahmani <lxsameer@gnu.org>
* Copyright (c) 2019-2021 Sameer Rahmani <lxsameer@gnu.org>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -21,34 +21,25 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef SIR_H
#define SIR_H
#ifndef SERENE_SLIR_UTILS_H
#define SERENE_SLIR_UTILS_H
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/MLIRContext.h"
#include "serene/exprs/expression.h"
#include "serene/sir/generator.hpp"
#include <memory>
#include "serene/reader/location.h"
namespace serene {
namespace sir {
class Namespace;
}
class SIR {
namespace serene::slir {
private:
mlir::MLIRContext context;
/**
* Convert a Serene location to MLIR FileLineLoc Location
*/
::mlir::Location toMLIRLocation(serene::Namespace &,
serene::reader::Location &);
public:
SIR();
mlir::OwningModuleRef generate(serene::Namespace *ns);
~SIR();
};
void dumpSIR(exprs::ast &t);
} // namespace sir
} // namespace serene
} // namespace serene::slir
#endif

View File

@ -104,9 +104,11 @@ class TraitBase {
protected:
/// Statically casts the object to the concrete type object to be
/// used in the Trait Types.
const ConcreteType &Object() const {
return static_cast<const ConcreteType &>(*this);
};
// const ConcreteType &Object() const {
// return static_cast<const ConcreteType &>(*this);
// };
ConcreteType &Object() { return static_cast<ConcreteType &>(*this); };
};
template <typename ConcreteType>

View File

@ -30,7 +30,8 @@ set(HEADER_LIST
"${INCLUDE_DIR}/serene/slir/slir.h"
"${INCLUDE_DIR}/serene/slir/dialect.h"
"${INCLUDE_DIR}/serene/slir/generator.h"
"${INCLUDE_DIR}/serene/slir/generatable.h"
"${INCLUDE_DIR}/serene/slir/utils.h"
"${INCLUDE_DIR}/serene/namespace.h"
"${INCLUDE_DIR}/serene/passes/slir_lowering.h")
@ -60,10 +61,11 @@ add_library(serene
errors/error.cpp
# IR
slir/slir.cpp
slir/dialect.cpp
slir/value_op.cpp
slir/generator.cpp
slir/generatable.cpp
slir/utils.cpp
passes/slir_lowering.cpp
${HEADER_LIST})

View File

@ -24,6 +24,8 @@
*/
#include "serene/exprs/number.h"
#include "serene/slir/dialect.h"
#include "serene/slir/utils.h"
namespace serene {
namespace exprs {
@ -44,5 +46,17 @@ bool Number::classof(const Expression *e) {
int Number::toI64() { return std::stoi(this->value); };
void Number::generateIR(serene::Namespace &ns) {
mlir::OpBuilder &builder = ns.getBuilder();
mlir::ModuleOp &module = ns.getModule();
auto op = builder.create<serene::slir::ValueOp>(
serene::slir::toMLIRLocation(ns, location.start), toI64());
if (op) {
module.push_back(op);
}
// TODO: in case of failure attach the error to the NS
};
} // namespace exprs
} // namespace serene

View File

@ -23,10 +23,14 @@
*/
#include "serene/namespace.h"
#include "mlir/IR/BuiltinOps.h"
#include "serene/context.h"
#include "serene/exprs/expression.h"
#include "serene/llvm/IR/Value.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/raw_ostream.h"
#include <stdexcept>
#include <string>
using namespace std;
@ -34,9 +38,11 @@ using namespace llvm;
namespace serene {
Namespace::Namespace(llvm::StringRef ns_name,
Namespace::Namespace(SereneContext &ctx, llvm::StringRef ns_name,
llvm::Optional<llvm::StringRef> filename)
: name(ns_name) {
: ctx(ctx), builder(&ctx.mlirContext), name(ns_name),
// TODO: Fix the unknown location by pointing to the `ns` form
module(mlir::ModuleOp::create(builder.getUnknownLoc(), ns_name)) {
if (filename.hasValue()) {
this->filename.emplace(filename.getValue().str());
}
@ -56,15 +62,49 @@ mlir::LogicalResult Namespace::setTree(exprs::Ast &t) {
std::shared_ptr<Namespace>
makeNamespace(SereneContext &ctx, llvm::StringRef name,
llvm::Optional<llvm::StringRef> filename, bool setCurrent) {
auto nsPtr = std::make_shared<Namespace>(name, filename);
auto nsPtr = std::make_shared<Namespace>(ctx, name, filename);
ctx.insertNS(nsPtr);
if (setCurrent) {
assert(ctx.setCurrentNS(nsPtr->name) && "Couldn't set the current NS");
if (!ctx.setCurrentNS(nsPtr->name)) {
throw std::runtime_error("Couldn't set the current NS");
}
}
return nsPtr;
};
uint Namespace::nextFnCounter() { return fn_counter++; };
mlir::OpBuilder &Namespace::getBuilder() { return this->builder; };
mlir::ModuleOp &Namespace::getModule() { return this->module; };
SereneContext &Namespace::getContext() { return this->ctx; };
mlir::ModuleOp &Namespace::generate() {
for (auto &x : getTree()) {
x->generateIR(*this);
}
return module;
}
mlir::LogicalResult Namespace::runPasses() { return ctx.pm.run(module); };
void Namespace::dumpSLIR() {
mlir::ModuleOp &m = generate();
m->dump();
};
void Namespace::dumpToIR() {
// We don't want this module just yet
mlir::ModuleOp &m = generate();
if (mlir::failed(runPasses())) {
// TODO: throw a proper errer
return;
}
m->dump();
};
Namespace::~Namespace() {}
} // namespace serene

View File

@ -1,46 +0,0 @@
/**
* Serene programming language.
*
* Copyright (c) 2020 Sameer Rahmani <lxsameer@gnu.org>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "serene/sir/dialect.hpp"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/OpImplementation.h"
namespace serene {
namespace sir {
/// Dialect initialization, the instance will be owned by the context. This is
/// the point of registration of types and operations for the dialect.
void SereneDialect::initialize() {
addOperations<
#define GET_OP_LIST
#include "serene/sir/ops.cpp.inc"
>();
}
} // namespace sir
} // namespace serene
#define GET_OP_CLASSES
#include "serene/sir/ops.cpp.inc"

View File

@ -1,200 +0,0 @@
/**
* Serene programming language.
*
* Copyright (c) 2020 Sameer Rahmani <lxsameer@gnu.org>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "serene/sir/generator.hpp"
#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 "serene/expr.hpp"
#include "serene/sir/dialect.hpp"
#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"
namespace serene {
namespace sir {
mlir::ModuleOp Generator::generate() {
// for (auto x : ns->Tree()) {
// generate(x.get());
// }
return module;
};
mlir::Operation *Generator::generate(AExpr *x) {
// switch (x->getType()) {
// case SereneType::Number: {
// return generate(llvm::cast<Number>(x));
// }
// case SereneType::List: {
// generate(llvm::cast<List>(x));
// return nullptr;
// }
// default: {
return builder.create<ValueOp>(builder.getUnknownLoc(), (uint64_t)3);
// }
// }
};
mlir::Value Generator::generate(List *l) {
// auto first = l->at(0);
// if (!first) {
// // Empty list.
// // TODO: Return Nil or empty list.
// // Just for now.
// return builder.create<ValueOp>(builder.getUnknownLoc(), (uint64_t)0);
// }
// if (first->get()->getType() == SereneType::Symbol) {
// auto fnNameSymbol = llvm::dyn_cast<Symbol>(first->get());
// if (fnNameSymbol->getName() == "fn") {
// if (l->count() <= 3) {
// module.emitError("'fn' form needs exactly 2 arguments.");
// }
// auto args = llvm::dyn_cast<List>(l->at(1).getValue().get());
// auto body = llvm::dyn_cast<List>(l->from(2).get());
// if (!args) {
// module.emitError("The first element of 'def' has to be a symbol.");
// }
// // Create a new anonymous function and push it to the anonymous
// functions
// // map, later on we
// auto loc(fnNameSymbol->location->start);
// auto anonymousName = fmt::format("__fn_{}__", anonymousFnCounter);
// anonymousFnCounter++;
// auto fn = generateFn(loc, anonymousName, args, body);
// mlir::Identifier fnid = builder.getIdentifier(anonymousName);
// anonymousFunctions.insert({fnid, fn});
// return builder.create<FnIdOp>(builder.getUnknownLoc(), fnid.str());
// }
// }
// // auto rest = l->from(1);
// // auto loc = toMLIRLocation(&first->get()->location->start);
// // for (auto x : *rest) {
// // generate(x.get());
// // }
return builder.create<ValueOp>(builder.getUnknownLoc(), (uint64_t)100);
};
// mlir::FuncOp Generator::generateFn(serene::reader::Location loc,
// std::string name, List *args, List *body)
// {
// auto location = toMLIRLocation(&loc);
// llvm::SmallVector<mlir::Type, 4> arg_types(args->count(),
// builder.getI64Type());
// auto func_type = builder.getFunctionType(arg_types, builder.getI64Type());
// auto proto = mlir::FuncOp::create(location, name, func_type);
// mlir::FuncOp fn(proto);
// if (!fn) {
// module.emitError("Can not create the function.");
// }
// auto &entryBlock = *fn.addEntryBlock();
// llvm::ScopedHashTableScope<llvm::StringRef, mlir::Value>
// scope(symbolTable);
// // Declare all the function arguments in the symbol table.
// for (const auto arg :
// llvm::zip(args->asArrayRef(), entryBlock.getArguments())) {
// auto argSymbol = llvm::dyn_cast<Symbol>(std::get<0>(arg).get());
// if (!argSymbol) {
// module.emitError("Function parameters must be symbols");
// }
// if (symbolTable.count(argSymbol->getName())) {
// return nullptr;
// }
// symbolTable.insert(argSymbol->getName(), std::get<1>(arg));
// }
// // Set the insertion point in the builder to the beginning of the function
// // body, it will be used throughout the codegen to create operations in
// this
// // function.
// builder.setInsertionPointToStart(&entryBlock);
// // Emit the body of the function.
// if (!generate(body)) {
// fn.erase();
// return nullptr;
// }
// // // Implicitly return void if no return statement was emitted.
// // // FIXME: we may fix the parser instead to always return the last
// // expression
// // // (this would possibly help the REPL case later)
// // ReturnOp returnOp;
// // if (!entryBlock.empty())
// // returnOp = dyn_cast<ReturnOp>(entryBlock.back());
// // if (!returnOp) {
// // builder.create<ReturnOp>(loc(funcAST.getProto()->loc()));
// // } else if (returnOp.hasOperand()) {
// // // Otherwise, if this return operation has an operand then add a
// result
// // to
// // // the function.
// // function.setType(builder.getFunctionType(function.getType().getInputs(),
// // getType(VarType{})));
// // }
// return fn;
// }
mlir::Operation *Generator::generate(Number *x) {
return builder.create<ValueOp>(builder.getUnknownLoc(), x->toI64());
};
/**
* Convert a Serene location to MLIR FileLineLoc Location
*/
::mlir::Location Generator::toMLIRLocation(serene::reader::Location *loc) {
auto file = ns->filename;
std::string filename{file.getValueOr("REPL")};
return mlir::FileLineColLoc::get(builder.getIdentifier(filename), loc->line,
loc->col);
}
Generator::~Generator(){};
} // namespace sir
} // namespace serene

View File

@ -1,59 +0,0 @@
/**
* Serene programming language.
*
* Copyright (c) 2020 Sameer Rahmani <lxsameer@gnu.org>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "serene/sir/sir.hpp"
#include "mlir/IR/MLIRContext.h"
#include "serene/exprs/expression.h"
#include "serene/sir/dialect.hpp"
#include "serene/sir/generator.hpp"
#include <memory>
namespace serene {
namespace sir {
SIR::SIR() { context.getOrLoadDialect<::serene::sir::SereneDialect>(); }
mlir::OwningModuleRef SIR::generate(::serene::Namespace *ns) {
auto g = std::make_unique<Generator>(context, ns);
return g->generate();
};
SIR::~SIR() {}
void dumpSIR(exprs::ast &t) {
auto ns = new ::serene::Namespace("user", llvm::None);
SIR s{};
if (failed(ns->setTree(t))) {
llvm::errs() << "Can't set the body of the namespace";
return;
}
auto module = s.generate(ns);
module->dump();
};
} // namespace sir
} // namespace serene

View File

@ -1,34 +0,0 @@
/**
* Serene programming language.
*
* Copyright (c) 2020 Sameer Rahmani <lxsameer@gnu.org>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "mlir/IR/Builders.h"
#include "mlir/IR/MLIRContext.h"
#include "mlir/IR/Value.h"
#include "serene/sir/dialect.hpp"
#include "serene/sir/sir.hpp"
#include "llvm/Support/Casting.h"
namespace serene {
namespace sir {} // namespace sir
} // namespace serene

View File

@ -22,14 +22,16 @@
* SOFTWARE.
*/
#include "serene/slir/generator.h"
#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 "serene/exprs/expression.h"
#include "mlir/Support/LogicalResult.h"
//#include "serene/exprs/expression.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"
@ -40,83 +42,82 @@
namespace serene {
namespace slir {
mlir::ModuleOp Generator::generate() {
for (auto &x : ns->getTree()) {
auto *num = llvm::dyn_cast<exprs::Number>(x.get());
if (num) {
generate(*num);
} else {
llvm::outs() << "else\n";
}
}
return module;
template <typename T> mlir::ModuleOp &Generatable<T>::generate() {
return this->Object().generate();
};
mlir::Operation *Generator::generate(exprs::Expression *x) {
// switch (x->getType()) {
// case SereneType::Number: {
// return generate(llvm::cast<Number>(x));
// }
// case SereneType::List: {
// generate(llvm::cast<List>(x));
// return nullptr;
// }
// default: {
return builder.create<ValueOp>(builder.getUnknownLoc(), (uint64_t)3);
// }
// }
template <typename T> mlir::LogicalResult Generatable<T>::runPasses() {
return this->Object().runPasses();
};
mlir::Value Generator::generate(exprs::List *l) {
// auto first = l->at(0);
// if (!first) {
// // Empty list.
// // TODO: Return Nil or empty list.
// // Just for now.
// return builder.create<ValueOp>(builder.getUnknownLoc(), (uint64_t)0);
// }
// if (first->get()->getType() == SereneType::Symbol) {
// auto fnNameSymbol = llvm::dyn_cast<Symbol>(first->get());
// if (fnNameSymbol->getName() == "fn") {
// if (l->count() <= 3) {
// module.emitError("'fn' form needs exactly 2 arguments.");
// }
// auto args = llvm::dyn_cast<List>(l->at(1).getValue().get());
// auto body = llvm::dyn_cast<List>(l->from(2).get());
// if (!args) {
// module.emitError("The first element of 'def' has to be a symbol.");
// }
// // Create a new anonymous function and push it to the anonymous
// functions
// // map, later on we
// auto loc(fnNameSymbol->location->start);
// auto anonymousName = fmt::format("__fn_{}__", anonymousFnCounter);
// anonymousFnCounter++;
// auto fn = generateFn(loc, anonymousName, args, body);
// mlir::Identifier fnid = builder.getIdentifier(anonymousName);
// anonymousFunctions.insert({fnid, fn});
// return builder.create<FnIdOp>(builder.getUnknownLoc(), fnid.str());
// }
// }
// // auto rest = l->from(1);
// // auto loc = toMLIRLocation(&first->get()->location->start);
// // for (auto x : *rest) {
// // generate(x.get());
// // }
return builder.create<ValueOp>(builder.getUnknownLoc(), (uint64_t)100);
template <typename T> void Generatable<T>::dumpSLIR() {
this->Object().dumpSLIR();
};
// mlir::Operation *Generatable::generate(exprs::Expression *x) {
// switch (x->getType()) {
// case SereneType::Number: {
// return generate(llvm::cast<Number>(x));
// }
// case SereneType::List: {
// generate(llvm::cast<List>(x));
// return nullptr;
// }
// default: {
// return builder.create<ValueOp>(builder.getUnknownLoc(), (uint64_t)3);
// }
// }
//};
// mlir::Value Generator::generate(exprs::List *l) {
// auto first = l->at(0);
// if (!first) {
// // Empty list.
// // TODO: Return Nil or empty list.
// // Just for now.
// return builder.create<ValueOp>(builder.getUnknownLoc(), (uint64_t)0);
// }
// if (first->get()->getType() == SereneType::Symbol) {
// auto fnNameSymbol = llvm::dyn_cast<Symbol>(first->get());
// if (fnNameSymbol->getName() == "fn") {
// if (l->count() <= 3) {
// module.emitError("'fn' form needs exactly 2 arguments.");
// }
// auto args = llvm::dyn_cast<List>(l->at(1).getValue().get());
// auto body = llvm::dyn_cast<List>(l->from(2).get());
// if (!args) {
// module.emitError("The first element of 'def' has to be a symbol.");
// }
// // Create a new anonymous function and push it to the anonymous
// functions
// // map, later on we
// auto loc(fnNameSymbol->location->start);
// auto anonymousName = fmt::format("__fn_{}__", anonymousFnCounter);
// anonymousFnCounter++;
// auto fn = generateFn(loc, anonymousName, args, body);
// mlir::Identifier fnid = builder.getIdentifier(anonymousName);
// anonymousFunctions.insert({fnid, fn});
// return builder.create<FnIdOp>(builder.getUnknownLoc(), fnid.str());
// }
// }
// // auto rest = l->from(1);
// // auto loc = toMLIRLocation(&first->get()->location->start);
// // for (auto x : *rest) {
// // generate(x.get());
// // }
// return builder.create<ValueOp>(builder.getUnknownLoc(), (uint64_t)100);
//};
// mlir::FuncOp Generator::generateFn(serene::reader::Location loc,
// std::string name, List *args, List *body)
// {
@ -183,28 +184,6 @@ mlir::Value Generator::generate(exprs::List *l) {
// return fn;
// }
void Generator::generate(exprs::Number &x) {
auto op =
builder.create<ValueOp>(toMLIRLocation(x.location.start), x.toI64());
if (op) {
module.push_back(op);
}
};
/**
* Convert a Serene location to MLIR FileLineLoc Location
*/
::mlir::Location Generator::toMLIRLocation(serene::reader::Location &loc) {
auto file = this->ns->filename;
std::string filename{file.getValueOr("REPL")};
return mlir::FileLineColLoc::get(builder.getIdentifier(filename), loc.line,
loc.col);
}
Generator::~Generator(){};
} // namespace slir
} // namespace serene

View File

@ -1,66 +0,0 @@
/* -*- C++ -*-
* Serene programming language.
*
* Copyright (c) 2019-2021 Sameer Rahmani <lxsameer@gnu.org>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "serene/slir/slir.h"
#include "mlir/IR/MLIRContext.h"
#include "serene/exprs/expression.h"
#include "serene/namespace.h"
#include "serene/slir/dialect.h"
#include "serene/slir/generator.h"
#include "llvm/Support/raw_ostream.h"
#include <memory>
namespace serene {
namespace slir {
SLIR::SLIR(serene::SereneContext &ctx) : context(ctx) {
context.mlirContext.getOrLoadDialect<serene::slir::SereneDialect>();
}
mlir::OwningModuleRef SLIR::generate(llvm::StringRef ns_name) {
auto g = std::make_unique<Generator>(context, ns_name);
return g->generate();
};
SLIR::~SLIR() {}
void dumpSLIR(serene::SereneContext &ctx, llvm::StringRef ns_name) {
SLIR s(ctx);
auto ns = ctx.getNS(ns_name);
assert(ns && "No such a namespace to dump!");
auto module = s.generate(ns_name);
if (mlir::failed(ctx.pm.run(*module))) {
// TODO: throw a proper errer
llvm::outs() << "Pass manager has faild!\n";
}
module->dump();
};
} // namespace slir
} // namespace serene

View File

@ -1,7 +1,7 @@
/**
/* -*- C++ -*-
* Serene programming language.
*
* Copyright (c) 2020 Sameer Rahmani <lxsameer@gnu.org>
* Copyright (c) 2019-2021 Sameer Rahmani <lxsameer@gnu.org>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -22,22 +22,19 @@
* SOFTWARE.
*/
#ifndef DIALECT_H_
#define DIALECT_H_
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/Dialect.h"
#include "mlir/Interfaces/SideEffectInterfaces.h"
#include "serene/namespace.h"
#include "serene/reader/location.h"
// Include the auto-generated header file containing the declaration of the
// serene's dialect.
#include "serene/sir/dialect.hpp.inc"
namespace serene::slir {
::mlir::Location toMLIRLocation(serene::Namespace &ns,
serene::reader::Location &loc) {
mlir::OpBuilder &builder = ns.getBuilder();
auto file = ns.filename;
std::string filename{file.getValueOr("REPL")};
// Include the auto-generated header file containing the declarations of the
// serene's operations.
// for more on GET_OP_CLASSES: https://mlir.llvm.org/docs/OpDefinitions/
#define GET_OP_CLASSES
return mlir::FileLineColLoc::get(builder.getIdentifier(filename), loc.line,
loc.col);
}
#include "serene/sir/ops.hpp.inc"
#endif // DIALECT_H_
} // namespace serene::slir