├── .clang-format ├── .github └── workflows │ └── buildAndTest.yml ├── .gitignore ├── CMakeLists.txt ├── LICENSE.TXT ├── README.md ├── cmake └── modules │ └── sanitizers.cmake ├── include ├── CMakeLists.txt ├── Dialect │ ├── CMakeLists.txt │ └── LLHD │ │ ├── CMakeLists.txt │ │ ├── LLHDBase.td │ │ ├── LLHDDialect.h │ │ ├── LLHDOps.h │ │ └── LLHDOps.td ├── LLHDToLLVM │ ├── CMakeLists.txt │ ├── LLHDToLLVM.h │ └── Passes.td ├── Simulator │ ├── Engine.h │ ├── State.h │ └── signals-runtime-wrappers.h ├── Target │ ├── TranslateToVerilog.h │ └── VerilogPrinter.h └── Transforms │ ├── CMakeLists.txt │ ├── Passes.h │ └── Passes.td ├── lib ├── CMakeLists.txt ├── Dialect │ ├── CMakeLists.txt │ └── LLHD │ │ ├── CMakeLists.txt │ │ ├── LLHDDialect.cpp │ │ └── LLHDOps.cpp ├── LLHDToLLVM │ ├── CMakeLists.txt │ └── LLHDToLLVM.cpp ├── Simulator │ ├── CMakeLists.txt │ ├── Engine.cpp │ ├── State.cpp │ └── signals-runtime-wrappers.cpp ├── Target │ ├── CMakeLists.txt │ └── VerilogPrinter.cpp └── Transforms │ ├── CMakeLists.txt │ ├── FunctionEliminationPass.cpp │ └── ProcessLoweringPass.cpp ├── test ├── CMakeLists.txt ├── Dialect │ └── LLHD │ │ ├── arithmetic.mlir │ │ ├── bitwise.mlir │ │ ├── const.mlir │ │ ├── entity.mlir │ │ ├── ext.mlir │ │ ├── ins.mlir │ │ ├── inst.mlir │ │ ├── proc.mlir │ │ ├── reg.mlir │ │ ├── sig.mlir │ │ ├── time.mlir │ │ ├── tuple.mlir │ │ ├── vec.mlir │ │ └── wait.mlir ├── Examples │ ├── CMakeLists.txt │ ├── acc.mlir │ ├── graycode.mlir │ ├── simple.c │ └── simple.mlir ├── LLHDToLLVM │ ├── convert_bitwise.mlir │ ├── convert_entity.mlir │ ├── convert_process.mlir │ ├── convert_signals.mlir │ ├── convert_simple.mlir │ └── convert_value_manip.mlir ├── Simulator │ └── sim_simple.mlir ├── Target │ └── Verilog │ │ ├── verilog_arithmetic.mlir │ │ ├── verilog_bitwise.mlir │ │ ├── verilog_entity.mlir │ │ ├── verilog_relations.mlir │ │ └── verilog_sig.mlir ├── Transforms │ ├── canonicalization.mlir │ ├── processLowering.mlir │ └── totalFunctionInlining.mlir ├── lit.cfg.py └── lit.site.cfg.py.in └── tools ├── CMakeLists.txt ├── llhd-sim ├── CMakeLists.txt └── llhd-sim.cpp ├── llhd-translate ├── CMakeLists.txt └── llhd-translate.cpp └── llhdc ├── CMakeLists.txt └── llhdc.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: LLVM 2 | AlwaysBreakTemplateDeclarations: Yes -------------------------------------------------------------------------------- /.github/workflows/buildAndTest.yml: -------------------------------------------------------------------------------- 1 | name: Build and Test 2 | 3 | on: [push, pull_request] 4 | 5 | env: 6 | LLVM_COMMIT: fb9f9dc318d62788885a122aaee9dcd4272e87b1 7 | CMAKE_FLAGS: '-DMLIR_DIR=$GITHUB_WORKSPACE/llvm/install/lib/cmake/mlir/ -DLLVM_DIR=$GITHUB_WORKSPACE/llvm/install/lib/cmake/llvm/' 8 | CMAKE_TOOLCHAIN_FLAGS: '-DCMAKE_LINKER=lld -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++' 9 | CMAKE_LIT_PATH: '-DLLVM_EXTERNAL_LIT=$GITHUB_WORKSPACE/llvm/build/bin/llvm-lit' 10 | 11 | jobs: 12 | lint: 13 | name: Check Formatting 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Get LLHD 17 | uses: actions/checkout@v2 18 | - name: clang-format 19 | uses: DoozyX/clang-format-lint-action@v0.5 20 | with: 21 | source: '.' 22 | extensions: 'h,cpp' 23 | clangFormatVersion: 9 24 | 25 | build: 26 | name: Build and Test 27 | runs-on: ubuntu-latest 28 | steps: 29 | - name: Configure Environment 30 | run: echo "::add-path::$GITHUB_WORKSPACE/llvm/install/bin" 31 | - name: Get LLHD 32 | uses: actions/checkout@v2 33 | with: 34 | path: 'llhd' 35 | - name: Cache LLVM 36 | id: cache-llvm 37 | uses: actions/cache@v1 38 | with: 39 | path: llvm 40 | key: ${{ runner.os }}-llvm-install-${{ env.LLVM_COMMIT }} 41 | - name: Get LLVM 42 | if: steps.cache-llvm.outputs.cache-hit != 'true' 43 | uses: actions/checkout@v2 44 | with: 45 | repository: 'llvm/llvm-project' 46 | ref: '${{ env.LLVM_COMMIT }}' 47 | path: 'llvm' 48 | - name: Install LLVM 49 | if: steps.cache-llvm.outputs.cache-hit != 'true' 50 | run: | 51 | mkdir $GITHUB_WORKSPACE/llvm/build 52 | mkdir $GITHUB_WORKSPACE/llvm/install 53 | cd $GITHUB_WORKSPACE/llvm/build 54 | cmake $GITHUB_WORKSPACE/llvm/llvm -DLLVM_BUILD_EXAMPLES=OFF -DLLVM_TARGETS_TO_BUILD="host" -DCMAKE_INSTALL_PREFIX=$GITHUB_WORKSPACE/llvm/install -DLLVM_ENABLE_PROJECTS='mlir' -DLLVM_OPTIMIZED_TABLEGEN=ON -DLLVM_ENABLE_OCAMLDOC=OFF -DLLVM_ENABLE_BINDINGS=OFF -DLLVM_INSTALL_UTILS=ON -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DLLVM_ENABLE_LLD=ON -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_ASSERTIONS=ON 55 | cmake --build . --target install -- -j$(nproc) 56 | - name: Sanitizer build 57 | run: | 58 | mkdir $GITHUB_WORKSPACE/llhd/sanitizer-build 59 | cd $GITHUB_WORKSPACE/llhd/sanitizer-build 60 | cmake $GITHUB_WORKSPACE/llhd -DCMAKE_BUILD_TYPE=Debug -DUSE_SANITIZER='Address;Undefined' ${{ env.CMAKE_FLAGS }} ${{ env.CMAKE_TOOLCHAIN_FLAGS }} ${{ env.CMAKE_LIT_PATH }} 61 | cmake --build . --target check-llhdc -- -j$(nproc) 62 | - name: Release build 63 | run: | 64 | mkdir $GITHUB_WORKSPACE/llhd/build 65 | cd $GITHUB_WORKSPACE/llhd/build 66 | cmake $GITHUB_WORKSPACE/llhd -DCMAKE_BUILD_TYPE=Release ${{ env.CMAKE_FLAGS }} ${{ env.CMAKE_TOOLCHAIN_FLAGS }} ${{ env.CMAKE_LIT_PATH }} 67 | cmake --build . --target check-llhdc -- -j$(nproc) 68 | 69 | docgen: 70 | name: Generate Docs 71 | runs-on: ubuntu-latest 72 | needs: build 73 | if: github.ref == 'refs/heads/master' && github.event_name == 'push' 74 | steps: 75 | - name: Cache LLVM 76 | id: cache-llvm 77 | uses: actions/cache@v1 78 | with: 79 | path: llvm 80 | key: ${{ runner.os }}-llvm-install-${{ env.LLVM_COMMIT }} 81 | - name: Get LLHD 82 | if: steps.cache-llvm.outputs.cache-hit == 'true' 83 | uses: actions/checkout@v2 84 | with: 85 | path: 'llhd' 86 | - name: Get doc repo 87 | if: steps.cache-llvm.outputs.cache-hit == 'true' 88 | uses: actions/checkout@v2 89 | with: 90 | repository: rodonisi/llhd-docs 91 | token: ${{ secrets.PAT }} 92 | path: 'llhd-docs' 93 | - name: Generate documentation 94 | if: steps.cache-llvm.outputs.cache-hit == 'true' 95 | run: | 96 | mkdir $GITHUB_WORKSPACE/llhd/build 97 | cd $GITHUB_WORKSPACE/llhd/build 98 | cmake $GITHUB_WORKSPACE/llhd ${{ env.CMAKE_FLAGS }} 99 | cmake --build . --target mlir-doc 100 | - name: Add doc to target repo 101 | if: steps.cache-llvm.outputs.cache-hit == 'true' 102 | run: | 103 | cd $GITHUB_WORKSPACE 104 | cat llhd-docs/assets/templates/opdoc_frontmatter > llhd-docs/docs/LLHDOps.md 105 | cat llhd/build/docs/Dialect/llhd.md >> llhd-docs/docs/LLHDOps.md 106 | cat llhd-docs/assets/templates/convdoc_frontmatter > llhd-docs/docs/passes/LLHDToLLVM.md 107 | cat llhd/build/docs/Passes/LLHDToLLVM.md >> llhd-docs/docs/passes/LLHDToLLVM.md 108 | cat llhd-docs/assets/templates/transdoc_frontmatter > llhd-docs/docs/passes/Transformations.md 109 | cat llhd/build/docs/Passes/Transformations.md >> llhd-docs/docs/passes/Transformations.md 110 | - name: Commit and push to target repo 111 | if: steps.cache-llvm.outputs.cache-hit == 'true' 112 | run: | 113 | cd $GITHUB_WORKSPACE/llhd-docs 114 | git config --local user.name "GitHub Push Action" 115 | git config --local user.mail "action@generate_docs.com" 116 | git add docs/LLHDOps.md docs/passes/LLHDToLLVM.md docs/passes/Transformations.md 117 | git commit -m "push docs" || echo "No changes to commit" 118 | git push 119 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | build/ 3 | .clangd/ 4 | .vscode/ 5 | .idea/ 6 | cmake-build-debug/ 7 | cmake-build-release/ 8 | 9 | compile_commands.json 10 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | if(POLICY CMP0068) 4 | cmake_policy(SET CMP0068 NEW) 5 | set(CMAKE_BUILD_WITH_INSTALL_NAME_DIR ON) 6 | endif() 7 | 8 | if(POLICY CMP0075) 9 | cmake_policy(SET CMP0075 NEW) 10 | endif() 11 | 12 | if(POLICY CMP0077) 13 | cmake_policy(SET CMP0077 NEW) 14 | endif() 15 | 16 | project(standalone-dialect LANGUAGES CXX C) 17 | 18 | find_package(MLIR REQUIRED CONFIG) 19 | 20 | message(STATUS "Using MLIRConfig.cmake in: ${MLIR_DIR}") 21 | message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") 22 | 23 | set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/bin) 24 | set(LLVM_LIBRARY_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/lib) 25 | set(MLIR_BINARY_DIR ${CMAKE_BINARY_DIR}) 26 | 27 | list(APPEND CMAKE_MODULE_PATH "${MLIR_CMAKE_DIR}") 28 | list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") 29 | include(TableGen) 30 | include(AddLLVM) 31 | include(AddMLIR) 32 | include(HandleLLVMOptions) 33 | 34 | include_directories(${LLVM_INCLUDE_DIRS}) 35 | include_directories(${MLIR_INCLUDE_DIRS}) 36 | message(${PROJECT_SOURCE_DIR}) 37 | include_directories(${PROJECT_SOURCE_DIR}/include) 38 | include_directories(${PROJECT_BINARY_DIR}/include) 39 | link_directories(${LLVM_BUILD_LIBRARY_DIR}) 40 | add_definitions(${LLVM_DEFINITIONS}) 41 | 42 | set(LLVM_LIT_ARGS "-sv" CACHE STRING "lit default options") 43 | 44 | list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/modules") 45 | include(sanitizers) 46 | 47 | # add target for documentation generation 48 | add_custom_target(llhd-doc) 49 | 50 | add_subdirectory(include) 51 | add_subdirectory(lib) 52 | add_subdirectory(test) 53 | add_subdirectory(tools) 54 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LLHD 2 | 3 | ![](https://github.com/maerhart/llhd/workflows/Build%20and%20Test/badge.svg?event=push) 4 | [![LLHD Documentation](https://img.shields.io/badge/docs-link-informational)](https://rodonisi.github.io/llhd-docs/) 5 | 6 | Development repository for the LLHD Dialect. The repository depends on a build of llvm including mlir. Once the llvm and mlir are built setup configure the project using the following commands. 7 | 8 | ``` 9 | mkdir build && cd build 10 | cmake -G Ninja .. -DCMAKE_LINKER= -DLLVM_DIR=/lib/cmake/llvm/ -DLLVM_EXTERNAL_LIT=/bin/llvm-lit 11 | cmake --build . --target llhdc 12 | cmake --build . --target check-llhdc 13 | ``` 14 | 15 | In case an error occurs stating that `llvm_expand_pseudo_components` (or some other llvm related cmake command) is not found, make sure that cmake uses the `LLVMConfig.cmake` file built and installed previously (not the one of another installation, e.g. `/usr/...`) 16 | 17 | # llvm build instructions 18 | 19 | Cmake configuration for llvm 20 | 21 | ``` 22 | cmake -G Ninja ../llvm -DLLVM_BUILD_EXAMPLES=OFF -DLLVM_TARGETS_TO_BUILD="host" -DCMAKE_INSTALL_PREFIX= -DLLVM_ENABLE_PROJECTS='mlir' -DLLVM_OPTIMIZED_TABLEGEN=ON -DLLVM_ENABLE_OCAMLDOC=OFF -DLLVM_ENABLE_BINDINGS=OFF -DLLVM_INSTALL_UTILS=ON -DCMAKE_LINKER= -DLLVM_PARALLEL_LINK_JOBS=2 23 | ``` 24 | 25 | Build llvm with 26 | 27 | ``` 28 | cmake --build . --target install 29 | ``` 30 | -------------------------------------------------------------------------------- /cmake/modules/sanitizers.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Original source: Copyright (C) 2018 by George Cave - gcave@stablecoder.ca 3 | # Modified source: Copyright (C) 2020 by Jean-Michel Gorius 4 | # - jean-michel.gorius@ens-rennes.fr 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); you may not 7 | # use this file except in compliance with the License. You may obtain a copy of 8 | # the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 14 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 15 | # License for the specific language governing permissions and limitations under 16 | # the License. 17 | # 18 | # Adapted by Jean-Michel Gorius to forward sanitizer flags to the linker. 19 | # 20 | 21 | set(USE_SANITIZER 22 | "" 23 | CACHE 24 | STRING 25 | "Compile with a sanitizer. Options are: Address, Memory, MemoryWithOrigins, Undefined, Thread, Leak, 'Address;Undefined'" 26 | ) 27 | 28 | function(append value) 29 | foreach (variable ${ARGN}) 30 | set(${variable} 31 | "${${variable}} ${value}" 32 | PARENT_SCOPE) 33 | endforeach (variable) 34 | endfunction() 35 | 36 | if (USE_SANITIZER) 37 | append("-fno-omit-frame-pointer" 38 | CMAKE_C_FLAGS 39 | CMAKE_CXX_FLAGS) 40 | 41 | if (UNIX) 42 | 43 | if (uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG") 44 | append("-O1" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) 45 | endif () 46 | 47 | if (USE_SANITIZER MATCHES "([Aa]ddress);([Uu]ndefined)" 48 | OR USE_SANITIZER MATCHES "([Uu]ndefined);([Aa]ddress)") 49 | message(STATUS "Building with Address, Undefined sanitizers") 50 | append("-fsanitize=address,undefined" 51 | CMAKE_EXE_C_FLAGS 52 | CMAKE_EXE_CXX_FLAGS 53 | CMAKE_STATIC_C_FLAGS 54 | CMAKE_STATIC_CXX_FLAGS 55 | CMAKE_EXE_LINKER_FLAGS 56 | CMAKE_MODULE_LINKER_FLAGS) 57 | elseif (USE_SANITIZER MATCHES "([Aa]ddress)") 58 | # Optional: -fno-optimize-sibling-calls -fsanitize-address-use-after-scope 59 | message(STATUS "Building with Address sanitizer") 60 | append("-fsanitize=address" 61 | CMAKE_EXE_C_FLAGS 62 | CMAKE_EXE_CXX_FLAGS 63 | CMAKE_STATIC_C_FLAGS 64 | CMAKE_STATIC_CXX_FLAGS 65 | CMAKE_EXE_LINKER_FLAGS 66 | CMAKE_MODULE_LINKER_FLAGS) 67 | elseif (USE_SANITIZER MATCHES "([Mm]emory([Ww]ith[Oo]rigins)?)") 68 | # Optional: -fno-optimize-sibling-calls -fsanitize-memory-track-origins=2 69 | append("-fsanitize=memory" 70 | CMAKE_EXE_C_FLAGS 71 | CMAKE_EXE_CXX_FLAGS 72 | CMAKE_STATIC_C_FLAGS 73 | CMAKE_STATIC_CXX_FLAGS 74 | CMAKE_EXE_LINKER_FLAGS 75 | CMAKE_MODULE_LINKER_FLAGS) 76 | if (USE_SANITIZER MATCHES "([Mm]emory[Ww]ith[Oo]rigins)") 77 | message(STATUS "Building with MemoryWithOrigins sanitizer") 78 | append("-fsanitize-memory-track-origins" 79 | CMAKE_EXE_C_FLAGS 80 | CMAKE_EXE_CXX_FLAGS 81 | CMAKE_STATIC_C_FLAGS 82 | CMAKE_STATIC_CXX_FLAGS 83 | CMAKE_EXE_LINKER_FLAGS 84 | CMAKE_MODULE_LINKER_FLAGS) 85 | else () 86 | message(STATUS "Building with Memory sanitizer") 87 | endif () 88 | elseif (USE_SANITIZER MATCHES "([Uu]ndefined)") 89 | message(STATUS "Building with Undefined sanitizer") 90 | append("-fsanitize=undefined" 91 | CMAKE_EXE_C_FLAGS 92 | CMAKE_EXE_CXX_FLAGS 93 | CMAKE_STATIC_C_FLAGS 94 | CMAKE_STATIC_CXX_FLAGS 95 | CMAKE_EXE_LINKER_FLAGS 96 | CMAKE_MODULE_LINKER_FLAGS) 97 | if (EXISTS "${BLACKLIST_FILE}") 98 | append("-fsanitize-blacklist=${BLACKLIST_FILE}" 99 | CMAKE_EXE_C_FLAGS 100 | CMAKE_EXE_CXX_FLAGS 101 | CMAKE_STATIC_C_FLAGS 102 | CMAKE_STATIC_CXX_FLAGS 103 | CMAKE_EXE_LINKER_FLAGS 104 | CMAKE_MODULE_LINKER_FLAGS) 105 | endif () 106 | elseif (USE_SANITIZER MATCHES "([Tt]hread)") 107 | message(STATUS "Building with Thread sanitizer") 108 | append("-fsanitize=thread" 109 | CMAKE_EXE_C_FLAGS 110 | CMAKE_EXE_CXX_FLAGS 111 | CMAKE_STATIC_C_FLAGS 112 | CMAKE_STATIC_CXX_FLAGS 113 | CMAKE_EXE_LINKER_FLAGS 114 | CMAKE_MODULE_LINKER_FLAGS) 115 | elseif (USE_SANITIZER MATCHES "([Ll]eak)") 116 | message(STATUS "Building with Leak sanitizer") 117 | append("-fsanitize=leak" 118 | CMAKE_EXE_C_FLAGS 119 | CMAKE_EXE_CXX_FLAGS 120 | CMAKE_STATIC_C_FLAGS 121 | CMAKE_STATIC_CXX_FLAGS 122 | CMAKE_EXE_LINKER_FLAGS 123 | CMAKE_MODULE_LINKER_FLAGS) 124 | else () 125 | message( 126 | FATAL_ERROR "Unsupported value of USE_SANITIZER: ${USE_SANITIZER}") 127 | endif () 128 | elseif (MSVC) 129 | if (USE_SANITIZER MATCHES "([Aa]ddress)") 130 | message(STATUS "Building with Address sanitizer") 131 | append("-fsanitize=address" 132 | CMAKE_EXE_C_FLAGS 133 | CMAKE_EXE_CXX_FLAGS 134 | CMAKE_STATIC_C_FLAGS 135 | CMAKE_STATIC_CXX_FLAGS 136 | CMAKE_EXE_LINKER_FLAGS 137 | CMAKE_MODULE_LINKER_FLAGS) 138 | else () 139 | message( 140 | FATAL_ERROR 141 | "This sanitizer not yet supported in the MSVC environment: ${USE_SANITIZER}" 142 | ) 143 | endif () 144 | else () 145 | message(FATAL_ERROR "USE_SANITIZER is not supported on this platform.") 146 | endif () 147 | 148 | endif () 149 | 150 | -------------------------------------------------------------------------------- /include/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(Dialect) 2 | add_subdirectory(LLHDToLLVM) 3 | add_subdirectory(Transforms) 4 | -------------------------------------------------------------------------------- /include/Dialect/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(LLHD) 2 | -------------------------------------------------------------------------------- /include/Dialect/LLHD/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_mlir_dialect(LLHDOps llhd) 2 | add_mlir_doc(LLHDOps -gen-op-doc llhd Dialect/) 3 | 4 | set(LLVM_TARGET_DEFINITIONS LLHDOps.td) 5 | mlir_tablegen(LLHDOpsEnums.h.inc -gen-enum-decls) 6 | mlir_tablegen(LLHDOpsEnums.cpp.inc -gen-enum-defs) 7 | add_public_tablegen_target(MLIRLLHDEnumsIncGen) 8 | -------------------------------------------------------------------------------- /include/Dialect/LLHD/LLHDBase.td: -------------------------------------------------------------------------------- 1 | #ifndef LLHD_BASE 2 | #define LLHD_BASE 3 | 4 | include "mlir/IR/OpBase.td" 5 | 6 | //===----------------------------------------------------------------------===// 7 | // LLHD dialect definition 8 | //===----------------------------------------------------------------------===// 9 | 10 | def LLHD_Dialect : Dialect { 11 | let name = "llhd"; 12 | 13 | let description = [{ 14 | A low-level hardware description dialect in MLIR. 15 | }]; 16 | 17 | let cppNamespace = "llhd"; 18 | 19 | let hasConstantMaterializer = 1; 20 | } 21 | 22 | //===----------------------------------------------------------------------===// 23 | // LLHD type definitions 24 | //===----------------------------------------------------------------------===// 25 | 26 | // LLHD Time Type 27 | def LLHD_TimeType : Type()">, "LLHD time type">, 28 | BuildableType<"TimeType::get($_builder.getContext())">; 29 | 30 | // LLHD sig type 31 | class LLHD_SigType allowedTypes> 32 | : ContainerType, CPred<"$_self.isa()">, 33 | "$_self.cast().getUnderlyingType()", "LLHD sig type">; 34 | 35 | def LLHD_AnySigUnderlyingType : AnyTypeOf<[AnySignlessInteger, LLHD_TimeType]>; 36 | 37 | def LLHD_AnySigType : LLHD_SigType<[LLHD_AnySigUnderlyingType]>; 38 | 39 | //===----------------------------------------------------------------------===// 40 | // LLDH attribute definitions 41 | //===----------------------------------------------------------------------===// 42 | 43 | // LLHD time attr 44 | def LLHD_TimeAttr : Attr()">, "LLHD time attribute"> { 45 | let storageType= [{ TimeAttr }]; 46 | let returnType = [{ llvm::ArrayRef }]; 47 | let valueType = LLHD_TimeType; 48 | } 49 | 50 | //===----------------------------------------------------------------------===// 51 | // LLHD op definition 52 | //===----------------------------------------------------------------------===// 53 | 54 | // Base class for all LLHD ops. 55 | class LLHD_Op traits = []> : 56 | Op { 57 | 58 | // For each LLHD op, the following static functions need to be defined in 59 | // LLHDOps.cpp: 60 | // 61 | // * static ParseResult parse(OpAsmParser &parser, 62 | // OperationState &state); 63 | // * static void print(OpAsmPrinter &p, op) 64 | let parser = [{ return ::parse$cppClass(parser, result); }]; 65 | let printer = [{ ::print(p, *this); }]; 66 | } 67 | 68 | class LLHD_ArithmeticOrBitwiseOp traits = []> : 69 | Op { 71 | 72 | let results = (outs AnySignlessInteger); 73 | 74 | let parser = [{ 75 | return impl::parseOneResultSameOperandTypeOp(parser, result); 76 | }]; 77 | 78 | let printer = [{ 79 | impl::printOneResultOp(this->getOperation(), p); 80 | }]; 81 | } 82 | 83 | //===----------------------------------------------------------------------===// 84 | // LLHD trait definitions 85 | //===----------------------------------------------------------------------===// 86 | 87 | class SameTypeArbitraryWidth : PredOpTrait() || (lhsType.cast().getElementType() == rhsType.cast().getElementType()));}()">>; 91 | 92 | 93 | 94 | #endif // LLHD_BASE 95 | -------------------------------------------------------------------------------- /include/Dialect/LLHD/LLHDDialect.h: -------------------------------------------------------------------------------- 1 | #ifndef MLIR_DIALECT_LLHD_LLHDDIALECT_H 2 | #define MLIR_DIALECT_LLHD_LLHDDIALECT_H 3 | 4 | #include "mlir/IR/Dialect.h" 5 | #include "mlir/IR/Function.h" 6 | 7 | namespace mlir { 8 | namespace llhd { 9 | namespace detail { 10 | struct SigTypeStorage; 11 | struct TimeAttrStorage; 12 | } // namespace detail 13 | 14 | class LLHDDialect : public Dialect { 15 | public: 16 | explicit LLHDDialect(MLIRContext *context); 17 | 18 | /// Returns the prefix used in the textual IR to refer to LLHD operations 19 | static StringRef getDialectNamespace() { return "llhd"; } 20 | 21 | /// Parses a type registered to this dialect 22 | Type parseType(DialectAsmParser &parser) const override; 23 | 24 | /// Print a type registered to this dialect 25 | void printType(Type type, DialectAsmPrinter &printer) const override; 26 | 27 | /// Parse an attribute regustered to this dialect 28 | Attribute parseAttribute(DialectAsmParser &parser, Type type) const override; 29 | 30 | /// Print an attribute registered to this dialect 31 | void printAttribute(Attribute attr, 32 | DialectAsmPrinter &printer) const override; 33 | 34 | Operation *materializeConstant(OpBuilder &builder, Attribute value, Type type, 35 | Location loc) override; 36 | }; 37 | 38 | //===----------------------------------------------------------------------===// 39 | // LLHD Types 40 | //===----------------------------------------------------------------------===// 41 | namespace LLHDTypes { 42 | enum Kinds { 43 | Sig = mlir::Type::FIRST_PRIVATE_EXPERIMENTAL_0_TYPE, 44 | Time, 45 | }; 46 | } // namespace LLHDTypes 47 | 48 | class SigType 49 | : public mlir::Type::TypeBase { 50 | public: 51 | using Base::Base; 52 | 53 | /// Return whether the given kind is of type Sig 54 | static bool kindof(unsigned kind) { return kind == LLHDTypes::Sig; } 55 | 56 | /// Get a new instance of llhd sig type 57 | static SigType get(mlir::Type underlyingType); 58 | 59 | /// The underlying type of the sig type 60 | Type getUnderlyingType(); 61 | 62 | /// Get the keyword for the signal type 63 | static llvm::StringRef getKeyword() { return "sig"; } 64 | }; 65 | 66 | class TimeType : public Type::TypeBase { 67 | public: 68 | using Base::Base; 69 | 70 | /// Return whether the given kind is of type Time 71 | static bool kindof(unsigned kind) { return kind == LLHDTypes::Time; } 72 | 73 | /// Get a new instance of type Time 74 | static TimeType get(MLIRContext *context); 75 | 76 | /// Get the keyword for the time type 77 | static llvm::StringRef getKeyword() { return "time"; } 78 | }; 79 | 80 | //===----------------------------------------------------------------------===// 81 | // LLHD Attributes 82 | //===----------------------------------------------------------------------===// 83 | 84 | namespace LLHDAttrs { 85 | enum Kinds { 86 | Time = mlir::Attribute::FIRST_PRIVATE_EXPERIMENTAL_0_ATTR, 87 | }; 88 | } // namespace LLHDAttrs 89 | 90 | class TimeAttr 91 | : public Attribute::AttrBase { 92 | public: 93 | using Base::Base; 94 | using ValueType = llvm::ArrayRef; 95 | 96 | /// Returns whether the passed argument is of kind Time. 97 | static bool kindof(unsigned kind) { return kind == LLHDAttrs::Time; } 98 | 99 | /// Get a new instance of Time attribute. 100 | static TimeAttr get(Type type, llvm::ArrayRef timeValues, 101 | llvm::StringRef timeUnit); 102 | 103 | /// Verify construction invariants of a new time attribute. 104 | static LogicalResult 105 | verifyConstructionInvariants(Location loc, Type type, 106 | llvm::ArrayRef timeValues, 107 | llvm::StringRef timeUnit); 108 | 109 | /// Get the time values stored in the attribute. 110 | llvm::ArrayRef getValue() const; 111 | 112 | /// Get the real time value of the attribute. 113 | unsigned getTime() const; 114 | 115 | /// Get the delta step value of the attribute. 116 | unsigned getDelta() const; 117 | 118 | /// Get the epsilon value of the attribute. 119 | unsigned getEps() const; 120 | 121 | /// Get the real time unit used by the attribute. 122 | llvm::StringRef getTimeUnit() const; 123 | 124 | /// Get the keyword of the time attribute 125 | static llvm::StringRef getKeyword() { return "time"; } 126 | }; 127 | } // namespace llhd 128 | } // namespace mlir 129 | 130 | #endif // MLIR_DIALECT_LLHD_LLHDDIALECT_H 131 | -------------------------------------------------------------------------------- /include/Dialect/LLHD/LLHDOps.h: -------------------------------------------------------------------------------- 1 | #ifndef MLIR_DIALECT_LLHD_LLHDOPS_H 2 | #define MLIR_DIALECT_LLHD_LLHDOPS_H 3 | 4 | #include "Dialect/LLHD/LLHDDialect.h" 5 | #include "Dialect/LLHD/LLHDOpsEnums.h.inc" 6 | #include "mlir/IR/Matchers.h" 7 | #include "mlir/IR/StandardTypes.h" 8 | #include "mlir/Interfaces/ControlFlowInterfaces.h" 9 | #include "mlir/Interfaces/SideEffectInterfaces.h" 10 | 11 | namespace mlir { 12 | namespace llhd { 13 | 14 | template > 17 | Attribute constFoldUnaryOp(ArrayRef operands, 18 | const CalculationT &calculate) { 19 | assert(operands.size() == 1 && "unary op takes one operand"); 20 | if (!operands[0]) 21 | return {}; 22 | 23 | if (operands[0].isa()) { 24 | auto val = operands[0].cast(); 25 | 26 | return AttrElementT::get(val.getType(), calculate(val.getValue())); 27 | } else if (operands[0].isa()) { 28 | // Operand is a splat so we can avoid expanding the value out and 29 | // just fold based on the splat value. 30 | auto val = operands[0].cast(); 31 | 32 | auto elementResult = calculate(val.getSplatValue()); 33 | return DenseElementsAttr::get(val.getType(), elementResult); 34 | } else if (operands[0].isa()) { 35 | // Operand is ElementsAttr-derived; perform an element-wise fold by 36 | // expanding the values. 37 | auto val = operands[0].cast(); 38 | 39 | auto valIt = val.getValues().begin(); 40 | SmallVector elementResults; 41 | elementResults.reserve(val.getNumElements()); 42 | for (size_t i = 0, e = val.getNumElements(); i < e; ++i, ++valIt) 43 | elementResults.push_back(calculate(*valIt)); 44 | return DenseElementsAttr::get(val.getType(), elementResults); 45 | } 46 | return {}; 47 | } 48 | 49 | template > 53 | Attribute constFoldTernaryOp(ArrayRef operands, 54 | const CalculationT &calculate) { 55 | assert(operands.size() == 3 && "ternary op takes three operands"); 56 | if (!operands[0] || !operands[1] || !operands[2]) 57 | return {}; 58 | if (operands[0].getType() != operands[1].getType()) 59 | return {}; 60 | if (operands[0].getType() != operands[2].getType()) 61 | return {}; 62 | 63 | if (operands[0].isa() && operands[1].isa() && 64 | operands[2].isa()) { 65 | auto fst = operands[0].cast(); 66 | auto snd = operands[1].cast(); 67 | auto trd = operands[2].cast(); 68 | 69 | return AttrElementT::get( 70 | fst.getType(), 71 | calculate(fst.getValue(), snd.getValue(), trd.getValue())); 72 | } else if (operands[0].isa() && 73 | operands[1].isa() && 74 | operands[2].isa()) { 75 | // Operands are splats so we can avoid expanding the values out and 76 | // just fold based on the splat value. 77 | auto fst = operands[0].cast(); 78 | auto snd = operands[1].cast(); 79 | auto trd = operands[2].cast(); 80 | 81 | auto elementResult = calculate(fst.getSplatValue(), 82 | snd.getSplatValue(), 83 | trd.getSplatValue()); 84 | return DenseElementsAttr::get(fst.getType(), elementResult); 85 | } else if (operands[0].isa() && 86 | operands[1].isa() && 87 | operands[2].isa()) { 88 | // Operands are ElementsAttr-derived; perform an element-wise fold by 89 | // expanding the values. 90 | auto fst = operands[0].cast(); 91 | auto snd = operands[1].cast(); 92 | auto trd = operands[2].cast(); 93 | 94 | auto fstIt = fst.getValues().begin(); 95 | auto sndIt = snd.getValues().begin(); 96 | auto trdIt = trd.getValues().begin(); 97 | SmallVector elementResults; 98 | elementResults.reserve(fst.getNumElements()); 99 | for (size_t i = 0, e = fst.getNumElements(); i < e; 100 | ++i, ++fstIt, ++sndIt, ++trdIt) 101 | elementResults.push_back(calculate(*fstIt, *sndIt, *trdIt)); 102 | return DenseElementsAttr::get(fst.getType(), elementResults); 103 | } 104 | return {}; 105 | } 106 | 107 | struct constant_int_all_ones_matcher { 108 | bool match(Operation *op) { 109 | APInt value; 110 | return mlir::detail::constant_int_op_binder(&value).match(op) && 111 | value.isAllOnesValue(); 112 | } 113 | }; 114 | 115 | /// Retrieve the class declarations generated by TableGen 116 | #define GET_OP_CLASSES 117 | #include "Dialect/LLHD/LLHDOps.h.inc" 118 | 119 | } // namespace llhd 120 | } // namespace mlir 121 | 122 | #endif // MLIR_DIALECT_LLHD_LLHDOPS_H 123 | -------------------------------------------------------------------------------- /include/LLHDToLLVM/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(LLVM_TARGET_DEFINITIONS Passes.td) 2 | mlir_tablegen(Passes.h.inc -gen-pass-decls) 3 | add_public_tablegen_target(MLIRLLHDConversionPassIncGen) 4 | 5 | add_mlir_doc(Passes -gen-pass-doc LLHDToLLVM Passes/) 6 | -------------------------------------------------------------------------------- /include/LLHDToLLVM/LLHDToLLVM.h: -------------------------------------------------------------------------------- 1 | #ifndef LLHD_DIALECT_LLHD_LLHDTOLLVM_H 2 | #define LLHD_DIALECT_LLHD_LLHDTOLLVM_H 3 | 4 | #include "mlir/Pass/Pass.h" 5 | #include "mlir/Transforms/DialectConversion.h" 6 | 7 | namespace mlir { 8 | 9 | class ModuleOp; 10 | class LLVMTypeConverter; 11 | template 12 | class OperationPass; 13 | 14 | namespace llhd { 15 | 16 | /// Get the LLHD to LLVM conversion patterns. 17 | void populateLLHDToLLVMConversionPatterns(LLVMTypeConverter &converter, 18 | OwningRewritePatternList &patterns); 19 | 20 | /// Create an LLHD to LLVM conversion pass. 21 | std::unique_ptr> createConvertLLHDToLLVMPass(); 22 | 23 | /// Register the LLHD to LLVM convesion pass. 24 | inline void initLLHDToLLVMPass() { 25 | #define GEN_PASS_REGISTRATION 26 | #include "LLHDToLLVM/Passes.h.inc" 27 | } 28 | } // namespace llhd 29 | } // namespace mlir 30 | 31 | #endif // LLHD_DIALECT_LLHD_LLHDTOLLVM_H 32 | -------------------------------------------------------------------------------- /include/LLHDToLLVM/Passes.td: -------------------------------------------------------------------------------- 1 | #ifndef LLHD_LLHDTOLLVM_PASSES 2 | #define LLHD_LLHDTOLLVM_PASSES 3 | 4 | include "mlir/Pass/PassBase.td" 5 | 6 | def ConvertLLHDToLLVM : Pass<"convert-llhd-to-llvm", "ModuleOp"> { 7 | let summary = "Convert LLHD to LLVM"; 8 | // TODO: add description 9 | let description = [{ 10 | TODO 11 | }]; 12 | 13 | let constructor = "mlir::llhd::createConvertLLHDToLLVMPass()"; 14 | } 15 | 16 | #endif // LLHD_LLHDTOLLVM_PASSES 17 | -------------------------------------------------------------------------------- /include/Simulator/Engine.h: -------------------------------------------------------------------------------- 1 | #ifndef LLHD_SIMULATOR_ENGINE_H 2 | #define LLHD_SIMULATOR_ENGINE_H 3 | 4 | #include "Dialect/LLHD/LLHDOps.h" 5 | #include "Simulator/State.h" 6 | 7 | #include "mlir/ExecutionEngine/ExecutionEngine.h" 8 | #include "mlir/IR/Module.h" 9 | 10 | namespace mlir { 11 | namespace llhd { 12 | namespace sim { 13 | 14 | class Engine { 15 | public: 16 | /// Initialize an LLHD simulation engine. This initializes the state, as well 17 | /// as the mlir::ExecutionEngine with the given module. 18 | Engine(llvm::raw_ostream &out, OwningModuleRef &module, MLIRContext &context, 19 | std::string root); 20 | 21 | /// Run simulation up to n steps. Pass n=0 to run indefinitely. 22 | int simulate(int n); 23 | 24 | /// Build the instance layout of the design. 25 | void buildLayout(ModuleOp module); 26 | 27 | /// Get a reference to the module 28 | ModuleOp *getModuleRef() { return &module; } 29 | 30 | /// Get the simulation state. 31 | State *getState() { return state.get(); } 32 | 33 | private: 34 | void walkEntity(EntityOp entity, Instance &child); 35 | 36 | llvm::raw_ostream &out; 37 | std::string root; 38 | std::unique_ptr state; 39 | std::unique_ptr engine; 40 | ModuleOp module; 41 | }; 42 | 43 | } // namespace sim 44 | } // namespace llhd 45 | } // namespace mlir 46 | 47 | #endif // LLHD_SIMULATOR_ENGINE_H 48 | -------------------------------------------------------------------------------- /include/Simulator/State.h: -------------------------------------------------------------------------------- 1 | #ifndef LLHD_SIMULATOR_STATE_H 2 | #define LLHD_SIMULATOR_STATE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "llvm/ADT/APInt.h" 10 | #include "llvm/ADT/PriorityQueue.h" 11 | #include "llvm/ADT/StringMap.h" 12 | #include "llvm/Support/raw_ostream.h" 13 | 14 | namespace mlir { 15 | namespace llhd { 16 | namespace sim { 17 | 18 | /// The simulator's internal representation of time. 19 | struct Time { 20 | /// Empty (zero) time constructor. All the time values are defaulted to 0. 21 | Time() = default; 22 | 23 | /// Construct with given time values. 24 | Time(unsigned time, unsigned delta, unsigned eps) 25 | : time(time), delta(delta), eps(eps) {} 26 | 27 | /// Compare the time values in order of time, delta, eps. 28 | bool operator<(const Time &rhs) const; 29 | 30 | /// Return true if all the time values are equal. 31 | bool operator==(const Time &rhs) const; 32 | 33 | /// Add two time values. 34 | Time operator+(const Time &rhs) const; 35 | 36 | /// Return true if the time represents zero-time. 37 | bool isZero(); 38 | 39 | /// Get the stored time in a printable format. 40 | std::string dump(); 41 | 42 | unsigned time; 43 | unsigned delta; 44 | unsigned eps; 45 | 46 | private: 47 | }; 48 | 49 | /// Detail structure that can be easily accessed by the lowered code 50 | struct SignalDetail { 51 | uint8_t *value; 52 | uint64_t offset; 53 | }; 54 | 55 | /// The simulator's internal representation of a signal. 56 | struct Signal { 57 | /// Construct an "empty" signal. 58 | Signal(std::string name, std::string owner); 59 | 60 | /// Construct a signal with the given name, owner and initial value. 61 | Signal(std::string name, std::string owner, uint8_t *value, uint64_t size); 62 | 63 | /// Construct a subsignal of the signal at origin un the global signal table 64 | Signal(int origin, uint8_t *value, uint64_t size, uint64_t offset); 65 | 66 | /// Default signal destructor 67 | ~Signal() = default; 68 | 69 | /// Returns true if the signals match in name, owner, size and value 70 | bool operator==(const Signal &rhs) const; 71 | 72 | /// Returns true if the owner is lexically smaller than rhs, or the 73 | /// name is lexically smaller than rhs, in case they share the same owner 74 | bool operator<(const Signal &rhs) const; 75 | 76 | /// Return the signal value in dumpable format: "0x" 77 | std::string dump(); 78 | 79 | std::string name; 80 | std::string owner; 81 | // the list of instances this signal triggers 82 | std::vector triggers; 83 | // the list of instances this signal is an output of 84 | std::vector outOf; 85 | int origin = -1; 86 | uint64_t size; 87 | SignalDetail detail; 88 | }; 89 | 90 | /// The simulator's internal representation of one queue slot. 91 | struct Slot { 92 | /// Construct a new slot. 93 | Slot(Time time) : time(time) {} 94 | 95 | /// Returns true if the slot's time is smaller than the compared slot's time. 96 | bool operator<(const Slot &rhs) const; 97 | 98 | /// Returns true if the slot's time is greater than the compared slot's time. 99 | bool operator>(const Slot &rhs) const; 100 | 101 | /// Insert a change. 102 | void insertChange(int index, int bitOffset, llvm::APInt &bytes); 103 | 104 | /// Insert a scheduled process wakeup 105 | void insertChange(std::string inst); 106 | 107 | // > 108 | std::map>> changes; 109 | // processes with scheduled wakeup 110 | std::vector scheduled; 111 | Time time; 112 | }; 113 | 114 | /// This is equivalent to and std::priorityQueue ordered using the greater 115 | /// operator, which adds an insertion method to add changes to a slot. 116 | class UpdateQueue 117 | : public std::priority_queue, std::greater> { 118 | public: 119 | /// Check wheter a slot for the given time already exists. If that's the case, 120 | /// add the new change to it, else create a new slot and push it to the queue. 121 | void insertOrUpdate(Time time, int index, int bitOffset, llvm::APInt &bytes); 122 | 123 | /// Check wheter a slot for the given time already exists. If that's the case, 124 | /// add the scheduled wakeup to it, else create a new slot and push it to the 125 | /// queue. 126 | void insertOrUpdate(Time time, std::string inst); 127 | }; 128 | 129 | /// State structure for process persistence across suspension 130 | struct ProcState { 131 | char *inst; 132 | int resume; 133 | bool *senses; 134 | uint8_t *resumeState; 135 | }; 136 | 137 | /// The simulator internal representation of an instance 138 | struct Instance { 139 | Instance() = default; 140 | 141 | Instance(std::string name, std::string parent) 142 | : name(name), parent(parent), procState(nullptr) {} 143 | 144 | // the instance name 145 | std::string name; 146 | // the instance parent's name 147 | std::string parent; 148 | // the instance's base unit 149 | std::string unit; 150 | bool isEntity; 151 | // the signals the unit defines 152 | std::vector signalTable; 153 | // the input list 154 | std::vector sensitivityList; 155 | // the output list 156 | std::vector outputs; 157 | ProcState *procState; 158 | }; 159 | 160 | /// The simulator's state. It contains the current simulation time, signal 161 | /// values and the event queue. 162 | struct State { 163 | /// Construct a new empty (at 0 time) state. 164 | State() = default; 165 | 166 | /// State destructor, ensures all malloc'd signal regions are correctly free'd 167 | ~State(); 168 | 169 | /// Pop the head of the queue and update the simulation time. 170 | Slot popQueue(); 171 | 172 | /// Push a new event in the event queue. 173 | void pushQueue(Time time, int index, int bitOffset, llvm::APInt &bytes); 174 | 175 | /// Push a new scheduled wakeup event in the event queue. 176 | void pushQueue(Time time, std::string inst); 177 | 178 | /// Get the signal at position i in the signal list. 179 | Signal getSignal(int index); 180 | 181 | /// Add a new signal to the state. Returns the index of the new signal. 182 | int addSignal(std::string name, std::string owner); 183 | 184 | int addSignalData(int index, std::string owner, uint8_t *value, 185 | uint64_t size); 186 | 187 | /// Add a pointer to the process persistence state to a process instance 188 | void addProcPtr(std::string name, ProcState *procStatePtr); 189 | 190 | /// Dump a signal to the out stream. One entry is added for every instance 191 | /// the signal appears in. 192 | void dumpSignal(llvm::raw_ostream &out, int index); 193 | 194 | /// Dump the instance layout. Used for testing purposes. 195 | void dumpLayout(); 196 | 197 | /// Dump the instances each signal triggers. Used for testing purposes. 198 | void dumpSignalTriggers(); 199 | 200 | Time time; 201 | std::string root; 202 | int nSigs; 203 | llvm::StringMap instances; 204 | std::vector signals; 205 | UpdateQueue queue; 206 | }; 207 | 208 | } // namespace sim 209 | } // namespace llhd 210 | } // namespace mlir 211 | 212 | #endif // LLHD_SIMULATOR_STATE_H 213 | -------------------------------------------------------------------------------- /include/Simulator/signals-runtime-wrappers.h: -------------------------------------------------------------------------------- 1 | #ifndef LLHD_SIMULATOR_SIGNALS_RUNTIME_WRAPPERS_H 2 | #define LLHD_SIMULATOR_SIGNALS_RUNTIME_WRAPPERS_H 3 | 4 | #include "Simulator/State.h" 5 | 6 | extern "C" { 7 | 8 | //===----------------------------------------------------------------------===// 9 | // Runtime interfaces 10 | //===----------------------------------------------------------------------===// 11 | 12 | /// Allocate a new signal. The index of the new signal in the state's list of 13 | /// signals is returned. 14 | int alloc_signal(mlir::llhd::sim::State *state, int index, char *owner, 15 | uint8_t *value, int64_t size); 16 | 17 | /// Add allocated constructs to a process instance. 18 | void alloc_proc(mlir::llhd::sim::State *state, char *owner, 19 | mlir::llhd::sim::ProcState *procState); 20 | 21 | /// Gather the index of the signal in the signal list, given the name and the 22 | /// owner of the signal 23 | int gather_signal(mlir::llhd::sim::State *state, char *name, char *owner); 24 | 25 | /// Gather information of the signal at index. 26 | mlir::llhd::sim::SignalDetail *probe_signal(mlir::llhd::sim::State *state, 27 | int index); 28 | 29 | /// Drive a value onto a signal. 30 | void drive_signal(mlir::llhd::sim::State *state, int index, uint8_t *value, 31 | uint64_t width, int time, int delta, int eps); 32 | 33 | /// Add a temporary subsignal to the global signal table 34 | int add_subsignal(mlir::llhd::sim::State *state, int origin, uint8_t *ptr, 35 | uint64_t len, uint64_t offset); 36 | 37 | /// Suspend a process 38 | void llhd_suspend(mlir::llhd::sim::State *state, 39 | mlir::llhd::sim::ProcState *procState, int time, int delta, 40 | int eps); 41 | 42 | //===----------------------------------------------------------------------===// 43 | // Testing methods 44 | //===----------------------------------------------------------------------===// 45 | 46 | /// Initialize an empty state and return a pointer to it. 47 | mlir::llhd::sim::State *init_state(); 48 | 49 | /// Return whether the queue is empty. 50 | int queue_empty(mlir::llhd::sim::State *state); 51 | 52 | /// Pop the head of the queue. 53 | void pop_queue(mlir::llhd::sim::State *state); 54 | 55 | /// Dump the list of changes in the queue head. 56 | void dump_changes(mlir::llhd::sim::State *state); 57 | } 58 | 59 | #endif // LLHD_SIMULATOR_SIGNALS_RUNTIME_WRAPPERS_H 60 | -------------------------------------------------------------------------------- /include/Target/TranslateToVerilog.h: -------------------------------------------------------------------------------- 1 | #include "Target/VerilogPrinter.h" 2 | #include "mlir/Translation.h" 3 | 4 | using namespace mlir; 5 | 6 | namespace mlir { 7 | namespace llhd { 8 | 9 | void registerToVerilogTranslation() { 10 | TranslateFromMLIRRegistration registration( 11 | "llhd-to-verilog", [](ModuleOp module, raw_ostream &output) { 12 | formatted_raw_ostream out(output); 13 | llhd::VerilogPrinter printer(out); 14 | printer.printModule(module); 15 | return success(); 16 | }); 17 | } 18 | 19 | } // namespace llhd 20 | } // namespace mlir 21 | -------------------------------------------------------------------------------- /include/Target/VerilogPrinter.h: -------------------------------------------------------------------------------- 1 | #ifndef TARGET_VERILOGPRINTER_H 2 | #define TARGET_VERILOGPRINTER_H 3 | 4 | #include "Dialect/LLHD/LLHDOps.h" 5 | 6 | #include "mlir/Dialect/StandardOps/IR/Ops.h" 7 | #include "mlir/IR/Module.h" 8 | #include "llvm/ADT/Twine.h" 9 | #include "llvm/Support/FormattedStream.h" 10 | 11 | using namespace llvm; 12 | 13 | namespace mlir { 14 | namespace llhd { 15 | 16 | class VerilogPrinter { 17 | public: 18 | VerilogPrinter(formatted_raw_ostream &output) : out(output) {} 19 | 20 | LogicalResult printModule(ModuleOp op); 21 | LogicalResult printOperation(Operation *op, unsigned indentAmount = 0); 22 | 23 | private: 24 | LogicalResult printType(Type type); 25 | LogicalResult printUnaryOp(Operation *op, StringRef opSymbol, 26 | unsigned indentAmount = 0); 27 | LogicalResult printBinaryOp(Operation *op, StringRef opSymbol, 28 | unsigned indentAmount = 0); 29 | LogicalResult printSignedBinaryOp(Operation *op, StringRef opSymbol, 30 | unsigned indentAmount = 0); 31 | 32 | /// Prints a SSA value. In case no mapping to a name exists yet, a new one is 33 | /// added. 34 | Twine getVariableName(Value value); 35 | 36 | Twine getNewInstantiationName() { 37 | return Twine("inst_") + Twine(instCount++); 38 | } 39 | 40 | /// Adds an alias for an existing SSA value. In case doesn't exist, it just 41 | /// adds the alias as a new value. 42 | void addAliasVariable(Value alias, Value existing); 43 | 44 | unsigned instCount = 0; 45 | formatted_raw_ostream &out; 46 | unsigned nextValueNum = 0; 47 | DenseMap mapValueToName; 48 | DenseMap timeValueMap; 49 | }; 50 | 51 | } // namespace llhd 52 | } // namespace mlir 53 | 54 | #endif // TARGET_VERILOGPRINTER_H 55 | -------------------------------------------------------------------------------- /include/Transforms/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(LLVM_TARGET_DEFINITIONS Passes.td) 2 | mlir_tablegen(Passes.h.inc -gen-pass-decls) 3 | add_public_tablegen_target(MLIRLLHDTransformsIncGen) 4 | 5 | add_mlir_doc(Passes -gen-pass-doc Transformations Passes/) 6 | -------------------------------------------------------------------------------- /include/Transforms/Passes.h: -------------------------------------------------------------------------------- 1 | #ifndef LLHD_TRANSFORMS_PASSES_H 2 | #define LLHD_TRANSFORMS_PASSES_H 3 | 4 | #include "mlir/IR/Module.h" 5 | #include "mlir/Pass/Pass.h" 6 | 7 | namespace mlir { 8 | namespace llhd { 9 | 10 | #define GEN_PASS_CLASSES 11 | #include "Transforms/Passes.h.inc" 12 | 13 | std::unique_ptr> createProcessLoweringPass(); 14 | 15 | std::unique_ptr> createFunctionEliminationPass(); 16 | 17 | /// Register the LLHD Transformation passes. 18 | inline void initLLHDTransformationPasses() { 19 | #define GEN_PASS_REGISTRATION 20 | #include "Transforms/Passes.h.inc" 21 | } 22 | 23 | } // namespace llhd 24 | } // namespace mlir 25 | 26 | #endif // LLHD_TRANSFORMS_PASSES_H 27 | -------------------------------------------------------------------------------- /include/Transforms/Passes.td: -------------------------------------------------------------------------------- 1 | #ifndef MLIR_LLHD_TRANSFORMS_PASSES 2 | #define MLIR_LLHD_TRANSFORMS_PASSES 3 | 4 | include "mlir/Pass/PassBase.td" 5 | 6 | def ProcessLowering : Pass<"llhd-process-lowering", "ModuleOp"> { 7 | let summary = "Lowers LLHD Processes to Entities."; 8 | let description = [{ 9 | TODO 10 | }]; 11 | 12 | let constructor = "mlir::llhd::createProcessLoweringPass()"; 13 | } 14 | 15 | def FunctionElimination : Pass<"llhd-function-elimination", "ModuleOp"> { 16 | let summary = "Deletes all functions."; 17 | let description = [{ 18 | Deletes all functions in the module. In case there is still a function 19 | call in an entity or process, it fails. 20 | This pass is intended as a post-inlining pass to check if all functions 21 | could be successfully inlined and remove the inlined functions. This 22 | is necessary because Structural LLHD does not allow functions. Fails in 23 | the case that there is still a function call left in a `llhd.proc` or 24 | `llhd.entity`. 25 | }]; 26 | 27 | let constructor = "mlir::llhd::createFunctionEliminationPass()"; 28 | } 29 | 30 | #endif // MLIR_LLHD_TRANSFORMS_PASSES 31 | -------------------------------------------------------------------------------- /lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(Dialect) 2 | add_subdirectory(Target) 3 | add_subdirectory(Transforms) 4 | add_subdirectory(LLHDToLLVM) 5 | add_subdirectory(Simulator) 6 | -------------------------------------------------------------------------------- /lib/Dialect/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(LLHD) 2 | -------------------------------------------------------------------------------- /lib/Dialect/LLHD/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_mlir_dialect_library(MLIRLLHD 2 | LLHDDialect.cpp 3 | LLHDOps.cpp 4 | 5 | ADDITIONAL_HEADER_DIRS 6 | ${PROJECT_SOURCE_DIR}/include/Dialect/LLHD 7 | 8 | DEPENDS 9 | MLIRLLHDEnumsIncGen 10 | MLIRLLHDOpsIncGen 11 | 12 | LINK_LIBS PUBLIC 13 | MLIREDSC 14 | MLIRIR 15 | MLIRSideEffectInterfaces 16 | MLIRControlFlowInterfaces 17 | MLIRCallInterfaces 18 | ) 19 | -------------------------------------------------------------------------------- /lib/Dialect/LLHD/LLHDDialect.cpp: -------------------------------------------------------------------------------- 1 | #include "Dialect/LLHD/LLHDDialect.h" 2 | #include "Dialect/LLHD/LLHDOps.h" 3 | #include "mlir/IR/Builders.h" 4 | #include "mlir/IR/DialectImplementation.h" 5 | #include "mlir/Transforms/InliningUtils.h" 6 | #include "llvm/ADT/ArrayRef.h" 7 | #include "llvm/ADT/StringRef.h" 8 | 9 | using namespace mlir; 10 | using namespace mlir::llhd; 11 | 12 | //===----------------------------------------------------------------------===// 13 | // LLHDDialect Interfaces 14 | //===----------------------------------------------------------------------===// 15 | 16 | namespace { 17 | /// This class defines the interface for handling inlining with LLHD operations. 18 | struct LLHDInlinerInterface : public DialectInlinerInterface { 19 | using DialectInlinerInterface::DialectInlinerInterface; 20 | 21 | //===--------------------------------------------------------------------===// 22 | // Analysis Hooks 23 | //===--------------------------------------------------------------------===// 24 | 25 | /// All operations within LLHD can be inlined. 26 | bool isLegalToInline(Operation *, Region *, 27 | BlockAndValueMapping &) const final { 28 | return true; 29 | } 30 | 31 | bool isLegalToInline(Region *, Region *src, 32 | BlockAndValueMapping &) const final { 33 | // Don't inline processes and entities 34 | return !isa(src->getParentOp()) && 35 | !isa(src->getParentOp()); 36 | } 37 | }; 38 | } // end anonymous namespace 39 | 40 | //===----------------------------------------------------------------------===// 41 | // LLHD Dialect 42 | //===----------------------------------------------------------------------===// 43 | 44 | LLHDDialect::LLHDDialect(mlir::MLIRContext *context) 45 | : Dialect(getDialectNamespace(), context) { 46 | addTypes(); 47 | addAttributes(); 48 | addOperations< 49 | #define GET_OP_LIST 50 | #include "Dialect/LLHD/LLHDOps.cpp.inc" 51 | >(); 52 | addInterfaces(); 53 | } 54 | 55 | Operation *LLHDDialect::materializeConstant(OpBuilder &builder, Attribute value, 56 | Type type, Location loc) { 57 | return builder.create(loc, type, value); 58 | } 59 | 60 | //===----------------------------------------------------------------------===// 61 | // Type parsing 62 | //===----------------------------------------------------------------------===// 63 | 64 | /// Parse a signal type. 65 | /// Syntax: sig ::= !llhd.sig 66 | static Type parseSigType(DialectAsmParser &parser) { 67 | Type underlyingType; 68 | if (parser.parseLess()) 69 | return Type(); 70 | 71 | llvm::SMLoc loc = parser.getCurrentLocation(); 72 | if (parser.parseType(underlyingType)) { 73 | parser.emitError(loc, "No signal type found. Signal needs an underlying " 74 | "type."); 75 | return nullptr; 76 | } 77 | 78 | if (parser.parseGreater()) 79 | return Type(); 80 | return SigType::get(underlyingType); 81 | } 82 | 83 | Type LLHDDialect::parseType(DialectAsmParser &parser) const { 84 | llvm::StringRef typeKeyword; 85 | // parse the type keyword first 86 | if (parser.parseKeyword(&typeKeyword)) 87 | return Type(); 88 | if (typeKeyword == SigType::getKeyword()) { 89 | return parseSigType(parser); 90 | } 91 | if (typeKeyword == TimeType::getKeyword()) 92 | return TimeType::get(getContext()); 93 | return Type(); 94 | } 95 | 96 | //===----------------------------------------------------------------------===// 97 | // Type printing 98 | //===----------------------------------------------------------------------===// 99 | 100 | /// Print a signal type with custom syntax: 101 | /// type ::= !sig.type 102 | static void printSigType(SigType sig, DialectAsmPrinter &printer) { 103 | printer << sig.getKeyword() << "<"; 104 | printer.printType(sig.getUnderlyingType()); 105 | printer << ">"; 106 | } 107 | 108 | void LLHDDialect::printType(Type type, DialectAsmPrinter &printer) const { 109 | switch (type.getKind()) { 110 | case LLHDTypes::Sig: { 111 | SigType sig = type.dyn_cast(); 112 | printSigType(sig, printer); 113 | break; 114 | } 115 | case LLHDTypes::Time: { 116 | TimeType time = type.dyn_cast(); 117 | printer << time.getKeyword(); 118 | break; 119 | } 120 | 121 | default: 122 | break; 123 | } 124 | } 125 | 126 | //===----------------------------------------------------------------------===// 127 | // Attribute parsing 128 | //===----------------------------------------------------------------------===// 129 | 130 | /// Parse a time attribute with the custom syntax: 131 | /// time ::= #llhd.time