diff --git a/.bazeliskrc b/.bazeliskrc new file mode 100644 index 00000000..dbb7b4bc --- /dev/null +++ b/.bazeliskrc @@ -0,0 +1 @@ +USE_BAZEL_VERSION=6.4.0 \ No newline at end of file diff --git a/.bazelrc b/.bazelrc index 590738ca..27bf9f9e 100644 --- a/.bazelrc +++ b/.bazelrc @@ -2,4 +2,6 @@ build --incompatible_strict_action_env build --verbose_failures build --workspace_status_command "python3 workspace_status.py" build:macos --define client_type=macos +build:macos --cxxopt=-std=c++20 --host_cxxopt=-std=c++20 build:android --define client_type=android +common --noenable_bzlmod diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index b04f4018..91a5591a 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -49,6 +49,16 @@ jobs: working-directory: ${{github.workspace}}/build/test run: ctest -C ${{env.BUILD_TYPE}} --output-on-failure + - name: Configure CMake with MLIR + run: PKG_CONFIG_PATH=/usr/local/opt/icu4c/lib/pkgconfig cmake -B ${{github.workspace}}/build3 -DCMAKE_BUILD_TYPE=${{matrix.mode}} -G Ninja -DUSE_CCACHE=ON -DPSCM_ENABLE_MLIR_CODEGEN=ON + + - name: Build with MLIR + run: cmake --build ${{github.workspace}}/build3 --config ${{matrix.mode}} --verbose -j + + - name: Test with MLIR + working-directory: ${{github.workspace}}/build3/test + run: ctest -C ${{env.BUILD_TYPE}} --output-on-failure + - name: Configure CMake with C++20 Modules run: PKG_CONFIG_PATH=/usr/local/opt/icu4c/lib/pkgconfig CXX=/usr/local/opt/llvm/bin/clang++ CC=/usr/local/opt/llvm/bin/clang cmake -B ${{github.workspace}}/build2 -DCMAKE_BUILD_TYPE=${{matrix.mode}} -DCMAKE_MAKE_PROGRAM=/usr/local/bin/ninja -G Ninja -DUSE_CCACHE=ON -DPSCM_USE_CXX20_MODULES=ON diff --git a/BUILD.bazel b/BUILD.bazel index ee733da4..241f4e32 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -1,6 +1,12 @@ load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library") load("version.bzl", "gen_pscm_version_info") load("test.bzl", "collect_pscm_tests") +load("@llvm-project//mlir:tblgen.bzl", "gentbl_cc_library", "td_library") + +config_setting( + name = "mlir_codegen", + values = {"define": "codegen=mlir"}, +) py_binary( name = "gen_cpp", @@ -24,7 +30,11 @@ cc_library( [ "src/**/*.cpp", ], - ) + [ + exclude = ["src/codegen/**"], + ) + select({ + ":mlir_codegen": glob(["src/codegen/**/*.cpp"]), + "//conditions:default": [], + }) + [ ":src/version.cpp", ], hdrs = glob( @@ -42,6 +52,9 @@ cc_library( defines = select({ "@platforms//cpu:wasm32": ["WASM_PLATFORM"], "//conditions:default": [], + }) + select({ + ":mlir_codegen": ["PSCM_ENABLE_MLIR_CODEGEN"], + "//conditions:default": [], }), features = select({ # only wasm need add exceptions explict @@ -74,7 +87,51 @@ cc_library( # "@optional", # "@string-view-lite", # "@variant", - ], + ] + select({ + ":mlir_codegen": [ + ":pscm-ops-inc-gen", + "@llvm-project//llvm:Core", + "@llvm-project//llvm:OrcJIT", + "@llvm-project//llvm:Support", + "@llvm-project//mlir:AffineDialect", + "@llvm-project//mlir:AffineToStandard", + "@llvm-project//mlir:AffineTransforms", + "@llvm-project//mlir:AllPassesAndDialects", + "@llvm-project//mlir:Analysis", + "@llvm-project//mlir:ArithDialect", + "@llvm-project//mlir:ArithToLLVM", + "@llvm-project//mlir:BuiltinToLLVMIRTranslation", + "@llvm-project//mlir:CastInterfaces", + "@llvm-project//mlir:ControlFlowToLLVM", + "@llvm-project//mlir:ExecutionEngine", + "@llvm-project//mlir:ExecutionEngineUtils", + "@llvm-project//mlir:FuncDialect", + "@llvm-project//mlir:FuncExtensions", + "@llvm-project//mlir:FuncToLLVM", + "@llvm-project//mlir:IR", + "@llvm-project//mlir:LLVMCommonConversion", + "@llvm-project//mlir:LLVMDialect", + "@llvm-project//mlir:LLVMIRTransforms", + "@llvm-project//mlir:LLVMToLLVMIRTranslation", + "@llvm-project//mlir:MemRefDialect", + "@llvm-project//mlir:MemRefToLLVM", + "@llvm-project//mlir:Parser", + "@llvm-project//mlir:Pass", + "@llvm-project//mlir:SCFDialect", + "@llvm-project//mlir:SCFToControlFlow", + "@llvm-project//mlir:SideEffectInterfaces", + "@llvm-project//mlir:Support", + "@llvm-project//mlir:ToLLVMIRTranslation", + "@llvm-project//mlir:TransformUtils", + "@llvm-project//mlir:Transforms", + + # clang + "@llvm-project//clang:driver", + "@llvm-project//clang:frontend", + "@llvm-project//clang:tooling", + ], + "//conditions:default": [], + }), ) cc_binary( @@ -85,3 +142,45 @@ cc_binary( ) collect_pscm_tests() + +td_library( + name = "pscm-ops-td-files", + srcs = [ + "include/pscm/codegen/mlir/Ops.td", + ], + includes = ["include"], + tags = ["manual"], + deps = [ + "@llvm-project//mlir:CallInterfacesTdFiles", + "@llvm-project//mlir:CastInterfacesTdFiles", + "@llvm-project//mlir:FunctionInterfacesTdFiles", + "@llvm-project//mlir:OpBaseTdFiles", + "@llvm-project//mlir:SideEffectInterfacesTdFiles", + ], +) + +gentbl_cc_library( + name = "pscm-ops-inc-gen", + tags = ["manual"], + tbl_outs = [ + ( + ["-gen-op-decls"], + "Ops.h.inc", + ), + ( + ["-gen-op-defs"], + "Ops.cpp.inc", + ), + ( + ["-gen-dialect-decls"], + "Dialect.h.inc", + ), + ( + ["-gen-dialect-defs"], + "Dialect.cpp.inc", + ), + ], + tblgen = "@llvm-project//mlir:mlir-tblgen", + td_file = "include/pscm/codegen/mlir/Ops.td", + deps = [":pscm-ops-td-files"], +) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7600737a..6124e399 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,18 +1,22 @@ cmake_minimum_required(VERSION 3.26) SET(CMAKE_OSX_DEPLOYMENT_TARGET "13.3" CACHE STRING "Minimum OS X deployment version" FORCE) -project(pscm VERSION 0.3.0 LANGUAGES CXX) +project(pscm VERSION 0.3.0 LANGUAGES C CXX) option(PSCM_USE_CXX20_MODULES "enable c++20 modules" OFF) +option(PSCM_ENABLE_MLIR_CODEGEN "enable codegen with MLIR" OFF) if (WIN32) set(CMAKE_CXX_STANDARD 20) else () if (PSCM_USE_CXX20_MODULES) if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") - # CMake 3.26 - # set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "2182bf5c-ef0d-489a-91da-49dbc3090d2a") - # CMake 3.27 - set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "aa1f7df0-828a-4fcd-9afc-2dc80491aca7") - # set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "ac01f462-0f5f-432a-86aa-acef252918a6") - include(cxx_modules_rules_clang.cmake) + if (${CMAKE_MINOR_VERSION} STREQUAL 26) + set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "2182bf5c-ef0d-489a-91da-49dbc3090d2a") + include(cxx_modules_rules_clang.cmake) + elseif (${CMAKE_MINOR_VERSION} STREQUAL 27) + set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "aa1f7df0-828a-4fcd-9afc-2dc80491aca7") + else () + # https://cmake.org/cmake/help/latest/policy/CMP0155.html#policy:CMP0155 + cmake_policy(SET CMP0155 NEW) + endif () set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_EXTENSIONS OFF) else () @@ -27,7 +31,7 @@ endif () set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -add_library(pscm) +add_library(pscm STATIC) if (EMSCRIPTEN) target_link_options(pscm PUBLIC "-sUSE_ICU=1") target_compile_options(pscm PUBLIC "-sUSE_ICU=1") @@ -36,7 +40,7 @@ elseif (WIN32) target_link_libraries(pscm PUBLIC icu) else () find_package(PkgConfig REQUIRED) - pkg_check_modules (ICU REQUIRED icu-i18n icu-uc icu-io IMPORTED_TARGET) + pkg_check_modules(ICU REQUIRED icu-i18n icu-uc icu-io IMPORTED_TARGET) target_link_libraries(pscm PUBLIC PkgConfig::ICU) endif () @@ -97,6 +101,54 @@ endif () file(GLOB PSCM_SRCS "src/*.cpp") target_sources(pscm PRIVATE ${PSCM_SRCS}) +if (PSCM_ENABLE_MLIR_CODEGEN) + message(STATUS "Enable codegen with MLIR") + target_compile_definitions(pscm PRIVATE PSCM_ENABLE_MLIR_CODEGEN) + file(GLOB CODEGEN_SRCS "src/codegen/*.cpp" src/codegen/mlir/*.cpp) + target_sources(pscm PRIVATE ${CODEGEN_SRCS}) + set(CMAKE_MODULE_PATH /usr/local/opt/llvm/lib/cmake/clang /usr/local/opt/llvm/lib/cmake/lld /usr/local/opt/llvm/lib/cmake/llvm /usr/local/opt/llvm/lib/cmake/mlir) + set(CMAKE_PREFIX_PATH /usr/local/opt/llvm/lib/cmake/clang /usr/local/opt/llvm/lib/cmake/lld /usr/local/opt/llvm/lib/cmake/llvm /usr/local/opt/llvm/lib/cmake/mlir) + find_package(LLVM REQUIRED) + find_package(MLIR REQUIRED) + find_package(Clang REQUIRED) + include(TableGen) + include(AddMLIR) + include_directories(/usr/local/opt/llvm/include) + set(LLVM_TARGET_DEFINITIONS include/pscm/codegen/mlir/Ops.td) + mlir_tablegen(generate/Ops.h.inc -gen-op-decls) + mlir_tablegen(generate/Ops.cpp.inc -gen-op-defs) + mlir_tablegen(generate/Dialect.h.inc -gen-dialect-decls) + mlir_tablegen(generate/Dialect.cpp.inc -gen-dialect-defs) + add_public_tablegen_target(pscm-inc-gen) + add_dependencies(pscm pscm-inc-gen) + get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS) + get_property(conversion_libs GLOBAL PROPERTY MLIR_CONVERSION_LIBS) + get_property(extension_libs GLOBAL PROPERTY MLIR_EXTENSION_LIBS) + target_link_libraries(pscm PRIVATE + ${dialect_libs} + ${conversion_libs} + ${extension_libs} + + MLIRAnalysis + MLIRBuiltinToLLVMIRTranslation + MLIRCastInterfaces + MLIRCallInterfaces + MLIRExecutionEngine + MLIRLLVMToLLVMIRTranslation + MLIRMemRefDialect + MLIRIR + MLIRParser + MLIRPass + MLIRSideEffectInterfaces + MLIRSupport + MLIRTargetLLVMIRExport + MLIRTransforms + + clangDriver + clangTooling + clangFrontend + ) +endif () target_sources(pscm PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/generate/src/version.cpp src/logger/Logger.cpp diff --git a/WORKSPACE.bazel b/WORKSPACE.bazel index 3ad392a7..069bf4d0 100644 --- a/WORKSPACE.bazel +++ b/WORKSPACE.bazel @@ -2,6 +2,7 @@ workspace(name = "dev_pscm") load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository", "new_git_repository") +load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") new_git_repository( name = "cpp-linenoise", @@ -237,3 +238,87 @@ git_repository( commit = "1c1933fa1ebadd6954fe9eff18e8bb0d018594ff", remote = "https://github.com/PikachuHy/icu.bazel.git", ) + +new_git_repository( + name = "llvm-raw", + build_file_content = "# empty", + commit = "6009708b4367171ccdbf4b5905cb6a803753fe18", + remote = "https://github.com/llvm/llvm-project.git" +) + +load("@llvm-raw//utils/bazel:configure.bzl", "llvm_configure") + +llvm_configure(name = "llvm-project") + +maybe( + http_archive, + name = "llvm_zlib", + build_file = "@llvm-raw//utils/bazel/third_party_build:zlib-ng.BUILD", + sha256 = "e36bb346c00472a1f9ff2a0a4643e590a254be6379da7cddd9daeb9a7f296731", + strip_prefix = "zlib-ng-2.0.7", + urls = [ + "https://github.com/zlib-ng/zlib-ng/archive/refs/tags/2.0.7.zip", + ], +) + +maybe( + http_archive, + name = "vulkan_headers", + build_file = "@llvm-raw//utils/bazel/third_party_build:vulkan_headers.BUILD", + sha256 = "19f491784ef0bc73caff877d11c96a48b946b5a1c805079d9006e3fbaa5c1895", + strip_prefix = "Vulkan-Headers-9bd3f561bcee3f01d22912de10bb07ce4e23d378", + urls = [ + "https://github.com/KhronosGroup/Vulkan-Headers/archive/9bd3f561bcee3f01d22912de10bb07ce4e23d378.tar.gz", + ], +) + +load("@llvm-raw//utils/bazel:vulkan_sdk.bzl", "vulkan_sdk_setup") + +maybe( + vulkan_sdk_setup, + name = "vulkan_sdk", +) + +maybe( + http_archive, + name = "gmp", + build_file = "@llvm-raw//utils/bazel/third_party_build:gmp.BUILD", + sha256 = "fd4829912cddd12f84181c3451cc752be224643e87fac497b69edddadc49b4f2", + strip_prefix = "gmp-6.2.1", + urls = [ + "https://gmplib.org/download/gmp/gmp-6.2.1.tar.xz", + "https://ftp.gnu.org/gnu/gmp/gmp-6.2.1.tar.xz", + ], +) + +# https://www.mpfr.org/mpfr-current/ +# +# When updating to a newer version, don't use URLs with "mpfr-current" in them. +# Instead, find a stable URL like the one used currently. +maybe( + http_archive, + name = "mpfr", + build_file = "@llvm-raw//utils/bazel/third_party_build:mpfr.BUILD", + sha256 = "9cbed5d0af0d9ed5e9f8dd013e17838eb15e1db9a6ae0d371d55d35f93a782a7", + strip_prefix = "mpfr-4.1.1", + urls = ["https://www.mpfr.org/mpfr-4.1.1/mpfr-4.1.1.tar.gz"], +) + +maybe( + new_git_repository, + name = "pfm", + build_file = "@llvm-raw//utils/bazel/third_party_build:pfm.BUILD", + remote = "https://git.code.sf.net/p/perfmon2/libpfm4", + tag = "v4.12.1", +) + +maybe( + http_archive, + name = "llvm_zstd", + build_file = "@llvm-raw//utils/bazel/third_party_build:zstd.BUILD", + sha256 = "7c42d56fac126929a6a85dbc73ff1db2411d04f104fae9bdea51305663a83fd0", + strip_prefix = "zstd-1.5.2", + urls = [ + "https://github.com/facebook/zstd/releases/download/v1.5.2/zstd-1.5.2.tar.gz" + ], +) \ No newline at end of file diff --git a/build.pscm b/build.pscm index c19dd5c6..c6e703ff 100644 --- a/build.pscm +++ b/build.pscm @@ -31,7 +31,7 @@ (cpp_library (name "pscm") (srcs - (glob "src/**/*.cpp" "src/**/*.cppm") + (glob "src/icu/*.cpp" "src/logger/*.cpp" "src/misc/*.cpp" "src/*.cpp" "src/**/*.cppm") "build/generate/src/version.cpp" ) (hdrs diff --git a/include/pscm/Cell.h b/include/pscm/Cell.h index 444c6d01..470246c6 100644 --- a/include/pscm/Cell.h +++ b/include/pscm/Cell.h @@ -149,6 +149,7 @@ class Cell { }; UString to_string() const; UString pretty_string() const; + std::string to_std_string() const; void display(Port& port); static Cell nil() { diff --git a/include/pscm/Scheme.h b/include/pscm/Scheme.h index 8ca52a4c..ac0bda39 100644 --- a/include/pscm/Scheme.h +++ b/include/pscm/Scheme.h @@ -46,6 +46,7 @@ class Scheme { std::vector module_list_; std::unordered_map module_map_; bool use_register_machine_; + bool use_mlir_ = true; bool in_repl_ = false; friend class SchemeProxy; }; diff --git a/include/pscm/codegen/codegen.h b/include/pscm/codegen/codegen.h new file mode 100644 index 00000000..441caeff --- /dev/null +++ b/include/pscm/codegen/codegen.h @@ -0,0 +1,7 @@ +#pragma once +#include "pscm/Cell.h" +#include + +namespace pscm { +std::optional mlir_codegen_and_run_jit(Cell expr); +} \ No newline at end of file diff --git a/include/pscm/codegen/mlir/Dialect.h b/include/pscm/codegen/mlir/Dialect.h new file mode 100644 index 00000000..5a6fa028 --- /dev/null +++ b/include/pscm/codegen/mlir/Dialect.h @@ -0,0 +1,14 @@ +#pragma once + +#include "mlir/IR/BuiltinTypes.h" +#include "mlir/IR/Dialect.h" +#include "mlir/IR/FunctionInterfaces.h" +#include "mlir/IR/SymbolTable.h" +#include "mlir/Interfaces/CallInterfaces.h" +#include "mlir/Interfaces/CastInterfaces.h" +#include "mlir/Interfaces/SideEffectInterfaces.h" + +#include "Dialect.h.inc" + +#define GET_OP_CLASSES +#include "Ops.h.inc" \ No newline at end of file diff --git a/include/pscm/codegen/mlir/Ops.td b/include/pscm/codegen/mlir/Ops.td new file mode 100644 index 00000000..fbdb9349 --- /dev/null +++ b/include/pscm/codegen/mlir/Ops.td @@ -0,0 +1,107 @@ +#ifndef PSCM_OPS +#define PSCM_OPS + +include "mlir/IR/OpBase.td" +include "mlir/IR/FunctionInterfaces.td" +include "mlir/IR/SymbolInterfaces.td" +include "mlir/Interfaces/CallInterfaces.td" +include "mlir/Interfaces/CastInterfaces.td" +include "mlir/Interfaces/SideEffectInterfaces.td" + +def PSCM_Dialect : Dialect { + let name = "pscm"; + let cppNamespace = "::pscm"; + // let hasConstantMaterializer = 1; + // let useDefaultTypePrinterParser = 1; +} + +class PSCM_Op traits = []> : + Op; + +def PSCM_Type : AnyTypeOf<[I64]>; + +def ConstantOp : PSCM_Op<"constant", + [Pure]> { + let summary = "constant"; + let description = [{ + Constant operation + }]; + let arguments = (ins I64Attr:$value); + let results = (outs I64); + + // let hasCustomAssemblyFormat = 1; + + let builders = [ + OpBuilder<(ins "int":$value)> + ]; + + let hasVerifier = 1; + +} + +def AddOp : PSCM_Op<"add", + [Pure]> { + let summary = "addition operation"; + let description = [{ + The "add" operation performs addidtion + }]; + + let arguments = (ins I64:$lhs, I64:$rhs); + let results = (outs I64); + + let hasCustomAssemblyFormat = 1; + + let builders = [ + OpBuilder<(ins "Value":$lhs, "Value":$rhs)> + ]; + +} + +def FuncOp : PSCM_Op<"func", [DeclareOpInterfaceMethods, FunctionOpInterface, IsolatedFromAbove]> { + let summary = ""; + let description = [{}]; + + let arguments = (ins + SymbolNameAttr:$sym_name, + TypeAttrOf:$function_type, + OptionalAttr:$arg_attrs, + OptionalAttr:$res_attrs + ); + let regions = (region AnyRegion:$body); + let builders = [OpBuilder<(ins + "StringRef":$name, "FunctionType":$type, + CArg<"llvm::ArrayRef", "{}">:$attrs + )>]; + let extraClassDeclaration = [{ + llvm::ArrayRef getArgumentTypes() { return getFunctionType().getInputs(); } + llvm::ArrayRef getResultTypes() { return getFunctionType().getResults(); } + }]; + let hasCustomAssemblyFormat = 1; + let skipDefaultBuilders = 1; +} + +def ReturnOp : PSCM_Op<"return", [Pure, HasParent<"FuncOp">, Terminator]> { + let arguments = (ins Variadic:$input); + let assemblyFormat = "($input^ `:` type($input))? attr-dict"; + let builders = [ + OpBuilder<(ins), [{ build($_builder, $_state, std::nullopt); }]> + ]; + let extraClassDeclaration = [{ + bool hasOperand() { return getNumOperands() != 0; } + }]; + let hasVerifier = 1; +} + + +def PrintOp : PSCM_Op<"print"> { + let summary = "print operation"; + let description = [{ + The "print" builtin operation prints a given input tensor, and produces + no results. + }]; + + let arguments = (ins I64:$input); + + let assemblyFormat = "$input attr-dict `:` type($input)"; +} +#endif diff --git a/include/pscm/codegen/mlir/Passes.h b/include/pscm/codegen/mlir/Passes.h new file mode 100644 index 00000000..184f31f6 --- /dev/null +++ b/include/pscm/codegen/mlir/Passes.h @@ -0,0 +1,12 @@ +#pragma once + +#include + +namespace mlir { +class Pass; +} // namespace mlir + +namespace pscm { +std::unique_ptr createLowerToLLVMPass(); +std::unique_ptr createLowerToAffinePass(); +} // namespace pscm diff --git a/src/Cell.cpp b/src/Cell.cpp index dcee3912..0a8a736d 100644 --- a/src/Cell.cpp +++ b/src/Cell.cpp @@ -298,6 +298,13 @@ UString Cell::pretty_string() const { return to_string(); } +std::string Cell::to_std_string() const { + auto s = to_string(); + std::string converted; + s.toUTF8String(converted); + return converted; +} + bool Cell::to_bool(SourceLocation loc PSCM_CXX20_MODULES_DEFAULT_ARG_COMPAT) const { PSCM_ASSERT_WITH_LOC(is_bool(), loc); return data_ != nullptr; diff --git a/src/Scheme.cpp b/src/Scheme.cpp index 849cdca8..70c6783e 100644 --- a/src/Scheme.cpp +++ b/src/Scheme.cpp @@ -37,6 +37,11 @@ import linenoise; #include "pscm/version.h" #include "spdlog/spdlog.h" #include "unicode/schriter.h" + +#ifdef PSCM_ENABLE_MLIR_CODEGEN +#include "pscm/codegen/codegen.h" +#endif + #include #include #include @@ -470,6 +475,18 @@ Cell Scheme::eval(const UString& code) { if (use_register_machine_) { ret = Evaluator(*this).eval(ret, current_module_->env()); } +#ifdef PSCM_ENABLE_MLIR_CODEGEN + else if (use_mlir_) { + auto run_ret = mlir_codegen_and_run_jit(ret); + if (run_ret.has_value()) { + ret = run_ret.value(); + } + else { + // failback to direct eval + ret = eval(ret); + } + } +#endif else { ret = eval(ret); } diff --git a/src/codegen/codegen.cpp b/src/codegen/codegen.cpp new file mode 100644 index 00000000..5fd0d757 --- /dev/null +++ b/src/codegen/codegen.cpp @@ -0,0 +1,304 @@ +#include "pscm/codegen/mlir/Passes.h" + +using namespace mlir; + +#include "pscm/codegen/codegen.h" +#include "pscm/codegen/mlir/Dialect.h" + +#include "mlir/Dialect/Func/Extensions/AllExtensions.h" + +#include "mlir/Dialect/Affine/Passes.h" +#include "mlir/Dialect/LLVMIR/Transforms/Passes.h" +#include "mlir/ExecutionEngine/ExecutionEngine.h" +#include "mlir/ExecutionEngine/OptUtils.h" +#include "mlir/IR/AsmState.h" +#include "mlir/IR/BuiltinOps.h" +#include "mlir/IR/MLIRContext.h" +#include "mlir/IR/Verifier.h" +#include "mlir/InitAllDialects.h" +#include "mlir/Parser/Parser.h" +#include "mlir/Pass/Pass.h" +#include "mlir/Pass/PassManager.h" +#include "mlir/Target/LLVMIR/Dialect/Builtin/BuiltinToLLVMIRTranslation.h" +#include "mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.h" +#include "mlir/Target/LLVMIR/Export.h" +#include "mlir/Transforms/Passes.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Support/raw_ostream.h" + +#include "llvm/ADT/ScopedHashTable.h" + +#include "pscm/Number.h" +#include "pscm/Symbol.h" +#include "pscm/common_def.h" +#include "pscm/scm_utils.h" + +#include +#include +#include +#include +#include +#include + +#include +PSCM_INLINE_LOG_DECLARE("pscm.codegen"); + +namespace pscm { + +mlir::Value create_i64(mlir::OpBuilder& builder, int64_t data) { + auto dataType = builder.getI64Type(); + auto dataAttr = builder.getI64IntegerAttr(data); + auto dataValue = builder.create(builder.getUnknownLoc(), dataType, dataAttr); + return dataValue; +} + +int link_to_executable(llvm::LLVMContext& ctx) { + llvm::IntrusiveRefCntPtr opts = new clang::DiagnosticOptions; + clang::DiagnosticsEngine diags(new clang::DiagnosticIDs, opts, + new clang::TextDiagnosticPrinter(llvm::errs(), opts.get())); + + clang::driver::Driver d("clang", llvm::sys::getDefaultTargetTriple(), diags, "pscm compiler"); + std::vector args = { "pscmc" }; + + args.push_back("output.o"); + args.push_back("-o"); + args.push_back("a.out"); + args.push_back("-isysroot"); + args.push_back("/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk"); + args.push_back("-v"); + + d.setCheckInputsExist(false); + + std::unique_ptr compilation; + compilation.reset(d.BuildCompilation(args)); + + if (!compilation) { + return 1; + } + + llvm::SmallVector> failCommand; + // compilation->ExecuteJobs(compilation->getJobs(), failCommand); + + d.ExecuteCompilation(*compilation, failCommand); + if (failCommand.empty()) { + llvm::outs() << "Done!\n"; + } + else { + llvm::errs() << "Linking failed!\n"; + return -1; + } + return 0; +} + +int run_jit(mlir::ModuleOp m) { + mlir::registerBuiltinDialectTranslation(*m->getContext()); + mlir::registerLLVMDialectTranslation(*m->getContext()); + llvm::LLVMContext ctx; + auto llvm_module = mlir::translateModuleToLLVMIR(m, ctx); + if (!llvm_module) { + llvm::errs() << "Failed to emit LLVM IR " + << "\n"; + return -1; + } + llvm::InitializeNativeTarget(); + llvm::InitializeNativeTargetAsmPrinter(); + + auto builder = llvm::orc::JITTargetMachineBuilder::detectHost(); + if (!builder) { + llvm::errs() << "Could not create JITTargetMachineBuilder" + << "\n"; + return -1; + } + auto machine = builder->createTargetMachine(); + if (!machine) { + llvm::errs() << "Could not create TargetMachine" + << "\n"; + return -1; + } + mlir::ExecutionEngine::setupTargetTripleAndDataLayout(llvm_module.get(), machine.get().get()); + auto opt = mlir::makeOptimizingTransformer(0, 0, nullptr); + if (auto err = opt(llvm_module.get())) { + llvm::errs() << "Failed to optimize LLVM IR" + << "\n"; + return -1; + } + // llvm::errs() << *llvm_module << "\n"; + + mlir::ExecutionEngineOptions engine_options; + engine_options.transformer = opt; + + auto engine = mlir::ExecutionEngine::create(m, engine_options); + + if (!engine) { + llvm::errs() << "Failed to construct an execution engine" + << "\n"; + return -1; + } + auto invocationResult = engine.get()->invokePacked("main"); + if (invocationResult) { + llvm::errs() << "JIT invocation failed" + << "\n"; + return -1; + } + + std::error_code ec; + llvm::raw_fd_ostream dest("output.o", ec, llvm::sys::fs::OF_None); + llvm::legacy::PassManager pass; + auto fileType = llvm::CGFT_ObjectFile; + if (machine.get()->addPassesToEmitFile(pass, dest, nullptr, fileType)) { + llvm::errs() << "TheTargetMachine can't emit a file of this type"; + return 1; + } + + pass.run(*llvm_module); + machine.get()->getTargetTriple(); + // FIXME + // error: unable to execute command: Segmentation fault: 11 + // error: linker command failed due to signal (use -v to see invocation) + // link_to_executable(ctx); + // engine.get()->dumpToObjectFile("pscm.jit.o"); + return 0; +} + +int create_mlir(mlir::MLIRContext& ctx, mlir::OwningOpRef& m) { + mlir::OpBuilder builder(&ctx); + llvm::ScopedHashTable symbolTable; + m = mlir::ModuleOp::create(builder.getUnknownLoc()); + builder.setInsertionPointToEnd(m->getBody()); + llvm::SmallVector argTypes; + argTypes.reserve(0); + auto mainFuncType = builder.getFunctionType(argTypes, std::nullopt); + auto mainFunc = builder.create(builder.getUnknownLoc(), "main", mainFuncType); + mlir::Block& entryBlock = mainFunc.front(); + builder.setInsertionPointToStart(&entryBlock); + + auto lhs = create_i64(builder, 1); + auto rhs = create_i64(builder, 2); + + auto ret = builder.create(builder.getUnknownLoc(), lhs, rhs); + + builder.create(builder.getUnknownLoc(), ret); + + builder.create(builder.getUnknownLoc(), llvm::ArrayRef()); + + if (failed(mlir::verify(*m))) { + m->emitError("module verfification error"); + return -1; + } + + return 0; +} + +int create_mlir_add(mlir::MLIRContext& ctx, mlir::OwningOpRef& m, Cell a, Cell b) { + mlir::OpBuilder builder(&ctx); + llvm::ScopedHashTable symbolTable; + m = mlir::ModuleOp::create(builder.getUnknownLoc()); + builder.setInsertionPointToEnd(m->getBody()); + llvm::SmallVector argTypes; + argTypes.reserve(0); + auto mainFuncType = builder.getFunctionType(argTypes, std::nullopt); + auto mainFunc = builder.create(builder.getUnknownLoc(), "main", mainFuncType); + mlir::Block& entryBlock = mainFunc.front(); + builder.setInsertionPointToStart(&entryBlock); + PSCM_ASSERT(a.is_num()); + PSCM_ASSERT(b.is_num()); + auto num1 = a.to_num(); + auto num2 = b.to_num(); + auto lhs = create_i64(builder, num1->to_int()); + auto rhs = create_i64(builder, num2->to_int()); + + auto ret = builder.create(builder.getUnknownLoc(), lhs, rhs); + + builder.create(builder.getUnknownLoc(), ret); + + builder.create(builder.getUnknownLoc(), llvm::ArrayRef()); + + if (failed(mlir::verify(*m))) { + m->emitError("module verfification error"); + return -1; + } + + return 0; +} + +std::optional mlir_codegen_and_run_jit(Cell expr) { + mlir::registerAsmPrinterCLOptions(); + mlir::registerMLIRContextCLOptions(); + mlir::registerPassManagerCLOptions(); + + mlir::DialectRegistry registry; + mlir::func::registerAllExtensions(registry); + + mlir::MLIRContext context(registry); + context.getOrLoadDialect(); + + mlir::OwningOpRef module; + + std::cout << "expr: " << expr.to_std_string() << std::endl; + if (!expr.is_pair()) { + return std::nullopt; + } + Cell fakeResult; + // hardcode only suport (+ num1 num2) + if (car(expr).is_sym() && *car(expr).to_sym() == "+"_sym) { + auto num1 = cadr(expr); + auto num2 = caddr(expr); + if (!cdddr(expr).is_nil()) { + return std::nullopt; + } + if (!num1.is_num() || !num2.is_num()) { + return std::nullopt; + } + auto n1 = num1.to_num(); + auto n2 = num2.to_num(); + if (!n1->is_int() || !n2->is_int()) { + return std::nullopt; + } + if (auto err = create_mlir_add(context, module, cadr(expr), caddr(expr))) { + llvm::errs() << "create mlir error" + << "\n"; + return std::nullopt; + } + fakeResult = new pscm::Number(n1->to_int() + n2->to_int()); + } + else { + llvm::errs() << "not supported now" + << "\n"; + return std::nullopt; + } + + module->dump(); + mlir::PassManager pm(module.get()->getName()); + if (mlir::failed(mlir::applyPassManagerCLOptions(pm))) { + llvm::errs() << "applyPassManagerCLOptions error" + << "\n"; + return std::nullopt; + } + mlir::OpPassManager& optPM = pm.nest(); + optPM.addPass(mlir::createCanonicalizerPass()); + optPM.addPass(mlir::createCanonicalizerPass()); + optPM.addPass(mlir::createCSEPass()); + pm.addPass(createLowerToAffinePass()); + pm.addPass(createLowerToLLVMPass()); + pm.addNestedPass(mlir::LLVM::createDIScopeForLLVMFuncOpPass()); + if (mlir::failed(pm.run(*module))) { + llvm::errs() << "run pass error" + << "\n"; + return std::nullopt; + } + module->dump(); + if (auto err = run_jit(*module)) { + llvm::errs() << "run mlir error" + << "\n"; + return std::nullopt; + } + return fakeResult; +} +} // namespace pscm diff --git a/src/codegen/mlir/Dialect.cpp b/src/codegen/mlir/Dialect.cpp new file mode 100644 index 00000000..dc65f33c --- /dev/null +++ b/src/codegen/mlir/Dialect.cpp @@ -0,0 +1,142 @@ +#include "pscm/codegen/mlir/Passes.h" +using namespace mlir; +#include "pscm/codegen/mlir/Dialect.h" + +#include "mlir/IR/Builders.h" +#include "mlir/IR/BuiltinTypes.h" +#include "mlir/IR/FunctionImplementation.h" +#include "mlir/IR/OpImplementation.h" +#include "mlir/Transforms/InliningUtils.h" + +#include "Dialect.cpp.inc" +using namespace pscm; + +static mlir::ParseResult parseBinaryOp(mlir::OpAsmParser& parser, mlir::OperationState& result) { + SmallVector operands; + SMLoc operandsLoc = parser.getCurrentLocation(); + Type type; + if (parser.parseOperandList(operands, 2) || parser.parseOptionalAttrDict(result.attributes) || + parser.parseColonType(type)) + return mlir::failure(); + + if (FunctionType funcType = llvm::dyn_cast(type)) { + if (parser.resolveOperands(operands, funcType.getInputs(), operandsLoc, result.operands)) + return mlir::failure(); + result.addTypes(funcType.getResults()); + return mlir::success(); + } + + if (parser.resolveOperands(operands, type, result.operands)) + return mlir::failure(); + result.addTypes(type); + return mlir::success(); +} + +static void printBinaryOp(mlir::OpAsmPrinter& printer, mlir::Operation *op) { + printer << " " << op->getOperands(); + printer.printOptionalAttrDict(op->getAttrs()); + printer << " : "; + + Type resultType = *op->result_type_begin(); + if (llvm::all_of(op->getOperandTypes(), [=](Type type) { + return type == resultType; + })) { + printer << resultType; + return; + } + + printer.printFunctionalType(op->getOperandTypes(), op->getResultTypes()); +} + +void ConstantOp::build(mlir::OpBuilder& builder, mlir::OperationState& state, int value) { +} + +mlir::LogicalResult ConstantOp::verify() { + return mlir::success(); +} + +void AddOp::build(mlir::OpBuilder& builder, mlir::OperationState& state, mlir::Value lhs, mlir::Value rhs) { + state.addTypes(builder.getI64Type()); + state.addOperands({ lhs, rhs }); +} + +mlir::ParseResult AddOp::parse(mlir::OpAsmParser& parser, mlir::OperationState& result) { + return parseBinaryOp(parser, result); +} + +void AddOp::print(mlir::OpAsmPrinter& p) { + printBinaryOp(p, *this); +} + +void FuncOp::build(mlir::OpBuilder& builder, mlir::OperationState& state, llvm::StringRef name, mlir::FunctionType type, + llvm::ArrayRef attrs) { + buildWithEntryBlock(builder, state, name, type, attrs, type.getInputs()); +} + +mlir::ParseResult FuncOp::parse(mlir::OpAsmParser& parser, mlir::OperationState& result) { + auto buildFuncType = [](mlir::Builder& builder, llvm::ArrayRef argTypes, + llvm::ArrayRef results, mlir::function_interface_impl::VariadicFlag, + std::string&) { + return builder.getFunctionType(argTypes, results); + }; + + return mlir::function_interface_impl::parseFunctionOp(parser, result, false, getFunctionTypeAttrName(result.name), + buildFuncType, getArgAttrsAttrName(result.name), + getResAttrsAttrName(result.name)); +} + +void FuncOp::print(mlir::OpAsmPrinter& p) { + mlir::function_interface_impl::printFunctionOp(p, *this, false, getFunctionTypeAttrName(), getArgAttrsAttrName(), + getResAttrsAttrName()); +} + +mlir::Region *FuncOp::getCallableRegion() { + return &getBody(); +} + +llvm::ArrayRef FuncOp::getCallableResults() { + return getFunctionType().getResults(); +} + +ArrayAttr FuncOp::getCallableArgAttrs() { + return getArgAttrs().value_or(nullptr); +} + +ArrayAttr FuncOp::getCallableResAttrs() { + return getResAttrs().value_or(nullptr); +} + +mlir::LogicalResult ReturnOp::verify() { + auto function = cast((*this)->getParentOp()); + + if (getNumOperands() > 1) + return emitOpError() << "expects at most 1 return operand"; + + const auto& results = function.getFunctionType().getResults(); + if (getNumOperands() != results.size()) + return emitOpError() << "does not return the same number of values (" << getNumOperands() + << ") as the enclosing function (" << results.size() << ")"; + + if (!hasOperand()) + return mlir::success(); + + auto inputType = *operand_type_begin(); + auto resultType = results.front(); + + if (inputType == resultType || llvm::isa(inputType) || + llvm::isa(resultType)) + return mlir::success(); + + return emitError() << "type of return operand (" << inputType << ") doesn't match function result type (" + << resultType << ")"; +} + +void PSCMDialect::initialize() { + addOperations< +#define GET_OP_LIST +#include "Ops.cpp.inc" + >(); +} + +#define GET_OP_CLASSES +#include "Ops.cpp.inc" \ No newline at end of file diff --git a/src/codegen/mlir/LowerToAffine.cpp b/src/codegen/mlir/LowerToAffine.cpp new file mode 100644 index 00000000..21bede63 --- /dev/null +++ b/src/codegen/mlir/LowerToAffine.cpp @@ -0,0 +1,76 @@ +#include "pscm/codegen/mlir/Passes.h" +using namespace mlir; + +#include "mlir/IR/BuiltinDialect.h" +#include "pscm/codegen/mlir/Dialect.h" + +#include "mlir/Dialect/Affine/IR/AffineOps.h" +#include "mlir/Dialect/Arith/IR/Arith.h" +#include "mlir/Dialect/Func/IR/FuncOps.h" +#include "mlir/Dialect/MemRef/IR/MemRef.h" +#include "mlir/Pass/Pass.h" +#include "mlir/Transforms/DialectConversion.h" +#include "llvm/ADT/Sequence.h" + +using namespace mlir; + +namespace { +struct FuncOpLowering : public OpConversionPattern { + using OpConversionPattern::OpConversionPattern; + + LogicalResult matchAndRewrite(pscm::FuncOp op, OpAdaptor adaptor, ConversionPatternRewriter& rewriter) const final { + if (op.getName() != "main") + return failure(); + if (op.getNumArguments() || op.getFunctionType().getNumResults()) { + return rewriter.notifyMatchFailure(op, [](Diagnostic& diag) { + diag << "expected 'main' to have 0 inputs and 0 results"; + }); + } + auto func = rewriter.create(op.getLoc(), op.getName(), op.getFunctionType()); + rewriter.inlineRegionBefore(op.getRegion(), func.getBody(), func.end()); + rewriter.eraseOp(op); + return success(); + } +}; + +struct ReturnOpLowering : public OpRewritePattern { + using OpRewritePattern::OpRewritePattern; + + LogicalResult matchAndRewrite(pscm::ReturnOp op, PatternRewriter& rewriter) const final { + if (op.hasOperand()) + return failure(); + rewriter.replaceOpWithNewOp(op); + return success(); + } +}; + +} // namespace + +struct PSCMToAffineLoweringPass : public PassWrapper> { + MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(PSCMToAffineLoweringPass) + + void getDependentDialects(DialectRegistry& registry) const override { + registry.insert(); + } + + void runOnOperation() override final { + + ConversionTarget target(getContext()); + + target.addLegalDialect(); + + RewritePatternSet patterns(&getContext()); + patterns.add(&getContext()); + + if (failed(applyPartialConversion(getOperation(), target, std::move(patterns)))) + signalPassFailure(); + } +}; + +namespace pscm { + +std::unique_ptr createLowerToAffinePass() { + return std::make_unique(); +} +} // namespace pscm diff --git a/src/codegen/mlir/LowerToLLVM.cpp b/src/codegen/mlir/LowerToLLVM.cpp new file mode 100644 index 00000000..d15c4a50 --- /dev/null +++ b/src/codegen/mlir/LowerToLLVM.cpp @@ -0,0 +1,161 @@ +#include "pscm/codegen/mlir/Passes.h" + +using namespace mlir; +#include "pscm/codegen/mlir/Dialect.h" + +#include "mlir/Conversion/AffineToStandard/AffineToStandard.h" +#include "mlir/Conversion/ArithToLLVM/ArithToLLVM.h" +#include "mlir/Conversion/ControlFlowToLLVM/ControlFlowToLLVM.h" +#include "mlir/Conversion/FuncToLLVM/ConvertFuncToLLVM.h" +#include "mlir/Conversion/FuncToLLVM/ConvertFuncToLLVMPass.h" +#include "mlir/Conversion/LLVMCommon/ConversionTarget.h" +#include "mlir/Conversion/LLVMCommon/TypeConverter.h" +#include "mlir/Conversion/MemRefToLLVM/MemRefToLLVM.h" +#include "mlir/Conversion/SCFToControlFlow/SCFToControlFlow.h" +#include "mlir/Dialect/Affine/IR/AffineOps.h" +#include "mlir/Dialect/Arith/IR/Arith.h" +#include "mlir/Dialect/Func/IR/FuncOps.h" +#include "mlir/Dialect/LLVMIR/LLVMDialect.h" +#include "mlir/Dialect/MemRef/IR/MemRef.h" +#include "mlir/Dialect/SCF/IR/SCF.h" +#include "mlir/Pass/Pass.h" +#include "mlir/Transforms/DialectConversion.h" +#include "llvm/ADT/Sequence.h" + +using namespace pscm; + +namespace { +struct ConstantOpLowering : public OpRewritePattern { + using OpRewritePattern::OpRewritePattern; + + LogicalResult matchAndRewrite(ConstantOp op, PatternRewriter& rewriter) const final { + auto value = op.getValueAttr(); + auto loc = op.getLoc(); + auto new_value = rewriter.create(loc, value); + rewriter.replaceOp(op, new_value); + return success(); + } +}; + +struct AddOpLowering : public ConversionPattern { + explicit AddOpLowering(MLIRContext *ctx) + : ConversionPattern(AddOp::getOperationName(), 1, ctx) { + } + + LogicalResult matchAndRewrite(Operation *op, llvm::ArrayRef operands, + ConversionPatternRewriter& rewriter) const override { + typename AddOp::Adaptor binaryAdaptor(operands); + auto loc = op->getLoc(); + auto new_op = rewriter.create(loc, binaryAdaptor.getLhs(), binaryAdaptor.getRhs()); + rewriter.replaceOp(op, new_op); + return success(); + } +}; + +class PrintOpLowering : public ConversionPattern { +public: + explicit PrintOpLowering(MLIRContext *context) + : ConversionPattern(pscm::PrintOp::getOperationName(), 1, context) { + } + + LogicalResult matchAndRewrite(Operation *op, ArrayRef operands, + ConversionPatternRewriter& rewriter) const override { + auto loc = op->getLoc(); + + ModuleOp parentModule = op->getParentOfType(); + + auto printfRef = getOrInsertPrintf(rewriter, parentModule); + Value formatSpecifierCst = + getOrCreateGlobalString(loc, rewriter, "frmt_spec", StringRef("jit: %d \0", 8), parentModule); + Value newLineCst = getOrCreateGlobalString(loc, rewriter, "nl", StringRef("\n\0", 2), parentModule); + + rewriter.create(loc, printfRef, rewriter.getIntegerType(32), + llvm::ArrayRef({ formatSpecifierCst, operands[0] })); + + rewriter.create(loc, printfRef, rewriter.getIntegerType(32), llvm::ArrayRef({ newLineCst })); + + rewriter.eraseOp(op); + return success(); + } + +private: + /// Return a symbol reference to the printf function, inserting it into the + /// module if necessary. + static FlatSymbolRefAttr getOrInsertPrintf(PatternRewriter& rewriter, ModuleOp module) { + auto *context = module.getContext(); + if (module.lookupSymbol("printf")) + return SymbolRefAttr::get(context, "printf"); + + // Create a function declaration for printf, the signature is: + // * `i32 (i8*, ...)` + auto llvmI32Ty = IntegerType::get(context, 32); + auto llvmI8PtrTy = LLVM::LLVMPointerType::get(IntegerType::get(context, 8)); + auto llvmFnType = LLVM::LLVMFunctionType::get(llvmI32Ty, llvmI8PtrTy, + /*isVarArg=*/true); + + // Insert the printf function into the body of the parent module. + PatternRewriter::InsertionGuard insertGuard(rewriter); + rewriter.setInsertionPointToStart(module.getBody()); + rewriter.create(module.getLoc(), "printf", llvmFnType); + return SymbolRefAttr::get(context, "printf"); + } + + /// Return a value representing an access into a global string with the given + /// name, creating the string if necessary. + static Value getOrCreateGlobalString(Location loc, OpBuilder& builder, StringRef name, StringRef value, + ModuleOp module) { + // Create the global at the entry of the module. + LLVM::GlobalOp global; + if (!(global = module.lookupSymbol(name))) { + OpBuilder::InsertionGuard insertGuard(builder); + builder.setInsertionPointToStart(module.getBody()); + auto type = LLVM::LLVMArrayType::get(IntegerType::get(builder.getContext(), 8), value.size()); + global = builder.create(loc, type, /*isConstant=*/true, LLVM::Linkage::Internal, name, + builder.getStringAttr(value), + /*alignment=*/0); + } + + // Get the pointer to the first character in the global string. + Value globalPtr = builder.create(loc, global); + Value cst0 = builder.create(loc, builder.getI64Type(), builder.getIndexAttr(0)); + return builder.create(loc, LLVM::LLVMPointerType::get(IntegerType::get(builder.getContext(), 8)), + globalPtr, ArrayRef({ cst0, cst0 })); + } +}; +} // namespace + +namespace pscm { +struct PSCMToLLVMLoweringPass : public PassWrapper> { + MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(PSCMToLLVMLoweringPass) + + void getDependentDialects(DialectRegistry& registry) const override { + registry.insert(); + } + + void runOnOperation() override final { + LLVMConversionTarget target(getContext()); + target.addLegalOp(); + LLVMTypeConverter typeConverter(&getContext()); + RewritePatternSet patterns(&getContext()); + populateAffineToStdConversionPatterns(patterns); + populateSCFToControlFlowConversionPatterns(patterns); + mlir::arith::populateArithToLLVMConversionPatterns(typeConverter, patterns); + cf::populateControlFlowToLLVMConversionPatterns(typeConverter, patterns); + populateFuncToLLVMConversionPatterns(typeConverter, patterns); + + patterns.add(&getContext()); + + auto module = getOperation(); + + if (failed(applyFullConversion(module, target, std::move(patterns)))) { + llvm::errs() << "apply full conversion error" + << "\n"; + signalPassFailure(); + } + } +}; + +std::unique_ptr createLowerToLLVMPass() { + return std::make_unique(); +} +} // namespace pscm \ No newline at end of file diff --git a/src/mlir/BUILD.bazel b/src/mlir/BUILD.bazel new file mode 100644 index 00000000..7b44fbc9 --- /dev/null +++ b/src/mlir/BUILD.bazel @@ -0,0 +1,131 @@ +load("@llvm-project//mlir:tblgen.bzl", "gentbl_cc_library", "td_library") + +licenses(["notice"]) + +package(default_visibility = ["//visibility:public"]) + +# td_library( +# name = "ToyOpsTdFiles", +# srcs = [ +# "include/toy/Ops.td", +# "include/toy/ShapeInferenceInterface.td", +# ], +# includes = ["include"], +# deps = [ +# "//mlir:CallInterfacesTdFiles", +# "//mlir:CastInterfacesTdFiles", +# "//mlir:FunctionInterfacesTdFiles", +# "//mlir:OpBaseTdFiles", +# "//mlir:SideEffectInterfacesTdFiles", +# ], +# ) + +# gentbl_cc_library( +# name = "ToyInterfacesIncGen", +# tbl_outs = [ +# ( +# ["-gen-op-interface-decls"], +# "include/toy/ShapeInferenceOpInterfaces.h.inc", +# ), +# ( +# ["-gen-op-interface-defs"], +# "include/toy/ShapeInferenceOpInterfaces.cpp.inc", +# ), +# ], +# tblgen = "//mlir:mlir-tblgen", +# td_file = "include/toy/ShapeInferenceInterface.td", +# deps = [":ToyOpsTdFiles"], +# ) + +# gentbl_cc_library( +# name = "ToyOpsIncGen", +# tbl_outs = [ +# ( +# ["-gen-op-decls"], +# "include/toy/Ops.h.inc", +# ), +# ( +# ["-gen-op-defs"], +# "include/toy/Ops.cpp.inc", +# ), +# ( +# ["-gen-dialect-decls"], +# "include/toy/Dialect.h.inc", +# ), +# ( +# ["-gen-dialect-defs"], +# "include/toy/Dialect.cpp.inc", +# ), +# ], +# tblgen = "//mlir:mlir-tblgen", +# td_file = "include/toy/Ops.td", +# deps = [":ToyOpsTdFiles"], +# ) + +# gentbl_cc_library( +# name = "ToyCombineIncGen", +# strip_include_prefix = "mlir", +# tbl_outs = [ +# ( +# ["-gen-rewriters"], +# "mlir/ToyCombine.inc", +# ), +# ], +# tblgen = "//mlir:mlir-tblgen", +# td_file = "mlir/ToyCombine.td", +# deps = [":ToyOpsTdFiles"], +# ) + +cc_binary( + name = "toyc", + # srcs = [ + # "mlir/Dialect.cpp", + # "mlir/LowerToAffineLoops.cpp", + # "mlir/LowerToLLVM.cpp", + # "mlir/MLIRGen.cpp", + # "mlir/ShapeInferencePass.cpp", + # "mlir/ToyCombine.cpp", + # "parser/AST.cpp", + # "toyc.cpp", + # ] + glob(["include/toy/*.h"]), + includes = ["include/"], + deps = [ + # ":ToyCombineIncGen", + # ":ToyInterfacesIncGen", + # ":ToyOpsIncGen", + "@llvm-project//llvm:Core", + "@llvm-project//llvm:OrcJIT", + "@llvm-project//llvm:Support", + "@llvm-project//mlir:AffineDialect", + "@llvm-project//mlir:AffineToStandard", + "@llvm-project//mlir:AffineTransforms", + "@llvm-project//mlir:AllPassesAndDialects", + "@llvm-project//mlir:Analysis", + "@llvm-project//mlir:ArithDialect", + "@llvm-project//mlir:ArithToLLVM", + "@llvm-project//mlir:BuiltinToLLVMIRTranslation", + "@llvm-project//mlir:CastInterfaces", + "@llvm-project//mlir:ControlFlowToLLVM", + "@llvm-project//mlir:ExecutionEngine", + "@llvm-project//mlir:ExecutionEngineUtils", + "@llvm-project//mlir:FuncDialect", + "@llvm-project//mlir:FuncExtensions", + "@llvm-project//mlir:FuncToLLVM", + "@llvm-project//mlir:IR", + "@llvm-project//mlir:LLVMCommonConversion", + "@llvm-project//mlir:LLVMDialect", + "@llvm-project//mlir:LLVMIRTransforms", + "@llvm-project//mlir:LLVMToLLVMIRTranslation", + "@llvm-project//mlir:MemRefDialect", + "@llvm-project//mlir:MemRefToLLVM", + "@llvm-project//mlir:Parser", + "@llvm-project//mlir:Pass", + "@llvm-project//mlir:SCFDialect", + "@llvm-project//mlir:SCFToControlFlow", + "@llvm-project//mlir:SideEffectInterfaces", + "@llvm-project//mlir:Support", + "@llvm-project//mlir:ToLLVMIRTranslation", + "@llvm-project//mlir:TransformUtils", + "@llvm-project//mlir:Transforms", + ], +) \ No newline at end of file diff --git a/xmake.lua b/xmake.lua index c3d13242..36d37d18 100644 --- a/xmake.lua +++ b/xmake.lua @@ -30,7 +30,10 @@ target("pscm") do add_packages({"spdlog", "universal_stacktrace", "cpp-linenoise"}) add_packages({"icu4c", "mscharconv"}, {public = true}) add_files({ - "src/**.cpp", + "src/*.cpp", + "src/icu/**.cpp", + "src/logger/**.cpp", + "src/misc/*.cpp", "$(buildir)/version.cpp"}) if is_mode("coverage") then