diff --git a/devtools/slir-opt.cpp b/devtools/slir-opt.cpp index 3638609..36cf7f2 100644 --- a/devtools/slir-opt.cpp +++ b/devtools/slir-opt.cpp @@ -16,6 +16,7 @@ * along with this program. If not, see . */ +#include "serene/passes.h" #include "serene/slir/dialect.h" #include @@ -28,7 +29,9 @@ int main(int argc, char **argv) { serene::slir::registerTo(registry); registry.insert(); - // TODO: Register passes here + + serene::passes::registerAllPasses(); + return static_cast( mlir::failed(mlir::MlirOptMain(argc, argv, "slir-opt", registry))); } diff --git a/docs/examples/slir/hello_world.mlir b/docs/examples/slir/hello_world.mlir index e3413e3..ec33768 100644 --- a/docs/examples/slir/hello_world.mlir +++ b/docs/examples/slir/hello_world.mlir @@ -1,13 +1,14 @@ -module @some.ns { +serene.ns @some.ns { // Value operator ---- %0 = "serene.value"(){value= 3} : () -> i64 // compact form %1 = serene.value 3 : i32 + %x = serene.symbol "some.ns" "x" // Def operator ---- - %foo = "serene.def"(%0){sym_name = "foo"}: (i64) -> !serene.symbol + %foo = "serene.define"(%0){sym_name = "foo"}: (i64) -> !serene.symbol // compact form - %bar = serene.def "bar", %0 : i64 + %bar = serene.define "bar", %0 : i64 // Fn operator ---- %f1 = "serene.fn"()({ @@ -15,7 +16,7 @@ module @some.ns { %2 = serene.value 3 : i32 // Def operator ---- - %baz = "serene.def"(%fnarg1){sym_name = "baz"}: (i1) -> !serene.symbol + %baz = "serene.define"(%fnarg1){sym_name = "baz"}: (i1) -> !serene.symbol serene.ret %baz : !serene.symbol }, { @@ -23,10 +24,10 @@ module @some.ns { %3 = serene.value 4 : i32 // Def operator ---- - %baz1 = "serene.def"(%3){sym_name = "baz"}: (i32) -> !serene.symbol + %baz1 = "serene.define"(%3){sym_name = "baz"}: (i32) -> !serene.symbol serene.ret %baz1 : !serene.symbol ^b2: - %baz2 = "serene.def"(%3){sym_name = "baz"}: (i32) -> !serene.symbol + %baz2 = "serene.define"(%3){sym_name = "baz"}: (i32) -> !serene.symbol serene.ret %baz2 : !serene.symbol }){name = "some-fn", return_type = i32} : () -> !serene.fn diff --git a/libserene/include/CMakeLists.txt b/libserene/include/CMakeLists.txt index 1542268..1c51b2a 100644 --- a/libserene/include/CMakeLists.txt +++ b/libserene/include/CMakeLists.txt @@ -1,2 +1,3 @@ add_subdirectory("serene/slir/") +add_subdirectory("serene/passes/") add_subdirectory("serene/errors/") diff --git a/libserene/include/serene/passes.h b/libserene/include/serene/passes.h index 5e28890..47db599 100644 --- a/libserene/include/serene/passes.h +++ b/libserene/include/serene/passes.h @@ -19,10 +19,16 @@ #ifndef SERENE_PASSES_H #define SERENE_PASSES_H +#include "serene/export.h" + #include namespace serene::passes { +/// Return a pass to lower the serene.symbol op +SERENE_EXPORT std::unique_ptr createLowerSymbol(); + +SERENE_EXPORT void registerAllPasses(); /// Return a pass to convert SLIR dialect to built-in dialects /// of MLIR. std::unique_ptr createSLIRLowerToMLIRPass(); diff --git a/libserene/include/serene/passes/CMakeLists.txt b/libserene/include/serene/passes/CMakeLists.txt new file mode 100644 index 0000000..0b30d08 --- /dev/null +++ b/libserene/include/serene/passes/CMakeLists.txt @@ -0,0 +1,9 @@ +set(LLVM_TARGET_DEFINITIONS passes.td) + +mlir_tablegen(passes.h.inc -gen-pass-decls) + +if(SERENE_ENABLE_DOCS) + mlir_tablegen(passes.md.inc -gen-pass-doc) +endif() + +add_public_tablegen_target(SerenePassGen) diff --git a/libserene/include/serene/passes/passes.td b/libserene/include/serene/passes/passes.td new file mode 100644 index 0000000..be5e8ef --- /dev/null +++ b/libserene/include/serene/passes/passes.td @@ -0,0 +1,49 @@ +/* + * 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_PASSES_TD +#define SERENE_PASSES_TD + +include "mlir/Pass/PassBase.td" + +def LowerSymbol : Pass<"lower-symbol", "slir::SymbolOp"> { + let summary = "Lowers `serene.symbol` operation to LLVM dialect"; + + let description = [{Lowers `serene.symbol` operation to LLVM dialect as an struct}]; + + // This is how we can create the default instance of this pass. + // via `createLowerSymbol` function + let constructor = "serene::passes::createLowerSymbol()"; +} + +def LowerSLIR : Pass<"lower-slir", "slir::NsOp"> { + let summary = "Lowers the SLIR dialect to LLVM IR indirectly"; + + let description = [{ + Lowers the SLIR dialect to LLVM IR indirectly meaning + that it will lower SLIR to other dialects that in turn will + eventually lower to llvm ir. + }]; + + // This is how we can create the default instance of this pass. + // via `createLowerSymbol` function + let constructor = "serene::passes::createLowerSLIR()"; + let dependentDialects = ["slir::SereneDialect", "mlir::func::FuncDialect"]; +} + +#endif // SERENE_PASSES_TD diff --git a/libserene/include/serene/slir/ops.td b/libserene/include/serene/slir/ops.td index 7e6ca3a..ef65d7a 100644 --- a/libserene/include/serene/slir/ops.td +++ b/libserene/include/serene/slir/ops.td @@ -1,4 +1,4 @@ -/* -*- C++ -*- +/* * Serene Programming Language * * Copyright (c) 2019-2022 Sameer Rahmani @@ -21,7 +21,9 @@ include "mlir/IR/OpBase.td" include "mlir/Interfaces/CallInterfaces.td" +include "mlir/IR/RegionKindInterface.td" include "mlir/IR/SymbolInterfaces.td" +include "mlir/IR/OpAsmInterface.td" // Base class for Serene dialect operations. This operation inherits from the base // `Op` class in OpBase.td, and provides: @@ -75,21 +77,48 @@ def ValueOp : Serene_Op<"value", [ let assemblyFormat = "attr-dict $value"; } +// Symbol Op +def SymbolOp : Serene_Op<"symbol", [ + ConstantLike, NoSideEffect, IsolatedFromAbove +]> { -// Def -def DefOp: Serene_Op<"def", [Symbol]> { + let summary = "This operation is the compile time contructor for symbol type"; + let description = [{ + The `symbol` operation produces an SSA value that holds a value of type + symbol at compile time. + + Example: + + ``` + + %1 = serene.symbol "some.ns" "symbol_name" + + // Equivalent generic form + %1 = "serene.symbol"() {ns = "some.ns", name = "symbol_name"} : () -> i32 + ``` + }]; + + let arguments = (ins StrAttr:$ns, StrAttr:$name); + let results = (outs SereneSymbol:$result); + + let assemblyFormat = "attr-dict $ns $name"; +} + + +// Define +def DefnieOp: Serene_Op<"define", [Symbol]> { let summary = "This operation defines a global binding in the current namespace"; let description = [{ - `def` defines a global binding in the current namespace. It always return a + `define` defines a global binding in the current namespace. It always return a symbol type. Examples: ```mlir - %foo = "serene.def"(%0){name = "foo"}: (i64) -> !serene.symbol + %foo = "serene.define"(%0){name = "foo"}: (i64) -> !serene.symbol // compact form - %bar = serene.def "bar", %0 : i64 + %bar = serene.define "bar", %0 : i64 ``` }]; @@ -174,4 +203,63 @@ def CallOp : Serene_Op<"call", }]; } +def NsOp : Serene_Op<"ns", [ + AffineScope, IsolatedFromAbove, NoRegionArguments, SymbolTable, Symbol, + OpAsmOpInterface +] # GraphRegionNoTerminator.traits> { + let summary = "This operation represents a Serene namespace."; + let description = [{ + The `serene.ns` operation represents a namespace that will eventually + lowers to a `mlir::ModuleOp`. + + Example: + + ```mlir + serene.ns @some.ns { + .... + } + ``` + }]; + + // TODO: Create a new Attr type that is an array to represent + // required namespaces + let arguments = (ins SymbolNameAttr:$sym_name, + OptionalAttr:$sym_visibility); + + let regions = (region SizedRegion<1>:$body); + + let assemblyFormat = "$sym_name attr-dict-with-keyword $body"; + + let builders = [ + OpBuilder<(ins CArg<"llvm::Optional", "{}">:$name)> + ]; + + let extraClassDeclaration = [{ + /// Construct a namespace from the given location with an optional name. + // static NsOp create(slir::reader::LocationRange loc, Optional name = llvm::None); + + /// Return the name of this module if present. + llvm::StringRef getName() { return sym_name(); } + + //===------------------------------------------------------------------===// + // SymbolOpInterface Methods + //===------------------------------------------------------------------===// + + /// A ModuleOp may optionally define a symbol. + bool isOptionalSymbol() { return false; } + + //===------------------------------------------------------------------===// + // DataLayoutOpInterface Methods + //===------------------------------------------------------------------===// + mlir::DataLayoutSpecInterface getDataLayoutSpec(); + + //===------------------------------------------------------------------===// + // OpAsmOpInterface Methods + //===------------------------------------------------------------------===// + static ::llvm::StringRef getDefaultDialect() { + return "builtin"; + } + }]; +} + #endif // SERENE_DIALECT_OPS diff --git a/libserene/include/serene/slir/types.td b/libserene/include/serene/slir/types.td index 26aef12..b0b0c7d 100644 --- a/libserene/include/serene/slir/types.td +++ b/libserene/include/serene/slir/types.td @@ -1,4 +1,4 @@ -/* -*- C++ -*- +/* * Serene Programming Language * * Copyright (c) 2019-2022 Sameer Rahmani diff --git a/libserene/lib/CMakeLists.txt b/libserene/lib/CMakeLists.txt index 261c3ba..c69f2ed 100644 --- a/libserene/lib/CMakeLists.txt +++ b/libserene/lib/CMakeLists.txt @@ -108,7 +108,7 @@ else() endif() # Generate the tablegen ODS files before this target -add_dependencies(serene SereneTablegen SereneDialectGen SereneErrorGen) +add_dependencies(serene SereneTablegen SereneDialectGen SerenePassGen SereneErrorGen) # We need this directory, and users of our library will need it too target_include_directories(serene PUBLIC "$") diff --git a/libserene/lib/passes/slir_lowering.cpp b/libserene/lib/passes/slir_lowering.cpp index afeda8e..32ed239 100644 --- a/libserene/lib/passes/slir_lowering.cpp +++ b/libserene/lib/passes/slir_lowering.cpp @@ -21,6 +21,7 @@ #include "serene/utils.h" #include +#include #include #include #include @@ -34,6 +35,27 @@ #include namespace serene::passes { +#define GEN_PASS_CLASSES +#include "serene/passes/passes.h.inc" + +class LowerSymbol : public LowerSymbolBase { + void runOnOperation() override { llvm::outs() << "here\n"; } +}; + +std::unique_ptr createLowerSymbol() { + return std::make_unique(); +} + +class LowerSLIR : public LowerSLIRBase { + void runOnOperation() override { llvm::outs() << "here\n"; } +}; + +std::unique_ptr createLowerSLIR() { + return std::make_unique(); +} + +#define GEN_PASS_REGISTRATION +#include "serene/passes/passes.h.inc" // ---------------------------------------------------------------------------- // ValueOp lowering to constant op @@ -191,4 +213,6 @@ void SLIRToMLIRPass::runOnModule() { std::unique_ptr createSLIRLowerToMLIRPass() { return std::make_unique(); }; + +void registerAllPasses() { registerPasses(); } } // namespace serene::passes diff --git a/libserene/lib/slir/ops.cpp b/libserene/lib/slir/ops.cpp index 38e2fda..159dbf3 100644 --- a/libserene/lib/slir/ops.cpp +++ b/libserene/lib/slir/ops.cpp @@ -24,4 +24,16 @@ #include #include -namespace serene::slir {} // namespace serene::slir +namespace serene::slir { + +mlir::DataLayoutSpecInterface NsOp::getDataLayoutSpec() { + // Take the first and only (if present) attribute that implements the + // interface. This needs a linear search, but is called only once per data + // layout object construction that is used for repeated queries. + for (mlir::NamedAttribute attr : getOperation()->getAttrs()) + if (auto spec = attr.getValue().dyn_cast()) + return spec; + return {}; +} + +} // namespace serene::slir