├── .circleci ├── config.yml └── task_format.sh ├── .clang-format ├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── LICENSE ├── README.md ├── THIRD-PARTY-LICENSES ├── cmake ├── FindGMP.cmake └── OpenScop.cmake ├── docker ├── build.sh ├── demo.dockerfile └── push.sh ├── docs ├── dialect_examples.png └── dialect_overview.png ├── include ├── CMakeLists.txt ├── hcl-c │ ├── Dialect │ │ ├── Dialects.h │ │ ├── HCLAttributes.h │ │ ├── HCLTypes.h │ │ └── Registration.h │ ├── SharedLib │ │ └── HCLRuntimeUtils.h │ └── Translation │ │ ├── EmitIntelHLS.h │ │ └── EmitVivadoHLS.h └── hcl │ ├── Bindings │ ├── CMakeLists.txt │ └── Python │ │ ├── CMakeLists.txt │ │ ├── HCLModule.h │ │ ├── hcl │ │ ├── __init__.py │ │ ├── build_ir.py │ │ ├── dialects │ │ │ ├── AffineOps.td │ │ │ ├── HeteroCLBinding.td │ │ │ ├── _affine_ops_ext.py │ │ │ ├── _affine_ops_gen.py │ │ │ ├── _linalg_ops_ext.py │ │ │ ├── affine.py │ │ │ └── hcl.py │ │ └── exceptions.py │ │ └── setup.py │ ├── CMakeLists.txt │ ├── Conversion │ ├── CMakeLists.txt │ ├── Passes.h │ └── Passes.td │ ├── Dialect │ ├── CMakeLists.txt │ ├── HeteroCLAttrs.h │ ├── HeteroCLAttrs.td │ ├── HeteroCLDialect.h │ ├── HeteroCLDialect.td │ ├── HeteroCLOps.h │ ├── HeteroCLOps.td │ ├── HeteroCLTypes.h │ ├── HeteroCLTypes.td │ ├── TransformOps │ │ ├── CMakeLists.txt │ │ ├── HCLTransformOps.h │ │ └── HCLTransformOps.td │ └── Visitor.h │ ├── Support │ └── Utils.h │ ├── Target │ └── OpenSCoP │ │ ├── ExtractScopStmt.h │ │ ├── OpenScop.h │ │ ├── OslScop.h │ │ ├── OslScopStmtOpSet.h │ │ ├── OslSymbolTable.h │ │ ├── ScatteringUtils.h │ │ └── ScopStmt.h │ ├── Transforms │ ├── CMakeLists.txt │ ├── Passes.h │ └── Passes.td │ └── Translation │ ├── EmitIntelHLS.h │ ├── EmitVivadoHLS.h │ └── Utils.h ├── lib ├── Bindings │ └── Python │ │ ├── HCLAttributes.cpp │ │ ├── HCLModule.cpp │ │ └── HCLTypes.cpp ├── CAPI │ ├── CMakeLists.txt │ ├── Dialect │ │ ├── CMakeLists.txt │ │ ├── Dialects.cpp │ │ ├── HCLAttributes.cpp │ │ ├── HCLTypes.cpp │ │ └── Registration.cpp │ ├── SharedLib │ │ ├── CMakeLists.txt │ │ └── HCLRuntimeUtils.cpp │ └── Translation │ │ ├── CMakeLists.txt │ │ ├── EmitIntelHLS.cpp │ │ └── EmitVivadoHLS.cpp ├── CMakeLists.txt ├── Conversion │ ├── CMakeLists.txt │ ├── FixedPointToInteger.cpp │ ├── HCLToLLVM.cpp │ ├── LowerBitOps.cpp │ ├── LowerCompositeType.cpp │ ├── LowerPrintOps.cpp │ └── Passes.cpp ├── Dialect │ ├── CMakeLists.txt │ ├── HeteroCLDialect.cpp │ ├── HeteroCLOps.cpp │ └── TransformOps │ │ ├── CMakeLists.txt │ │ └── HCLTransformOps.cpp ├── Support │ ├── CMakeLists.txt │ └── Utils.cpp ├── Target │ ├── CMakeLists.txt │ └── OpenSCoP │ │ ├── CMakeLists.txt │ │ ├── ConvertToOpenScop.cpp │ │ ├── ExtractScopStmt.cpp │ │ ├── OslScop.cpp │ │ ├── OslScopStmtOpSet.cpp │ │ ├── OslSymbolTable.cpp │ │ ├── ScatteringUtils.cpp │ │ └── ScopStmt.cpp ├── Transforms │ ├── AnyWidthInteger.cpp │ ├── CMakeLists.txt │ ├── DataPlacement.cpp │ ├── LegalizeCast.cpp │ ├── LoopTransformations.cpp │ ├── MemRefDCE.cpp │ ├── MoveReturnToInput.cpp │ ├── PassDetail.h │ ├── Passes.cpp │ ├── RemoveStrideMap.cpp │ └── TransformInterpreter.cpp └── Translation │ ├── CMakeLists.txt │ ├── EmitIntelHLS.cpp │ ├── EmitVivadoHLS.cpp │ └── Utils.cpp ├── scripts ├── add_license_header.py ├── check_license_header.py └── git-clang-format.sh ├── test ├── Bindings │ ├── test_codegen.py │ ├── test_for_loops.py │ ├── test_if.py │ ├── test_llvm.py │ ├── test_registration.py │ ├── test_scf.py │ └── test_types.py ├── CMakeLists.txt ├── Integration │ ├── affine_dialect.mlir │ ├── llvm_dialect.mlir │ ├── test_execution_engine.py │ └── test_lower_pass.py ├── Operations │ ├── bitops │ │ ├── bit_reverse.mlir │ │ ├── get_bit.mlir │ │ ├── get_slice.mlir │ │ ├── set_bit.mlir │ │ └── set_slice.mlir │ ├── composite │ │ └── struct.mlir │ ├── logicops │ │ ├── and.mlir │ │ └── or.mlir │ ├── misc │ │ ├── clone.mlir │ │ └── const_tensor.mlir │ ├── print │ │ ├── print-f32.mlir │ │ ├── print-fixed.mlir │ │ ├── print.mlir │ │ └── print_memref.mlir │ └── typecast │ │ ├── fixed_to_fixed.mlir │ │ ├── fixed_to_float.mlir │ │ ├── fixed_to_int.mlir │ │ ├── float_to_fixed.mlir │ │ └── int_to_fixed.mlir ├── Runtime │ └── load_memref.mlir ├── Transforms │ ├── compute │ │ ├── cascade.mlir │ │ ├── compute_at.mlir │ │ ├── fusing.mlir │ │ ├── reordering.mlir │ │ ├── stages.mlir │ │ ├── systolic.mlir │ │ ├── thread_binding.mlir │ │ ├── tiling.mlir │ │ └── types.mlir │ ├── datatype │ │ ├── anywidth-skip.mlir │ │ ├── anywidth-unsigned.mlir │ │ ├── anywidthint.mlir │ │ ├── fixedpoint.mlir │ │ └── fti_funcsig.mlir │ ├── interface │ │ ├── customization.mlir │ │ ├── layout.mlir │ │ ├── move_return.mlir │ │ ├── move_return_func_call.mlir │ │ └── outline.mlir │ ├── memory │ │ ├── buffer_add.mlir │ │ ├── buffer_conv.mlir │ │ ├── buffer_gemm.mlir │ │ ├── partition.mlir │ │ ├── reuse.mlir │ │ └── strided_reuse_iv_update.mlir │ └── template │ │ └── gemm.mlir ├── Translation │ └── mm.mlir ├── lit.cfg.py └── lit.site.cfg.py.in └── tools ├── CMakeLists.txt ├── hcl-opt ├── CMakeLists.txt └── hcl-opt.cpp └── hcl-translate ├── CMakeLists.txt └── hcl-translate.cpp /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # Python CircleCI 2.0 configuration file 5 | # 6 | # Check https://circleci.com/docs/2.0/language-python/ for more details 7 | 8 | version: 2 9 | jobs: 10 | build: 11 | working_directory: ~/hcl-dialect 12 | docker: 13 | - image: chhzh123/llvm-project:18.x 14 | auth: 15 | username: $DOCKERHUB_USERNAME 16 | password: $DOCKERHUB_PASSWORD 17 | resource_class: large 18 | steps: 19 | - checkout # checkout source code to working directory 20 | - run: 21 | name: Build HCL-MLIR 22 | command: | 23 | export BUILD_DIR=/root/llvm-project/build 24 | export PREFIX=/root/llvm-project/build 25 | source activate hcl-dev 26 | mkdir -p build && cd build 27 | cmake -G "Unix Makefiles" .. \ 28 | -DMLIR_DIR=$PREFIX/lib/cmake/mlir \ 29 | -DLLVM_EXTERNAL_LIT=$BUILD_DIR/bin/llvm-lit \ 30 | -DPYTHON_BINDING=ON \ 31 | -DPython3_EXECUTABLE=`which python3` \ 32 | -DCMAKE_CXX_FLAGS="-Wfatal-errors -std=c++17" 33 | make -j4 34 | export PYTHONPATH=$(pwd)/tools/hcl/python_packages/hcl_core:${PYTHONPATH} 35 | - run: 36 | name: Formatting Check 37 | command: | 38 | source activate hcl-dev 39 | python3 -m pip install clang-format 40 | bash ./.circleci/task_format.sh 41 | - run: 42 | name: Test 43 | command: | 44 | source activate hcl-dev 45 | cd build 46 | cmake --build . --target check-hcl -------------------------------------------------------------------------------- /.circleci/task_format.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright HeteroCL authors. All Rights Reserved. 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | set -e 6 | set -u 7 | set -o pipefail 8 | 9 | echo "Check license header..." 10 | python3 scripts/check_license_header.py HEAD~1 11 | python3 scripts/check_license_header.py origin/main 12 | 13 | echo "Check C/C++ formats using clang-format..." 14 | bash ./scripts/git-clang-format.sh HEAD~1 15 | bash ./scripts/git-clang-format.sh origin/main 16 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: LLVM -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | build 35 | .vscode 36 | 37 | # MLIR intermediate results 38 | *.opt 39 | 40 | # HLS 41 | *.log 42 | *.prj 43 | 44 | tmp 45 | *.pyc -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "externals/openscop"] 2 | path = externals/openscop 3 | url = https://github.com/periscop/openscop.git 4 | [submodule "externals/llvm-project"] 5 | path = externals/llvm-project 6 | url = https://github.com/llvm/llvm-project.git 7 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | cmake_minimum_required(VERSION 3.13.4) 5 | cmake_policy(SET CMP0116 NEW) 6 | 7 | project(hcl-dialect LANGUAGES CXX C) 8 | 9 | set(CMAKE_BUILD_WITH_INSTALL_NAME_DIR ON) 10 | 11 | set(CMAKE_CXX_STANDARD 17 CACHE STRING "C++ standard to conform to") 12 | add_compile_options ( -Wtype-limits -Waddress ) 13 | 14 | set(CMAKE_BUILD_TYPE Debug) 15 | 16 | find_package(MLIR REQUIRED CONFIG) 17 | 18 | message(STATUS "Using MLIRConfig.cmake in: ${MLIR_DIR}") 19 | message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") 20 | 21 | set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/bin) 22 | set(LLVM_LIBRARY_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/lib) 23 | set(MLIR_BINARY_DIR ${CMAKE_BINARY_DIR}) 24 | 25 | if(OPENSCOP) 26 | message(STATUS "Building OpenSCoP extraction") 27 | # ----------------------------- Customize CMake 28 | 29 | set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${CMAKE_CURRENT_SOURCE_DIR}/cmake") 30 | 31 | # ----------------------- Setup for required dependencies --------------- 32 | # GMP required for OpenScop library link up 33 | # Find whether the GMP package exists. 34 | find_package(GMP REQUIRED) 35 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -lgmp -DOPENSCOP" ) 36 | 37 | # Openscop for OpenSCoP extraction from MLIR code (Affine as of now) 38 | include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/OpenScop.cmake") 39 | include_directories("${OSL_INCLUDE_DIR}") 40 | endif() 41 | 42 | list(APPEND CMAKE_MODULE_PATH "${MLIR_CMAKE_DIR}") 43 | list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") 44 | include(TableGen) 45 | include(AddLLVM) 46 | include(AddMLIR) 47 | include(HandleLLVMOptions) 48 | 49 | include_directories(${LLVM_INCLUDE_DIRS}) 50 | include_directories(${MLIR_INCLUDE_DIRS}) 51 | include_directories(${PROJECT_SOURCE_DIR}/include) 52 | include_directories(${PROJECT_BINARY_DIR}/include) 53 | link_directories(${LLVM_BUILD_LIBRARY_DIR}) 54 | add_definitions(${LLVM_DEFINITIONS}) 55 | 56 | if(PYTHON_BINDING) 57 | message(STATUS "Using Python binding") 58 | include(MLIRDetectPythonEnv) 59 | find_package(Python3 COMPONENTS Interpreter Development NumPy REQUIRED) 60 | message(STATUS "Found Python include dirs: ${Python3_INCLUDE_DIRS}") 61 | message(STATUS "Found Python libraries: ${Python3_LIBRARIES}") 62 | message(STATUS "Found Python executable: ${Python3_EXECUTABLE}") 63 | message(STATUS "Found numpy v${Python3_NumPy_VERSION}: ${Python3_NumPy_INCLUDE_DIRS}") 64 | include_directories(${Python3_INCLUDE_DIRS}) 65 | include_directories(${Python3_NumPy_INCLUDE_DIRS}) 66 | 67 | mlir_detect_pybind11_install() 68 | find_package(pybind11 REQUIRED) 69 | message(STATUS "Found pybind11 v${pybind11_VERSION}: ${pybind11_INCLUDE_DIR}") 70 | message(STATUS "Python prefix = '${PYTHON_MODULE_PREFIX}', " 71 | "suffix = '${PYTHON_MODULE_SUFFIX}', " 72 | "extension = '${PYTHON_MODULE_EXTENSION}'") 73 | include_directories(${pybind11_INCLUDE_DIR}) 74 | endif() 75 | 76 | add_subdirectory(include) 77 | add_subdirectory(lib) 78 | add_subdirectory(test) 79 | add_subdirectory(tools) 80 | -------------------------------------------------------------------------------- /cmake/FindGMP.cmake: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | # Modified from the Polymer project: 4 | # https://github.com/kumasento/polymer 5 | 6 | # Find GMP. 7 | 8 | set(GMP_PREFIX "" CACHE PATH "path ") 9 | 10 | find_path(GMP_INCLUDE_DIR gmp.h gmpxx.h 11 | PATHS ${GMP_PREFIX}/include /usr/include /usr/local/include ) 12 | 13 | find_library(GMP_LIBRARY NAMES gmp libgmp 14 | PATHS ${GMP_PREFIX}/lib /usr/lib /usr/local/lib) 15 | 16 | if(GMP_INCLUDE_DIR AND GMP_LIBRARY) 17 | get_filename_component(GMP_LIBRARY_DIR ${GMP_LIBRARY} PATH) 18 | set(GMP_FOUND TRUE) 19 | endif() 20 | 21 | if(GMP_FOUND) 22 | if(NOT GMP_FIND_QUIETLY) 23 | MESSAGE(STATUS "Found GMP: ${GMP_LIBRARY}") 24 | endif() 25 | elseif(GMP_FOUND) 26 | if(GMP_FIND_REQUIRED) 27 | message(FATAL_ERROR "Could not find GMP") 28 | endif() 29 | endif() 30 | -------------------------------------------------------------------------------- /cmake/OpenScop.cmake: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | # Modified from the Polymer project: https://github.com/kumasento/polymer 4 | 5 | include(ExternalProject) 6 | 7 | set(OSL_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/openscop") 8 | set(OSL_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/openscop/include") 9 | set(OSL_LIB_DIR "${CMAKE_CURRENT_BINARY_DIR}/openscop/lib") 10 | set(OSL_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/openscop") 11 | 12 | ExternalProject_Add( 13 | osl 14 | PREFIX ${OSL_BINARY_DIR} 15 | SOURCE_DIR ${OSL_SOURCE_DIR} 16 | CONFIGURE_COMMAND "${OSL_SOURCE_DIR}/autogen.sh" && "${OSL_SOURCE_DIR}/configure" --prefix=${OSL_BINARY_DIR} 17 | BUILD_COMMAND make -j 4 18 | INSTALL_COMMAND make install 19 | BUILD_IN_SOURCE 1 20 | BUILD_BYPRODUCTS "${OSL_LIB_DIR}/libosl.a" 21 | ) 22 | 23 | add_library(libosl SHARED IMPORTED) 24 | set_target_properties(libosl PROPERTIES IMPORTED_LOCATION "${OSL_LIB_DIR}/libosl.so") 25 | add_dependencies(libosl osl) 26 | -------------------------------------------------------------------------------- /docker/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Copyright HeteroCL authors. All Rights Reserved. 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | docker build -f demo.dockerfile -t hcl-dialect:latest . 6 | -------------------------------------------------------------------------------- /docker/demo.dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | FROM ubuntu:latest 5 | ENV DEBIAN_FRONTEND=noninteractive 6 | 7 | RUN apt-get update && \ 8 | apt-get -y install sudo 9 | 10 | USER root 11 | 12 | # install essentials 13 | RUN sudo apt-get update && apt-get -y install git wget vim gdb gcc make software-properties-common libssl-dev 14 | 15 | # install gcc-9 16 | RUN sudo apt -y install build-essential && \ 17 | sudo apt-get update && \ 18 | sudo add-apt-repository ppa:ubuntu-toolchain-r/ppa -y && \ 19 | sudo apt-get update && \ 20 | sudo apt -y install gcc-9 g++-9 && \ 21 | sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-9 60 \ 22 | --slave /usr/bin/g++ g++ /usr/bin/g++-9 && \ 23 | sudo update-alternatives --config gcc 24 | 25 | # install cmake 26 | WORKDIR /root/ 27 | RUN cd /root/ && wget https://github.com/Kitware/CMake/releases/download/v3.27.9/cmake-3.27.9.tar.gz && \ 28 | tar -xzvf cmake-3.27.9.tar.gz && \ 29 | cd cmake-3.27.9 && \ 30 | ./bootstrap && \ 31 | make -j`nproc` 32 | ENV PATH="${PATH}:/root/cmake-3.27.9/bin" 33 | 34 | # install conda env 35 | RUN wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O /root/miniconda.sh && \ 36 | bash /root/miniconda.sh -b -p /root/miniconda && \ 37 | eval "$(/root/miniconda/bin/conda shell.bash hook)" && \ 38 | conda create --name hcl-dev python=3.12 -y && \ 39 | conda activate hcl-dev 40 | 41 | SHELL ["/root/miniconda/bin/conda", "run", "-n", "hcl-dev", "/bin/bash", "-c"] 42 | 43 | # download llvm-project 44 | RUN cd /root/ && git clone https://github.com/llvm/llvm-project.git 45 | 46 | # install llvm 47 | RUN cd /root/llvm-project && \ 48 | git checkout tags/llvmorg-18-init && \ 49 | python3 -m pip install --upgrade pip && \ 50 | python3 -m pip install numpy PyYAML dataclasses pybind11>=2.9.0 && \ 51 | mkdir build && cd build && \ 52 | cmake -G "Unix Makefiles" ../llvm -DLLVM_ENABLE_PROJECTS=mlir \ 53 | -DLLVM_BUILD_EXAMPLES=ON -DLLVM_TARGETS_TO_BUILD="X86" \ 54 | -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_ASSERTIONS=ON \ 55 | -DLLVM_INSTALL_UTILS=ON -DMLIR_ENABLE_BINDINGS_PYTHON=ON \ 56 | -DPython3_EXECUTABLE=`which python3` && \ 57 | make -j`nproc` 58 | 59 | # download hcl-dialect 60 | RUN cd /root/ && git clone https://github.com/cornell-zhang/hcl-dialect.git 61 | 62 | # install hcl-dialect 63 | RUN cd /root/hcl-dialect && \ 64 | mkdir build && cd build && \ 65 | cmake -G "Unix Makefiles" .. \ 66 | -DMLIR_DIR=/root/llvm-project/build/lib/cmake/mlir \ 67 | -DLLVM_EXTERNAL_LIT=/root/llvm-project/build/bin/llvm-lit \ 68 | -DPYTHON_BINDING=ON \ 69 | -DOPENSCOP=OFF \ 70 | -DPython3_EXECUTABLE=`which python3` \ 71 | -DCMAKE_CXX_FLAGS="-Wfatal-errors -std=c++17" && \ 72 | make -j`nproc` && \ 73 | cd tools/hcl/python_packages/hcl_core && \ 74 | python3 -m pip install -e . 75 | 76 | # initialize conda environment 77 | ENV PATH="${PATH}:/root/miniconda/bin" 78 | RUN conda init bash && \ 79 | echo "conda activate hcl-dev" >> ~/.bashrc -------------------------------------------------------------------------------- /docker/push.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Copyright HeteroCL authors. All Rights Reserved. 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | set -e 6 | 7 | # 8 | # Push the docker image to docker hub. 9 | # 10 | # Usage: push.sh 11 | # 12 | # PASSWORD: The docker hub account password. 13 | # 14 | DOCKER_HUB_ACCOUNT=chhzh123 15 | 16 | # Get the docker hub account password. 17 | PASSWORD="$1" 18 | shift 1 19 | 20 | LOCAL_IMAGE_NAME=hcl-dialect:latest 21 | REMOTE_IMAGE_NAME_VER=${DOCKER_HUB_ACCOUNT}/hcl-dialect:llvm-18.x-py3.12 22 | 23 | echo "Login docker hub" 24 | docker login -u ${DOCKER_HUB_ACCOUNT} -p ${PASSWORD} 25 | 26 | echo "Uploading ${LOCAL_IMAGE_NAME} as ${REMOTE_IMAGE_NAME_VER}" 27 | docker tag ${LOCAL_IMAGE_NAME} ${REMOTE_IMAGE_NAME_VER} 28 | docker push ${REMOTE_IMAGE_NAME_VER} -------------------------------------------------------------------------------- /docs/dialect_examples.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cornell-zhang/hcl-dialect/e17d3ea573b880060fe84f734fb5377dfda24c39/docs/dialect_examples.png -------------------------------------------------------------------------------- /docs/dialect_overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cornell-zhang/hcl-dialect/e17d3ea573b880060fe84f734fb5377dfda24c39/docs/dialect_overview.png -------------------------------------------------------------------------------- /include/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | add_subdirectory(hcl) 5 | -------------------------------------------------------------------------------- /include/hcl-c/Dialect/Dialects.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #ifndef HCL_C_DIALECT_HLSCPP_H 7 | #define HCL_C_DIALECT_HLSCPP_H 8 | 9 | #include "mlir-c/RegisterEverything.h" 10 | 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | 15 | MLIR_DECLARE_CAPI_DIALECT_REGISTRATION(HCL, hcl); 16 | 17 | #ifdef __cplusplus 18 | } 19 | #endif 20 | 21 | #endif // HCL_C_DIALECT_HLSCPP_H 22 | -------------------------------------------------------------------------------- /include/hcl-c/Dialect/HCLAttributes.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #ifndef HCL_MLIR_C_HCL_ATTRIBUTES__H 7 | #define HCL_MLIR_C_HCL_ATTRIBUTES__H 8 | 9 | #include "mlir-c/IR.h" 10 | #include "mlir-c/IntegerSet.h" 11 | #include "mlir-c/Support.h" 12 | #include "mlir/CAPI/IntegerSet.h" 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | // MLIR_CAPI_EXPORTED bool mlirAttributeIsAIntegerSet(MlirAttribute attr); 19 | MLIR_CAPI_EXPORTED MlirAttribute mlirIntegerSetAttrGet(MlirIntegerSet set); 20 | 21 | MLIR_CAPI_EXPORTED bool mlirAttributeIsAPartitionKind(MlirAttribute attr); 22 | MLIR_CAPI_EXPORTED MlirAttribute mlirPartitionKindGet(MlirContext ctx, 23 | MlirAttribute kind); 24 | 25 | MLIR_CAPI_EXPORTED bool mlirAttributeIsANDRangeDimKind(MlirAttribute attr); 26 | MLIR_CAPI_EXPORTED MlirAttribute mlirNDRangeDimKindGet(MlirContext ctx, 27 | MlirAttribute kind); 28 | 29 | #ifdef __cplusplus 30 | } 31 | #endif 32 | 33 | #endif // HCL_MLIR_C_HCL_ATTRIBUTES__H 34 | -------------------------------------------------------------------------------- /include/hcl-c/Dialect/HCLTypes.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #ifndef HCL_MLIR_C_HCLTYPES_H 7 | #define HCL_MLIR_C_HCLTYPES_H 8 | 9 | #include "mlir-c/IR.h" 10 | #include "mlir-c/Support.h" 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif 15 | 16 | MLIR_CAPI_EXPORTED bool hclMlirTypeIsALoopHandle(MlirType type); 17 | MLIR_CAPI_EXPORTED MlirType hclMlirLoopHandleTypeGet(MlirContext ctx); 18 | 19 | MLIR_CAPI_EXPORTED bool hclMlirTypeIsAOpHandle(MlirType type); 20 | MLIR_CAPI_EXPORTED MlirType hclMlirOpHandleTypeGet(MlirContext ctx); 21 | 22 | MLIR_CAPI_EXPORTED bool hclMlirTypeIsAFixedType(MlirType type); 23 | MLIR_CAPI_EXPORTED MlirType hclMlirFixedTypeGet(MlirContext ctx, size_t width, size_t frac); 24 | MLIR_CAPI_EXPORTED unsigned hclMlirFixedTypeGetWidth(MlirType type); 25 | MLIR_CAPI_EXPORTED unsigned hclMlirFixedTypeGetFrac(MlirType type); 26 | 27 | MLIR_CAPI_EXPORTED bool hclMlirTypeIsAUFixedType(MlirType type); 28 | MLIR_CAPI_EXPORTED MlirType hclMlirUFixedTypeGet(MlirContext ctx, size_t width, size_t frac); 29 | MLIR_CAPI_EXPORTED unsigned hclMlirUFixedTypeGetWidth(MlirType type); 30 | MLIR_CAPI_EXPORTED unsigned hclMlirUFixedTypeGetFrac(MlirType type); 31 | 32 | MLIR_CAPI_EXPORTED bool hclMlirTypeIsAStructType(MlirType type); 33 | MLIR_CAPI_EXPORTED MlirType hclMlirStructTypeGet(MlirContext ctx, intptr_t numElements, 34 | MlirType const *elements); 35 | MLIR_CAPI_EXPORTED MlirType hclMlirStructGetEleType(MlirType type, size_t pos); 36 | MLIR_CAPI_EXPORTED unsigned hclMlirStructTypeGetNumFields(MlirType type); 37 | 38 | #ifdef __cplusplus 39 | } 40 | #endif 41 | 42 | #endif // HCL_MLIR_C_HCLTYPES_H -------------------------------------------------------------------------------- /include/hcl-c/Dialect/Registration.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #ifndef HCL_MLIR_C_REGISTRATION_H 7 | #define HCL_MLIR_C_REGISTRATION_H 8 | 9 | #include "mlir/CAPI/IR.h" 10 | #include "mlir-c/IR.h" 11 | #include "mlir-c/Support.h" 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | /** Registers all dialects with a context. 18 | * This is needed before creating IR for these Dialects. 19 | */ 20 | MLIR_CAPI_EXPORTED void hclMlirRegisterAllDialects(MlirContext context); 21 | 22 | /** Registers all passes for symbolic access with the global registry. */ 23 | MLIR_CAPI_EXPORTED void hclMlirRegisterAllPasses(); 24 | 25 | #ifdef __cplusplus 26 | } 27 | #endif 28 | 29 | #endif // HCL_MLIR_C_REGISTRATION_H -------------------------------------------------------------------------------- /include/hcl-c/SharedLib/HCLRuntimeUtils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #ifndef HCLC_SHARED_LIB_HCL_RUNTIME_UTILS_H 7 | #define HCLC_SHARED_LIB_HCL_RUNTIME_UTILS_H 8 | 9 | #ifdef _WIN32 10 | #ifndef HCL_RUNTIME_UTILS_EXPORT 11 | #ifdef hcl_runtime_utils_EXPORTS 12 | // We are building this library 13 | #define HCL_RUNTIME_UTILS_EXPORT __declspec(dllexport) 14 | #define HCL_RUNTIME_UTILS_DEFINE_FUNCTIONS 15 | #else 16 | // We are using this library 17 | #define HCL_RUNTIME_UTILS_EXPORT __declspec(dllimport) 18 | #endif // hcl_runtime_utils_EXPORTS 19 | #endif // HCL_RUNTIME_UTILS_EXPORT 20 | #else // _WIN32 21 | // Non-windows: use visibility attributes. 22 | #define HCL_RUNTIME_UTILS_EXPORT __attribute__((visibility("default"))) 23 | #define HCL_RUNTIME_UTILS_DEFINE_FUNCTIONS 24 | #endif // _WIN32 25 | 26 | #include 27 | #include "mlir/ExecutionEngine/CRunnerUtils.h" 28 | 29 | extern "C" HCL_RUNTIME_UTILS_EXPORT void 30 | readMemrefI32(int64_t rank, void *ptr, char *str); 31 | 32 | extern "C" HCL_RUNTIME_UTILS_EXPORT void 33 | readMemrefI64(int64_t rank, void *ptr, char *str); 34 | 35 | extern "C" HCL_RUNTIME_UTILS_EXPORT void 36 | readMemrefF32(int64_t rank, void *ptr, char *str); 37 | 38 | extern "C" HCL_RUNTIME_UTILS_EXPORT void 39 | readMemrefF64(int64_t rank, void *ptr, char *str); 40 | 41 | extern "C" HCL_RUNTIME_UTILS_EXPORT void 42 | writeMemrefI32(int64_t rank, void *ptr, char *str); 43 | 44 | extern "C" HCL_RUNTIME_UTILS_EXPORT void 45 | writeMemrefI64(int64_t rank, void *ptr, char *str); 46 | 47 | extern "C" HCL_RUNTIME_UTILS_EXPORT void 48 | writeMemrefF32(int64_t rank, void *ptr, char *str); 49 | 50 | extern "C" HCL_RUNTIME_UTILS_EXPORT void 51 | writeMemrefF64(int64_t rank, void *ptr, char *str); 52 | 53 | #endif // HCLC_SHARED_LIB_HCL_RUNTIME_UTILS_H -------------------------------------------------------------------------------- /include/hcl-c/Translation/EmitIntelHLS.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #ifndef HCL_C_TRANSLATION_EMITINTELHLS_H 7 | #define HCL_C_TRANSLATION_EMITINTELHLS_H 8 | 9 | #include "mlir-c/IR.h" 10 | 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | 15 | MLIR_CAPI_EXPORTED MlirLogicalResult mlirEmitIntelHls( 16 | MlirModule module, MlirStringCallback callback, void *userData); 17 | 18 | #ifdef __cplusplus 19 | } 20 | #endif 21 | 22 | #endif // HCL_C_TRANSLATION_EMITINTELHLS_H 23 | -------------------------------------------------------------------------------- /include/hcl-c/Translation/EmitVivadoHLS.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #ifndef HCL_C_TRANSLATION_EMITVIVADOHLS_H 7 | #define HCL_C_TRANSLATION_EMITVIVADOHLS_H 8 | 9 | #include "mlir-c/IR.h" 10 | 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | 15 | MLIR_CAPI_EXPORTED MlirLogicalResult mlirEmitVivadoHls(MlirModule module, 16 | MlirStringCallback callback, 17 | void *userData); 18 | 19 | #ifdef __cplusplus 20 | } 21 | #endif 22 | 23 | #endif // HCL_C_TRANSLATION_EMITVIVADOHLS_H 24 | -------------------------------------------------------------------------------- /include/hcl/Bindings/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | add_subdirectory(Python) -------------------------------------------------------------------------------- /include/hcl/Bindings/Python/HCLModule.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #ifndef HCL_BINDINGS_PYTHON_IRMODULES_H 7 | #define HCL_BINDINGS_PYTHON_IRMODULES_H 8 | 9 | // #include "PybindUtils.h" 10 | #include "mlir/Bindings/Python/PybindAdaptors.h" 11 | 12 | namespace mlir { 13 | namespace python { 14 | 15 | void populateHCLIRTypes(pybind11::module &m); 16 | void populateHCLAttributes(pybind11::module &m); 17 | 18 | } // namespace python 19 | } // namespace mlir 20 | 21 | #endif // HCL_BINDINGS_PYTHON_IRMODULES_H -------------------------------------------------------------------------------- /include/hcl/Bindings/Python/hcl/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from .build_ir import * 5 | from .exceptions import * -------------------------------------------------------------------------------- /include/hcl/Bindings/Python/hcl/dialects/AffineOps.td: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #ifndef PYTHON_BINDINGS_AFFINE_OPS 7 | #define PYTHON_BINDINGS_AFFINE_OPS 8 | 9 | include "mlir/Bindings/Python/Attributes.td" 10 | include "mlir/Dialect/Affine/IR/AffineOps.td" 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /include/hcl/Bindings/Python/hcl/dialects/HeteroCLBinding.td: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #ifndef BINDINGS_PYTHON_HCL_OPS_TD 7 | #define BINDINGS_PYTHON_HCL_OPS_TD 8 | 9 | include "hcl/Dialect/HeteroCLOps.td" 10 | 11 | #endif // BINDINGS_PYTHON_HCL_OPS_TD -------------------------------------------------------------------------------- /include/hcl/Bindings/Python/hcl/dialects/_affine_ops_gen.py: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | # Autogenerated by mlir-tblgen; don't manually edit. 4 | 5 | from ..ir import * 6 | from ._ods_common import _cext as _ods_cext 7 | from ._ods_common import extend_opview_class as _ods_extend_opview_class, segmented_accessor as _ods_segmented_accessor, equally_sized_accessor as _ods_equally_sized_accessor, get_default_loc_context as _ods_get_default_loc_context 8 | _ods_ir = _ods_cext.ir 9 | 10 | try: 11 | from . import _affine_ops_ext as _ods_ext_module 12 | except ImportError: 13 | _ods_ext_module = None 14 | 15 | import builtins 16 | 17 | @_ods_cext.register_dialect 18 | class _Dialect(_ods_ir.Dialect): 19 | DIALECT_NAMESPACE = "affine" 20 | pass 21 | 22 | @_ods_cext.register_operation(_Dialect) 23 | @_ods_extend_opview_class(_ods_ext_module) 24 | class AffineForOp(_ods_ir.OpView): 25 | OPERATION_NAME = "affine.for" 26 | 27 | _ODS_REGIONS = (1, True) 28 | 29 | @builtins.property 30 | def results_(self): 31 | _ods_variadic_group_length = len(self.operation.results) - 1 + 1 32 | return self.operation.results[0:0 + _ods_variadic_group_length] 33 | 34 | @_ods_cext.register_operation(_Dialect) 35 | @_ods_extend_opview_class(_ods_ext_module) 36 | class AffineIfOp(_ods_ir.OpView): 37 | OPERATION_NAME = "affine.if" 38 | 39 | _ODS_REGIONS = (2, True) 40 | 41 | @builtins.property 42 | def results_(self): 43 | _ods_variadic_group_length = len(self.operation.results) - 1 + 1 44 | return self.operation.results[0:0 + _ods_variadic_group_length] 45 | 46 | @_ods_cext.register_operation(_Dialect) 47 | @_ods_extend_opview_class(_ods_ext_module) 48 | class AffineLoadOp(_ods_ir.OpView): 49 | OPERATION_NAME = "affine.load" 50 | 51 | _ODS_REGIONS = (0, True) 52 | 53 | def __init__(self, result, memref, indices, map=None, *, loc=None, ip=None): 54 | operands = [] 55 | results = [] 56 | results.append(result) 57 | operands.append(memref) 58 | operands.extend(indices) 59 | attributes = {} 60 | if map == None: 61 | identity_map = AffineMap.get_identity(len(indices)) 62 | map = AffineMapAttr.get(identity_map) 63 | attributes["map"] = map 64 | super().__init__(self.build_generic( 65 | attributes=attributes, results=results, operands=operands, 66 | loc=loc, ip=ip)) 67 | 68 | @builtins.property 69 | def memref(self): 70 | return self.operation.operands[0] 71 | 72 | @builtins.property 73 | def indices(self): 74 | _ods_variadic_group_length = len(self.operation.operands) - 2 + 1 75 | return self.operation.operands[1:1 + _ods_variadic_group_length] 76 | 77 | @builtins.property 78 | def result(self): 79 | return self.operation.results[0] 80 | 81 | @_ods_cext.register_operation(_Dialect) 82 | @_ods_extend_opview_class(_ods_ext_module) 83 | class AffineStoreOp(_ods_ir.OpView): 84 | OPERATION_NAME = "affine.store" 85 | 86 | _ODS_REGIONS = (0, True) 87 | 88 | @builtins.property 89 | def value(self): 90 | return self.operation.operands[0] 91 | 92 | @builtins.property 93 | def memref(self): 94 | return self.operation.operands[1] 95 | 96 | @builtins.property 97 | def indices(self): 98 | _ods_variadic_group_length = len(self.operation.operands) - 3 + 1 99 | return self.operation.operands[2:2 + _ods_variadic_group_length] 100 | 101 | @_ods_cext.register_operation(_Dialect) 102 | @_ods_extend_opview_class(_ods_ext_module) 103 | class AffineYieldOp(_ods_ir.OpView): 104 | OPERATION_NAME = "affine.yield" 105 | 106 | _ODS_REGIONS = (0, True) 107 | 108 | def __init__(self, operands_, *, loc=None, ip=None): 109 | operands = [] 110 | results = [] 111 | attributes = {} 112 | operands.extend(operands_) 113 | super().__init__(self.build_generic( 114 | attributes=attributes, results=results, operands=operands, 115 | loc=loc, ip=ip)) 116 | 117 | @builtins.property 118 | def operands_(self): 119 | _ods_variadic_group_length = len(self.operation.operands) - 1 + 1 120 | return self.operation.operands[0:0 + _ods_variadic_group_length] -------------------------------------------------------------------------------- /include/hcl/Bindings/Python/hcl/dialects/affine.py: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 | # See https://llvm.org/LICENSE.txt for license information. 5 | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 | 7 | from ._affine_ops_gen import * 8 | -------------------------------------------------------------------------------- /include/hcl/Bindings/Python/hcl/dialects/hcl.py: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from ._hcl_ops_gen import * 5 | from .._mlir_libs._hcl.hcl import * 6 | -------------------------------------------------------------------------------- /include/hcl/Bindings/Python/setup.py: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | import setuptools 5 | 6 | def setup(): 7 | setuptools.setup( 8 | name="hcl_mlir", 9 | description="HCL-MLIR: A HeteroCL-MLIR Dialect for Heterogeneous Computing", 10 | version="0.1", 11 | author="HeteroCL", 12 | setup_requires=[], 13 | install_requires=[], 14 | packages=setuptools.find_packages(), 15 | url="https://github.com/cornell-zhang/hcl-dialect", 16 | python_requires=">=3.6", 17 | classifiers=[ 18 | "Programming Language :: Python :: 3.6", 19 | "Programming Language :: Python :: 3.7", 20 | "Programming Language :: Python :: 3.8", 21 | "Programming Language :: Python :: 3.9", 22 | "Programming Language :: Python :: 3.10", 23 | "Topic :: Scientific/Engineering :: Accelerator Design", 24 | "Operating System :: OS Independent", 25 | ], 26 | zip_safe=True, 27 | ) 28 | 29 | 30 | if __name__ == "__main__": 31 | setup() 32 | -------------------------------------------------------------------------------- /include/hcl/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | if (PYTHON_BINDING) 5 | add_subdirectory(Bindings) 6 | endif() 7 | add_subdirectory(Conversion) 8 | add_subdirectory(Dialect) 9 | add_subdirectory(Transforms) 10 | -------------------------------------------------------------------------------- /include/hcl/Conversion/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | set(LLVM_TARGET_DEFINITIONS Passes.td) 5 | mlir_tablegen(Passes.h.inc -gen-pass-decls) 6 | add_public_tablegen_target(MLIRHeteroCLConversionPassesIncGen) 7 | 8 | # add_mlir_doc(HeteroCLPass HeteroCLPass HeteroCL/ -gen-pass-doc) -------------------------------------------------------------------------------- /include/hcl/Conversion/Passes.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #ifndef HCL_CONVERSION_PASSES_H 7 | #define HCL_CONVERSION_PASSES_H 8 | 9 | #include "mlir/IR/BuiltinOps.h" 10 | #include "mlir/Pass/Pass.h" 11 | #include "mlir/Pass/PassRegistry.h" 12 | 13 | #include "hcl/Dialect/HeteroCLOps.h" 14 | 15 | namespace mlir { 16 | namespace hcl { 17 | 18 | // HeteroCL Dialect -> LLVM Dialect 19 | std::unique_ptr> createHCLToLLVMLoweringPass(); 20 | std::unique_ptr> createFixedPointToIntegerPass(); 21 | std::unique_ptr> createLowerCompositeTypePass(); 22 | std::unique_ptr> createLowerBitOpsPass(); 23 | std::unique_ptr> createLowerPrintOpsPass(); 24 | 25 | bool applyHCLToLLVMLoweringPass(ModuleOp &module, MLIRContext &context); 26 | bool applyFixedPointToInteger(ModuleOp &module); 27 | bool applyLowerCompositeType(ModuleOp &module); 28 | bool applyLowerBitOps(ModuleOp &module); 29 | bool applyLowerPrintOps(ModuleOp &module); 30 | 31 | /// Registers all HCL conversion passes 32 | void registerHCLConversionPasses(); 33 | 34 | #define GEN_PASS_CLASSES 35 | #include "hcl/Conversion/Passes.h.inc" 36 | 37 | } // namespace hcl 38 | } // namespace mlir 39 | 40 | #endif // HCL_CONVERSION_PASSES_H -------------------------------------------------------------------------------- /include/hcl/Conversion/Passes.td: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #ifndef HCL_MLIR_PASSES 7 | #define HCL_MLIR_PASSES 8 | 9 | include "mlir/Pass/PassBase.td" 10 | 11 | def HCLToLLVMLowering : Pass<"hcl-lower-to-llvm", "ModuleOp"> { 12 | let summary = "HCL to LLVM conversion pass"; 13 | let constructor = "mlir::hcl::createHCLToLLVMLoweringPass()"; 14 | } 15 | 16 | def FixedToInteger : Pass<"fixed-to-integer", "ModuleOp"> { 17 | let summary = "Fixed-point operations to integer"; 18 | let constructor = "mlir::hcl::createFixedPointToIntegerPass()"; 19 | } 20 | 21 | def LowerCompositeType : Pass<"lower-composite-type", "ModuleOp"> { 22 | let summary = "Lower composite types"; 23 | let constructor = "mlir::hcl::createLowerCompositeTypePass()"; 24 | } 25 | 26 | def LowerBitOps : Pass<"lower-bit-ops", "ModuleOp"> { 27 | let summary = "Lower bit operations"; 28 | let constructor = "mlir::hcl::createLowerBitOpsPass()"; 29 | } 30 | 31 | def LowerPrintOps : Pass<"lower-print-ops", "ModuleOp"> { 32 | let summary = "Lower print operations"; 33 | let constructor = "mlir::hcl::createLowerPrintOpsPass()"; 34 | } 35 | 36 | #endif // HCL_MLIR_PASSES -------------------------------------------------------------------------------- /include/hcl/Dialect/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | set(LLVM_TARGET_DEFINITIONS HeteroCLOps.td) 5 | mlir_tablegen(HeteroCLOps.h.inc -gen-op-decls) 6 | mlir_tablegen(HeteroCLOps.cpp.inc -gen-op-defs) 7 | mlir_tablegen(HeteroCLDialect.h.inc -gen-dialect-decls -dialect=hcl) 8 | mlir_tablegen(HeteroCLDialect.cpp.inc -gen-dialect-defs -dialect=hcl) 9 | add_public_tablegen_target(MLIRHeteroCLOpsIncGen) 10 | add_dependencies(mlir-headers MLIRHeteroCLOpsIncGen) 11 | 12 | set(LLVM_TARGET_DEFINITIONS HeteroCLTypes.td) 13 | mlir_tablegen(HeteroCLTypes.h.inc -gen-typedef-decls) 14 | mlir_tablegen(HeteroCLTypes.cpp.inc -gen-typedef-defs) 15 | add_public_tablegen_target(MLIRHeteroCLTypesIncGen) 16 | 17 | set(LLVM_TARGET_DEFINITIONS HeteroCLAttrs.td) 18 | mlir_tablegen(HeteroCLAttrs.h.inc -gen-attrdef-decls) 19 | mlir_tablegen(HeteroCLAttrs.cpp.inc -gen-attrdef-defs) 20 | add_public_tablegen_target(MLIRHeteroCLAttrsIncGen) 21 | 22 | set(LLVM_TARGET_DEFINITIONS HeteroCLAttrs.td) 23 | mlir_tablegen(HeteroCLEnums.h.inc -gen-enum-decls) 24 | mlir_tablegen(HeteroCLEnums.cpp.inc -gen-enum-defs) 25 | add_public_tablegen_target(MLIRHeteroCLEnumsIncGen) 26 | 27 | add_mlir_doc(HeteroCLDialect HeteroCLDialect HeteroCL/ -gen-dialect-doc) 28 | add_mlir_doc(HeteroCLOps HeteroCLOps HeteroCL/ -gen-op-doc) 29 | 30 | add_subdirectory(TransformOps) 31 | -------------------------------------------------------------------------------- /include/hcl/Dialect/HeteroCLAttrs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #ifndef HCLATTRS_H 7 | #define HCLATTRS_H 8 | 9 | #include "mlir/IR/BuiltinAttributes.h" 10 | 11 | #include "hcl/Dialect/HeteroCLEnums.h.inc" 12 | 13 | #define GET_ATTRDEF_CLASSES 14 | #include "hcl/Dialect/HeteroCLAttrs.h.inc" 15 | 16 | #endif // HCLATTRS_H -------------------------------------------------------------------------------- /include/hcl/Dialect/HeteroCLAttrs.td: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #ifndef HCL_ATTRS 7 | #define HCL_ATTRS 8 | 9 | include "hcl/Dialect/HeteroCLDialect.td" 10 | include "mlir/IR/EnumAttr.td" 11 | 12 | // https://mlir.llvm.org/docs/OpDefinitions/#enum-attributes 13 | def CompletePartition: I32EnumAttrCase<"CompletePartition", 0>; 14 | def BlockPartition: I32EnumAttrCase<"BlockPartition", 1>; 15 | def CyclicPartition: I32EnumAttrCase<"CyclicPartition", 2>; 16 | 17 | def PartitionKindEnum: I32EnumAttr<"PartitionKindEnum", 18 | "An example partition enum", 19 | [CompletePartition,BlockPartition,CyclicPartition]> { 20 | let cppNamespace = "mlir::hcl"; 21 | let stringToSymbolFnName = "ConvertToPartitionEnum"; 22 | let symbolToStringFnName = "ConvertToPartitionString"; 23 | } 24 | 25 | // NDRange dimension binding 26 | def BlockIdxX: I32EnumAttrCase<"BlockIdxX", 0>; 27 | def BlockIdxY: I32EnumAttrCase<"BlockIdxY", 1>; 28 | def BlockIdxZ: I32EnumAttrCase<"BlockIdxZ", 2>; 29 | def ThreadIdxX: I32EnumAttrCase<"ThreadIdxX", 3>; 30 | def ThreadIdxY: I32EnumAttrCase<"ThreadIdxY", 4>; 31 | def ThreadIdxZ: I32EnumAttrCase<"ThreadIdxZ", 5>; 32 | 33 | def NDRangeDimKindEnum: I32EnumAttr<"NDRangeDimKindEnum", 34 | "A NDRange dimension binding enum", 35 | [BlockIdxX,BlockIdxY,BlockIdxZ,ThreadIdxX,ThreadIdxY,ThreadIdxZ]> { 36 | let cppNamespace = "mlir::hcl"; 37 | let stringToSymbolFnName = "ConvertToNDRangeDimEnum"; 38 | let symbolToStringFnName = "ConvertToNDRangeDimString"; 39 | } 40 | 41 | def UnknownDevice: I32EnumAttrCase<"UnknownDevice", 0>; 42 | def CPUDevice: I32EnumAttrCase<"CPUDevice", 1>; 43 | def FPGADevice: I32EnumAttrCase<"FPGADevice", 2>; 44 | def GPUDevice: I32EnumAttrCase<"GPUDevice", 3>; 45 | 46 | def DeviceEnum: I32EnumAttr<"DeviceEnum", 47 | "A device enum", 48 | [UnknownDevice, CPUDevice, FPGADevice, GPUDevice]> { 49 | let cppNamespace = "mlir::hcl"; 50 | let stringToSymbolFnName = "ConvertToDeviceEnum"; 51 | let symbolToStringFnName = "ConvertToDeviceString"; 52 | } 53 | 54 | def CMP_FIXED_P_EQ : I64EnumAttrCase<"eq", 0>; 55 | def CMP_FIXED_P_NE : I64EnumAttrCase<"ne", 1>; 56 | def CMP_FIXED_P_SLT : I64EnumAttrCase<"slt", 2>; 57 | def CMP_FIXED_P_SLE : I64EnumAttrCase<"sle", 3>; 58 | def CMP_FIXED_P_SGT : I64EnumAttrCase<"sgt", 4>; 59 | def CMP_FIXED_P_SGE : I64EnumAttrCase<"sge", 5>; 60 | def CMP_FIXED_P_ULT : I64EnumAttrCase<"ult", 6>; 61 | def CMP_FIXED_P_ULE : I64EnumAttrCase<"ule", 7>; 62 | def CMP_FIXED_P_UGT : I64EnumAttrCase<"ugt", 8>; 63 | def CMP_FIXED_P_UGE : I64EnumAttrCase<"uge", 9>; 64 | 65 | def CmpFixedPredicateAttr : I64EnumAttr< 66 | "CmpFixedPredicate", "", 67 | [CMP_FIXED_P_EQ, CMP_FIXED_P_NE, CMP_FIXED_P_SLT, CMP_FIXED_P_SLE, CMP_FIXED_P_SGT, 68 | CMP_FIXED_P_SGE, CMP_FIXED_P_ULT, CMP_FIXED_P_ULE, CMP_FIXED_P_UGT, CMP_FIXED_P_UGE]> { 69 | let cppNamespace = "mlir::hcl"; 70 | } 71 | 72 | // def FooAttr : HeteroCL_Attr<"FooAttr"> { 73 | // let mnemonic = "FooAttr"; 74 | // let parameters = (ins ); 75 | // bit hasCustomAssemblyFormat = 1; 76 | // let printer = [{ 77 | // $_printer << "FooAttr"; 78 | // }]; 79 | // let parser = [{ 80 | // return get($_ctxt); 81 | // }]; 82 | // } 83 | 84 | #endif // HCL_ATTRS -------------------------------------------------------------------------------- /include/hcl/Dialect/HeteroCLDialect.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #ifndef HETEROCL_DIALECT_H 7 | #define HETEROCL_DIALECT_H 8 | 9 | #include "mlir/IR/Dialect.h" 10 | 11 | #include "hcl/Dialect/HeteroCLDialect.h.inc" 12 | 13 | #endif // HETEROCL_DIALECT_H 14 | -------------------------------------------------------------------------------- /include/hcl/Dialect/HeteroCLDialect.td: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #ifndef HETEROCL_DIALECT 7 | #define HETEROCL_DIALECT 8 | 9 | include "mlir/IR/AttrTypeBase.td" 10 | include "mlir/IR/OpBase.td" 11 | 12 | //===----------------------------------------------------------------------===// 13 | // hcl dialect definition. 14 | //===----------------------------------------------------------------------===// 15 | 16 | def HeteroCL_Dialect : Dialect { 17 | let name = "hcl"; 18 | let summary = "A hcl out-of-tree MLIR dialect."; 19 | let description = [{ 20 | This dialect is an example of an out-of-tree MLIR dialect designed to 21 | illustrate the basic setup required to develop MLIR-based tools without 22 | working inside of the LLVM source tree. 23 | }]; 24 | let useDefaultTypePrinterParser = 1; 25 | let cppNamespace = "::mlir::hcl"; 26 | } 27 | 28 | //===----------------------------------------------------------------------===// 29 | // Base hcl operation definition. 30 | //===----------------------------------------------------------------------===// 31 | 32 | class HeteroCL_Op traits = []> : 33 | Op; 34 | 35 | class HeteroCL_Type traits = []> : 36 | TypeDef; 37 | 38 | class HeteroCL_Attr traits = []> : 39 | AttrDef; 40 | 41 | #endif // HETEROCL_DIALECT 42 | -------------------------------------------------------------------------------- /include/hcl/Dialect/HeteroCLOps.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #ifndef HETEROCL_OPS_H 7 | #define HETEROCL_OPS_H 8 | 9 | #include "mlir/IR/BuiltinTypes.h" 10 | #include "mlir/IR/FunctionInterfaces.h" 11 | #include "mlir/IR/Matchers.h" 12 | #include "mlir/IR/OpDefinition.h" 13 | #include "mlir/IR/OpImplementation.h" 14 | #include "mlir/IR/SymbolTable.h" 15 | #include "mlir/Interfaces/CallInterfaces.h" 16 | #include "mlir/Interfaces/CastInterfaces.h" 17 | #include "mlir/Interfaces/ControlFlowInterfaces.h" 18 | #include "mlir/Interfaces/InferTypeOpInterface.h" 19 | #include "mlir/Interfaces/SideEffectInterfaces.h" 20 | 21 | #include "hcl/Dialect/HeteroCLAttrs.h" 22 | #include "hcl/Dialect/HeteroCLTypes.h" 23 | 24 | #define GET_OP_CLASSES 25 | #include "hcl/Dialect/HeteroCLOps.h.inc" 26 | 27 | #endif // HETEROCL_OPS_H 28 | -------------------------------------------------------------------------------- /include/hcl/Dialect/HeteroCLTypes.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #ifndef HCLTYPES_H 7 | #define HCLTYPES_H 8 | 9 | #include "mlir/IR/BuiltinTypes.h" 10 | #include "mlir/IR/DialectImplementation.h" 11 | 12 | #define GET_TYPEDEF_CLASSES 13 | #include "hcl/Dialect/HeteroCLTypes.h.inc" 14 | 15 | #endif // HCLTYPES_H -------------------------------------------------------------------------------- /include/hcl/Dialect/HeteroCLTypes.td: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #ifndef HCL_TYPES 7 | #define HCL_TYPES 8 | 9 | include "hcl/Dialect/HeteroCLDialect.td" 10 | include "mlir/IR/BuiltinTypeInterfaces.td" 11 | 12 | def Type : HeteroCL_Type<"Type", [MemRefElementTypeInterface]> { 13 | let summary = "generic type"; 14 | let mnemonic = "Type"; 15 | } 16 | 17 | // // https://mlir.llvm.org/docs/Tutorials/DefiningAttributesAndTypes/#defining-custom-parsers-and-printers-using-assembly-formats 18 | // https://github.com/llvm/torch-mlir/blob/main/include/torch-mlir/Dialect/Torch/IR/TorchTypes.td#L50 19 | def LoopHandle : HeteroCL_Type<"LoopHandle"> { 20 | let summary = "loop handle"; 21 | let mnemonic = "LoopHandle"; 22 | } 23 | 24 | def OpHandle : HeteroCL_Type<"OpHandle"> { 25 | let summary = "op handle"; 26 | let mnemonic = "OpHandle"; 27 | } 28 | 29 | def Fixed : HeteroCL_Type<"Fixed", [MemRefElementTypeInterface]> { 30 | let summary = "fixed point"; 31 | let mnemonic = "Fixed"; 32 | let parameters = (ins "std::size_t":$width, "std::size_t":$frac); 33 | let assemblyFormat = "`<` $width `,` $frac `>`"; 34 | } 35 | 36 | def UFixed : HeteroCL_Type<"UFixed", [MemRefElementTypeInterface]> { 37 | let summary = "unsigned fixed point"; 38 | let mnemonic = "UFixed"; 39 | let parameters = (ins "std::size_t":$width, "std::size_t":$frac); 40 | let assemblyFormat = "`<` $width `,` $frac `>`"; 41 | } 42 | 43 | def Struct : HeteroCL_Type<"Struct", [MemRefElementTypeInterface]> { 44 | let summary = "struct type"; 45 | let mnemonic = "struct"; 46 | let parameters = (ins ArrayRefParameter<"Type", "elementTypes">:$elementTypes); 47 | bit hasCustomAssemblyFormat = 1; 48 | } 49 | 50 | #endif // HCL_TYPES -------------------------------------------------------------------------------- /include/hcl/Dialect/TransformOps/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | set(LLVM_TARGET_DEFINITIONS HCLTransformOps.td) 5 | mlir_tablegen(HCLTransformOps.h.inc -gen-op-decls) 6 | mlir_tablegen(HCLTransformOps.cpp.inc -gen-op-defs) 7 | add_public_tablegen_target(MLIRHCLTransformOpsIncGen) 8 | -------------------------------------------------------------------------------- /include/hcl/Dialect/TransformOps/HCLTransformOps.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #ifndef MLIR_DIALECT_TRANSFORMOPS_HCLTRANSFORMOPS_H 7 | #define MLIR_DIALECT_TRANSFORMOPS_HCLTRANSFORMOPS_H 8 | 9 | #include "mlir/Dialect/PDL/IR/PDLTypes.h" 10 | #include "mlir/Dialect/Transform/IR/TransformInterfaces.h" 11 | #include "mlir/Dialect/Transform/IR/MatchInterfaces.h" 12 | #include "mlir/Dialect/Transform/IR/TransformAttrs.h" 13 | #include "mlir/Dialect/Transform/IR/TransformDialect.h" 14 | #include "mlir/Dialect/Transform/IR/TransformTypes.h" 15 | #include "mlir/IR/OpImplementation.h" 16 | #include "mlir/IR/FunctionInterfaces.h" 17 | #include "mlir/IR/OpDefinition.h" 18 | #include "mlir/IR/PatternMatch.h" 19 | #include "mlir/IR/SymbolTable.h" 20 | #include "mlir/Interfaces/CallInterfaces.h" 21 | #include "mlir/Interfaces/CastInterfaces.h" 22 | #include "mlir/Interfaces/ControlFlowInterfaces.h" 23 | #include "mlir/Interfaces/LoopLikeInterface.h" 24 | #include "mlir/Dialect/Affine/IR/AffineOps.h" 25 | 26 | namespace mlir { 27 | namespace func { 28 | class FuncOp; 29 | } // namespace func 30 | namespace affine { 31 | class AffineForOp; 32 | } // namespace affine 33 | namespace hcl { 34 | class ForOp; 35 | } // namespace hcl 36 | } // namespace mlir 37 | 38 | namespace mlir { 39 | namespace transform { 40 | 41 | enum class FailurePropagationMode : uint32_t; 42 | class FailurePropagationModeAttr; 43 | 44 | /// A builder function that populates the body of a SequenceOp. 45 | using SequenceBodyBuilderFn = ::llvm::function_ref; 47 | using SequenceBodyBuilderArgsFn = 48 | ::llvm::function_ref; 50 | 51 | } // namespace transform 52 | } // namespace mlir 53 | 54 | #define GET_OP_CLASSES 55 | #include "hcl/Dialect/TransformOps/HCLTransformOps.h.inc" 56 | 57 | namespace mlir { 58 | class DialectRegistry; 59 | 60 | namespace hcl { 61 | void registerTransformDialectExtension(DialectRegistry ®istry); 62 | } // namespace hcl 63 | } // namespace mlir 64 | 65 | #endif // MLIR_DIALECT_TRANSFORMOPS_HCLTRANSFORMOPS_H 66 | -------------------------------------------------------------------------------- /include/hcl/Target/OpenSCoP/ExtractScopStmt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * Modification: Polymer 5 | * https://github.com/kumasento/polymer 6 | */ 7 | 8 | //===- ExtractScopStmt.h - Extract scop stmt to func ------------------C++-===// 9 | // 10 | // This file declares the transformation that extracts scop statements into MLIR 11 | // functions. 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | #ifndef HCL_TARGET_EXTRACTSCOPSTMT_H 16 | #define HCL_TARGET_EXTRACTSCOPSTMT_H 17 | 18 | #include "mlir/IR/BuiltinOps.h" 19 | 20 | #define SCOP_STMT_ATTR_NAME "scop.stmt" 21 | 22 | namespace mlir { 23 | class ModuleOp; 24 | struct LogicalResult; 25 | } // namespace mlir 26 | 27 | namespace mlir { 28 | namespace hcl { 29 | 30 | LogicalResult extractOpenScop( 31 | ModuleOp module, 32 | llvm::raw_ostream &os); 33 | 34 | void registerToOpenScopExtractTranslation(); 35 | 36 | } // namespace hcl 37 | } // namespace mlir 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /include/hcl/Target/OpenSCoP/OpenScop.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * Modification: Polymer 5 | * https://github.com/kumasento/polymer 6 | */ 7 | 8 | //===- OpenScop.h -----------------------------------------------*- C++ -*-===// 9 | // 10 | // This file declares the interfaces for converting OpenScop representation to 11 | // MLIR modules. 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | #ifndef HCL_TARGET_OPENSCOP_H 16 | #define HCL_TARGET_OPENSCOP_H 17 | 18 | #include 19 | 20 | #include "mlir/Support/LLVM.h" 21 | #include "llvm/ADT/DenseMap.h" 22 | #include "llvm/ADT/StringMap.h" 23 | 24 | #define SCOP_STMT_ATTR_NAME "scop.stmt" 25 | 26 | namespace mlir { 27 | class OwningModuleRef; 28 | class MLIRContext; 29 | class ModuleOp; 30 | class FuncOp; 31 | struct LogicalResult; 32 | class Operation; 33 | class Value; 34 | } // namespace mlir 35 | 36 | namespace mlir { 37 | namespace hcl { 38 | 39 | class OslScop; 40 | class OslSymbolTable; 41 | 42 | std::unique_ptr createOpenScopFromFuncOp( 43 | mlir::FuncOp funcOp, 44 | OslSymbolTable &symTable 45 | ); 46 | 47 | /// Create a function (FuncOp) from the given OpenScop object in the given 48 | /// module (ModuleOp). 49 | //mlir::Operation * 50 | //createFuncOpFromOpenScop(std::unique_ptr scop, mlir::ModuleOp module, 51 | // OslSymbolTable &symTable, mlir::MLIRContext *context, 52 | // PlutoProg *prog = nullptr, 53 | // const char *dumpClastAfterPluto = nullptr); 54 | // 55 | //mlir::OwningModuleRef translateOpenScopToModule(std::unique_ptr scop, 56 | // mlir::MLIRContext *context); 57 | // 58 | //mlir::LogicalResult translateModuleToOpenScop( 59 | // mlir::ModuleOp module, 60 | // llvm::SmallVectorImpl> &scops, 61 | // llvm::raw_ostream &os); 62 | // 63 | //void registerToOpenScopTranslation(); 64 | //void registerFromOpenScopTranslation(); 65 | 66 | } // namespace hcl 67 | } // namespace mlir 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /include/hcl/Target/OpenSCoP/OslScopStmtOpSet.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * Modification: Polymer 5 | * https://github.com/kumasento/polymer 6 | */ 7 | 8 | //===- OslScopStmtOpSet.h ---------------------------------------*- C++ -*-===// 9 | // 10 | // This file declares the class OslScopStmtOpSet. 11 | // 12 | //===----------------------------------------------------------------------===// 13 | #ifndef HCL_SUPPORT_OSLSCOPSTMTOPSET_H 14 | #define HCL_SUPPORT_OSLSCOPSTMTOPSET_H 15 | 16 | #include "llvm/ADT/SetVector.h" 17 | 18 | using namespace llvm; 19 | 20 | namespace mlir { 21 | class Operation; 22 | struct LogicalResult; 23 | class FlatAffineValueConstraints; 24 | } // namespace mlir 25 | 26 | namespace mlir { 27 | namespace hcl { 28 | 29 | /// This class contains a set of operations that will correspond to a single 30 | /// OpenScop statement body. The underlying data structure is SetVector. 31 | class OslScopStmtOpSet { 32 | public: 33 | using Set = llvm::SetVector; 34 | using iterator = Set::iterator; 35 | using reverse_iterator = Set::reverse_iterator; 36 | 37 | OslScopStmtOpSet() {} 38 | 39 | /// The core store op. There should be only one of it. 40 | mlir::Operation *getStoreOp() { return storeOp; } 41 | 42 | /// Insert. 43 | void insert(mlir::Operation *op); 44 | 45 | /// Count. 46 | unsigned count(mlir::Operation *op) { return opSet.count(op); }; 47 | 48 | /// Size. 49 | unsigned size() { return opSet.size(); } 50 | 51 | /// Iterators. 52 | iterator begin() { return opSet.begin(); } 53 | iterator end() { return opSet.end(); } 54 | reverse_iterator rbegin() { return opSet.rbegin(); } 55 | reverse_iterator rend() { return opSet.rend(); } 56 | 57 | mlir::Operation *get(unsigned i) { return opSet[i]; } 58 | 59 | /// The domain of a stmtOpSet is the union of all load/store operations in 60 | /// that set. We calculate such a union by concatenating the constraints of 61 | /// domain defined by FlatAffineValueConstraints. 62 | /// TODO: improve the interface. 63 | mlir::LogicalResult getDomain(mlir::FlatAffineValueConstraints &domain); 64 | mlir::LogicalResult 65 | getDomain(mlir::FlatAffineValueConstraints &domain, 66 | SmallVectorImpl &enclosingOps); 67 | 68 | /// Get the enclosing operations for the opSet. 69 | mlir::LogicalResult 70 | getEnclosingOps(SmallVectorImpl &enclosingOps); 71 | 72 | private: 73 | Set opSet; 74 | 75 | mlir::Operation *storeOp = nullptr; 76 | }; 77 | 78 | } // namespace hcl 79 | } // namespece mlir 80 | 81 | #endif 82 | -------------------------------------------------------------------------------- /include/hcl/Target/OpenSCoP/OslSymbolTable.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * Modification: Polymer 5 | * https://github.com/kumasento/polymer 6 | */ 7 | 8 | //===- OslSymbolTable.h -----------------------------------------*- C++ -*-===// 9 | // 10 | // This file declares the OslSymbolTable class that stores the mapping between 11 | // symbols and MLIR values. 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | #ifndef HCL_SUPPORT_OSLSYMBOLTABLE_H 16 | #define HCL_SUPPORT_OSLSYMBOLTABLE_H 17 | 18 | #include "mlir/Support/LLVM.h" 19 | #include "llvm/ADT/StringMap.h" 20 | 21 | using namespace llvm; 22 | using namespace mlir; 23 | 24 | namespace mlir { 25 | class Operation; 26 | class Value; 27 | } // namespace mlir 28 | 29 | namespace mlir { 30 | namespace hcl { 31 | 32 | class OslScopStmtOpSet; 33 | 34 | class OslSymbolTable { 35 | public: 36 | using OpSet = OslScopStmtOpSet; 37 | using OpSetPtr = std::unique_ptr; 38 | 39 | enum SymbolType { LoopIV, Memref, StmtOpSet }; 40 | 41 | Value getValue(StringRef key); 42 | 43 | OpSet getOpSet(StringRef key); 44 | 45 | void setValue(StringRef key, Value val, SymbolType type); 46 | 47 | void setOpSet(StringRef key, OpSet val, SymbolType type); 48 | 49 | unsigned getNumValues(SymbolType type); 50 | 51 | unsigned getNumOpSets(SymbolType type); 52 | 53 | void getValueSymbols(SmallVectorImpl &symbols); 54 | 55 | void getOpSetSymbols(SmallVectorImpl &symbols); 56 | 57 | private: 58 | StringMap nameToStmtOpSet; 59 | StringMap nameToLoopIV; 60 | StringMap nameToMemref; 61 | }; 62 | 63 | } // namespace hcl 64 | } // namespace mlir 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /include/hcl/Target/OpenSCoP/ScatteringUtils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * Modification: Polymer 5 | * https://github.com/kumasento/polymer 6 | */ 7 | 8 | //===- ScatteringUtils.h ----------------------------------------*- C++ -*-===// 9 | // 10 | // This file declares the C++ wrapper for the Scop scattering. 11 | // 12 | //===----------------------------------------------------------------------===// 13 | #ifndef HCL_SUPPORT_SCATTERINGUTILS_H 14 | #define HCL_SUPPORT_SCATTERINGUTILS_H 15 | 16 | #include 17 | 18 | #include "llvm/ADT/ArrayRef.h" 19 | #include "llvm/ADT/SmallVector.h" 20 | 21 | namespace mlir { 22 | class Value; 23 | class Operation; 24 | } // namespace mlir 25 | 26 | namespace mlir { 27 | namespace hcl { 28 | 29 | class ScatTreeNodeImpl; 30 | 31 | /// Tree that holds scattering information. This node can represent an induction 32 | /// variable or a statement. A statement is constructed as a leaf node. 33 | class ScatTreeNode { 34 | public: 35 | ScatTreeNode(); 36 | ScatTreeNode(mlir::Value iv); 37 | 38 | ~ScatTreeNode(); 39 | 40 | ScatTreeNode(ScatTreeNode &&); 41 | ScatTreeNode(const ScatTreeNode &) = delete; 42 | ScatTreeNode &operator=(ScatTreeNode &&); 43 | ScatTreeNode &operator=(const ScatTreeNode &) = delete; 44 | 45 | void insertScopStmt(llvm::ArrayRef ops, 46 | llvm::SmallVectorImpl &scats); 47 | /// Get the depth of the tree starting from this node. 48 | unsigned getDepth() const; 49 | 50 | private: 51 | std::unique_ptr impl; 52 | }; 53 | 54 | } // namespace hcl 55 | } // namespace mlir 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /include/hcl/Target/OpenSCoP/ScopStmt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * Modification: Polymer 5 | * https://github.com/kumasento/polymer 6 | */ 7 | 8 | //===- ScopStmt.h -----------------------------------------------*- C++ -*-===// 9 | // 10 | // This file declares the class ScopStmt. 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #ifndef HCL_SUPPORT_SCOPSTMT_H 15 | #define HCL_SUPPORT_SCOPSTMT_H 16 | 17 | #include 18 | 19 | #include "llvm/ADT/SmallVector.h" 20 | 21 | namespace mlir { 22 | class Operation; 23 | class FlatAffineValueConstraints; 24 | class AffineValueMap; 25 | class FuncOp; 26 | class CallOp; 27 | class Value; 28 | } // namespace mlir 29 | 30 | namespace mlir { 31 | namespace hcl { 32 | 33 | class ScopStmtImpl; 34 | 35 | /// Class that stores all the essential information for a Scop statement, 36 | /// including the MLIR operations and Scop relations, and handles the processing 37 | /// of them. 38 | class ScopStmt { 39 | public: 40 | ScopStmt(mlir::Operation *caller, mlir::Operation *callee); 41 | ~ScopStmt(); 42 | 43 | ScopStmt(ScopStmt &&); 44 | ScopStmt(const ScopStmt &) = delete; 45 | ScopStmt &operator=(ScopStmt &&); 46 | ScopStmt &operator=(const ScopStmt &&) = delete; 47 | 48 | mlir::FlatAffineValueConstraints *getDomain() const; 49 | 50 | /// Get a copy of the enclosing operations. 51 | void getEnclosingOps(llvm::SmallVectorImpl &ops, 52 | bool forOnly = false) const; 53 | /// Get the callee of this scop stmt. 54 | mlir::FuncOp getCallee() const; 55 | /// Get the caller of this scop stmt. 56 | mlir::CallOp getCaller() const; 57 | /// Get the access AffineValueMap of an op in the callee and the memref in the 58 | /// caller scope that this op is using. 59 | void getAccessMapAndMemRef(mlir::Operation *op, mlir::AffineValueMap *vMap, 60 | mlir::Value *memref) const; 61 | 62 | private: 63 | std::unique_ptr impl; 64 | }; 65 | } // namespace hcl 66 | } // namespace mlir 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /include/hcl/Transforms/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | set(LLVM_TARGET_DEFINITIONS Passes.td) 5 | mlir_tablegen(Passes.h.inc -gen-pass-decls) 6 | add_public_tablegen_target(MLIRHeteroCLPassesIncGen) 7 | 8 | add_mlir_doc(HeteroCLPass HeteroCLPass HeteroCL/ -gen-pass-doc) -------------------------------------------------------------------------------- /include/hcl/Transforms/Passes.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #ifndef HCL_TRANSFORMS_PASSES_H 7 | #define HCL_TRANSFORMS_PASSES_H 8 | 9 | #include "mlir/IR/BuiltinOps.h" 10 | #include "mlir/Pass/Pass.h" 11 | 12 | namespace mlir { 13 | namespace hcl { 14 | 15 | std::unique_ptr> createLoopTransformationPass(); 16 | std::unique_ptr> createAnyWidthIntegerPass(); 17 | std::unique_ptr> createMoveReturnToInputPass(); 18 | std::unique_ptr> createLegalizeCastPass(); 19 | std::unique_ptr> createRemoveStrideMapPass(); 20 | std::unique_ptr> createMemRefDCEPass(); 21 | std::unique_ptr> createDataPlacementPass(); 22 | std::unique_ptr> createTransformInterpreterPass(); 23 | 24 | bool applyLoopTransformation(ModuleOp &f); 25 | bool applyAnyWidthInteger(ModuleOp &module); 26 | bool applyMoveReturnToInput(ModuleOp &module); 27 | bool applyLegalizeCast(ModuleOp &module); 28 | bool applyRemoveStrideMap(ModuleOp &module); 29 | bool applyMemRefDCE(ModuleOp &module); 30 | bool applyDataPlacement(ModuleOp &module); 31 | 32 | /// Registers all HCL transformation passes 33 | void registerHCLPasses(); 34 | 35 | } // namespace hcl 36 | } // namespace mlir 37 | 38 | #endif // HCL_TRANSFORMS_PASSES_H -------------------------------------------------------------------------------- /include/hcl/Transforms/Passes.td: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #ifndef HCL_MLIR_PASSES 7 | #define HCL_MLIR_PASSES 8 | 9 | include "mlir/Pass/PassBase.td" 10 | 11 | def LoopTransformation : Pass<"loop-opt", "ModuleOp"> { 12 | let summary = "Loop transformation pass"; 13 | let constructor = "mlir::hcl::createLoopTransformationPass()"; 14 | } 15 | 16 | def DataPlacement : Pass<"data-placement", "ModuleOp"> { 17 | let summary = "Data placement pass"; 18 | let constructor = "mlir::hcl::createDataPlacementPass()"; 19 | } 20 | 21 | def AnyWidthInteger : Pass<"anywidth-integer", "ModuleOp"> { 22 | let summary = "Transform anywidth-integer input to 64-bit"; 23 | let constructor = "mlir::hcl::createAnyWidthIntegerPass()"; 24 | } 25 | 26 | def MoveReturnToInput : Pass<"return-to-input", "ModuleOp"> { 27 | let summary = "Move return values to input argument list"; 28 | let constructor = "mlir::hcl::createMoveReturnToInputPass()"; 29 | } 30 | 31 | def LegalizeCast : Pass<"legalize-cast", "ModuleOp"> { 32 | let summary = "Legalize cast operations"; 33 | let constructor = "mlir::hcl::createLegalizeCastPass()"; 34 | } 35 | 36 | def RemoveStrideMap : Pass<"remove-stride-map", "ModuleOp"> { 37 | let summary = "Remove stride map from partitioned memref"; 38 | let constructor = "mlir::hcl::createRemoveStrideMapPass()"; 39 | } 40 | 41 | def MemRefDCE : Pass<"memref-dce", "ModuleOp"> { 42 | let summary = "Remove MemRefs that are never loaded from"; 43 | let constructor = "mlir::hcl::createMemRefDCEPass()"; 44 | } 45 | 46 | def TransformInterpreter : Pass<"transform-interpreter", "ModuleOp"> { 47 | let summary = "Rewrite the IR by interpreting transform ops"; 48 | let constructor = "mlir::hcl::createTransformInterpreterPass()"; 49 | } 50 | 51 | #endif // HCL_MLIR_PASSES -------------------------------------------------------------------------------- /include/hcl/Translation/EmitIntelHLS.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #ifndef HCL_TRANSLATION_EMITINTELHLS_H 7 | #define HCL_TRANSLATION_EMITINTELHLS_H 8 | 9 | #include "mlir/IR/BuiltinOps.h" 10 | 11 | namespace mlir { 12 | namespace hcl { 13 | 14 | LogicalResult emitIntelHLS(ModuleOp module, llvm::raw_ostream &os); 15 | void registerEmitIntelHLSTranslation(); 16 | 17 | } // namespace hcl 18 | } // namespace mlir 19 | 20 | #endif // HCL_TRANSLATION_EMITINTELHLS_H -------------------------------------------------------------------------------- /include/hcl/Translation/EmitVivadoHLS.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #ifndef HCL_TRANSLATION_EMITVIVADOHLS_H 7 | #define HCL_TRANSLATION_EMITVIVADOHLS_H 8 | 9 | #include "mlir/IR/BuiltinOps.h" 10 | 11 | namespace mlir { 12 | namespace hcl { 13 | 14 | LogicalResult emitVivadoHLS(ModuleOp module, llvm::raw_ostream &os); 15 | void registerEmitVivadoHLSTranslation(); 16 | 17 | } // namespace hcl 18 | } // namespace mlir 19 | 20 | #endif // HCL_TRANSLATION_EMITVIVADOHLS_H -------------------------------------------------------------------------------- /include/hcl/Translation/Utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #ifndef HCL_TRANSLATION_UTILS_H 7 | #define HCL_TRANSLATION_UTILS_H 8 | 9 | #include "mlir/Dialect/Affine/IR/AffineValueMap.h" 10 | #include "mlir/IR/AffineExprVisitor.h" 11 | #include "mlir/IR/IntegerSet.h" 12 | #include "mlir/InitAllDialects.h" 13 | #include "mlir/Tools/mlir-translate/Translation.h" 14 | #include "llvm/Support/raw_ostream.h" 15 | 16 | #include "hcl/Dialect/HeteroCLDialect.h" 17 | #include "hcl/Dialect/HeteroCLOps.h" 18 | 19 | using namespace mlir; 20 | using namespace hcl; 21 | 22 | //===----------------------------------------------------------------------===// 23 | // Base Classes 24 | //===----------------------------------------------------------------------===// 25 | 26 | /// This class maintains the mutable state that cross-cuts and is shared by the 27 | /// various emitters. 28 | class HCLEmitterState { 29 | public: 30 | explicit HCLEmitterState(raw_ostream &os) : os(os) {} 31 | 32 | // The stream to emit to. 33 | raw_ostream &os; 34 | 35 | bool encounteredError = false; 36 | unsigned currentIndent = 0; 37 | 38 | // This table contains all declared values. 39 | DenseMap> nameTable; 40 | std::map nameConflictCnt; 41 | 42 | private: 43 | HCLEmitterState(const HCLEmitterState &) = delete; 44 | void operator=(const HCLEmitterState &) = delete; 45 | }; 46 | 47 | /// This is the base class for all of the HLSCpp Emitter components. 48 | class HCLEmitterBase { 49 | public: 50 | explicit HCLEmitterBase(HCLEmitterState &state) 51 | : state(state), os(state.os) {} 52 | 53 | InFlightDiagnostic emitError(Operation *op, const Twine &message) { 54 | state.encounteredError = true; 55 | return op->emitError(message); 56 | } 57 | 58 | raw_ostream &indent() { return os.indent(state.currentIndent); } 59 | 60 | void addIndent() { state.currentIndent += 2; } 61 | void reduceIndent() { state.currentIndent -= 2; } 62 | 63 | // All of the mutable state we are maintaining. 64 | HCLEmitterState &state; 65 | 66 | // The stream to emit to. 67 | raw_ostream &os; 68 | 69 | /// Value name management methods. 70 | SmallString<8> addName(Value val, bool isPtr = false, std::string name = ""); 71 | 72 | SmallString<8> getName(Value val); 73 | 74 | bool isDeclared(Value val) { 75 | if (getName(val).empty()) { 76 | return false; 77 | } else 78 | return true; 79 | } 80 | 81 | private: 82 | HCLEmitterBase(const HCLEmitterBase &) = delete; 83 | void operator=(const HCLEmitterBase &) = delete; 84 | }; 85 | 86 | void fixUnsignedType(Value &result, bool isUnsigned); 87 | void fixUnsignedType(memref::GlobalOp &op, bool isUnsigned); 88 | 89 | #endif // HCL_TRANSLATION_UTILS_H -------------------------------------------------------------------------------- /lib/Bindings/Python/HCLAttributes.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #include "mlir-c/BuiltinAttributes.h" 7 | #include "mlir-c/IR.h" 8 | #include "mlir-c/Support.h" 9 | #include "mlir/Bindings/Python/PybindAdaptors.h" 10 | #include "mlir/CAPI/IR.h" 11 | 12 | #include "hcl-c/Dialect/HCLAttributes.h" 13 | #include "hcl/Bindings/Python/HCLModule.h" 14 | 15 | #include 16 | #include 17 | 18 | namespace py = pybind11; 19 | using namespace mlir::python::adaptors; 20 | 21 | using namespace mlir; 22 | using namespace mlir::python; 23 | 24 | namespace pybind11 { 25 | namespace detail { 26 | 27 | /// Casts object <-> MlirIntegerSet. 28 | template <> struct type_caster { 29 | PYBIND11_TYPE_CASTER(MlirIntegerSet, _("MlirIntegerSet")); 30 | bool load(handle src, bool) { 31 | py::object capsule = mlirApiObjectToCapsule(src); 32 | value = mlirPythonCapsuleToIntegerSet(capsule.ptr()); 33 | if (mlirIntegerSetIsNull(value)) { 34 | return false; 35 | } 36 | return true; 37 | } 38 | static handle cast(MlirIntegerSet v, return_value_policy, handle) { 39 | py::object capsule = 40 | py::reinterpret_steal(mlirPythonIntegerSetToCapsule(v)); 41 | return py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir")) 42 | .attr("IntegerSet") 43 | .attr(MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule) 44 | .release(); 45 | } 46 | }; 47 | 48 | } // namespace detail 49 | } // namespace pybind11 50 | 51 | void mlir::python::populateHCLAttributes(py::module &m) { 52 | mlir_attribute_subclass(m, "IntegerSetAttr", mlirAttributeIsAIntegerSet) 53 | .def_classmethod( 54 | "get", 55 | [](py::object cls, MlirIntegerSet IntegerSet, MlirContext ctx) { 56 | return cls(mlirIntegerSetAttrGet(IntegerSet)); 57 | }, 58 | py::arg("cls"), py::arg("integer_set"), 59 | py::arg("context") = py::none(), 60 | "Gets an attribute wrapping an IntegerSet."); 61 | 62 | mlir_attribute_subclass(m, "PartitionKindEnum", mlirAttributeIsAPartitionKind) 63 | .def_classmethod( 64 | "get", 65 | [](py::object cls, MlirAttribute kind, MlirContext ctx) { 66 | return cls(mlirPartitionKindGet(ctx, kind)); 67 | }, 68 | py::arg("cls"), py::arg("kind"), py::arg("context") = py::none(), 69 | "Gets an attribute wrapping a partition kind."); 70 | 71 | mlir_attribute_subclass(m, "NDRangeDimKindEnum", 72 | mlirAttributeIsANDRangeDimKind) 73 | .def_classmethod( 74 | "get", 75 | [](py::object cls, MlirAttribute kind, MlirContext ctx) { 76 | return cls(mlirNDRangeDimKindGet(ctx, kind)); 77 | }, 78 | py::arg("cls"), py::arg("kind"), py::arg("context") = py::none(), 79 | "Gets an attribute wrapping a NDRange dimension kind."); 80 | } 81 | -------------------------------------------------------------------------------- /lib/Bindings/Python/HCLTypes.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #include "mlir-c/IR.h" 7 | #include "mlir-c/Support.h" 8 | #include "mlir/Bindings/Python/PybindAdaptors.h" 9 | #include "mlir/CAPI/IR.h" 10 | 11 | #include "hcl-c/Dialect/HCLTypes.h" 12 | #include "hcl/Bindings/Python/HCLModule.h" 13 | 14 | #include 15 | #include 16 | 17 | namespace py = pybind11; 18 | using namespace mlir::python::adaptors; 19 | 20 | using namespace mlir; 21 | using namespace mlir::python; 22 | 23 | void mlir::python::populateHCLIRTypes(py::module &m) { 24 | mlir_type_subclass(m, "LoopHandleType", hclMlirTypeIsALoopHandle) 25 | .def_classmethod( 26 | "get", 27 | [](py::object cls, MlirContext ctx) { 28 | return cls(hclMlirLoopHandleTypeGet(ctx)); 29 | }, 30 | "Get an instance of LoopHandleType in given context.", py::arg("cls"), 31 | py::arg("context") = py::none()); 32 | 33 | mlir_type_subclass(m, "OpHandleType", hclMlirTypeIsAOpHandle) 34 | .def_classmethod( 35 | "get", 36 | [](py::object cls, MlirContext ctx) { 37 | return cls(hclMlirOpHandleTypeGet(ctx)); 38 | }, 39 | "Get an instance of OpHandleType in given context.", py::arg("cls"), 40 | py::arg("context") = py::none()); 41 | 42 | mlir_type_subclass(m, "FixedType", hclMlirTypeIsAFixedType) 43 | .def_classmethod( 44 | "get", 45 | [](py::object cls, size_t width, size_t frac, MlirContext ctx) { 46 | return cls(hclMlirFixedTypeGet(ctx, width, frac)); 47 | }, 48 | "Get an instance of FixedType in given context.", py::arg("cls"), 49 | py::arg("width"), py::arg("frac"), py::arg("context") = py::none()) 50 | .def_property_readonly( 51 | "width", [](MlirType type) { return hclMlirFixedTypeGetWidth(type); }, 52 | "Returns the width of the fixed point type") 53 | .def_property_readonly( 54 | "frac", [](MlirType type) { return hclMlirFixedTypeGetFrac(type); }, 55 | "Returns the fraction of the fixed point type"); 56 | 57 | mlir_type_subclass(m, "UFixedType", hclMlirTypeIsAUFixedType) 58 | .def_classmethod( 59 | "get", 60 | [](py::object cls, size_t width, size_t frac, MlirContext ctx) { 61 | return cls(hclMlirUFixedTypeGet(ctx, width, frac)); 62 | }, 63 | "Get an instance of FixedType in given context.", py::arg("cls"), 64 | py::arg("width"), py::arg("frac"), py::arg("context") = py::none()) 65 | .def_property_readonly( 66 | "width", 67 | [](MlirType type) { return hclMlirUFixedTypeGetWidth(type); }, 68 | "Returns the width of the fixed point type") 69 | .def_property_readonly( 70 | "frac", [](MlirType type) { return hclMlirUFixedTypeGetFrac(type); }, 71 | "Returns the fraction of the fixed point type"); 72 | mlir_type_subclass(m, "StructType", hclMlirTypeIsAStructType) 73 | .def_classmethod( 74 | "get", 75 | [](py::object cls, const std::vector &members, 76 | MlirContext ctx) { 77 | return cls( 78 | hclMlirStructTypeGet(ctx, members.size(), members.data())); 79 | }, 80 | "Get an instance of StructType in given context.", py::arg("cls"), 81 | py::arg("members"), py::arg("context") = py::none()) 82 | .def_property_readonly( 83 | "field_types", 84 | [](MlirType type) { 85 | py::list types; 86 | unsigned num_fields = hclMlirStructTypeGetNumFields(type); 87 | for (size_t i = 0; i < num_fields; i++) { 88 | types.append(hclMlirStructGetEleType(type, i)); 89 | } 90 | return types; 91 | }, 92 | "Get a field type of a struct type by index."); 93 | } -------------------------------------------------------------------------------- /lib/CAPI/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | add_subdirectory(Dialect) 5 | add_subdirectory(Translation) 6 | add_subdirectory(SharedLib) -------------------------------------------------------------------------------- /lib/CAPI/Dialect/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | add_mlir_public_c_api_library(MLIRHCLCAPI 5 | Dialects.cpp 6 | HCLTypes.cpp 7 | HCLAttributes.cpp 8 | Registration.cpp 9 | ${PROJECT_SOURCE_DIR}/lib/Transforms/Passes.cpp 10 | ${PROJECT_SOURCE_DIR}/lib/Transforms/LoopTransformations.cpp 11 | 12 | ADDITIONAL_HEADER_DIRS 13 | ${MLIR_MAIN_INCLUDE_DIR}/mlir-c 14 | 15 | LINK_LIBS PUBLIC 16 | MLIRIR 17 | MLIRCAPIIR 18 | MLIRSupport 19 | MLIRHeteroCL 20 | MLIRHCLTransformOps 21 | MLIRHCLPasses 22 | MLIRHCLConversion 23 | ) 24 | -------------------------------------------------------------------------------- /lib/CAPI/Dialect/Dialects.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #include "hcl-c/Dialect/Dialects.h" 7 | 8 | #include "hcl/Dialect/HeteroCLDialect.h" 9 | #include "mlir/CAPI/Registration.h" 10 | 11 | MLIR_DEFINE_CAPI_DIALECT_REGISTRATION(HCL, hcl, mlir::hcl::HeteroCLDialect) -------------------------------------------------------------------------------- /lib/CAPI/Dialect/HCLAttributes.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #include "hcl-c/Dialect/HCLAttributes.h" 7 | #include "hcl/Dialect/HeteroCLAttrs.h" 8 | #include "hcl/Dialect/HeteroCLDialect.h" 9 | #include "mlir/CAPI/Registration.h" 10 | 11 | using namespace mlir; 12 | using namespace hcl; 13 | 14 | // bool mlirAttributeIsAIntegerSet(MlirAttribute attr) { 15 | // return unwrap(attr).isa(); 16 | // } 17 | 18 | MlirAttribute mlirIntegerSetAttrGet(MlirIntegerSet set) { 19 | return wrap(IntegerSetAttr::get(unwrap(set))); 20 | } 21 | 22 | bool mlirAttributeIsAPartitionKind(MlirAttribute attr) { 23 | return unwrap(attr).isa(); 24 | } 25 | 26 | MlirAttribute mlirPartitionKindGet(MlirContext ctx, MlirAttribute kind) { 27 | IntegerAttr attr = unwrap(kind).cast(); 28 | PartitionKindEnum kindEnum = static_cast(attr.getInt()); 29 | return wrap(PartitionKindEnumAttr::get(unwrap(ctx), kindEnum)); 30 | } 31 | 32 | bool mlirAttributeIsANDRangeDimKind(MlirAttribute attr) { 33 | return unwrap(attr).isa(); 34 | } 35 | 36 | MlirAttribute mlirNDRangeDimKindGet(MlirContext ctx, MlirAttribute kind) { 37 | IntegerAttr attr = unwrap(kind).cast(); 38 | NDRangeDimKindEnum kindEnum = static_cast(attr.getInt()); 39 | return wrap(NDRangeDimKindEnumAttr::get(unwrap(ctx), kindEnum)); 40 | } -------------------------------------------------------------------------------- /lib/CAPI/Dialect/HCLTypes.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #include "hcl-c/Dialect/HCLTypes.h" 7 | #include "hcl/Dialect/HeteroCLTypes.h" 8 | #include "mlir/CAPI/Registration.h" 9 | 10 | using namespace mlir; 11 | using namespace hcl; 12 | 13 | bool hclMlirTypeIsALoopHandle(MlirType type) { 14 | return unwrap(type).isa(); 15 | } 16 | 17 | MlirType hclMlirLoopHandleTypeGet(MlirContext ctx) { 18 | return wrap(hcl::LoopHandleType::get(unwrap(ctx))); 19 | } 20 | 21 | bool hclMlirTypeIsAOpHandle(MlirType type) { 22 | return unwrap(type).isa(); 23 | } 24 | 25 | MlirType hclMlirOpHandleTypeGet(MlirContext ctx) { 26 | return wrap(hcl::OpHandleType::get(unwrap(ctx))); 27 | } 28 | 29 | bool hclMlirTypeIsAFixedType(MlirType type) { 30 | return unwrap(type).isa(); 31 | } 32 | 33 | MlirType hclMlirFixedTypeGet(MlirContext ctx, size_t width, size_t frac) { 34 | return wrap(hcl::FixedType::get(unwrap(ctx), width, frac)); 35 | } 36 | 37 | unsigned hclMlirFixedTypeGetWidth(MlirType type) { 38 | return unwrap(type).cast().getWidth(); 39 | } 40 | 41 | unsigned hclMlirFixedTypeGetFrac(MlirType type) { 42 | return unwrap(type).cast().getFrac(); 43 | } 44 | 45 | bool hclMlirTypeIsAUFixedType(MlirType type) { 46 | return unwrap(type).isa(); 47 | } 48 | 49 | MlirType hclMlirUFixedTypeGet(MlirContext ctx, size_t width, size_t frac) { 50 | return wrap(hcl::UFixedType::get(unwrap(ctx), width, frac)); 51 | } 52 | 53 | unsigned hclMlirUFixedTypeGetWidth(MlirType type) { 54 | return unwrap(type).cast().getWidth(); 55 | } 56 | 57 | unsigned hclMlirUFixedTypeGetFrac(MlirType type) { 58 | return unwrap(type).cast().getFrac(); 59 | } 60 | 61 | bool hclMlirTypeIsAStructType(MlirType type) { 62 | return unwrap(type).isa(); 63 | } 64 | 65 | MlirType hclMlirStructTypeGet(MlirContext ctx, intptr_t numElements, 66 | MlirType const *elements) { 67 | SmallVector types; 68 | ArrayRef typeRef = unwrapList(numElements, elements, types); 69 | return wrap(hcl::StructType::get(unwrap(ctx), typeRef)); 70 | } 71 | 72 | MlirType hclMlirStructGetEleType(MlirType type, size_t pos) { 73 | return wrap(unwrap(type).cast().getElementTypes()[pos]); 74 | } 75 | 76 | unsigned hclMlirStructTypeGetNumFields(MlirType type) { 77 | return unwrap(type).cast().getElementTypes().size(); 78 | } -------------------------------------------------------------------------------- /lib/CAPI/Dialect/Registration.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #include "hcl-c/Dialect/Registration.h" 7 | #include "hcl/Conversion/Passes.h" 8 | #include "hcl/Transforms/Passes.h" 9 | 10 | #include "mlir/Conversion/Passes.h" 11 | #include "mlir/Dialect/Affine/Passes.h" 12 | #include "mlir/Dialect/Arith/Transforms/Passes.h" 13 | #include "mlir/Dialect/Func/Transforms/Passes.h" 14 | #include "mlir/Dialect/LLVMIR/Transforms/Passes.h" 15 | #include "mlir/Dialect/Linalg/Passes.h" 16 | #include "mlir/Dialect/MemRef/Transforms/Passes.h" 17 | #include "mlir/Transforms/Passes.h" 18 | 19 | #include "hcl/Dialect/HeteroCLDialect.h" 20 | #include "hcl/Dialect/TransformOps/HCLTransformOps.h" 21 | #include "mlir/InitAllDialects.h" 22 | 23 | void hclMlirRegisterAllDialects(MlirContext context) { 24 | mlir::DialectRegistry registry; 25 | registry.insert(); 30 | mlir::hcl::registerTransformDialectExtension(registry); 31 | unwrap(context)->appendDialectRegistry(registry); 32 | unwrap(context)->loadAllAvailableDialects(); 33 | } 34 | 35 | void hclMlirRegisterAllPasses() { 36 | // General passes 37 | mlir::registerTransformsPasses(); 38 | 39 | // Conversion passes 40 | mlir::registerConversionPasses(); 41 | 42 | // Dialect passes 43 | mlir::affine::registerAffinePasses(); 44 | mlir::arith::registerArithPasses(); 45 | mlir::LLVM::registerLLVMPasses(); 46 | mlir::memref::registerMemRefPasses(); 47 | mlir::registerLinalgPasses(); 48 | mlir::registerTransformsPasses(); 49 | 50 | mlir::hcl::registerHCLPasses(); 51 | mlir::hcl::registerHCLConversionPasses(); 52 | } -------------------------------------------------------------------------------- /lib/CAPI/SharedLib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | add_mlir_library(hcl_runtime_utils 5 | SHARED 6 | HCLRuntimeUtils.cpp 7 | ) 8 | target_compile_definitions(hcl_runtime_utils PRIVATE hcl_runtime_utils_EXPORTS) -------------------------------------------------------------------------------- /lib/CAPI/SharedLib/HCLRuntimeUtils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #include "hcl-c/SharedLib/HCLRuntimeUtils.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // reference: 13 | // https://github.com/llvm/llvm-project/blob/bd672e2fc03823e536866da6721b9f053cfd586b/mlir/lib/ExecutionEngine/CRunnerUtils.cpp#L59 14 | 15 | #define MAX_LINE_LENGTH 4096 16 | 17 | template void readMemref(int64_t rank, void *ptr, char *str) { 18 | // Open the input file 19 | FILE *fp = fopen(str, "r"); 20 | if (!fp) { 21 | perror("Error opening file"); 22 | return; 23 | } 24 | 25 | // Read the file line by line 26 | char line[MAX_LINE_LENGTH]; 27 | T *array = NULL; 28 | int array_size = 0; 29 | while (fgets(line, MAX_LINE_LENGTH, fp)) { 30 | // Parse the line and add the values to the array 31 | char *token = strtok(line, ","); 32 | while (token) { 33 | // Resize the array if necessary 34 | if (array_size % 8 == 0) { 35 | array = (T *)realloc(array, (array_size + 8) * sizeof(T)); 36 | } 37 | // Convert the token to a float and add it to the array 38 | array[array_size++] = atof(token); 39 | // Get the next token 40 | token = strtok(NULL, ","); 41 | } 42 | } 43 | 44 | // Close the file 45 | fclose(fp); 46 | 47 | // Print the array 48 | printf("LoadMemref: array loaded from file (%d elements):\n", array_size); 49 | for (int i = 0; i < array_size; i++) { 50 | std::cout << array[i] << " "; 51 | } 52 | printf("\n"); 53 | 54 | // Copy data from array to memref buffer 55 | UnrankedMemRefType unranked_memref = {rank, ptr}; 56 | DynamicMemRefType memref(unranked_memref); 57 | memcpy(memref.data, array, array_size * sizeof(T)); 58 | 59 | // Free the array 60 | free(array); 61 | } 62 | 63 | extern "C" void readMemrefI32(int64_t rank, void *ptr, char *str) { 64 | readMemref(rank, ptr, str); 65 | } 66 | 67 | extern "C" void readMemrefI64(int64_t rank, void *ptr, char *str) { 68 | readMemref(rank, ptr, str); 69 | } 70 | 71 | extern "C" void readMemrefF32(int64_t rank, void *ptr, char *str) { 72 | readMemref(rank, ptr, str); 73 | } 74 | 75 | extern "C" void readMemrefF64(int64_t rank, void *ptr, char *str) { 76 | readMemref(rank, ptr, str); 77 | } 78 | 79 | template 80 | void writeMemref(int64_t rank, void *ptr, char *filename, std::string fmt) { 81 | // Define the array and its size 82 | UnrankedMemRefType unranked_memref = {rank, ptr}; 83 | DynamicMemRefType memref(unranked_memref); 84 | int array_size = 1; 85 | for (int i = 0; i < rank; i++) { 86 | array_size *= memref.sizes[i]; 87 | } 88 | T *array = (T *)malloc(array_size * sizeof(T)); 89 | memcpy(array, memref.data, array_size * sizeof(T)); 90 | 91 | // Print a message saying writing to file 92 | printf("Writing memref to file: %s\n", filename); 93 | 94 | // Open the file for writing 95 | FILE *fp = fopen(filename, "w"); 96 | if (fp == NULL) { 97 | // File opening failed 98 | printf("Error opening file!\n"); 99 | return; 100 | } 101 | 102 | // Write the array to the file, with comma separators 103 | for (int i = 0; i < array_size; i++) { 104 | fprintf(fp, fmt.c_str(), array[i]); 105 | if (i < array_size - 1) { 106 | // Add a comma separator, unless this is the last element 107 | fprintf(fp, ", "); 108 | } 109 | } 110 | 111 | // Close the file 112 | fclose(fp); 113 | 114 | // Free the array 115 | free(array); 116 | } 117 | 118 | extern "C" void writeMemrefI32(int64_t rank, void *ptr, char *str) { 119 | writeMemref(rank, ptr, str, "%d"); 120 | } 121 | 122 | extern "C" void writeMemrefI64(int64_t rank, void *ptr, char *str) { 123 | writeMemref(rank, ptr, str, "%ld"); 124 | } 125 | 126 | extern "C" void writeMemrefF32(int64_t rank, void *ptr, char *str) { 127 | writeMemref(rank, ptr, str, "%.6f "); 128 | } 129 | 130 | extern "C" void writeMemrefF64(int64_t rank, void *ptr, char *str) { 131 | writeMemref(rank, ptr, str, "%.6f "); 132 | } -------------------------------------------------------------------------------- /lib/CAPI/Translation/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | add_mlir_public_c_api_library(MLIRHCLCAPIEmitHLSCpp 5 | EmitVivadoHLS.cpp 6 | EmitIntelHLS.cpp 7 | 8 | ADDITIONAL_HEADER_DIRS 9 | ${MLIR_MAIN_INCLUDE_DIR}/mlir-c 10 | 11 | LINK_LIBS PUBLIC 12 | MLIRCAPIIR 13 | MLIRHCLEmitHLSCpp 14 | ) 15 | -------------------------------------------------------------------------------- /lib/CAPI/Translation/EmitIntelHLS.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #include "hcl/Translation/EmitIntelHLS.h" 7 | #include "hcl-c/Translation/EmitIntelHLS.h" 8 | #include "mlir/CAPI/IR.h" 9 | #include "mlir/CAPI/Support.h" 10 | #include "mlir/CAPI/Utils.h" 11 | 12 | using namespace mlir; 13 | using namespace hcl; 14 | 15 | MlirLogicalResult mlirEmitIntelHls(MlirModule module, 16 | MlirStringCallback callback, 17 | void *userData) { 18 | mlir::detail::CallbackOstream stream(callback, userData); 19 | return wrap(emitIntelHLS(unwrap(module), stream)); 20 | } -------------------------------------------------------------------------------- /lib/CAPI/Translation/EmitVivadoHLS.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #include "hcl/Translation/EmitVivadoHLS.h" 7 | #include "hcl-c/Translation/EmitVivadoHLS.h" 8 | #include "mlir/CAPI/IR.h" 9 | #include "mlir/CAPI/Support.h" 10 | #include "mlir/CAPI/Utils.h" 11 | 12 | using namespace mlir; 13 | using namespace hcl; 14 | 15 | MlirLogicalResult mlirEmitVivadoHls(MlirModule module, 16 | MlirStringCallback callback, 17 | void *userData) { 18 | mlir::detail::CallbackOstream stream(callback, userData); 19 | return wrap(emitVivadoHLS(unwrap(module), stream)); 20 | } -------------------------------------------------------------------------------- /lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | if (PYTHON_BINDING) 5 | add_subdirectory(CAPI) 6 | endif() 7 | add_subdirectory(Conversion) 8 | add_subdirectory(Dialect) 9 | add_subdirectory(Transforms) 10 | add_subdirectory(Translation) 11 | add_subdirectory(Support) 12 | add_subdirectory(Target) 13 | -------------------------------------------------------------------------------- /lib/Conversion/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | file(GLOB globbed *.cpp) 5 | 6 | get_property(conversion_libs GLOBAL PROPERTY MLIR_CONVERSION_LIBS) 7 | 8 | add_mlir_dialect_library(MLIRHCLConversion 9 | ${globbed} 10 | 11 | ADDITIONAL_HEADER_DIRS 12 | ${PROJECT_SOURCE_DIR}/include/hcl 13 | 14 | DEPENDS 15 | MLIRHeteroCLOpsIncGen 16 | MLIRHeteroCLTypesIncGen 17 | MLIRHeteroCLPassesIncGen 18 | MLIRHeteroCLConversionPassesIncGen 19 | 20 | LINK_LIBS PUBLIC 21 | ${conversion_libs} 22 | MLIRIR 23 | MLIRPass 24 | MLIRMathTransforms 25 | MLIRHeteroCL 26 | MLIRHCLSupport 27 | ) -------------------------------------------------------------------------------- /lib/Conversion/Passes.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #include "hcl/Conversion/Passes.h" 7 | #include "mlir/Pass/PassManager.h" 8 | 9 | //===----------------------------------------------------------------------===// 10 | // Pass registration 11 | //===----------------------------------------------------------------------===// 12 | 13 | /// Generate the code for registering passes. 14 | namespace { 15 | #define GEN_PASS_REGISTRATION 16 | #include "hcl/Conversion/Passes.h.inc" 17 | } // end namespace 18 | 19 | void mlir::hcl::registerHCLConversionPasses() { ::registerPasses(); } 20 | -------------------------------------------------------------------------------- /lib/Dialect/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | add_mlir_dialect_library(MLIRHeteroCL 5 | HeteroCLDialect.cpp 6 | HeteroCLOps.cpp 7 | 8 | ADDITIONAL_HEADER_DIRS 9 | ${PROJECT_SOURCE_DIR}/include/hcl 10 | 11 | DEPENDS 12 | MLIRHeteroCLOpsIncGen 13 | MLIRHeteroCLTypesIncGen 14 | MLIRHeteroCLAttrsIncGen 15 | MLIRHeteroCLEnumsIncGen 16 | 17 | LINK_LIBS PUBLIC 18 | MLIRIR 19 | ) 20 | 21 | add_subdirectory(TransformOps) 22 | -------------------------------------------------------------------------------- /lib/Dialect/TransformOps/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | add_mlir_dialect_library(MLIRHCLTransformOps 5 | HCLTransformOps.cpp 6 | 7 | ADDITIONAL_HEADER_DIRS 8 | ${PROJECT_SOURCE_DIR}/include/hcl/Dialect/TransformOps 9 | 10 | DEPENDS 11 | MLIRHCLTransformOpsIncGen 12 | 13 | LINK_LIBS PUBLIC 14 | MLIRAffineDialect 15 | MLIRFuncDialect 16 | MLIRIR 17 | MLIRPDLDialect 18 | MLIRSCFDialect 19 | MLIRSCFTransforms 20 | MLIRSCFUtils 21 | MLIRTransformDialect 22 | MLIRVectorDialect 23 | ) 24 | -------------------------------------------------------------------------------- /lib/Support/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | file(GLOB globbed *.cpp) 5 | 6 | add_mlir_library(MLIRHCLSupport 7 | ${globbed} 8 | 9 | LINK_LIBS PUBLIC 10 | MLIRIR 11 | MLIRParser 12 | MLIRPass 13 | MLIRSPIRVDialect 14 | MLIRTranslateLib 15 | MLIRHeteroCL 16 | MLIRMemRefDialect 17 | MLIRAnalysis 18 | MLIRAffineAnalysis 19 | ) 20 | -------------------------------------------------------------------------------- /lib/Target/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | if (OPENSCOP) 5 | add_subdirectory(OpenSCoP) 6 | endif() 7 | -------------------------------------------------------------------------------- /lib/Target/OpenSCoP/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | file(GLOB globbed *.cpp) 5 | 6 | add_mlir_library(MLIRHCLEmitOpenSCoP 7 | ${globbed} 8 | 9 | ADDITIONAL_HEADER_DIRS 10 | "${OSL_SOURCE_DIR}/include" 11 | 12 | LINK_LIBS PUBLIC 13 | MLIRPass 14 | MLIRIR 15 | MLIRAffine 16 | MLIRAffineUtils 17 | MLIRTranslation 18 | MLIRParser 19 | MLIRSPIRV 20 | MLIRTranslation 21 | MLIRHeteroCL 22 | MLIRMemRef 23 | MLIRAnalysis 24 | # Needed for the OpenSCoPLib linkup. 25 | # Can link up other Polyhedral tools as needed 26 | libosl 27 | MLIRAffineAnalysis 28 | ) 29 | -------------------------------------------------------------------------------- /lib/Target/OpenSCoP/OslScopStmtOpSet.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * Modification: Polymer 5 | * https://github.com/kumasento/polymer 6 | */ 7 | 8 | //===- OslScopStmtOpSet.cc --------------------------------------*- C++ -*-===// 9 | // 10 | // This file implements the class OslScopStmtOpSet. 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include "hcl/Target/OpenSCoP/OslScopStmtOpSet.h" 15 | 16 | #include "mlir/Dialect/Affine/Analysis/AffineAnalysis.h" 17 | #include "mlir/Dialect/Affine/Analysis/AffineStructures.h" 18 | // #include "mlir/Analysis/Utils.h" 19 | #include "mlir/Dialect/Affine/Analysis/Utils.h" 20 | #include "mlir/Dialect/Affine/IR/AffineOps.h" 21 | #include "mlir/IR/Operation.h" 22 | #include "mlir/Support/LogicalResult.h" 23 | 24 | #include "llvm/ADT/SetVector.h" 25 | #include "llvm/ADT/SmallPtrSet.h" 26 | #include "llvm/ADT/SmallVector.h" 27 | 28 | using namespace mlir; 29 | using namespace llvm; 30 | using namespace hcl; 31 | 32 | void OslScopStmtOpSet::insert(mlir::Operation *op) { 33 | opSet.insert(op); 34 | if (isa(op)) { 35 | assert(!storeOp && "There should be only one AffineStoreOp in the set."); 36 | storeOp = op; 37 | } 38 | } 39 | 40 | LogicalResult OslScopStmtOpSet::getEnclosingOps( 41 | SmallVectorImpl &enclosingOps) { 42 | SmallVector ops; 43 | SmallPtrSet visited; 44 | for (auto op : opSet) { 45 | if (isa(op)) { 46 | ops.clear(); 47 | getEnclosingAffineForAndIfOps(*op, &ops); 48 | for (auto enclosingOp : ops) { 49 | if (visited.find(enclosingOp) == visited.end()) { 50 | visited.insert(enclosingOp); 51 | enclosingOps.push_back(enclosingOp); 52 | } 53 | } 54 | } 55 | } 56 | 57 | return success(); 58 | } 59 | 60 | LogicalResult 61 | OslScopStmtOpSet::getDomain(FlatAffineValueConstraints &domain, 62 | SmallVectorImpl &enclosingOps) { 63 | return getIndexSet(enclosingOps, &domain); 64 | } 65 | 66 | LogicalResult OslScopStmtOpSet::getDomain(FlatAffineValueConstraints &domain) { 67 | SmallVector enclosingOps; 68 | if (failed(getEnclosingOps(enclosingOps))) 69 | return failure(); 70 | 71 | return getDomain(domain, enclosingOps); 72 | } 73 | -------------------------------------------------------------------------------- /lib/Target/OpenSCoP/OslSymbolTable.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * Modification: Polymer 5 | * https://github.com/kumasento/polymer 6 | */ 7 | 8 | //===- OslSymbolTable.cc ----------------------------------------*- C++ -*-===// 9 | // 10 | // This file implements the OslSymbolTable class that stores the mapping between 11 | // symbols and MLIR values. 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | #include "hcl/Target/OpenSCoP/OslSymbolTable.h" 16 | #include "hcl/Target/OpenSCoP/OslScopStmtOpSet.h" 17 | 18 | #include "mlir/IR/Operation.h" 19 | #include "mlir/IR/Value.h" 20 | 21 | using namespace mlir; 22 | using namespace llvm; 23 | using namespace hcl; 24 | 25 | Value OslSymbolTable::getValue(StringRef key) { 26 | // Key is a loop IV. 27 | if (nameToLoopIV.find(key) != nameToLoopIV.end()) 28 | return nameToLoopIV.lookup(key); 29 | // Key is a memref value. 30 | if (nameToMemref.find(key) != nameToMemref.end()) 31 | return nameToMemref.lookup(key); 32 | // If nothing is found, return NULL. 33 | return nullptr; 34 | } 35 | 36 | OslSymbolTable::OpSet OslSymbolTable::getOpSet(StringRef key) { 37 | // If key corresponds to an Op of a statement. 38 | assert(nameToStmtOpSet.find(key) != nameToStmtOpSet.end() && 39 | "Key is not found."); 40 | return nameToStmtOpSet.lookup(key); 41 | } 42 | 43 | void OslSymbolTable::setValue(StringRef key, Value val, SymbolType type) { 44 | switch (type) { 45 | case LoopIV: 46 | nameToLoopIV[key] = val; 47 | break; 48 | case Memref: 49 | nameToMemref[key] = val; 50 | break; 51 | default: 52 | assert(false && "Symbole type for Value not recognized."); 53 | } 54 | } 55 | 56 | void OslSymbolTable::setOpSet(StringRef key, OpSet val, SymbolType type) { 57 | switch (type) { 58 | case StmtOpSet: 59 | nameToStmtOpSet[key] = val; 60 | break; 61 | default: 62 | assert(false && "Symbole type for OpSet not recognized."); 63 | } 64 | } 65 | 66 | unsigned OslSymbolTable::getNumValues(SymbolType type) { 67 | switch (type) { 68 | case LoopIV: 69 | return nameToLoopIV.size(); 70 | case Memref: 71 | return nameToMemref.size(); 72 | default: 73 | assert(false && "Symbole type for Value not recognized."); 74 | } 75 | } 76 | 77 | unsigned OslSymbolTable::getNumOpSets(SymbolType type) { 78 | switch (type) { 79 | case StmtOpSet: 80 | return nameToStmtOpSet.size(); 81 | default: 82 | assert(false && "Symbole type for OpSet not recognized."); 83 | } 84 | } 85 | 86 | void OslSymbolTable::getValueSymbols(SmallVectorImpl &symbols) { 87 | symbols.reserve(getNumValues(Memref) + getNumValues(LoopIV)); 88 | 89 | for (auto &it : nameToLoopIV) 90 | symbols.push_back(it.first()); 91 | for (auto &it : nameToMemref) 92 | symbols.push_back(it.first()); 93 | } 94 | void OslSymbolTable::getOpSetSymbols(SmallVectorImpl &symbols) { 95 | symbols.reserve(getNumOpSets(StmtOpSet)); 96 | 97 | for (auto &it : nameToStmtOpSet) 98 | symbols.push_back(it.first()); 99 | } 100 | -------------------------------------------------------------------------------- /lib/Transforms/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | add_mlir_library(MLIRHCLPasses 5 | LoopTransformations.cpp 6 | AnyWidthInteger.cpp 7 | MoveReturnToInput.cpp 8 | Passes.cpp 9 | LegalizeCast.cpp 10 | RemoveStrideMap.cpp 11 | MemRefDCE.cpp 12 | DataPlacement.cpp 13 | TransformInterpreter.cpp 14 | 15 | ADDITIONAL_HEADER_DIRS 16 | ${PROJECT_SOURCE_DIR}/include/hcl 17 | 18 | DEPENDS 19 | MLIRHeteroCLOpsIncGen 20 | MLIRHeteroCLTypesIncGen 21 | MLIRHeteroCLPassesIncGen 22 | 23 | LINK_COMPONENTS 24 | Core 25 | 26 | LINK_LIBS PUBLIC 27 | MLIRIR 28 | MLIRPass 29 | MLIRHeteroCL 30 | MLIRHCLSupport 31 | ) -------------------------------------------------------------------------------- /lib/Transforms/LegalizeCast.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #include "PassDetail.h" 7 | 8 | #include "hcl/Dialect/HeteroCLDialect.h" 9 | #include "hcl/Dialect/HeteroCLOps.h" 10 | #include "hcl/Dialect/HeteroCLTypes.h" 11 | #include "hcl/Transforms/Passes.h" 12 | 13 | #include "mlir/Dialect/Arith/IR/Arith.h" 14 | #include "mlir/Dialect/Func/IR/FuncOps.h" 15 | 16 | using namespace mlir; 17 | using namespace hcl; 18 | 19 | namespace mlir { 20 | namespace hcl { 21 | 22 | void legalizeCast(func::FuncOp &func) { 23 | SmallVector IntToFPOps; 24 | func.walk([&](Operation *op) { 25 | if (auto intToFloatCastOp = dyn_cast(op)) { 26 | IntToFPOps.push_back(intToFloatCastOp); 27 | } else if (auto uintToFloatCastOp = dyn_cast(op)) { 28 | IntToFPOps.push_back(uintToFloatCastOp); 29 | } 30 | }); 31 | 32 | for (auto op : IntToFPOps) { 33 | auto input = op->getOperand(0); 34 | auto res = op->getResult(0); 35 | Location loc = op->getLoc(); 36 | OpBuilder rewriter(op); 37 | size_t twidth = res.getType().getIntOrFloatBitWidth(); // target width 38 | size_t iwidth = input.getType().getIntOrFloatBitWidth(); // input width 39 | bool isSigned; 40 | if (auto intToFloatCastOp = dyn_cast(op)) { 41 | isSigned = true; 42 | } else if (auto uintToFloatCastOp = dyn_cast(op)) { 43 | isSigned = false; 44 | } else { 45 | llvm_unreachable("unexpected op"); 46 | } 47 | 48 | Type targetIntType = IntegerType::get(op->getContext(), twidth); 49 | if (iwidth > twidth) { 50 | // If the input is wider than the target, we need to truncate it. 51 | Value truncated = 52 | rewriter.create(loc, targetIntType, input); 53 | op->setOperand(0, truncated); 54 | } else if (iwidth < twidth) { 55 | // If the input is narrower than the target, we need to extend it. 56 | if (isSigned) { 57 | Value extended = 58 | rewriter.create(loc, targetIntType, input); 59 | op->setOperand(0, extended); 60 | } else { 61 | Value extended = 62 | rewriter.create(loc, targetIntType, input); 63 | op->setOperand(0, extended); 64 | } 65 | } else { 66 | continue; // No legalization needed 67 | } 68 | } 69 | } 70 | 71 | /// Pass entry point 72 | bool applyLegalizeCast(ModuleOp &module) { 73 | for (func::FuncOp func : module.getOps()) { 74 | legalizeCast(func); 75 | } 76 | return true; 77 | } 78 | 79 | } // namespace hcl 80 | } // namespace mlir 81 | 82 | namespace { 83 | struct HCLLegalizeCastTransformation 84 | : public LegalizeCastBase { 85 | void runOnOperation() override { 86 | auto mod = getOperation(); 87 | if (!applyLegalizeCast(mod)) { 88 | signalPassFailure(); 89 | } 90 | } 91 | }; 92 | } // namespace 93 | 94 | namespace mlir { 95 | namespace hcl { 96 | std::unique_ptr> createLegalizeCastPass() { 97 | return std::make_unique(); 98 | } 99 | } // namespace hcl 100 | } // namespace mlir -------------------------------------------------------------------------------- /lib/Transforms/MemRefDCE.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | //===----------------------------------------------------------------------===// 7 | // MemRefDCE Pass 8 | // This pass removes memrefs that are not loaded from. 9 | // We only look at memrefs allocated in functions. 10 | // Global memrefs and memrefs in function args are not removed. 11 | //===----------------------------------------------------------------------===// 12 | #include "PassDetail.h" 13 | #include "hcl/Transforms/Passes.h" 14 | 15 | #include "mlir/Dialect/Affine/IR/AffineOps.h" 16 | #include "mlir/Dialect/Func/IR/FuncOps.h" 17 | #include "mlir/Dialect/MemRef/IR/MemRef.h" 18 | 19 | using namespace mlir; 20 | using namespace hcl; 21 | 22 | namespace mlir { 23 | namespace hcl { 24 | 25 | void cleanUpUnusedOps(func::FuncOp &func) { 26 | func.walk([&](Operation *op) { 27 | if (op->getNumResults() != 0 && op->use_empty()) { 28 | op->erase(); 29 | } 30 | }); 31 | } 32 | 33 | void removeNeverLoadedMemRef(func::FuncOp &func) { 34 | SmallVector memRefAllocOps; 35 | func.walk([&](Operation *op) { 36 | if (auto memRefAllocOp = dyn_cast(op)) { 37 | memRefAllocOps.push_back(memRefAllocOp); 38 | } 39 | }); 40 | std::reverse(memRefAllocOps.begin(), memRefAllocOps.end()); 41 | for (auto op : memRefAllocOps) { 42 | auto v = op->getResult(0); 43 | bool loaded_from = false; 44 | for (auto u : v.getUsers()) { 45 | if (isa(u)) { 46 | loaded_from = true; 47 | break; 48 | } else if (isa(u)) { 49 | loaded_from = true; 50 | break; 51 | } else if (isa(u)) { 52 | loaded_from = true; 53 | break; 54 | } else if (isa(u)) { 55 | loaded_from = true; 56 | break; 57 | } 58 | } 59 | if (!loaded_from) { 60 | // erase op and all known uses 61 | for (auto u : v.getUsers()) { 62 | u->erase(); 63 | } 64 | op->erase(); 65 | } 66 | } 67 | } 68 | 69 | /// Pass entry point 70 | bool applyMemRefDCE(ModuleOp &mod) { 71 | for (auto func : mod.getOps()) { 72 | removeNeverLoadedMemRef(func); 73 | cleanUpUnusedOps(func); 74 | } 75 | return true; 76 | } 77 | } // namespace hcl 78 | } // namespace mlir 79 | 80 | namespace { 81 | struct HCLMemRefDCETransformation 82 | : public MemRefDCEBase { 83 | void runOnOperation() override { 84 | auto mod = getOperation(); 85 | if (!applyMemRefDCE(mod)) { 86 | return signalPassFailure(); 87 | } 88 | } 89 | }; 90 | } // namespace 91 | 92 | namespace mlir { 93 | namespace hcl { 94 | 95 | std::unique_ptr> createMemRefDCEPass() { 96 | return std::make_unique(); 97 | } 98 | } // namespace hcl 99 | } // namespace mlir -------------------------------------------------------------------------------- /lib/Transforms/MoveReturnToInput.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | //===----------------------------------------------------------------------===// 7 | // MoveReturnToInput Pass 8 | // This pass is to support multiple return values for LLVM backend. 9 | // The input program may have multiple return values 10 | // The output program has no return values, all the return values 11 | // is moved to the input argument list 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include "PassDetail.h" 15 | 16 | #include "hcl/Dialect/HeteroCLDialect.h" 17 | #include "hcl/Dialect/HeteroCLOps.h" 18 | #include "hcl/Dialect/HeteroCLTypes.h" 19 | #include "hcl/Transforms/Passes.h" 20 | 21 | #include "mlir/Dialect/Affine/IR/AffineOps.h" 22 | #include "mlir/Dialect/Affine/Utils.h" 23 | #include "mlir/Dialect/Func/IR/FuncOps.h" 24 | #include "mlir/Dialect/MemRef/IR/MemRef.h" 25 | #include "mlir/Dialect/MemRef/Transforms/Passes.h" 26 | 27 | using namespace mlir; 28 | using namespace hcl; 29 | 30 | namespace mlir { 31 | namespace hcl { 32 | 33 | void moveReturnToInput(func::FuncOp &funcOp) { 34 | FunctionType functionType = funcOp.getFunctionType(); 35 | SmallVector resTypes = llvm::to_vector<4>(functionType.getResults()); 36 | SmallVector argTypes; 37 | for (auto &arg : funcOp.getArguments()) { 38 | argTypes.push_back(arg.getType()); 39 | } 40 | 41 | // Create corresponding block args for return values 42 | SmallVector blockArgs; 43 | for (Block &block : funcOp.getBlocks()) { 44 | for (Type t : resTypes) { 45 | auto bArg = block.addArgument(t, funcOp.getLoc()); 46 | blockArgs.push_back(bArg); 47 | } 48 | } 49 | 50 | // Find the allocation op for return values 51 | // and replace their uses with newly created block args 52 | SmallVector returnOps; 53 | funcOp.walk([&](Operation *op) { 54 | if (auto add_op = dyn_cast(op)) { 55 | returnOps.push_back(op); 56 | } 57 | }); 58 | 59 | // Build loops to copy return values to block args 60 | OpBuilder builder(funcOp.getContext()); 61 | // build right before the terminator 62 | builder.setInsertionPointToEnd(&funcOp.getBlocks().back()); 63 | for (auto op : returnOps) { 64 | for (unsigned i = 0; i < op->getNumOperands(); i++) { 65 | Value arg = op->getOperand(i); 66 | if (MemRefType type = arg.getType().dyn_cast()) { 67 | BlockArgument bArg = blockArgs[i]; 68 | // build an memref.copy op to copy the return value to block arg 69 | builder.create(op->getLoc(), arg, bArg); 70 | } else { 71 | // issue an error 72 | op->emitError("MoveReturnToInput Pass does not support non-memref " 73 | "return values now."); 74 | } 75 | } 76 | // erase return op 77 | op->erase(); 78 | } 79 | // build a new empty return op 80 | builder.create(funcOp.getLoc()); 81 | 82 | // Append resTypes to argTypes and clear resTypes 83 | argTypes.insert(std::end(argTypes), std::begin(resTypes), std::end(resTypes)); 84 | resTypes.clear(); 85 | // Update function signature 86 | FunctionType newFuncType = 87 | FunctionType::get(funcOp.getContext(), argTypes, resTypes); 88 | funcOp.setType(newFuncType); 89 | } 90 | 91 | /// entry point 92 | bool applyMoveReturnToInput(ModuleOp &mod) { 93 | // Find top-level function 94 | bool isFoundTopFunc = false; 95 | func::FuncOp *topFunc; 96 | for (func::FuncOp func : mod.getOps()) { 97 | if (func->hasAttr("top")) { 98 | isFoundTopFunc = true; 99 | topFunc = &func; 100 | break; 101 | } 102 | } 103 | 104 | if (isFoundTopFunc && topFunc) { 105 | moveReturnToInput(*topFunc); 106 | } 107 | return true; 108 | } 109 | 110 | } // namespace hcl 111 | } // namespace mlir 112 | 113 | namespace { 114 | 115 | struct HCLMoveReturnToInputTransformation 116 | : public MoveReturnToInputBase { 117 | 118 | void runOnOperation() override { 119 | auto mod = getOperation(); 120 | if (!applyMoveReturnToInput(mod)) 121 | return signalPassFailure(); 122 | } 123 | }; 124 | } // namespace 125 | 126 | namespace mlir { 127 | namespace hcl { 128 | 129 | std::unique_ptr> createMoveReturnToInputPass() { 130 | return std::make_unique(); 131 | } 132 | 133 | } // namespace hcl 134 | } // namespace mlir -------------------------------------------------------------------------------- /lib/Transforms/PassDetail.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #ifndef HCL_MLIR_PASSDETAIL_H 7 | #define HCL_MLIR_PASSDETAIL_H 8 | 9 | #include "mlir/IR/BuiltinOps.h" 10 | #include "mlir/Pass/Pass.h" 11 | 12 | namespace mlir { 13 | namespace hcl { 14 | 15 | #define GEN_PASS_CLASSES 16 | #include "hcl/Transforms/Passes.h.inc" 17 | 18 | } // namespace hcl 19 | } // end namespace mlir 20 | 21 | #endif // HCL_MLIR_PASSDETAIL_H 22 | -------------------------------------------------------------------------------- /lib/Transforms/Passes.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #include "hcl/Transforms/Passes.h" 7 | #include "mlir/Pass/PassManager.h" 8 | #include "mlir/Transforms/Passes.h" 9 | 10 | //===----------------------------------------------------------------------===// 11 | // Pass registration 12 | //===----------------------------------------------------------------------===// 13 | 14 | /// Generate the code for registering passes. 15 | namespace { 16 | #define GEN_PASS_REGISTRATION 17 | #include "hcl/Transforms/Passes.h.inc" 18 | } // end namespace 19 | 20 | void mlir::hcl::registerHCLPasses() { ::registerPasses(); } -------------------------------------------------------------------------------- /lib/Transforms/TransformInterpreter.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #include "PassDetail.h" 7 | #include "hcl/Transforms/Passes.h" 8 | #include "mlir/Dialect/Transform/IR/TransformInterfaces.h" 9 | 10 | using namespace mlir; 11 | using namespace hcl; 12 | 13 | namespace { 14 | struct TransformInterpreter 15 | : public hcl::TransformInterpreterBase { 16 | void runOnOperation() override; 17 | }; 18 | } // namespace 19 | 20 | void TransformInterpreter::runOnOperation() { 21 | ModuleOp module = getOperation(); 22 | // transform::TransformState state( 23 | // module.getBodyRegion(), module, 24 | // transform::TransformOptions().enableExpensiveChecks()); 25 | // for (auto op : module.getBody()->getOps()) 26 | // { 27 | // if (failed(state.applyTransform(op).checkAndReport())) 28 | // return signalPassFailure(); 29 | // } 30 | } 31 | 32 | std::unique_ptr> hcl::createTransformInterpreterPass() { 33 | return std::make_unique(); 34 | } 35 | -------------------------------------------------------------------------------- /lib/Translation/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | file(GLOB globbed *.cpp) 5 | 6 | add_mlir_library(MLIRHCLEmitHLSCpp 7 | ${globbed} 8 | 9 | LINK_LIBS PUBLIC 10 | MLIRHeteroCL 11 | MLIRHCLSupport 12 | MLIRMemRefDialect 13 | MLIRAnalysis 14 | ) -------------------------------------------------------------------------------- /lib/Translation/Utils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | #include "hcl/Translation/Utils.h" 7 | #include "llvm/Support/raw_ostream.h" 8 | 9 | using namespace mlir; 10 | using namespace hcl; 11 | 12 | // TODO: update naming rule. 13 | SmallString<8> HCLEmitterBase::addName(Value val, bool isPtr, 14 | std::string name) { 15 | assert(!isDeclared(val) && "has been declared before."); 16 | 17 | SmallString<8> valName; 18 | if (isPtr) 19 | valName += "*"; 20 | 21 | if (name != "") { 22 | if (state.nameConflictCnt.count(name) > 0) { 23 | state.nameConflictCnt[name]++; 24 | valName += StringRef(name + std::to_string(state.nameConflictCnt[name])); 25 | } else { // first time 26 | state.nameConflictCnt[name] = 0; 27 | valName += name; 28 | } 29 | } else { 30 | valName += StringRef("v" + std::to_string(state.nameTable.size())); 31 | } 32 | state.nameTable[val] = valName; 33 | 34 | return valName; 35 | }; 36 | 37 | SmallString<8> HCLEmitterBase::getName(Value val) { 38 | // For constant scalar operations, the constant number will be returned 39 | // rather than the value name. 40 | if (auto defOp = val.getDefiningOp()) { 41 | if (auto constOp = dyn_cast(defOp)) { 42 | auto constAttr = constOp.getValue(); 43 | 44 | if (auto boolAttr = constAttr.dyn_cast()) { 45 | return SmallString<8>(std::to_string(boolAttr.getValue())); 46 | 47 | } else if (auto floatAttr = constAttr.dyn_cast()) { 48 | auto value = floatAttr.getValueAsDouble(); 49 | if (std::isfinite(value)) 50 | return SmallString<8>(std::to_string(value)); 51 | else if (value > 0) 52 | return SmallString<8>("INFINITY"); 53 | else 54 | return SmallString<8>("-INFINITY"); 55 | 56 | } else if (auto intAttr = constAttr.dyn_cast()) { 57 | auto value = intAttr.getInt(); 58 | return SmallString<8>(std::to_string(value)); 59 | } 60 | } 61 | } 62 | return state.nameTable.lookup(val); 63 | }; 64 | 65 | void fixUnsignedType(Value &result, bool isUnsigned) { 66 | if (isUnsigned) { // unsigned type 67 | if (result.getType().isa()) { 68 | auto arrayType = result.getType().dyn_cast(); 69 | Type elt = IntegerType::get( 70 | arrayType.getContext(), 71 | arrayType.getElementType().cast().getWidth(), 72 | IntegerType::SignednessSemantics::Unsigned); 73 | result.setType(MemRefType::get(arrayType.getShape(), elt, 74 | arrayType.getLayout(), 75 | arrayType.getMemorySpace())); 76 | } else if (result.getType().isa()) { 77 | Type type = 78 | IntegerType::get(result.getType().getContext(), 79 | result.getType().cast().getWidth(), 80 | IntegerType::SignednessSemantics::Unsigned); 81 | result.setType(type); 82 | } 83 | } 84 | } 85 | 86 | void fixUnsignedType(memref::GlobalOp &op, bool isUnsigned) { 87 | if (isUnsigned) { // unsigned type 88 | auto type = op.getTypeAttr().getValue(); 89 | if (type.isa()) { 90 | auto arrayType = type.dyn_cast(); 91 | Type elt = IntegerType::get( 92 | arrayType.getContext(), 93 | arrayType.getElementType().cast().getWidth(), 94 | IntegerType::SignednessSemantics::Unsigned); 95 | // get a memref type attr 96 | op.setTypeAttr(TypeAttr::get( 97 | MemRefType::get(arrayType.getShape(), elt, arrayType.getLayout(), 98 | arrayType.getMemorySpace()))); 99 | } else if (type.isa()) { 100 | Type type = IntegerType::get(type.getContext(), 101 | type.cast().getWidth(), 102 | IntegerType::SignednessSemantics::Unsigned); 103 | op.setTypeAttr(TypeAttr::get(type)); 104 | } 105 | } 106 | } -------------------------------------------------------------------------------- /scripts/check_license_header.py: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | # Modification: Slapo. See https://github.com/awslabs/slapo/blob/main/scripts/lint/check_license_header.py 4 | 5 | """Helper tool to check license header.""" 6 | import os 7 | import sys 8 | import subprocess 9 | 10 | from add_license_header import get_file_fmt, has_license_header 11 | 12 | usage = """ 13 | Usage: python3 scripts/check_license_header.py 14 | Run license header check that changed since . If is "all", 15 | check all files. 16 | Examples: 17 | - Compare last one commit: python3 scripts/check_license_header.py HEAD~1 18 | - Compare against origin: python3 scripts/check_license_header.py origin/main 19 | - Check all files: python3 scripts/check_license_header.py all 20 | """ 21 | 22 | 23 | def check_license(fname): 24 | # Skip 3rdparty change and unsupported file format. 25 | if not os.path.isfile(fname) or get_file_fmt(fname) is None: 26 | return True 27 | 28 | lines = open(fname).readlines() 29 | return has_license_header(lines) 30 | 31 | 32 | def main(): 33 | if len(sys.argv) != 2: 34 | sys.stderr.write(usage) 35 | sys.stderr.flush() 36 | sys.exit(-1) 37 | 38 | commit = sys.argv[1] 39 | if commit == "all": 40 | cmd = ["git", "ls-tree", "--full-tree", "--name-only", "-r", "HEAD"] 41 | else: 42 | cmd = ["git", "diff", "--name-only", "--diff-filter=ACMRTUX", commit] 43 | proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 44 | (out, _) = proc.communicate() 45 | assert proc.returncode == 0, f'{" ".join(cmd)} errored: {out}' 46 | res = out.decode("utf-8") 47 | 48 | error_list = [] 49 | for fname in res.split(): 50 | if not check_license(fname): 51 | error_list.append(fname) 52 | 53 | if error_list: 54 | report = "-----Check report-----\n" 55 | report += "\n".join(error_list) + "\n" 56 | report += ( 57 | "-----Found %d files that cannot pass the license header check-----\n" 58 | % len(error_list) 59 | ) 60 | sys.stderr.write(report) 61 | sys.stderr.flush() 62 | sys.exit(-1) 63 | 64 | print("all checks passed...") 65 | 66 | 67 | if __name__ == "__main__": 68 | main() 69 | -------------------------------------------------------------------------------- /scripts/git-clang-format.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright HeteroCL authors. All Rights Reserved. 3 | # SPDX-License-Identifier: Apache-2.0 4 | # Modification: Slapo, Amazon.com, Inc. Apache-2.0 5 | # https://github.com/awslabs/slapo/blob/main/scripts/lint/git-black.sh 6 | 7 | 8 | set -e 9 | set -u 10 | set -o pipefail 11 | 12 | if [[ "$1" == "-i" ]]; then 13 | INPLACE_FORMAT=1 14 | shift 1 15 | else 16 | INPLACE_FORMAT=0 17 | fi 18 | 19 | if [[ "$#" -lt 1 ]]; then 20 | echo "Usage: tests/git-clang-format.sh [-i] " 21 | echo "" 22 | echo "Run clang-format on C/C++ files that changed since " 23 | echo "Examples:" 24 | echo "- Compare last one commit: tests/git-clang-format.sh HEAD~1" 25 | echo "- Compare against upstream/main: tests/git-clang-format.sh upstream/main" 26 | echo "The -i will use clang-format to format files in-place instead of checking them." 27 | exit 1 28 | fi 29 | 30 | # required to make clang-format's dep click to work 31 | export LC_ALL=C.UTF-8 32 | export LANG=C.UTF-8 33 | 34 | # Print out specific version 35 | echo "Version Information: $(clang-format --version)" 36 | 37 | # Compute C/C++ files which changed to compare. 38 | IFS=$'\n' read -a FILES -d'\n' < <(git diff --name-only --diff-filter=ACMRTUX $1 -- "*.c" "*.cpp") || true 39 | echo "Read returned $?" 40 | if [ -z ${FILES+x} ]; then 41 | echo "No changes in C/C++ files" 42 | exit 0 43 | fi 44 | echo "Files: ${FILES[@]}" 45 | 46 | if [[ ${INPLACE_FORMAT} -eq 1 ]]; then 47 | echo "Running clang-format on C/C++ files against revision" $1: 48 | CMD=( "clang-format" "-i" "${FILES[@]}" ) 49 | echo "${CMD[@]}" 50 | "${CMD[@]}" 51 | else 52 | echo "Running clang-format in checking mode" 53 | clang-format --dry-run --Werror ${FILES[@]} 54 | fi 55 | -------------------------------------------------------------------------------- /test/Bindings/test_codegen.py: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # RUN: %PYTHON %s 5 | 6 | import io 7 | from hcl_mlir.ir import Context, Module 8 | from hcl_mlir.dialects import hcl as hcl_d 9 | 10 | 11 | def test_codegen(): 12 | mlir_code = """ 13 | module { 14 | func.func @gemm(%A: memref<1024x512xf32>, %B: memref<512x1024xf32>, %C: memref<1024x1024xf32>) 15 | { 16 | affine.for %i = 0 to 1024 { 17 | affine.for %j = 0 to 1024 { 18 | affine.for %k = 0 to 512 { 19 | %a = affine.load %A[%i, %k] : memref<1024x512xf32> 20 | %b = affine.load %B[%k, %j] : memref<512x1024xf32> 21 | %c = affine.load %C[%i, %j] : memref<1024x1024xf32> 22 | %prod = arith.mulf %a, %b : f32 23 | %sum = arith.addf %prod, %c: f32 24 | affine.store %sum, %C[%i, %j] : memref<1024x1024xf32> 25 | } { loop_name = "k" } 26 | } { loop_name = "j" } 27 | } { loop_name = "i", op_name = "s" } 28 | return 29 | } 30 | } 31 | """ 32 | ctx = Context() 33 | mod = Module.parse(mlir_code, ctx) 34 | buf = io.StringIO() 35 | res = hcl_d.emit_vhls(mod, buf) 36 | if res: 37 | buf.seek(0) 38 | hls_code = buf.read() 39 | print(hls_code) 40 | print("Done HLS code generation") 41 | else: 42 | raise RuntimeError("HLS codegen failed") 43 | 44 | 45 | if __name__ == "__main__": 46 | test_codegen() 47 | -------------------------------------------------------------------------------- /test/Bindings/test_for_loops.py: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # RUN: %PYTHON %s 5 | 6 | from hcl_mlir.ir import * 7 | from hcl_mlir.dialects import func, arith, memref, affine 8 | from hcl_mlir.dialects import hcl as hcl_d 9 | import hcl_mlir 10 | 11 | with Context() as ctx, Location.unknown() as loc: 12 | hcl_d.register_dialect(ctx) 13 | module = Module.create() 14 | f32 = F32Type.get() 15 | i32 = IntegerType.get_signless(32) 16 | memref_type = MemRefType.get((1024, 1024), f32) 17 | 18 | with InsertionPoint(module.body): 19 | op = hcl_d.CreateOpHandleOp(StringAttr.get("s")) 20 | hcl_d.CreateLoopHandleOp(op.result, StringAttr.get("i")) 21 | hcl_d.CreateLoopHandleOp(op.result, StringAttr.get("j")) 22 | hcl_d.CreateLoopHandleOp(op.result, StringAttr.get("k")) 23 | 24 | @func.FuncOp.from_py_func(memref_type, memref_type, memref_type) 25 | def gemm(A, B, C): 26 | for_i = hcl_mlir.make_for(0, 1024, name="i") 27 | with InsertionPoint(for_i.body.operations[0]): 28 | for_j = hcl_mlir.make_for(0, 1024, name="j") 29 | with InsertionPoint(for_j.body.operations[0]): 30 | for_k = hcl_mlir.make_for(0, 1024, name="k") 31 | with InsertionPoint(for_k.body.operations[0]): 32 | a = memref.LoadOp( 33 | A, [for_i.induction_variable, 34 | for_k.induction_variable] 35 | ) 36 | b = memref.LoadOp( 37 | B, [for_k.induction_variable, 38 | for_j.induction_variable] 39 | ) 40 | c = memref.LoadOp( 41 | C, [for_i.induction_variable, 42 | for_j.induction_variable] 43 | ) 44 | prod = arith.MulFOp(a.result, b.result) 45 | sum_ = arith.AddFOp(prod.result, c.result) 46 | memref.StoreOp( 47 | sum_.result, 48 | C, 49 | [for_i.induction_variable, for_j.induction_variable], 50 | ) 51 | 52 | for_i = hcl_mlir.make_for(0, 1024, name="i") 53 | with InsertionPoint(for_i.body.operations[0]): 54 | for_j = hcl_mlir.make_for(0, 1024, name="j") 55 | with InsertionPoint(for_j.body.operations[0]): 56 | for_k = hcl_mlir.make_for(0, 1024, name="k") 57 | with InsertionPoint(for_k.body.operations[0]): 58 | # make if 59 | d0 = AffineDimExpr.get(0) 60 | d1 = AffineDimExpr.get(1) 61 | if_cond_set = IntegerSet.get(2, 0, [d0 - d1], [False]) 62 | attr = hcl_d.IntegerSetAttr.get(if_cond_set) 63 | set_operands = [ 64 | for_i.induction_variable, 65 | for_j.induction_variable, 66 | ] 67 | if_op = affine.AffineIfOp(attr, set_operands) 68 | with InsertionPoint(if_op.then_block): 69 | a = affine.AffineLoadOp( 70 | A, [for_i.induction_variable, 71 | for_k.induction_variable] 72 | ) 73 | b = affine.AffineLoadOp( 74 | B, [for_k.induction_variable, 75 | for_j.induction_variable] 76 | ) 77 | c = affine.AffineLoadOp( 78 | C, [for_i.induction_variable, 79 | for_j.induction_variable] 80 | ) 81 | prod = arith.MulFOp(a.result, b.result) 82 | sum_ = arith.AddFOp(prod.result, c.result) 83 | memref.StoreOp( 84 | sum_.result, 85 | C, 86 | [for_i.induction_variable, 87 | for_j.induction_variable], 88 | ) 89 | affine.AffineYieldOp([]) 90 | 91 | return C 92 | 93 | module.dump() 94 | Module.parse(str(module)) 95 | print("Built done!") 96 | -------------------------------------------------------------------------------- /test/Bindings/test_if.py: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # RUN: %PYTHON %s 5 | 6 | from hcl_mlir.build_ir import IterVar 7 | from hcl_mlir.ir import * 8 | from hcl_mlir.dialects import func, arith, memref, affine 9 | from hcl_mlir.dialects import hcl as hcl_d 10 | import hcl_mlir 11 | 12 | with Context() as ctx, Location.unknown() as loc: 13 | hcl_d.register_dialect(ctx) 14 | module = Module.create() 15 | f32 = F32Type.get() 16 | i32 = IntegerType.get_signless(32) 17 | idx_type = IndexType.get() 18 | memref_type = MemRefType.get((1024,), f32) 19 | hcl_mlir.enable_build_inplace() 20 | 21 | with InsertionPoint(module.body): 22 | 23 | @func.FuncOp.from_py_func(memref_type) 24 | def kernel(A): 25 | for_i = hcl_mlir.make_for(0, 1024, name="i") 26 | hcl_mlir.GlobalInsertionPoint.save( 27 | InsertionPoint(for_i.body.operations[0])) 28 | var = IterVar(for_i.induction_variable) 29 | var.dtype = idx_type 30 | with InsertionPoint(for_i.body.operations[0]): 31 | 32 | def make_if_block(arg): 33 | a = memref.LoadOp(A, [for_i.induction_variable]) 34 | cst = hcl_mlir.ConstantOp(idx_type, 0) 35 | cmp = hcl_mlir.CmpOp(var, cst, arg) 36 | if_op = hcl_mlir.make_if(cmp) 37 | with InsertionPoint(if_op.then_block.operations[0]): 38 | add = arith.AddFOp(a.result, a.result) 39 | 40 | make_if_block("eq") 41 | # make_if_block("ne") 42 | make_if_block("lt") 43 | make_if_block("le") 44 | make_if_block("gt") 45 | make_if_block("ge") 46 | 47 | return A 48 | 49 | module.dump() 50 | Module.parse(str(module)) 51 | print("Built done!") 52 | -------------------------------------------------------------------------------- /test/Bindings/test_llvm.py: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # RUN: %PYTHON %s 5 | 6 | from hcl_mlir.ir import * 7 | from hcl_mlir.dialects import hcl as hcl_d 8 | 9 | with Context() as ctx: 10 | hcl_d.register_dialect() 11 | print("Registration done!") 12 | 13 | mod = Module.parse( 14 | """ 15 | func.func @top () -> () { 16 | %0 = arith.constant 2 : i32 17 | %1 = arith.addi %0, %0 : i32 18 | return 19 | } 20 | """ 21 | ) 22 | print(str(mod)) 23 | print("Done module parsing!") 24 | 25 | res = hcl_d.lower_hcl_to_llvm(mod, ctx) 26 | if res: 27 | print(str(mod)) 28 | print("Done LLVM conversion") 29 | else: 30 | raise RuntimeError("LLVM pass error") 31 | -------------------------------------------------------------------------------- /test/Bindings/test_registration.py: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # RUN: %PYTHON %s 5 | 6 | import io 7 | 8 | from hcl_mlir.ir import * 9 | from hcl_mlir.dialects import hcl as hcl_d 10 | 11 | with Context() as ctx: 12 | hcl_d.register_dialect() 13 | print("Registration done!") 14 | 15 | mod = Module.parse( 16 | """ 17 | func.func @top () -> () { 18 | %0 = arith.constant 2 : i32 19 | %1 = arith.addi %0, %0 : i32 20 | return 21 | } 22 | """ 23 | ) 24 | print(str(mod)) 25 | print("Done module parsing!") 26 | 27 | res = hcl_d.loop_transformation(mod) 28 | if res: 29 | print(str(mod)) 30 | print("Done loop transformation!") 31 | else: 32 | raise RuntimeError("Loop transformation failed") 33 | 34 | buf = io.StringIO() 35 | res = hcl_d.emit_vhls(mod, buf) 36 | if res: 37 | buf.seek(0) 38 | hls_code = buf.read() 39 | print(hls_code) 40 | print("Done HLS code generation") 41 | else: 42 | raise RuntimeError("HLS codegen failed") 43 | -------------------------------------------------------------------------------- /test/Bindings/test_scf.py: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # RUN: %PYTHON %s | FileCheck %s 5 | 6 | from hcl_mlir.ir import * 7 | from hcl_mlir.dialects import arith 8 | # from hcl_mlir.dialects import func 9 | from hcl_mlir.dialects import scf 10 | from hcl_mlir.dialects import func 11 | 12 | 13 | def constructAndPrintInModule(f): 14 | print("\nTEST:", f.__name__) 15 | with Context(), Location.unknown(): 16 | module = Module.create() 17 | with InsertionPoint(module.body): 18 | f() 19 | print(module) 20 | return f 21 | 22 | 23 | # CHECK-LABEL: TEST: testSimpleLoop 24 | @constructAndPrintInModule 25 | def testSimpleLoop(): 26 | index_type = IndexType.get() 27 | 28 | @func.FuncOp.from_py_func(index_type, index_type, index_type) 29 | def simple_loop(lb, ub, step): 30 | loop = scf.ForOp(lb, ub, step, [lb, lb]) 31 | with InsertionPoint(loop.body): 32 | scf.YieldOp(loop.inner_iter_args) 33 | return 34 | 35 | 36 | # CHECK: func @simple_loop(%[[ARG0:.*]]: index, %[[ARG1:.*]]: index, %[[ARG2:.*]]: index) 37 | # CHECK: scf.for %{{.*}} = %[[ARG0]] to %[[ARG1]] step %[[ARG2]] 38 | # CHECK: iter_args(%[[I1:.*]] = %[[ARG0]], %[[I2:.*]] = %[[ARG0]]) 39 | # CHECK: scf.yield %[[I1]], %[[I2]] 40 | 41 | 42 | # CHECK-LABEL: TEST: testInductionVar 43 | @constructAndPrintInModule 44 | def testInductionVar(): 45 | index_type = IndexType.get() 46 | 47 | @func.FuncOp.from_py_func(index_type, index_type, index_type) 48 | def induction_var(lb, ub, step): 49 | loop = scf.ForOp(lb, ub, step, [lb]) 50 | with InsertionPoint(loop.body): 51 | scf.YieldOp([loop.induction_variable]) 52 | return 53 | 54 | 55 | # CHECK: func @induction_var(%[[ARG0:.*]]: index, %[[ARG1:.*]]: index, %[[ARG2:.*]]: index) 56 | # CHECK: scf.for %[[IV:.*]] = %[[ARG0]] to %[[ARG1]] step %[[ARG2]] 57 | # CHECK: scf.yield %[[IV]] 58 | 59 | 60 | @constructAndPrintInModule 61 | def testIfWithoutElse(): 62 | bool = IntegerType.get_signless(1) 63 | i32 = IntegerType.get_signless(32) 64 | 65 | @func.FuncOp.from_py_func(bool) 66 | def simple_if(cond): 67 | if_op = scf.IfOp(cond) 68 | with InsertionPoint(if_op.then_block): 69 | one = arith.ConstantOp(i32, 1) 70 | add = arith.AddIOp(one, one) 71 | scf.YieldOp([]) 72 | return 73 | 74 | 75 | # CHECK: func @simple_if(%[[ARG0:.*]]: i1) 76 | # CHECK: scf.if %[[ARG0:.*]] 77 | # CHECK: %[[ONE:.*]] = arith.constant 1 78 | # CHECK: %[[ADD:.*]] = arith.addi %[[ONE]], %[[ONE]] 79 | # CHECK: return 80 | 81 | 82 | @constructAndPrintInModule 83 | def testIfWithElse(): 84 | bool = IntegerType.get_signless(1) 85 | i32 = IntegerType.get_signless(32) 86 | 87 | @func.FuncOp.from_py_func(bool) 88 | def simple_if_else(cond): 89 | if_op = scf.IfOp(cond, [i32, i32], hasElse=True) 90 | with InsertionPoint(if_op.then_block): 91 | x_true = arith.ConstantOp(i32, 0) 92 | y_true = arith.ConstantOp(i32, 1) 93 | scf.YieldOp([x_true, y_true]) 94 | with InsertionPoint(if_op.else_block): 95 | x_false = arith.ConstantOp(i32, 2) 96 | y_false = arith.ConstantOp(i32, 3) 97 | scf.YieldOp([x_false, y_false]) 98 | add = arith.AddIOp(if_op.results[0], if_op.results[1]) 99 | return 100 | 101 | 102 | # CHECK: func @simple_if_else(%[[ARG0:.*]]: i1) 103 | # CHECK: %[[RET:.*]]:2 = scf.if %[[ARG0:.*]] 104 | # CHECK: %[[ZERO:.*]] = arith.constant 0 105 | # CHECK: %[[ONE:.*]] = arith.constant 1 106 | # CHECK: scf.yield %[[ZERO]], %[[ONE]] 107 | # CHECK: } else { 108 | # CHECK: %[[TWO:.*]] = arith.constant 2 109 | # CHECK: %[[THREE:.*]] = arith.constant 3 110 | # CHECK: scf.yield %[[TWO]], %[[THREE]] 111 | # CHECK: arith.addi %[[RET]]#0, %[[RET]]#1 112 | # CHECK: return 113 | -------------------------------------------------------------------------------- /test/Bindings/test_types.py: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # RUN: %PYTHON %s 5 | 6 | import hcl_mlir 7 | from hcl_mlir.ir import * 8 | from hcl_mlir.dialects import hcl as hcl_d 9 | 10 | 11 | def test_fixed(): 12 | with Context() as ctx, Location.unknown() as loc: 13 | hcl_d.register_dialect(ctx) # need to first register dialect 14 | fixed_type = hcl_d.FixedType.get(12, 6) 15 | ufixed_type = hcl_d.UFixedType.get(20, 12) 16 | print(fixed_type, ufixed_type) 17 | 18 | 19 | def test_print(): 20 | with Context() as ctx, Location.unknown() as loc: 21 | hcl_d.register_dialect(ctx) 22 | print(hcl_mlir.print_mlir_type(IntegerType.get_signless(1))) 23 | print(hcl_mlir.print_mlir_type(IntegerType.get_signless(8))) 24 | print(hcl_mlir.print_mlir_type(IntegerType.get_unsigned(16))) 25 | print(hcl_mlir.print_mlir_type(IntegerType.get_unsigned(12))) 26 | 27 | 28 | if __name__ == "__main__": 29 | test_fixed() 30 | test_print() 31 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | configure_lit_site_cfg( 5 | ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in 6 | ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg.py 7 | MAIN_CONFIG 8 | ${CMAKE_CURRENT_SOURCE_DIR}/lit.cfg.py 9 | ) 10 | 11 | set(STANDALONE_TEST_DEPENDS 12 | FileCheck count not 13 | hcl-opt 14 | hcl-translate 15 | ) 16 | 17 | add_lit_testsuite(check-hcl "Running the hcl regression tests" 18 | ${CMAKE_CURRENT_BINARY_DIR} 19 | DEPENDS ${STANDALONE_TEST_DEPENDS} 20 | ) 21 | set_target_properties(check-hcl PROPERTIES FOLDER "Tests") 22 | 23 | add_lit_testsuites(HETEROCL ${CMAKE_CURRENT_SOURCE_DIR} DEPENDS ${STANDALONE_TEST_DEPENDS}) 24 | -------------------------------------------------------------------------------- /test/Integration/affine_dialect.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt %s 5 | module { 6 | func.func @top(%arg0: memref<16x22xf32>, %arg1: memref<22x18xf32>, %arg2: memref<18x24xf32>, %arg3: memref<16x24xf32>) -> memref<16x24xf32> attributes {llvm.emit_c_interface} { 7 | %0 = memref.alloc() {name = "out_AB"} : memref<16x18xf32> 8 | affine.for %arg4 = 0 to 16 { 9 | affine.for %arg5 = 0 to 18 { 10 | %3 = memref.alloc() {name = "sum_rv"} : memref<1xf32> 11 | %c0 = arith.constant 0 : index 12 | %cst = arith.constant 0.000000e+00 : f32 13 | affine.store %cst, %3[%c0] {to = "sum_rv"} : memref<1xf32> 14 | affine.for %arg6 = 0 to 22 { 15 | %5 = affine.load %arg0[%arg4, %arg6] {from = "A"} : memref<16x22xf32> 16 | %6 = affine.load %arg1[%arg6, %arg5] {from = "B"} : memref<22x18xf32> 17 | %7 = arith.mulf %5, %6 : f32 18 | %8 = affine.load %3[%c0] {from = "sum_rv"} : memref<1xf32> 19 | %9 = arith.addf %7, %8 : f32 20 | affine.store %9, %3[%c0] {to = "sum_rv"} : memref<1xf32> 21 | } {loop_name = "r"} 22 | %c0_0 = arith.constant 0 : index 23 | %4 = affine.load %3[%c0_0] {from = "sum_rv"} : memref<1xf32> 24 | affine.store %4, %0[%arg4, %arg5] {to = "out_AB"} : memref<16x18xf32> 25 | } {loop_name = "y"} 26 | } {loop_name = "x", op_name = "out_AB"} 27 | %1 = memref.alloc() {name = "out_ABC"} : memref<16x24xf32> 28 | affine.for %arg4 = 0 to 16 { 29 | affine.for %arg5 = 0 to 24 { 30 | %3 = memref.alloc() {name = "sum_rv"} : memref<1xf32> 31 | %c0 = arith.constant 0 : index 32 | %cst = arith.constant 0.000000e+00 : f32 33 | affine.store %cst, %3[%c0] {to = "sum_rv"} : memref<1xf32> 34 | affine.for %arg6 = 0 to 18 { 35 | %5 = affine.load %0[%arg4, %arg6] {from = "out_AB"} : memref<16x18xf32> 36 | %6 = affine.load %arg2[%arg6, %arg5] {from = "C"} : memref<18x24xf32> 37 | %7 = arith.mulf %5, %6 : f32 38 | %8 = affine.load %3[%c0] {from = "sum_rv"} : memref<1xf32> 39 | %9 = arith.addf %7, %8 : f32 40 | affine.store %9, %3[%c0] {to = "sum_rv"} : memref<1xf32> 41 | } {loop_name = "k"} 42 | %c0_0 = arith.constant 0 : index 43 | %4 = affine.load %3[%c0_0] {from = "sum_rv"} : memref<1xf32> 44 | affine.store %4, %1[%arg4, %arg5] {to = "out_ABC"} : memref<16x24xf32> 45 | } {loop_name = "y"} 46 | } {loop_name = "x", op_name = "out_ABC"} 47 | %2 = memref.alloc() {name = "E"} : memref<16x24xf32> 48 | affine.for %arg4 = 0 to 16 { 49 | affine.for %arg5 = 0 to 24 { 50 | %cst = arith.constant 1.000000e-01 : f32 51 | %3 = affine.load %1[%arg4, %arg5] {from = "out_ABC"} : memref<16x24xf32> 52 | %4 = arith.mulf %cst, %3 : f32 53 | %cst_0 = arith.constant 1.000000e-01 : f32 54 | %5 = affine.load %arg3[%arg4, %arg5] {from = "D"} : memref<16x24xf32> 55 | %6 = arith.mulf %cst_0, %5 : f32 56 | %7 = arith.addf %4, %6 : f32 57 | affine.store %7, %2[%arg4, %arg5] {to = "E"} : memref<16x24xf32> 58 | } {loop_name = "y"} 59 | } {loop_name = "x", op_name = "E"} 60 | return %2 : memref<16x24xf32> 61 | } 62 | } -------------------------------------------------------------------------------- /test/Integration/test_execution_engine.py: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # RUN: %PYTHON %s 5 | import os 6 | import ctypes 7 | import numpy as np 8 | 9 | from hcl_mlir.ir import * 10 | from hcl_mlir.passmanager import * 11 | from hcl_mlir.execution_engine import * 12 | from hcl_mlir.runtime import * 13 | 14 | 15 | def lowerToLLVM(module): 16 | pm = PassManager.parse( 17 | "builtin.module(lower-affine,convert-scf-to-cf,memref-expand,finalize-memref-to-llvm,convert-arith-to-llvm,convert-func-to-llvm,convert-cf-to-llvm,reconcile-unrealized-casts)" 18 | ) 19 | pm.run(module.operation) 20 | # module.dump() 21 | return module 22 | 23 | 24 | def get_assembly(filename): 25 | with open(filename, "r") as f: 26 | code = f.read() 27 | return code 28 | 29 | 30 | def test_execution_engine(P=16, Q=22, R=18, S=24): 31 | code = get_assembly( 32 | os.path.join(os.path.dirname(os.path.abspath(__file__)), "affine_dialect.mlir") 33 | ) 34 | 35 | # Add shared library 36 | if os.getenv("LLVM_BUILD_DIR") is not None: 37 | shared_libs = [ 38 | os.path.join(os.getenv("LLVM_BUILD_DIR"), "lib", "libmlir_runner_utils.so"), 39 | os.path.join( 40 | os.getenv("LLVM_BUILD_DIR"), "lib", "libmlir_c_runner_utils.so" 41 | ), 42 | ] 43 | else: 44 | shared_libs = None 45 | 46 | A = np.random.randint(10, size=(P, Q)).astype(np.float32) 47 | B = np.random.randint(10, size=(Q, R)).astype(np.float32) 48 | C = np.random.randint(10, size=(R, S)).astype(np.float32) 49 | D = np.random.randint(10, size=(P, S)).astype(np.float32) 50 | # res1 = np.zeros((P, S), dtype=np.float32) 51 | 52 | A_memref = ctypes.pointer(ctypes.pointer(get_ranked_memref_descriptor(A))) 53 | B_memref = ctypes.pointer(ctypes.pointer(get_ranked_memref_descriptor(B))) 54 | C_memref = ctypes.pointer(ctypes.pointer(get_ranked_memref_descriptor(C))) 55 | D_memref = ctypes.pointer(ctypes.pointer(get_ranked_memref_descriptor(D))) 56 | # res1_memref = ctypes.pointer( 57 | # ctypes.pointer(get_ranked_memref_descriptor(res1)) 58 | # ) 59 | res1 = make_nd_memref_descriptor(2, ctypes.c_float)() 60 | res1_memref = ctypes.pointer(ctypes.pointer(res1)) 61 | 62 | with Context(): 63 | module = Module.parse(code) 64 | lowered = lowerToLLVM(module) 65 | if shared_libs is not None: 66 | execution_engine = ExecutionEngine( 67 | lowered, opt_level=3, shared_libs=shared_libs 68 | ) 69 | else: 70 | execution_engine = ExecutionEngine(lowered) 71 | execution_engine.invoke( 72 | "top", res1_memref, A_memref, B_memref, C_memref, D_memref 73 | ) 74 | 75 | ret = ranked_memref_to_numpy(res1_memref[0]) 76 | golden = 0.1 * np.matmul(np.matmul(A, B), C) + 0.1 * D 77 | assert np.allclose(ret, golden) 78 | print("Affine dialect test passed!") 79 | 80 | 81 | if __name__ == "__main__": 82 | test_execution_engine() 83 | -------------------------------------------------------------------------------- /test/Integration/test_lower_pass.py: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # RUN: %PYTHON %s 5 | import os 6 | import ctypes 7 | import numpy as np 8 | 9 | from hcl_mlir.ir import * 10 | from hcl_mlir.passmanager import * 11 | from hcl_mlir.execution_engine import * 12 | from hcl_mlir.runtime import * 13 | from hcl_mlir.dialects import hcl as hcl_d 14 | 15 | 16 | def get_assembly(filename): 17 | with open(filename, "r") as f: 18 | code = f.read() 19 | return code 20 | 21 | 22 | def test_execution_engine(P=16, Q=22, R=18, S=24): 23 | code = get_assembly(os.path.join(os.path.dirname( 24 | os.path.abspath(__file__)), "affine_dialect.mlir")) 25 | 26 | # Add shared library 27 | if os.getenv("LLVM_BUILD_DIR") is not None: 28 | shared_libs = [ 29 | os.path.join(os.getenv("LLVM_BUILD_DIR"), 30 | 'lib', 'libmlir_runner_utils.so'), 31 | os.path.join(os.getenv("LLVM_BUILD_DIR"), 32 | 'lib', 'libmlir_c_runner_utils.so') 33 | ] 34 | else: 35 | shared_libs = None 36 | 37 | A = np.random.randint(10, size=(P, Q)).astype(np.float32) 38 | B = np.random.randint(10, size=(Q, R)).astype(np.float32) 39 | C = np.random.randint(10, size=(R, S)).astype(np.float32) 40 | D = np.random.randint(10, size=(P, S)).astype(np.float32) 41 | # res1 = np.zeros((P, S), dtype=np.float32) 42 | 43 | A_memref = ctypes.pointer( 44 | ctypes.pointer(get_ranked_memref_descriptor(A))) 45 | B_memref = ctypes.pointer( 46 | ctypes.pointer(get_ranked_memref_descriptor(B))) 47 | C_memref = ctypes.pointer( 48 | ctypes.pointer(get_ranked_memref_descriptor(C))) 49 | D_memref = ctypes.pointer( 50 | ctypes.pointer(get_ranked_memref_descriptor(D))) 51 | # res1_memref = ctypes.pointer( 52 | # ctypes.pointer(get_ranked_memref_descriptor(res1)) 53 | # ) 54 | res1 = make_nd_memref_descriptor(2, ctypes.c_float)() 55 | res1_memref = ctypes.pointer(ctypes.pointer(res1)) 56 | 57 | with Context() as ctx: 58 | module = Module.parse(code) 59 | hcl_d.lower_hcl_to_llvm(module, ctx) 60 | if shared_libs is not None: 61 | execution_engine = ExecutionEngine( 62 | module, opt_level=3, shared_libs=shared_libs) 63 | else: 64 | execution_engine = ExecutionEngine(module) 65 | execution_engine.invoke( 66 | "top", res1_memref, A_memref, B_memref, C_memref, D_memref) 67 | 68 | ret = ranked_memref_to_numpy(res1_memref[0]) 69 | golden = 0.1 * np.matmul(np.matmul(A, B), C) + 0.1 * D 70 | assert np.allclose(ret, golden) 71 | 72 | 73 | if __name__ == "__main__": 74 | test_execution_engine() 75 | -------------------------------------------------------------------------------- /test/Operations/bitops/bit_reverse.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt %s --lower-bitops | FileCheck %s 5 | module { 6 | func.func @top(%arg0: memref<10xi8>, %arg1: memref<10xi8>) attributes {bit, itypes = "uu", otypes = ""} { 7 | affine.for %arg2 = 0 to 10 { 8 | %0 = affine.load %arg0[%arg2] {from = "compute_0", unsigned} : memref<10xi8> 9 | %1 = hcl.bit_reverse(%0 : i8) {unsigned} 10 | // CHECK: affine.for %[[ARG:.*]] = 0 to 8 { 11 | // CHECK: %[[ARG:.*]] = affine.load %[[ARG:.*]][%[[ARG:.*]]] : memref<1xi8> 12 | // CHECK: %[[ARG:.*]] = arith.subi %[[ARG:.*]], %[[ARG:.*]] : index 13 | // CHECK: %[[ARG:.*]] = hcl.get_bit(%[[ARG:.*]] : i8, %[[ARG:.*]]) -> i1 14 | // CHECK: hcl.set_bit 15 | // CHECK: affine.store %[[ARG:.*]], %[[ARG:.*]][%[[ARG:.*]]] : memref<1xi8> 16 | // CHECK: } 17 | %2 = affine.load %arg1[%arg2] {from = "compute_1", unsigned} : memref<10xi8> 18 | %c7 = arith.constant 7 : index 19 | %c0 = arith.constant 0 : index 20 | %3 = hcl.set_slice(%2 : i8, %c7, %c0, %1 : i8) -> i8 21 | affine.store %3, %arg1[%arg2] {to = "compute_1", unsigned} : memref<10xi8> 22 | } {loop_name = "loop_0"} 23 | return 24 | } 25 | } -------------------------------------------------------------------------------- /test/Operations/bitops/get_bit.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt %s --lower-print-ops --jit 5 | module { 6 | memref.global "private" @gv0 : memref<10xi8> = dense<[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]> 7 | func.func @top() -> () attributes {bit, itypes = "s", otypes = "s", top} { 8 | %0 = memref.get_global @gv0 : memref<10xi8> 9 | affine.for %arg1 = 0 to 10 { 10 | %1 = affine.load %0[%arg1] : memref<10xi8> 11 | affine.for %arg2 = 0 to 8 { 12 | %3 = hcl.get_bit(%1 : i8, %arg2) -> i1 13 | hcl.print(%3) {format="d", unsigned} : i1 14 | } 15 | } 16 | // LSB, MSB 17 | // 00000000 18 | // 10000000 19 | // 01000000 20 | // 11000000 21 | // 00100000 22 | // 10100000 23 | // 01100000 24 | // 11100000 25 | // 00010000 26 | // 10010000 27 | return 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/Operations/bitops/get_slice.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt %s --lower-print-ops --jit | FileCheck %s 5 | // Get bit 0,1,2 from a integer, the output should be 3 6 | module { 7 | memref.global "private" @gv0 : memref<1xi32> = dense<[11]> 8 | func.func @top() -> () attributes {bit, itypes = "s", otypes = "s", top} { 9 | %0 = memref.get_global @gv0 : memref<1xi32> 10 | %res =memref.alloc() : memref<1xi32> 11 | affine.for %arg1 = 0 to 1 { 12 | %1 = affine.load %0[%arg1] : memref<1xi32> 13 | %c1_i32 = arith.constant 1 : i32 14 | %low = arith.constant 0 : index 15 | %high = arith.constant 2 : index 16 | %3 = hcl.get_slice(%1 : i32, %high, %low) -> i3 17 | // CHECK: 3 18 | hcl.print(%3) {format="%d\n"} : i3 19 | %4 = arith.extui %3 : i3 to i32 20 | affine.store %4, %res[%arg1] : memref<1xi32> 21 | } 22 | return 23 | } 24 | } -------------------------------------------------------------------------------- /test/Operations/bitops/set_bit.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt %s --lower-print-ops --jit | FileCheck %s 5 | // Input: 0x0000 6 | // By setting the third bit to 1, we get 7 | // Output: 0x0004 8 | module { 9 | memref.global "private" @gv0 : memref<1xi32> = dense<[0]> 10 | func.func @top() -> () attributes {bit, itypes = "s", otypes = "s", top} { 11 | %0 = memref.get_global @gv0 : memref<1xi32> 12 | %res =memref.alloc() : memref<1xi32> 13 | affine.for %arg1 = 0 to 1 { 14 | %1 = affine.load %0[%arg1] : memref<1xi32> 15 | %c1_i32 = arith.constant 1 : i32 16 | %c2 = arith.constant 2 : index 17 | %val = arith.constant 1 : i1 18 | %2 = hcl.set_bit(%1 : i32, %c2, %val : i1) -> i32 19 | affine.store %2, %res[%arg1] : memref<1xi32> 20 | } 21 | // CHECK: 4 22 | %v = affine.load %res[0] : memref<1xi32> 23 | hcl.print(%v) {format="%d\n"}: i32 24 | return 25 | } 26 | } -------------------------------------------------------------------------------- /test/Operations/bitops/set_slice.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt %s --lower-print-ops --lower-bitops --jit | FileCheck %s 5 | // Input: 0x0000 6 | // By setting the 3,2,1 bits to 110, we get 7 | // Output: 12 (0x000C) 8 | module { 9 | memref.global "private" @gv0 : memref<1xi32> = dense<[0]> 10 | func.func @top() -> () attributes {bit, itypes = "s", otypes = "s", top} { 11 | %0 = memref.get_global @gv0 : memref<1xi32> 12 | %res =memref.alloc() : memref<1xi32> 13 | affine.for %arg1 = 0 to 1 { 14 | %1 = affine.load %0[%arg1] : memref<1xi32> 15 | %lo = arith.constant 1 : index 16 | %hi = arith.constant 3 : index 17 | %val = arith.constant 6 : i3 18 | %2 = hcl.set_slice(%1 : i32, %hi, %lo, %val : i3) -> i32 19 | affine.store %2, %res[%arg1] : memref<1xi32> 20 | } 21 | // CHECK: 12 22 | %v = affine.load %res[0] : memref<1xi32> 23 | hcl.print(%v) {format="%d\n"}: i32 24 | return 25 | } 26 | } -------------------------------------------------------------------------------- /test/Operations/composite/struct.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt --lower-composite --fixed-to-integer --lower-to-llvm %s 5 | module { 6 | 7 | func.func @basic () -> () { 8 | %1 = arith.constant 0 : i32 9 | %2 = arith.constant 1 : i32 10 | %3 = hcl.struct_construct(%1, %2) : i32, i32 -> !hcl.struct 11 | %4 = hcl.struct_get %3[0] : !hcl.struct -> i32 12 | %5 = hcl.struct_get %3[1] : !hcl.struct -> i32 13 | %6 = arith.addi %4, %5 : i32 14 | return 15 | } 16 | 17 | func.func @nested_struct() -> () { 18 | %1 = arith.constant 0 : i32 19 | %2 = arith.constant 1 : i32 20 | %3 = hcl.struct_construct(%1, %2) : i32, i32 -> !hcl.struct 21 | %4 = hcl.struct_construct(%3, %2) : !hcl.struct, i32 -> !hcl.struct, i32> 22 | %5 = hcl.struct_get %4[0] : !hcl.struct, i32> -> !hcl.struct 23 | %6 = hcl.struct_get %5[0] : !hcl.struct -> i32 24 | %7 = arith.addi %6, %2 : i32 25 | return 26 | } 27 | 28 | func.func @struct_memref() -> () { 29 | %1 = arith.constant 0 : i32 30 | %2 = arith.constant 1 : i32 31 | %3 = hcl.struct_construct(%1, %2) : i32, i32 -> !hcl.struct 32 | %4 = memref.alloc() : memref<2x2x!hcl.struct> 33 | return 34 | } 35 | 36 | 37 | func.func @top(%arg0: memref<100xi8>, %arg1: memref<100x!hcl.Fixed<13, 11>>, %arg2: memref<100xf32>) attributes {itypes = "s__", otypes = ""} { 38 | %0 = memref.alloc() {name = "compute_3"} : memref<100x!hcl.struct, f32>> 39 | affine.for %arg3 = 0 to 100 { 40 | %2 = affine.load %arg0[%arg3] {from = "compute_0"} : memref<100xi8> 41 | %3 = affine.load %arg1[%arg3] {from = "compute_1"} : memref<100x!hcl.Fixed<13, 11>> 42 | %4 = affine.load %arg2[%arg3] {from = "compute_2"} : memref<100xf32> 43 | %5 = hcl.struct_construct(%2, %3, %4) : i8, !hcl.Fixed<13, 11>, f32 -> , f32> 44 | affine.store %5, %0[%arg3] {to = "compute_3"} : memref<100x!hcl.struct, f32>> 45 | } {loop_name = "x", op_name = "compute_3"} 46 | %1 = memref.alloc() {name = "compute_4"} : memref<100xi8> 47 | affine.for %arg3 = 0 to 100 { 48 | %2 = affine.load %0[%arg3] {from = "compute_3"} : memref<100x!hcl.struct, f32>> 49 | %3 = hcl.struct_get %2[0] : , f32> -> i8 50 | affine.store %3, %1[%arg3] {to = "compute_4"} : memref<100xi8> 51 | } {loop_name = "x", op_name = "compute_4"} 52 | return 53 | } 54 | } -------------------------------------------------------------------------------- /test/Operations/logicops/and.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt %s 5 | module { 6 | func.func @top(%arg0 : memref<1xi1>) { 7 | %c0 = arith.constant 0 : index 8 | %1 = hcl.and { 9 | %true = arith.constant 1 : i1 10 | hcl.yield %true : i1 11 | }, { 12 | %0 = memref.load %arg0[%c0] : memref<1xi1> 13 | hcl.yield %0 : i1 14 | } : i1 15 | func.return 16 | } 17 | } -------------------------------------------------------------------------------- /test/Operations/logicops/or.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt %s 5 | module { 6 | func.func @top(%arg0 : memref<1xi1>) { 7 | %c0 = arith.constant 0 : index 8 | %2 = hcl.or { 9 | %true = arith.constant 1 : i1 10 | hcl.yield %true : i1 11 | }, { 12 | %0 = memref.load %arg0[%c0] : memref<1xi1> 13 | hcl.yield %0 : i1 14 | } : i1 15 | func.return 16 | } 17 | } -------------------------------------------------------------------------------- /test/Operations/misc/clone.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt %s 5 | module { 6 | func.func @sub_func () -> () { 7 | return 8 | } 9 | func.func @top() -> (){ 10 | call @sub_func() : () -> () 11 | %s = hcl.create_op_handle "sub_func" 12 | hcl.clone(@sub_func, %s) 13 | return 14 | } 15 | } -------------------------------------------------------------------------------- /test/Operations/misc/const_tensor.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt --fixed-to-integer --lower-print-ops --jit %s | FileCheck %s 5 | module { 6 | memref.global "private" @gv_cst : memref<2x2xi64> = dense<[[8, 0], [10, 20]]> 7 | 8 | func.func @top() -> () { 9 | %0 = hcl.get_global_fixed @gv_cst : memref<2x2x!hcl.Fixed<32,2>> 10 | hcl.print_memref (%0) {format = "%.1f \n"} : memref<2x2x!hcl.Fixed<32,2>> 11 | return 12 | } 13 | } 14 | 15 | // CHECK: 2, 0 16 | // CHECK: 2.5, 5 -------------------------------------------------------------------------------- /test/Operations/print/print-f32.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt --lower-print-ops --jit %s | FileCheck %s 5 | 6 | module { 7 | 8 | memref.global "private" @gv0 : memref<4x4xf32> = dense<[[1.0, 2.0, 3.0, 4.0], [1.0, 2.0, 3.0, 4.0], [1.0, 2.0, 3.0, 4.0], [1.0, 2.0, 3.0, 4.0]]> 9 | 10 | func.func @top() -> () { 11 | %0 = memref.get_global @gv0 : memref<4x4xf32> 12 | // CHECK: 1, 2, 3, 4 13 | // CHECK: 1, 2, 3, 4 14 | // CHECK: 1, 2, 3, 4 15 | // CHECK: 1, 2, 3, 4 16 | hcl.print_memref(%0) : memref<4x4xf32> 17 | return 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/Operations/print/print-fixed.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt %s --fixed-to-integer 5 | 6 | module { 7 | func.func @top(%0: memref<4x4x!hcl.Fixed<4, 2>>) -> () { 8 | hcl.print(%0) : memref<4x4x!hcl.Fixed<4, 2>> 9 | return 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/Operations/print/print.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt --fixed-to-integer --lower-print-ops --jit %s 5 | 6 | // This file tests hcl.print operations. 7 | // - Different types: int, float, fixed 8 | // - Different print formats 9 | // - Different number of values to print 10 | 11 | module { 12 | memref.global "private" @gv_cst : memref<1xi64> = dense<[8]> 13 | memref.global "private" @gv_f64 : memref<1xf64> = dense<[8.0]> 14 | func.func @top () -> () { 15 | %c1 = arith.constant 0 : index 16 | %fixed_memref = hcl.get_global_fixed @gv_cst : memref<1x!hcl.Fixed<32,2>> 17 | %loaded_fixed = affine.load %fixed_memref[%c1] : memref<1x!hcl.Fixed<32,2>> 18 | hcl.print(%loaded_fixed) {format="test fixed point print: %.2f \n"} : !hcl.Fixed<32,2> 19 | 20 | %c1_i32 = arith.constant 144 : i32 21 | hcl.print(%c1_i32) {format="test integer print: %d \n"} : i32 22 | 23 | %c2_i32 = arith.constant -128 : i22 24 | hcl.print(%c1_i32, %c2_i32) {format="test two integers print: %d %d \n"} : i32, i22 25 | 26 | %0 = memref.get_global @gv_f64 : memref<1xf64> 27 | %1 = memref.load %0[%c1] : memref<1xf64> 28 | %c1_f64 = arith.constant 1351.5 : f64 29 | hcl.print(%1) {format="loaded from memref: %.2f \n"} : f64 30 | hcl.print(%c1_f64) {format="constant result: %.2f \n"} : f64 31 | return 32 | } 33 | } -------------------------------------------------------------------------------- /test/Operations/print/print_memref.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt %s --lower-print-ops --jit | FileCheck %s 5 | // Get bit 0,1,2 from a integer, the output should be 3 6 | module { 7 | memref.global "private" @gv0 : memref<1xi32> = dense<[11]> 8 | func.func @top() -> () attributes {bit, itypes = "s", otypes = "s", top} { 9 | %0 = memref.get_global @gv0 : memref<1xi32> 10 | %res =memref.alloc() : memref<1xi32> 11 | affine.for %arg1 = 0 to 1 { 12 | %1 = affine.load %0[%arg1] : memref<1xi32> 13 | %c1_i32 = arith.constant 1 : i32 14 | %low = arith.constant 0 : index 15 | %high = arith.constant 2 : index 16 | %3 = hcl.get_slice(%1 : i32, %high, %low) -> i3 17 | // CHECK: 3 18 | hcl.print(%3) {format="%d\n"} : i3 19 | %4 = arith.extui %3 : i3 to i32 20 | affine.store %4, %res[%arg1] : memref<1xi32> 21 | } 22 | hcl.print_memref(%res) : memref<1xi32> 23 | return 24 | } 25 | } -------------------------------------------------------------------------------- /test/Operations/typecast/fixed_to_fixed.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt %s --fixed-to-integer --lower-print-ops --jit | FileCheck %s 5 | module { 6 | // 2.25, 2.50, 3.25, 6.25 7 | memref.global "private" @fixed_gv : memref<2x2xi64> = dense<[[9, 10], [13, 25]]> 8 | func.func @top() -> () { 9 | %0 = hcl.get_global_fixed @fixed_gv : memref<2x2x!hcl.Fixed<32,2>> 10 | %1 = memref.alloc() : memref<2x2x!hcl.Fixed<16,1>> 11 | affine.for %arg0 = 0 to 2 { 12 | affine.for %arg1 = 0 to 2 { 13 | %3 = affine.load %0[%arg0, %arg1] : memref<2x2x!hcl.Fixed<32,2>> 14 | %4 = hcl.fixed_to_fixed (%3) : !hcl.Fixed<32, 2> -> !hcl.Fixed<16, 1> 15 | affine.store %4, %1[%arg0, %arg1] : memref<2x2x!hcl.Fixed<16,1>> 16 | } 17 | } 18 | hcl.print_memref(%1) {format = "%.2f \n"} : memref<2x2x!hcl.Fixed<16,1>> 19 | return 20 | } 21 | } 22 | 23 | // CHECK: 2, 2.5 24 | // CHECK: 3, 6 -------------------------------------------------------------------------------- /test/Operations/typecast/fixed_to_float.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt %s --fixed-to-integer --lower-print-ops --jit | FileCheck %s 5 | module { 6 | memref.global "private" @fixed_gv : memref<2x2xi64> = dense<[[8, 0], [10, 20]]> 7 | func.func @top() -> () { 8 | %0 = hcl.get_global_fixed @fixed_gv : memref<2x2x!hcl.Fixed<32,2>> 9 | %1 = memref.alloc() : memref<2x2xf32> 10 | affine.for %arg0 = 0 to 2 { 11 | affine.for %arg1 = 0 to 2 { 12 | %3 = affine.load %0[%arg0, %arg1] : memref<2x2x!hcl.Fixed<32,2>> 13 | %4 = hcl.fixed_to_float (%3) : !hcl.Fixed<32, 2> -> f32 14 | affine.store %4, %1[%arg0, %arg1] : memref<2x2xf32> 15 | } 16 | } 17 | hcl.print_memref(%1) : memref<2x2xf32> 18 | return 19 | } 20 | } 21 | 22 | // CHECK: 2, 0 23 | // CHECK: 2.5, 5 -------------------------------------------------------------------------------- /test/Operations/typecast/fixed_to_int.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt %s --fixed-to-integer --lower-print-ops --jit | FileCheck %s 5 | module { 6 | memref.global "private" @fixed_gv : memref<2x2xi64> = dense<[[8, 0], [10, 20]]> 7 | func.func @top() -> () { 8 | %0 = hcl.get_global_fixed @fixed_gv : memref<2x2x!hcl.Fixed<32,2>> 9 | %1 = memref.alloc() : memref<2x2xi64> 10 | affine.for %arg0 = 0 to 2 { 11 | affine.for %arg1 = 0 to 2 { 12 | %3 = affine.load %0[%arg0, %arg1] : memref<2x2x!hcl.Fixed<32,2>> 13 | %4 = hcl.fixed_to_int (%3) : !hcl.Fixed<32, 2> -> i64 14 | affine.store %4, %1[%arg0, %arg1] : memref<2x2xi64> 15 | } 16 | } 17 | hcl.print_memref(%1) : memref<2x2xi64> 18 | return 19 | } 20 | } 21 | 22 | // CHECK: 2, 0 23 | // CHECK: 2, 5 -------------------------------------------------------------------------------- /test/Operations/typecast/float_to_fixed.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt %s --fixed-to-integer --lower-print-ops --jit | FileCheck %s 5 | module { 6 | memref.global "private" @float_gv : memref<2x2xf32> = dense<[[2.234, 1.223], [5.261, 1.2]]> 7 | func.func @top() -> () { 8 | %0 = memref.get_global @float_gv : memref<2x2xf32> 9 | %1 = memref.alloc() : memref<2x2x!hcl.Fixed<32, 2>> 10 | affine.for %arg0 = 0 to 2 { 11 | affine.for %arg1 = 0 to 2 { 12 | %3 = affine.load %0[%arg0, %arg1] : memref<2x2xf32> 13 | %4 = hcl.float_to_fixed (%3) : f32 -> !hcl.Fixed<32, 2> 14 | affine.store %4, %1[%arg0, %arg1] : memref<2x2x!hcl.Fixed<32, 2>> 15 | } 16 | } 17 | hcl.print_memref(%1) : memref<2x2x!hcl.Fixed<32,2>> 18 | return 19 | } 20 | } 21 | 22 | // CHECK: 2, 1 23 | // CHECK: 5.25, 1 -------------------------------------------------------------------------------- /test/Operations/typecast/int_to_fixed.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt %s --fixed-to-integer --lower-print-ops --jit | FileCheck %s 5 | module { 6 | memref.global "private" @int_gv : memref<2x2xi32> = dense<[[2, 4], [5, 15]]> 7 | func.func @top() -> () { 8 | %0 = memref.get_global @int_gv : memref<2x2xi32> 9 | %1 = memref.alloc() : memref<2x2x!hcl.Fixed<32, 2>> 10 | affine.for %arg0 = 0 to 2 { 11 | affine.for %arg1 = 0 to 2 { 12 | %3 = affine.load %0[%arg0, %arg1] : memref<2x2xi32> 13 | %4 = hcl.int_to_fixed (%3) : i32 -> !hcl.Fixed<32, 2> 14 | affine.store %4, %1[%arg0, %arg1] : memref<2x2x!hcl.Fixed<32, 2>> 15 | } 16 | } 17 | hcl.print_memref(%1) : memref<2x2x!hcl.Fixed<32,2>> 18 | return 19 | } 20 | } 21 | 22 | // CHECK: 2, 4 23 | // CHECK: 5, 15 -------------------------------------------------------------------------------- /test/Runtime/load_memref.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt %s 5 | 6 | // check https://github.com/zzzDavid/hcl-debug/tree/main/read_write_file for full runnable examples. 7 | // this test is only to make sure the generated IR is correct. 8 | // the IR here is not runnable, because read/write requires absolute path. 9 | 10 | module { 11 | llvm.mlir.global internal constant @str_global("input.txt\00") 12 | llvm.mlir.global internal constant @str_global2("output.txt\00") 13 | func.func private @readMemrefI64(memref<*xi64>, !llvm.ptr) 14 | func.func private @writeMemrefI64(memref<*xi64>, !llvm.ptr) 15 | func.func private @printMemrefI64(%ptr : memref<*xi64>) 16 | func.func @top () -> () { 17 | %0 = memref.alloc() : memref<2x2xi64> 18 | %1 = memref.cast %0 : memref<2x2xi64> to memref<*xi64> 19 | %2 = llvm.mlir.addressof @str_global : !llvm.ptr> 20 | %3 = llvm.mlir.constant(0 : index) : i64 21 | %4 = llvm.getelementptr %2[%3, %3] : (!llvm.ptr>, i64, i64) -> !llvm.ptr 22 | call @readMemrefI64(%1, %4) : (memref<*xi64>, !llvm.ptr) -> () 23 | call @printMemrefI64(%1) : (memref<*xi64>) -> () 24 | 25 | %5 = llvm.mlir.addressof @str_global2 : !llvm.ptr> 26 | %6 = llvm.mlir.constant(0 : index) : i64 27 | %7 = llvm.getelementptr %5[%6, %6] : (!llvm.ptr>, i64, i64) -> !llvm.ptr 28 | call @writeMemrefI64(%1, %7) : (memref<*xi64>, !llvm.ptr) -> () 29 | return 30 | } 31 | func.func @main() -> () { 32 | call @top() : () -> () 33 | return 34 | } 35 | } -------------------------------------------------------------------------------- /test/Transforms/compute/cascade.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt -opt %s | FileCheck %s 5 | 6 | // CHECK: #map = affine_map<(d0) -> (d0 * 16)> 7 | // CHECK: #map1 = affine_map<(d0, d1) -> (d1 + d0)> 8 | // CHECK: #map2 = affine_map<(d0) -> (d0 * 2)> 9 | // CHECK: #map3 = affine_map<(d0) -> (d0 * 4)> 10 | // CHECK: #map4 = affine_map<(d0) -> (d0 * 8)> 11 | module { 12 | func.func @gemm(%A: memref<1024x512xf32>, %B: memref<512x1024xf32>) -> memref<1024x1024xf32> 13 | { 14 | %C = memref.alloc() : memref<1024x1024xf32> 15 | // CHECK: affine.for %[[ARG:.*]] = 0 to 1024 { 16 | affine.for %i = 0 to 1024 { 17 | // CHECK: affine.for %[[ARG1:.*]] = 0 to 1024 { 18 | affine.for %j = 0 to 1024 { 19 | // CHECK: affine.for %[[ARG2:.*]] = 0 to 512 { 20 | affine.for %k = 0 to 512 { 21 | %a = affine.load %A[%i, %k] : memref<1024x512xf32> 22 | %b = affine.load %B[%k, %j] : memref<512x1024xf32> 23 | %c = affine.load %C[%i, %j] : memref<1024x1024xf32> 24 | %prod = arith.mulf %a, %b : f32 25 | %sum = arith.addf %prod, %c: f32 26 | affine.store %sum, %C[%i, %j] : memref<1024x1024xf32> 27 | } { loop_name = "k", reduction = 1 : i32} 28 | } { loop_name = "j" } 29 | } { loop_name = "i", op_name = "s" } 30 | return %C : memref<1024x1024xf32> 31 | } 32 | func.func @matrix_multiply(%A: memref<1024x512xf32>, %B: memref<512x1024xf32>, %C: memref<1024x1024xf32>) 33 | { 34 | %s = hcl.create_op_handle "s" 35 | %l1 = hcl.create_loop_handle %s, "i" 36 | %l2 = hcl.create_loop_handle %s, "j" 37 | %l3 = hcl.create_loop_handle %s, "k" 38 | // CHECK: affine.for %[[ARG:.*]] = 0 to 128 { 39 | // CHECK: affine.for %[[ARG1:.*]] = 0 to 8 { 40 | affine.for %i = 0 to 1024 { 41 | // CHECK: affine.for %[[ARG2:.*]] = 0 to 32 { 42 | // CHECK: affine.for %[[ARG3:.*]] = 0 to 16 { 43 | // CHECK: affine.for %[[ARG4:.*]] = 0 to 128 { 44 | affine.for %j = 0 to 1024 { 45 | // CHECK: affine.for %[[ARG5:.*]] = 0 to 2 { 46 | // CHECK: affine.for %[[ARG6:.*]] = 0 to 4 { 47 | affine.for %k = 0 to 512 { 48 | %a = affine.load %A[%i, %k] : memref<1024x512xf32> 49 | %b = affine.load %B[%k, %j] : memref<512x1024xf32> 50 | %c = affine.load %C[%i, %j] : memref<1024x1024xf32> 51 | %prod = arith.mulf %a, %b : f32 52 | %sum = arith.addf %prod, %c: f32 53 | affine.store %sum, %C[%i, %j] : memref<1024x1024xf32> 54 | } { loop_name = "k" } 55 | } { loop_name = "j" } 56 | } { loop_name = "i", op_name = "s" } 57 | %l4, %l5 = hcl.split (%l1, 8) 58 | %l6, %l7, %l8, %l9 = hcl.tile (%l2, %l3, 2, 4) // split & tile 59 | %l10, %l11 = hcl.split (%l6, 16) 60 | return 61 | } 62 | } -------------------------------------------------------------------------------- /test/Transforms/compute/fusing.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt -opt %s | FileCheck %s 5 | 6 | module { 7 | func.func @gemm_fuse_two(%A: memref<1024x512xf32>, %B: memref<512x1024xf32>, %C: memref<1024x1024xf32>) 8 | { 9 | %s = hcl.create_op_handle "s" 10 | %li = hcl.create_loop_handle %s, "i" 11 | %lj = hcl.create_loop_handle %s, "j" 12 | %lk = hcl.create_loop_handle %s, "k" 13 | // CHECK: affine.for %[[ARG:.*]] = 0 to 1048576 { 14 | affine.for %i = 0 to 1024 { 15 | affine.for %j = 0 to 1024 { 16 | affine.for %k = 0 to 512 { 17 | %a = affine.load %A[%i, %k] : memref<1024x512xf32> 18 | %b = affine.load %B[%k, %j] : memref<512x1024xf32> 19 | %c = affine.load %C[%i, %j] : memref<1024x1024xf32> 20 | %prod = arith.mulf %a, %b : f32 21 | %sum = arith.addf %prod, %c: f32 22 | affine.store %sum, %C[%i, %j] : memref<1024x1024xf32> 23 | } { loop_name = "k" } 24 | } { loop_name = "j" } 25 | } { loop_name = "i", op_name = "s" } 26 | %l_fused = hcl.fuse (%li, %lj) 27 | // (i,j)->(ij/1024,ij%1024) 28 | return 29 | } 30 | func.func @gemm_fuse_three(%A: memref<1024x512xf32>, %B: memref<512x1024xf32>, %C: memref<1024x1024xf32>) 31 | { 32 | %s = hcl.create_op_handle "s" 33 | %li = hcl.create_loop_handle %s, "i" 34 | %lj = hcl.create_loop_handle %s, "j" 35 | %lk = hcl.create_loop_handle %s, "k" 36 | // CHECK: affine.for %[[ARG:.*]] = 0 to 536870912 { 37 | affine.for %i = 0 to 1024 { 38 | affine.for %j = 0 to 1024 { 39 | affine.for %k = 0 to 512 { 40 | %a = affine.load %A[%i, %k] : memref<1024x512xf32> 41 | %b = affine.load %B[%k, %j] : memref<512x1024xf32> 42 | %c = affine.load %C[%i, %j] : memref<1024x1024xf32> 43 | %prod = arith.mulf %a, %b : f32 44 | %sum = arith.addf %prod, %c: f32 45 | affine.store %sum, %C[%i, %j] : memref<1024x1024xf32> 46 | } { loop_name = "k" } 47 | } { loop_name = "j" } 48 | } { loop_name = "i", op_name = "s" } 49 | %l_fused = hcl.fuse (%li, %lj, %lk) 50 | // (i,j,k)->(ijk/(1024*1024),ijk/1024%1024,ijk%1024) 51 | return 52 | } 53 | func.func @gemm_fuse_two_among_four(%A: memref<1024x512xf32>, %B: memref<512x1024xf32>, %C: memref<1024x1024xf32>) 54 | { 55 | %s = hcl.create_op_handle "s" 56 | %li = hcl.create_loop_handle %s, "i" 57 | %lj = hcl.create_loop_handle %s, "j" 58 | %lk = hcl.create_loop_handle %s, "k" 59 | %ll = hcl.create_loop_handle %s, "l" 60 | // CHECK: affine.for %[[ARG:.*]] = 0 to 1024 { 61 | affine.for %i = 0 to 1024 { 62 | // CHECK: affine.for %[[ARG1:.*]] = 0 to 1048576 { 63 | affine.for %j = 0 to 1024 { 64 | affine.for %l = 0 to 1024 { 65 | affine.for %k = 0 to 512 { 66 | %a = affine.load %A[%i, %k] : memref<1024x512xf32> 67 | %b = affine.load %B[%k, %j] : memref<512x1024xf32> 68 | %c = affine.load %C[%i, %j] : memref<1024x1024xf32> 69 | %prod = arith.mulf %a, %b : f32 70 | %sum = arith.addf %prod, %c: f32 71 | affine.store %sum, %C[%i, %j] : memref<1024x1024xf32> 72 | } { loop_name = "k" } 73 | } { loop_name = "l" } 74 | } { loop_name = "j" } 75 | } { loop_name = "i", op_name = "s" } 76 | %l_fused = hcl.fuse (%lj, %ll) 77 | // (i,j,k)->(ijk/(1024*1024),ijk/1024%1024,ijk%1024) 78 | return 79 | } 80 | } -------------------------------------------------------------------------------- /test/Transforms/compute/reordering.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt -opt %s | FileCheck %s 5 | 6 | module { 7 | func.func @gemm(%A: memref<1024x512xf32>, %B: memref<512x1024xf32>, %C: memref<1024x1024xf32>) 8 | { 9 | %s = hcl.create_op_handle "s" 10 | %li = hcl.create_loop_handle %s, "i" 11 | %lj = hcl.create_loop_handle %s, "j" 12 | %lk = hcl.create_loop_handle %s, "k" 13 | affine.for %i = 0 to 1024 { 14 | affine.for %j = 0 to 1024 { 15 | affine.for %k = 0 to 512 { 16 | %a = affine.load %A[%i, %k] : memref<1024x512xf32> 17 | %b = affine.load %B[%k, %j] : memref<512x1024xf32> 18 | %c = affine.load %C[%i, %j] : memref<1024x1024xf32> 19 | %prod = arith.mulf %a, %b : f32 20 | %sum = arith.addf %prod, %c: f32 21 | affine.store %sum, %C[%i, %j] : memref<1024x1024xf32> 22 | // CHECK: } {loop_name = "i.inner"} 23 | // CHECK: } {loop_name = "j"} 24 | } { loop_name = "k" } 25 | // CHECK: } {loop_name = "k"} 26 | } { loop_name = "j" } 27 | // CHECK: } {loop_name = "i.outer", op_name = "s"} 28 | } { loop_name = "i", op_name = "s" } 29 | %li_outer, %li_inner = hcl.split (%li, 8) 30 | hcl.reorder (%lk, %lj, %li_inner) 31 | return 32 | } 33 | func.func @gemm_reorder_outermost(%A: memref<1024x512xf32>, %B: memref<512x1024xf32>, %C: memref<1024x1024xf32>) 34 | { 35 | %s = hcl.create_op_handle "s" 36 | %li = hcl.create_loop_handle %s, "i" 37 | %lj = hcl.create_loop_handle %s, "j" 38 | %lk = hcl.create_loop_handle %s, "k" 39 | affine.for %i = 0 to 1024 { 40 | affine.for %j = 0 to 1024 { 41 | affine.for %k = 0 to 512 { 42 | %a = affine.load %A[%i, %k] : memref<1024x512xf32> 43 | %b = affine.load %B[%k, %j] : memref<512x1024xf32> 44 | %c = affine.load %C[%i, %j] : memref<1024x1024xf32> 45 | %prod = arith.mulf %a, %b : f32 46 | %sum = arith.addf %prod, %c: f32 47 | affine.store %sum, %C[%i, %j] : memref<1024x1024xf32> 48 | // CHECK: } {loop_name = "j"} 49 | } { loop_name = "k" } 50 | // CHECK: } {loop_name = "i"} 51 | } { loop_name = "j" } 52 | // CHECK: } {loop_name = "k", op_name = "s"} 53 | } { loop_name = "i", op_name = "s" } 54 | hcl.reorder (%lk, %li, %lj) 55 | return 56 | } 57 | } -------------------------------------------------------------------------------- /test/Transforms/compute/stages.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt -opt %s | FileCheck %s 5 | 6 | module { 7 | func.func @matrix_multiply(%A: memref<1024x1024xf32>, %B: memref<1024x1024xf32>, %C: memref<1024x1024xf32>) 8 | { 9 | %s1 = hcl.create_op_handle "s1" 10 | %l1 = hcl.create_loop_handle %s1, "i" 11 | %l2 = hcl.create_loop_handle %s1, "j" 12 | %l3 = hcl.create_loop_handle %s1, "k" 13 | %s2 = hcl.create_op_handle "s2" 14 | %l11 = hcl.create_loop_handle %s2, "i1" 15 | %l21 = hcl.create_loop_handle %s2, "j1" 16 | %l31 = hcl.create_loop_handle %s2, "k1" 17 | affine.for %i = 0 to 1024 { 18 | affine.for %j = 0 to 1024 { 19 | affine.for %k = 0 to 1024 { 20 | %a = affine.load %A[%i, %k] : memref<1024x1024xf32> 21 | %b = affine.load %B[%k, %j] : memref<1024x1024xf32> 22 | %c = affine.load %C[%i, %j] : memref<1024x1024xf32> 23 | %prod = arith.mulf %a, %b : f32 24 | %sum = arith.addf %prod, %c: f32 25 | affine.store %sum, %C[%i, %j] : memref<1024x1024xf32> 26 | // CHECK: } {loop_name = "j"} 27 | } { loop_name = "k" } 28 | // CHECK: } {loop_name = "k"} 29 | } { loop_name = "j" } 30 | // CHECK: } {loop_name = "i", op_name = "s1"} 31 | } { loop_name = "i", op_name = "s1" } 32 | affine.for %i = 0 to 1024 { 33 | affine.for %j = 0 to 1024 { 34 | affine.for %k = 0 to 1024 { 35 | %a = affine.load %A[%i, %k] : memref<1024x1024xf32> 36 | %b = affine.load %B[%k, %j] : memref<1024x1024xf32> 37 | %c = affine.load %C[%i, %j] : memref<1024x1024xf32> 38 | %prod = arith.mulf %a, %b : f32 39 | %sum = arith.addf %prod, %c: f32 40 | affine.store %sum, %C[%i, %j] : memref<1024x1024xf32> 41 | // CHECK: } {loop_name = "i1"} 42 | } { loop_name = "k1" } 43 | // CHECK: } {loop_name = "j1"} 44 | } { loop_name = "j1" } 45 | // CHECK: } {loop_name = "k1", op_name = "s2"} 46 | } { loop_name = "i1", op_name = "s2"} 47 | hcl.reorder (%l3, %l2) 48 | hcl.reorder (%l31, %l21, %l11) 49 | return 50 | } 51 | } -------------------------------------------------------------------------------- /test/Transforms/compute/systolic.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt -opt %s | FileCheck %s 5 | 6 | module { 7 | func.func private @S0(%arg0: index, %arg1: index, %arg2: memref<61xf32>, %arg3: index, %arg4: memref<64xf32>, %arg5: memref<3xf32>) attributes {scop.stmt} { 8 | %0 = affine.load %arg5[symbol(%arg0)+symbol(%arg1)] : memref<3xf32> 9 | %1 = affine.load %arg4[symbol(%arg1)] : memref<64xf32> 10 | %2 = arith.mulf %0, %1 : f32 11 | %3 = affine.load %arg2[symbol(%arg3)] : memref<61xf32> 12 | %4 = arith.addf %2, %3 : f32 13 | affine.store %4, %arg2[symbol(%arg3)] : memref<61xf32> 14 | return 15 | } 16 | 17 | func.func @conv1d(%A: memref<64xf32>, %W: memref<3xf32>, %C: memref<61xf32>) 18 | { 19 | %s = hcl.create_op_handle "s" 20 | %li = hcl.create_loop_handle %s, "i" 21 | %lj = hcl.create_loop_handle %s, "j" 22 | 23 | // Polymer (PoCC) post-procssed loop nest 24 | affine.for %i = 0 to 61 { 25 | affine.for %j = 0 to 3 { 26 | func.call @S0(%i, %j, %C, %j, %A, %W) : (index, index, memref<61xf32>, index, memref<64xf32>, memref<3xf32>) -> () 27 | // CHECK: } {dep_distance = 1 : i64, loop_name = "j", unroll = 3 : i32} 28 | } { loop_name = "j", dep_distance = 1 } 29 | } { loop_name = "i", op_name = "s", dep_distance = 0 } 30 | 31 | %pe_array = hcl.unfold( %lj, 3 ) 32 | hcl.to(%W : memref<3xf32>, %pe_array) { pe_index = [0,1,2] } -> memref<1xf32> 33 | %pe0_w = hcl.to(%W: memref<3xf32>, %pe_array) { pe_index = [0] } -> memref<1xf32> 34 | %pe1_w = hcl.to(%pe0_w: memref<1xf32>, %pe_array) { pe_index = [1] } -> memref<1xf32> 35 | return 36 | } 37 | } -------------------------------------------------------------------------------- /test/Transforms/compute/thread_binding.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt -opt %s | FileCheck %s 5 | 6 | module { 7 | func.func @vector_add(%A: memref<256xf32>, %B: memref<256xf32>, %C: memref<256xf32>) 8 | { 9 | %s = hcl.create_op_handle "s" 10 | %li = hcl.create_loop_handle %s, "i" 11 | // CHECK: affine.for %arg3 = 0 to 4 { 12 | // CHECK: affine.for %arg4 = 0 to 64 { 13 | affine.for %i = 0 to 256 { 14 | %a = affine.load %A[%i] : memref<256xf32> 15 | %b = affine.load %B[%i] : memref<256xf32> 16 | %sum = arith.addf %a, %b : f32 17 | affine.store %sum, %C[%i] : memref<256xf32> 18 | // CHECK: } {loop_name = "i.inner", thread_axis = 3 : i32} 19 | // CHECK: } {loop_name = "i.outer", op_name = "s", thread_axis = 0 : i32} 20 | } { loop_name = "i", op_name = "s" } 21 | 22 | %li_outer, %li_inner = hcl.split (%li, 64) 23 | hcl.bind (%li_outer, "BlockIdxX") 24 | hcl.bind (%li_inner, "ThreadIdxX") 25 | return 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/Transforms/compute/tiling.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt -opt %s | FileCheck %s 5 | 6 | module { 7 | func.func @matrix_multiply(%A: memref<1024x512xf32>, %B: memref<512x1024xf32>, %C: memref<1024x1024xf32>) 8 | { 9 | %s = hcl.create_op_handle "s" 10 | %li = hcl.create_loop_handle %s, "i" 11 | %lj = hcl.create_loop_handle %s, "j" 12 | %lk = hcl.create_loop_handle %s, "k" 13 | // CHECK: affine.for %arg3 = 0 to 8 { 14 | // CHECK: affine.for %arg4 = 0 to 8 { 15 | // CHECK: affine.for %arg5 = 0 to 2 { 16 | // CHECK: affine.for %arg6 = 0 to 2 { 17 | // CHECK: affine.for %arg7 = 0 to 2 { 18 | // CHECK: affine.for %arg8 = 0 to 2 { 19 | // CHECK: affine.for %arg9 = 0 to 64 { 20 | // CHECK: affine.for %arg10 = 0 to 64 { 21 | // CHECK: affine.for %arg11 = 0 to 16 { 22 | // CHECK: affine.for %arg12 = 0 to 8 { 23 | affine.for %i = 0 to 1024 { 24 | affine.for %j = 0 to 1024 { 25 | affine.for %k = 0 to 512 { 26 | %a = affine.load %A[%i, %k] : memref<1024x512xf32> 27 | %b = affine.load %B[%k, %j] : memref<512x1024xf32> 28 | %c = affine.load %C[%i, %j] : memref<1024x1024xf32> 29 | %prod = arith.mulf %a, %b : f32 30 | %sum = arith.addf %prod, %c: f32 31 | affine.store %sum, %C[%i, %j] : memref<1024x1024xf32> 32 | // CHECK: } {loop_name = "k.inner", unroll = 16 : i32} 33 | // CHECK: } {loop_name = "k.outer", pipeline_ii = 1 : i32} 34 | // CHECK: } {loop_name = "j.inner", parallel = 1 : i32} 35 | } { loop_name = "k" } 36 | } { loop_name = "j" } 37 | } { loop_name = "i", op_name = "s" } 38 | %li_outer, %li_inner = hcl.split (%li, 16) 39 | %li_in_out, %li_in_in = hcl.split (%li_inner, 4) // nest with split 40 | %li_out_out, %li_out_in = hcl.split (%li_outer, 8) // multiple split 41 | %lj_out, %lj_in, %lk_out, %lk_in = hcl.tile (%lj, %lk, 16, 8) // split & tile 42 | %l14, %l15, %l16, %l17 = hcl.tile (%li_in_out, %li_in_in, 2, 2) // nest with split (failed) 43 | hcl.unroll (%lk_in, 16) // unroll 44 | hcl.pipeline (%lk_out, 1) // pipeline 45 | hcl.parallel (%lj_in) // parallel 46 | return 47 | } 48 | } -------------------------------------------------------------------------------- /test/Transforms/compute/types.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt -opt %s | FileCheck %s 5 | 6 | module { 7 | // CHECK: func @test(%arg0: memref<1024x512x!hcl.Fixed<12, 6>>, %arg1: memref<512x1024x!hcl.UFixed<12, 2>>) { 8 | func.func @test(%A: memref<1024x512x!hcl.Fixed<12,6>>, %B: memref<512x1024x!hcl.UFixed<12,2>>) 9 | { 10 | affine.for %i = 0 to 1024 { 11 | affine.for %j = 0 to 1024 { 12 | %a = affine.load %A[%i, %j] : memref<1024x512x!hcl.Fixed<12,6>> 13 | %b = affine.load %B[%i, %j] : memref<512x1024x!hcl.UFixed<12,2>> 14 | } 15 | } 16 | return 17 | } 18 | } -------------------------------------------------------------------------------- /test/Transforms/datatype/anywidth-skip.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt %s --lower-anywidth-integer 5 | module { 6 | func.func @kernel(%arg0: memref<4x4xf32>, %arg1: f32, %arg2: f32) -> memref<4x4xf32> attributes {"top"} { 7 | return %arg0 : memref<4x4xf32> 8 | } 9 | } -------------------------------------------------------------------------------- /test/Transforms/datatype/anywidth-unsigned.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt %s --lower-anywidth-integer 5 | module { 6 | func.func @top(%arg0: memref<10xi32>) -> memref<10xi2> attributes {itypes = "u", otypes = "u", llvm.emit_c_interface, top} { 7 | %0 = memref.alloc() {name = "B", unsigned} : memref<10xi2> 8 | affine.for %arg1 = 0 to 10 { 9 | %1 = affine.load %arg0[%arg1] {from = "compute_0", unsigned} : memref<10xi32> 10 | %c1_i32 = arith.constant 1 : i32 11 | %2 = arith.addi %1, %c1_i32 {unsigned} : i32 12 | %3 = arith.trunci %2 : i32 to i2 13 | affine.store %3, %0[%arg1] {to = "B"} : memref<10xi2> 14 | } {loop_name = "x", op_name = "B"} 15 | return %0 : memref<10xi2> 16 | } 17 | } -------------------------------------------------------------------------------- /test/Transforms/datatype/anywidthint.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt %s --lower-anywidth-integer 5 | module { 6 | func.func @top_vadd(%arg0: memref<10xi10>, %arg1: memref<10xi10>) -> memref<10xi10> attributes {"top"} { 7 | %0 = memref.alloc() {name = "compute_2"} : memref<10xi10> 8 | affine.for %arg2 = 0 to 10 { 9 | %1 = affine.load %arg0[%arg2] {from = "compute_0"} : memref<10xi10> 10 | %2 = affine.load %arg1[%arg2] {from = "compute_1"} : memref<10xi10> 11 | %3 = arith.addi %1, %2 : i10 12 | affine.store %3, %0[%arg2] {to = "compute_2"} : memref<10xi10> 13 | } {loop_name = "x", op_name = "compute_2"} 14 | return %0 : memref<10xi10> 15 | } 16 | } -------------------------------------------------------------------------------- /test/Transforms/datatype/fti_funcsig.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt %s --fixed-to-integer | FileCheck %s 5 | 6 | module { 7 | func.func private @conv1(memref<1x1x28x28xf32>, memref<6x1x5x5xf32>) -> memref<1x6x28x28xi8> 8 | func.func private @relu(memref<1x6x28x28xi8>) -> memref<1x6x28x28xi8> 9 | func.func private @pool(memref<1x6x28x28xi8>) -> memref<1x6x14x14xi8> 10 | func.func private @conv2(memref<1x6x14x14xi8>, memref<16x6x5x5xf32>) -> memref<1x16x10x10xi8> 11 | func.func private @relu_1(memref<1x16x10x10xi8>) -> memref<1x16x10x10xi8> 12 | func.func private @pool_1(memref<1x16x10x10xi8>) -> memref<1x16x5x5xi8> 13 | func.func private @flatten(memref<1x16x5x5xi8>) -> memref<1x400xi8> 14 | func.func private @fc1(memref<1x400xi8>, memref<120x400xf32>, memref<1x120xf32>) -> memref<1x120x!hcl.Fixed<8, 4>> 15 | func.func private @relu_2(memref<1x120x!hcl.Fixed<8, 4>>) -> memref<1x120x!hcl.Fixed<8, 4>> 16 | func.func private @fc2(memref<1x120x!hcl.Fixed<8, 4>>, memref<84x120xf32>, memref<1x84xf32>) -> memref<1x84x!hcl.Fixed<8, 4>> 17 | func.func private @relu_3(memref<1x84x!hcl.Fixed<8, 4>>) -> memref<1x84x!hcl.Fixed<8, 4>> 18 | func.func private @fc3(memref<1x84x!hcl.Fixed<8, 4>>, memref<10x84xf32>, memref<1x10xf32>) -> memref<1x10xf32> 19 | func.func @main() { 20 | %0 = memref.alloc() : memref<1x1x28x28xf32> 21 | %1 = memref.alloc() : memref<6x1x5x5xf32> 22 | %2 = memref.alloc() : memref<16x6x5x5xf32> 23 | %3 = memref.alloc() : memref<120x400xf32> 24 | %4 = memref.alloc() : memref<1x120xf32> 25 | %5 = memref.alloc() : memref<84x120xf32> 26 | %6 = memref.alloc() : memref<1x84xf32> 27 | %7 = memref.alloc() : memref<10x84xf32> 28 | %8 = memref.alloc() : memref<1x10xf32> 29 | %9 = call @conv1(%0, %1) : (memref<1x1x28x28xf32>, memref<6x1x5x5xf32>) -> memref<1x6x28x28xi8> 30 | %10 = call @relu(%9) : (memref<1x6x28x28xi8>) -> memref<1x6x28x28xi8> 31 | %11 = call @pool(%10) : (memref<1x6x28x28xi8>) -> memref<1x6x14x14xi8> 32 | %12 = call @conv2(%11, %2) : (memref<1x6x14x14xi8>, memref<16x6x5x5xf32>) -> memref<1x16x10x10xi8> 33 | %13 = call @relu_1(%12) : (memref<1x16x10x10xi8>) -> memref<1x16x10x10xi8> 34 | %14 = call @pool_1(%13) : (memref<1x16x10x10xi8>) -> memref<1x16x5x5xi8> 35 | %15 = call @flatten(%14) : (memref<1x16x5x5xi8>) -> memref<1x400xi8> 36 | %16 = call @fc1(%15, %3, %4) : (memref<1x400xi8>, memref<120x400xf32>, memref<1x120xf32>) -> memref<1x120x!hcl.Fixed<8, 4>> 37 | // CHECK: call @fc1(%6, %alloc_2, %alloc_3) : (memref<1x400xi8>, memref<120x400xf32>, memref<1x120xf32>) -> memref<1x120xi8> 38 | %17 = call @relu_2(%16) : (memref<1x120x!hcl.Fixed<8, 4>>) -> memref<1x120x!hcl.Fixed<8, 4>> 39 | // CHECK: call @relu_2(%7) : (memref<1x120xi8>) -> memref<1x120xi8> 40 | %18 = call @fc2(%17, %5, %6) : (memref<1x120x!hcl.Fixed<8, 4>>, memref<84x120xf32>, memref<1x84xf32>) -> memref<1x84x!hcl.Fixed<8, 4>> 41 | // CHECK: call @fc2(%8, %alloc_4, %alloc_5) : (memref<1x120xi8>, memref<84x120xf32>, memref<1x84xf32>) -> memref<1x84xi8> 42 | %19 = call @relu_3(%18) : (memref<1x84x!hcl.Fixed<8, 4>>) -> memref<1x84x!hcl.Fixed<8, 4>> 43 | // CHECK: call @relu_3(%9) : (memref<1x84xi8>) -> memref<1x84xi8> 44 | %20 = call @fc3(%19, %7, %8) : (memref<1x84x!hcl.Fixed<8, 4>>, memref<10x84xf32>, memref<1x10xf32>) -> memref<1x10xf32> 45 | // CHECK: call @fc3(%10, %alloc_6, %alloc_7) : (memref<1x84xi8>, memref<10x84xf32>, memref<1x10xf32>) -> memref<1x10xf32> 46 | return 47 | } 48 | } -------------------------------------------------------------------------------- /test/Transforms/interface/customization.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt -opt %s | FileCheck %s 5 | 6 | // CHECK: #map = affine_map<(d0, d1) -> (0, d1, d0, 0)> 7 | module { 8 | hcl.customization @gemm_opt( 9 | %A: memref, 10 | %B: memref, 11 | %C: memref, 12 | %s: !hcl.OpHandle, 13 | %i: !hcl.LoopHandle, 14 | %j: !hcl.LoopHandle, 15 | %k: !hcl.LoopHandle 16 | ) { 17 | hcl.pipeline(%j, 1) 18 | hcl.partition(%A: memref, "CompletePartition", 2) 19 | hcl.partition(%B: memref, "CompletePartition", 2) 20 | hcl.partition(%C: memref, "CompletePartition", 2) 21 | hcl.end 22 | } 23 | func.func @top(%A: memref<64x32xi32>, %B: memref<32x64xi32>, %C: memref<64x64xi32>) -> memref<64x64xi32> 24 | { 25 | %s1 = hcl.create_op_handle "s1" 26 | %i1 = hcl.create_loop_handle %s1, "i1" 27 | %j1 = hcl.create_loop_handle %s1, "j1" 28 | %k1 = hcl.create_loop_handle %s1, "k1" 29 | // D = A * B 30 | %D = memref.alloc() : memref<64x64xi32> 31 | affine.for %i = 0 to 64 { 32 | affine.for %j = 0 to 64 { 33 | affine.for %k = 0 to 32 { 34 | // CHECK: affine.load %[[ARG:.*]][%[[I:.*]], %[[K:.*]]] : memref<64x32xi32, #map> 35 | %a = affine.load %A[%i, %k] : memref<64x32xi32> 36 | %b = affine.load %B[%k, %j] : memref<32x64xi32> 37 | %c = affine.load %D[%i, %j] : memref<64x64xi32> 38 | %prod = arith.muli %a, %b : i32 39 | %sum = arith.addi %prod, %c: i32 40 | affine.store %sum, %D[%i, %j] : memref<64x64xi32> 41 | } { loop_name = "k1" } 42 | // CHECK: } {loop_name = "j1", pipeline_ii = 1 : i32} 43 | } { loop_name = "j1" } 44 | } { loop_name = "i1", op_name = "s1" } 45 | %s2 = hcl.create_op_handle "s2" 46 | %i2 = hcl.create_loop_handle %s2, "i2" 47 | %j2 = hcl.create_loop_handle %s2, "j2" 48 | %k2 = hcl.create_loop_handle %s2, "k2" 49 | // E = C * D 50 | %E = memref.alloc() : memref<64x64xi32> 51 | affine.for %i = 0 to 64 { 52 | affine.for %j = 0 to 64 { 53 | affine.for %k = 0 to 64 { 54 | %c = affine.load %C[%i, %k] : memref<64x64xi32> 55 | %d = affine.load %D[%k, %j] : memref<64x64xi32> 56 | %e = affine.load %E[%i, %j] : memref<64x64xi32> 57 | %prod = arith.muli %c, %d : i32 58 | %sum = arith.addi %prod, %e: i32 59 | affine.store %sum, %E[%i, %j] : memref<64x64xi32> 60 | } { loop_name = "k2" } 61 | // CHECK: } {loop_name = "j2", pipeline_ii = 1 : i32} 62 | } { loop_name = "j2" } 63 | } { loop_name = "i2", op_name = "s2" } 64 | hcl.apply @gemm_opt(%A, %B, %D, %s1, %i1, %j1, %k1) : (memref<64x32xi32>, memref<32x64xi32>, memref<64x64xi32>, !hcl.OpHandle, !hcl.LoopHandle, !hcl.LoopHandle, !hcl.LoopHandle) -> () 65 | hcl.apply @gemm_opt(%C, %D, %E, %s2, %i2, %j2, %k2) : (memref<64x64xi32>, memref<64x64xi32>, memref<64x64xi32>, !hcl.OpHandle, !hcl.LoopHandle, !hcl.LoopHandle, !hcl.LoopHandle) -> () 66 | return %E : memref<64x64xi32> 67 | } 68 | } -------------------------------------------------------------------------------- /test/Transforms/interface/layout.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt -opt %s | FileCheck %s 5 | 6 | module { 7 | func.func @gemm(%A: memref<1024x512xf32>, %B: memref<512x1024xf32>) -> memref<1024x1024xf32> 8 | { 9 | %C = memref.alloc() : memref<1024x1024xf32> 10 | // CHECK: affine.for %[[ARG:.*]] = 0 to 1024 { 11 | affine.for %i = 0 to 1024 { 12 | // CHECK: affine.for %[[ARG1:.*]] = 0 to 1024 { 13 | affine.for %j = 0 to 1024 { 14 | // CHECK: affine.for %[[ARG2:.*]] = 0 to 512 { 15 | affine.for %k = 0 to 512 { 16 | %a = affine.load %A[%i, %k] : memref<1024x512xf32> 17 | // CHECK: affine.load %[[ARG3:.*]][%[[ARG1:.*]], %[[ARG2:.*]]] : memref<1024x512xf32> 18 | %b = affine.load %B[%k, %j] : memref<512x1024xf32> 19 | %c = affine.load %C[%i, %j] : memref<1024x1024xf32> 20 | %prod = arith.mulf %a, %b : f32 21 | %sum = arith.addf %prod, %c: f32 22 | affine.store %sum, %C[%i, %j] : memref<1024x1024xf32> 23 | } { loop_name = "k", reduction = 1 : i32} 24 | } { loop_name = "j" } 25 | } { loop_name = "i", stage_name = "s" } 26 | hcl.reform(%B : memref<512x1024xf32>) {layout=affine_map<(d0,d1)->(d1,d0)>} -> memref<1024x512xf32> 27 | return %C : memref<1024x1024xf32> 28 | } 29 | } -------------------------------------------------------------------------------- /test/Transforms/interface/move_return.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt %s --return-to-input 5 | module { 6 | func.func @top(%arg0: memref<10xi32>) -> (memref<10xi32>, memref<10xi32>) attributes {itypes = "s", otypes = "ss", top} { 7 | %0 = memref.alloc() {name = "compute_1"} : memref<10xi32> 8 | affine.for %arg1 = 0 to 10 { 9 | %2 = affine.load %arg0[%arg1] {from = "compute_0"} : memref<10xi32> 10 | %c1_i32 = arith.constant 1 : i32 11 | %3 = arith.addi %2, %c1_i32 : i32 12 | affine.store %3, %0[%arg1] {to = "compute_1"} : memref<10xi32> 13 | } {loop_name = "x", op_name = "compute_1"} 14 | %1 = memref.alloc() {name = "compute_2"} : memref<10xi32> 15 | affine.for %arg1 = 0 to 10 { 16 | %2 = affine.load %arg0[%arg1] {from = "compute_0"} : memref<10xi32> 17 | %c2_i32 = arith.constant 2 : i32 18 | %3 = arith.addi %2, %c2_i32 : i32 19 | affine.store %3, %1[%arg1] {to = "compute_2"} : memref<10xi32> 20 | } {loop_name = "x", op_name = "compute_2"} 21 | return %0, %1 : memref<10xi32>, memref<10xi32> 22 | } 23 | } -------------------------------------------------------------------------------- /test/Transforms/interface/move_return_func_call.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt %s --return-to-input 5 | module { 6 | func.func @gemm(%arg0: memref<32x32xi32>, %arg1: memref<32x32xi32>) -> memref<32x32xi32> { 7 | %0 = memref.alloc() {name = "C"} : memref<32x32xi32> 8 | %c0_i32 = arith.constant 0 : i32 9 | linalg.fill ins(%c0_i32 : i32) outs(%0 : memref<32x32xi32>) 10 | affine.for %arg2 = 0 to 32 { 11 | affine.for %arg3 = 0 to 32 { 12 | affine.for %arg4 = 0 to 32 { 13 | %1 = affine.load %arg0[%arg2, %arg4] {from = "A"} : memref<32x32xi32> 14 | %2 = affine.load %arg1[%arg4, %arg3] {from = "B"} : memref<32x32xi32> 15 | %3 = arith.muli %1, %2 : i32 16 | %4 = affine.load %0[%arg2, %arg3] {from = "C"} : memref<32x32xi32> 17 | %5 = arith.addi %4, %3 : i32 18 | affine.store %5, %0[%arg2, %arg3] {to = "C"} : memref<32x32xi32> 19 | } {loop_name = "k"} 20 | } {loop_name = "j"} 21 | } {loop_name = "i", op_name = "S_i_j_k"} 22 | return %0 : memref<32x32xi32> 23 | } 24 | // CHECK-LABEL: func @top(%arg0: memref<32x32xi32>, %arg1: memref<32x32xi32>, %arg2: memref<32x32xi32>) attributes {top} { 25 | func.func @top(%arg0: memref<32x32xi32>, %arg1: memref<32x32xi32>) -> memref<32x32xi32> attributes {top} { 26 | %0 = call @gemm(%arg0, %arg1) : (memref<32x32xi32>, memref<32x32xi32>) -> memref<32x32xi32> 27 | // CHECK: memref.copy 28 | return %0 : memref<32x32xi32> 29 | // CHECK: return 30 | } 31 | } -------------------------------------------------------------------------------- /test/Transforms/interface/outline.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt -opt %s | FileCheck %s 5 | 6 | module { 7 | func.func @top(%arg0: memref<10x32xi32>) -> memref<10x32xi32> attributes {itypes = "s", otypes = "s"} { 8 | %0 = memref.alloc() {name = "C"} : memref<10x32xi32> 9 | %3 = hcl.create_op_handle "C" 10 | %1 = hcl.create_loop_handle %3, "i" 11 | %2 = hcl.create_loop_handle %3, "j" 12 | affine.for %arg1 = 0 to 10 { 13 | affine.for %arg2 = 0 to 32 { 14 | %12 = affine.load %arg0[%arg1, %arg2] {from = "A"} : memref<10x32xi32> 15 | %c1_i32 = arith.constant 1 : i32 16 | %13 = arith.addi %12, %c1_i32 : i32 17 | affine.store %13, %0[%arg1, %arg2] {to = "C"} : memref<10x32xi32> 18 | } {loop_name = "j"} 19 | } {loop_name = "i", op_name = "C"} 20 | %4 = memref.alloc() {name = "D"} : memref<10x32xi32> 21 | %7 = hcl.create_op_handle "D" 22 | %5 = hcl.create_loop_handle %7, "i" 23 | %6 = hcl.create_loop_handle %7, "j" 24 | affine.for %arg1 = 0 to 10 { 25 | affine.for %arg2 = 0 to 32 { 26 | %12 = affine.load %0[%arg1, %arg2] {from = "C"} : memref<10x32xi32> 27 | %c2_i32 = arith.constant 2 : i32 28 | %13 = arith.muli %12, %c2_i32 : i32 29 | affine.store %13, %4[%arg1, %arg2] {to = "D"} : memref<10x32xi32> 30 | } {loop_name = "j"} 31 | } {loop_name = "i", op_name = "D"} 32 | %8 = memref.alloc() {name = "E"} : memref<10x32xi32> 33 | %11 = hcl.create_op_handle "E" 34 | %9 = hcl.create_loop_handle %11, "i" 35 | %10 = hcl.create_loop_handle %11, "j" 36 | affine.for %arg1 = 0 to 10 { 37 | affine.for %arg2 = 0 to 32 { 38 | %12 = affine.load %4[%arg1, %arg2] {from = "D"} : memref<10x32xi32> 39 | %c3_i32 = arith.constant 3 : i32 40 | %13 = arith.muli %12, %c3_i32 : i32 41 | affine.store %13, %8[%arg1, %arg2] {to = "E"} : memref<10x32xi32> 42 | } {loop_name = "j"} 43 | } {loop_name = "i", op_name = "E"} 44 | // CHECK: call @Stage_C 45 | hcl.outline (%3) 46 | // CHECK: call @Stage_D_E 47 | hcl.outline (%7, %11) 48 | return %8 : memref<10x32xi32> 49 | } 50 | func.func @top2(%arg0: memref<10x32xi32>) -> memref<10x32xi32> attributes {itypes = "s", otypes = "s"} { 51 | %0 = memref.alloc() {name = "C1"} : memref<10x32xi32> 52 | %3 = hcl.create_op_handle "C1" 53 | %1 = hcl.create_loop_handle %3, "i" 54 | %2 = hcl.create_loop_handle %3, "j" 55 | affine.for %arg1 = 0 to 10 { 56 | affine.for %arg2 = 0 to 32 { 57 | %12 = affine.load %arg0[%arg1, %arg2] {from = "A1"} : memref<10x32xi32> 58 | %c1_i32 = arith.constant 1 : i32 59 | %13 = arith.addi %12, %c1_i32 : i32 60 | affine.store %13, %0[%arg1, %arg2] {to = "C1"} : memref<10x32xi32> 61 | } {loop_name = "j"} 62 | } {loop_name = "i", op_name = "C1"} 63 | %4 = memref.alloc() {name = "D"} : memref<10x32xi32> 64 | %7 = hcl.create_op_handle "D1" 65 | %5 = hcl.create_loop_handle %7, "i" 66 | %6 = hcl.create_loop_handle %7, "j" 67 | affine.for %arg1 = 0 to 10 { 68 | affine.for %arg2 = 0 to 32 { 69 | %12 = affine.load %0[%arg1, %arg2] {from = "C1"} : memref<10x32xi32> 70 | %c2_i32 = arith.constant 2 : i32 71 | %13 = arith.muli %12, %c2_i32 : i32 72 | affine.store %13, %4[%arg1, %arg2] {to = "D1"} : memref<10x32xi32> 73 | } {loop_name = "j"} 74 | } {loop_name = "i", op_name = "D1"} 75 | %8 = memref.alloc() {name = "E1"} : memref<10x32xi32> 76 | %11 = hcl.create_op_handle "E1" 77 | %9 = hcl.create_loop_handle %11, "i" 78 | %10 = hcl.create_loop_handle %11, "j" 79 | affine.for %arg1 = 0 to 10 { 80 | affine.for %arg2 = 0 to 32 { 81 | %12 = affine.load %4[%arg1, %arg2] {from = "D1"} : memref<10x32xi32> 82 | %c3_i32 = arith.constant 3 : i32 83 | %13 = arith.muli %12, %c3_i32 : i32 84 | affine.store %13, %8[%arg1, %arg2] {to = "E1"} : memref<10x32xi32> 85 | } {loop_name = "j"} 86 | } {loop_name = "i", op_name = "E1"} 87 | // CHECK: call @Stage_C1 88 | hcl.outline (%3) 89 | // CHECK: call @Stage_C1 90 | hcl.outline (%7) {unify="Stage_C1"} 91 | // CHECK: affine.for %[[ARG:.*]] = 0 to 10 { 92 | // CHECK: affine.for %[[ARG1:.*]] = 0 to 32 { 93 | // CHECK: call @Stage_E1 94 | hcl.outline (%11) {axis = "j"} 95 | return %8 : memref<10x32xi32> 96 | } 97 | } -------------------------------------------------------------------------------- /test/Transforms/memory/buffer_add.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt -opt %s | FileCheck %s 5 | 6 | module { 7 | func.func @add_buffer_at_axis_0(%A: memref<1024x1024xf32>, %B: memref<1024x1024xf32>, %C: memref<1024x1024xf32>) 8 | { 9 | %s = hcl.create_op_handle "s" 10 | %l1 = hcl.create_loop_handle %s, "i" 11 | %l2 = hcl.create_loop_handle %s, "j" 12 | affine.for %i = 0 to 1024 { 13 | // CHECK: %[[MEM:.*]] = memref.alloc() : memref<1024xf32> 14 | // CHECK: %cst = arith.constant 0.000000e+00 : f32 15 | // CHECK: affine.for %[[VAR:.*]] = 0 to 1024 { 16 | // CHECK: affine.store %cst, %[[MEM]][%[[VAR]]] : memref<1024xf32> 17 | // CHECK: } {buffer, loop_name = "j_init", pipeline_ii = 1 : i32} 18 | // CHECK: affine.for %[[VAR]] = 0 to 1024 19 | affine.for %j = 0 to 1024 { 20 | // B[i, j] = A[i, j] + 1 21 | %a = affine.load %A[%i, %j] : memref<1024x1024xf32> 22 | %cst = arith.constant 1.0 : f32 23 | %sum = arith.addf %a, %cst: f32 //register 24 | // CHECK: affine.store {{.*}}, %[[MEM]][%[[VAR]]] : memref<1024xf32> 25 | affine.store %sum, %B[%i, %j] : memref<1024x1024xf32> 26 | } { loop_name = "j" } 27 | // CHECK: affine.for %[[VAR]] = 0 to 1024 { 28 | // CHECK: %[[RES:.*]] = affine.load %[[MEM]][%[[VAR]]] : memref<1024xf32> 29 | // CHECK: affine.store %[[RES]], {{.*}}[{{.*}}, %[[VAR]]] : memref<1024x1024xf32> 30 | // CHECK: } {buffer, loop_name = "j_back", pipeline_ii = 1 : i32} 31 | } { loop_name = "i", op_name = "s" } 32 | %buf = hcl.buffer_at(%B: memref<1024x1024xf32>, %l1) -> memref<1024xf32> 33 | return 34 | } 35 | // Notice: buffer_at cannot apply to the inner-most non-reduction loop 36 | // func @add_buffer_at_axis_1(%A: memref<1024x1024xf32>, %B: memref<1024x1024xf32>, %C: memref<1024x1024xf32>) 37 | // { 38 | // %s = hcl.create_op_handle "s" 39 | // %l1 = hcl.create_loop_handle %s, "i" 40 | // %l2 = hcl.create_loop_handle %s, "j" 41 | // affine.for %i = 0 to 1024 { 42 | // affine.for %j = 0 to 1024 { 43 | // // B[i, j] = A[i, j] + 1 44 | // %a = affine.load %A[%i, %j] : memref<1024x1024xf32> 45 | // %cst = arith.constant 1.0 : f32 46 | // %sum = arith.addf %a, %cst: f32 //register 47 | // affine.store %sum, %B[%i, %j] : memref<1024x1024xf32> 48 | // } { loop_name = "j" } 49 | // } { loop_name = "i", op_name = "s" } 50 | // // expected-error@+1 {{Cannot buffer at the inner-most loop: axis=1 inner-most axis=1}} 51 | // %buf = hcl.buffer_at(%B: memref<1024x1024xf32>, %l2) -> memref<1xf32> 52 | // return 53 | // } 54 | } -------------------------------------------------------------------------------- /test/Transforms/memory/partition.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt -opt %s | FileCheck %s 5 | 6 | // CHECK: #map = affine_map<(d0, d1) -> (d0 mod 4, d1 mod 4, d0 floordiv 4, d1 floordiv 4)> 7 | // CHECK: #map1 = affine_map<(d0, d1) -> (d0 floordiv 256, d1 floordiv 512, d0 mod 256, d1 mod 512)> 8 | // CHECK: #map2 = affine_map<(d0, d1) -> (d0, 0, 0, d1)> 9 | module { 10 | func.func @matrix_multiply(%A: memref<1024x1024xf32>, %B: memref<1024x1024xf32>, %C: memref<1024x1024xf32>) -> memref<1024x1024xf32> 11 | { 12 | %s = hcl.create_op_handle "s" 13 | %l1 = hcl.create_loop_handle %s, "i" 14 | %l2 = hcl.create_loop_handle %s, "j" 15 | %l3 = hcl.create_loop_handle %s, "k" 16 | affine.for %i = 0 to 1024 { 17 | affine.for %j = 0 to 1024 { 18 | affine.for %k = 0 to 1024 { 19 | %a = affine.load %A[%i, %k] : memref<1024x1024xf32> 20 | %b = affine.load %B[%k, %j] : memref<1024x1024xf32> 21 | %c = affine.load %C[%i, %j] : memref<1024x1024xf32> 22 | %prod = arith.mulf %a, %b : f32 23 | %sum = arith.addf %prod, %c: f32 24 | affine.store %sum, %C[%i, %j] : memref<1024x1024xf32> 25 | } { loop_name = "k" } 26 | } { loop_name = "j" } 27 | } { loop_name = "i", op_name = "s" } 28 | hcl.partition(%A: memref<1024x1024xf32>, "CyclicPartition", 0, 4) 29 | hcl.partition(%B: memref<1024x1024xf32>, "BlockPartition", 2, 2) 30 | hcl.partition(%B: memref<1024x1024xf32>, "BlockPartition", 1, 4) 31 | hcl.partition(%C: memref<1024x1024xf32>, "CompletePartition", 1) 32 | // CHECK: return %arg2 : memref<1024x1024xf32, #map2> 33 | return %C : memref<1024x1024xf32> 34 | } 35 | } -------------------------------------------------------------------------------- /test/Transforms/template/gemm.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt -opt %s | FileCheck %s 5 | module { 6 | // define a customization template 7 | hcl.customization @gemm_opt( 8 | %AA: memref, 9 | %BB: memref, 10 | %CC: memref, 11 | %i: !hcl.LoopHandle, 12 | %j: !hcl.LoopHandle, 13 | %k: !hcl.LoopHandle 14 | ) { 15 | hcl.pipeline(%j, 1) 16 | hcl.partition(%AA: memref, "CompletePartition", 2) 17 | hcl.partition(%BB: memref, "CompletePartition", 2) 18 | hcl.partition(%CC: memref, "CompletePartition", 2) 19 | hcl.end 20 | } 21 | 22 | // CHECK: #map = affine_map<(d0, d1) -> (0, d1, d0, 0)> 23 | func.func @top(%A: memref<64x32xi32>, %B: memref<32x64xi32>, %C: memref<64x64xi32>) -> memref<64x64xi32> 24 | { 25 | %s1 = hcl.create_op_handle "s1" 26 | %i1 = hcl.create_loop_handle %s1, "i1" 27 | %j1 = hcl.create_loop_handle %s1, "j1" 28 | %k1 = hcl.create_loop_handle %s1, "k1" 29 | // D = A * B 30 | %D = memref.alloc() : memref<64x64xi32> 31 | affine.for %i = 0 to 64 { 32 | affine.for %j = 0 to 64 { 33 | affine.for %k = 0 to 32 { 34 | %a = affine.load %A[%i, %k] : memref<64x32xi32> 35 | %b = affine.load %B[%k, %j] : memref<32x64xi32> 36 | %c = affine.load %D[%i, %j] : memref<64x64xi32> 37 | %prod = arith.muli %a, %b : i32 38 | %sum = arith.addi %prod, %c: i32 39 | affine.store %sum, %D[%i, %j] : memref<64x64xi32> 40 | } { loop_name = "k1" } 41 | // CHECK: pipeline_ii = 1 : i32 42 | } { loop_name = "j1" } 43 | } { loop_name = "i1", op_name = "s1" } 44 | %s2 = hcl.create_op_handle "s2" 45 | %i2 = hcl.create_loop_handle %s2, "i2" 46 | %j2 = hcl.create_loop_handle %s2, "j2" 47 | %k2 = hcl.create_loop_handle %s2, "k2" 48 | // E = C * D 49 | %E = memref.alloc() : memref<64x64xi32> 50 | affine.for %i = 0 to 64 { 51 | affine.for %j = 0 to 64 { 52 | affine.for %k = 0 to 64 { 53 | %c = affine.load %C[%i, %k] : memref<64x64xi32> 54 | %d = affine.load %D[%k, %j] : memref<64x64xi32> 55 | %e = affine.load %E[%i, %j] : memref<64x64xi32> 56 | %prod = arith.muli %c, %d : i32 57 | %sum = arith.addi %prod, %e: i32 58 | affine.store %sum, %E[%i, %j] : memref<64x64xi32> 59 | } { loop_name = "k2" } 60 | // CHECK: pipeline_ii = 1 : i32 61 | } { loop_name = "j2" } 62 | } { loop_name = "i2", op_name = "s2" } 63 | 64 | // apply the customization template 65 | hcl.apply @gemm_opt(%A, %B, %D, %i1, %j1, %k1) : (memref<64x32xi32>, memref<32x64xi32>, memref<64x64xi32>, !hcl.LoopHandle, !hcl.LoopHandle, !hcl.LoopHandle) -> () 66 | hcl.apply @gemm_opt(%C, %D, %E, %i2, %j2, %k2) : (memref<64x64xi32>, memref<64x64xi32>, memref<64x64xi32>, !hcl.LoopHandle, !hcl.LoopHandle, !hcl.LoopHandle) -> () 67 | return %E : memref<64x64xi32> 68 | } 69 | } -------------------------------------------------------------------------------- /test/Translation/mm.mlir: -------------------------------------------------------------------------------- 1 | // Copyright HeteroCL authors. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // RUN: hcl-opt --opt -jit %s | FileCheck %s 5 | 6 | module { 7 | 8 | memref.global "private" @gv0 : memref<4x4xf32> = dense<[[1.0, 2.0, 3.0, 4.0], [1.0, 2.0, 3.0, 4.0], [1.0, 2.0, 3.0, 4.0], [1.0, 2.0, 3.0, 4.0]]> 9 | memref.global "private" @gv1 : memref<4x4xf32> = dense<[[1.0, 2.0, 3.0, 4.0], [1.0, 2.0, 3.0, 4.0], [1.0, 2.0, 3.0, 4.0], [1.0, 2.0, 3.0, 4.0]]> 10 | memref.global "private" @gv2 : memref<4x4xf32> = dense<[[1.0, 2.0, 3.0, 4.0], [1.0, 2.0, 3.0, 4.0], [1.0, 2.0, 3.0, 4.0], [1.0, 2.0, 3.0, 4.0]]> 11 | 12 | func.func @matrix_multiply(%A: memref<4x4xf32>, %B: memref<4x4xf32>, %C: memref<4x4xf32>) 13 | { 14 | %s = hcl.create_op_handle "s" 15 | %li = hcl.create_loop_handle %s, "i" 16 | %lj = hcl.create_loop_handle %s, "j" 17 | %lk = hcl.create_loop_handle %s, "k" 18 | // CHECK: llvm.func @matrix_multiply(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: i64, %arg3: i64, %arg4: i64, %arg5: i64, %arg6: i64, %arg7: !llvm.ptr, %arg8: !llvm.ptr, %arg9: i64, %arg10: i64, %arg11: i64, %arg12: i64, %arg13: i64, %arg14: !llvm.ptr, %arg15: !llvm.ptr, %arg16: i64, %arg17: i64, %arg18: i64, %arg19: i64, %arg20: i64) { 19 | affine.for %i = 0 to 4 { 20 | affine.for %j = 0 to 4 { 21 | affine.for %k = 0 to 4 { 22 | %a = affine.load %A[%i, %k] : memref<4x4xf32> 23 | %b = affine.load %B[%k, %j] : memref<4x4xf32> 24 | %c = affine.load %C[%i, %j] : memref<4x4xf32> 25 | %prod = arith.mulf %a, %b : f32 26 | %sum = arith.addf %prod, %c: f32 27 | affine.store %sum, %C[%i, %j] : memref<4x4xf32> 28 | } {loop_name = "k"} 29 | } {loop_name = "j"} 30 | } {loop_name = "i", op_name="s"} 31 | 32 | %li0, %li1 = hcl.split (%li, 2) 33 | %lj0, %lj1 = hcl.split (%lj, 2) 34 | hcl.reorder(%li0, %lj0, %li1,%lj1) 35 | hcl.unroll(%lj1) 36 | hcl.pipeline(%lj1, 1) 37 | return 38 | } 39 | 40 | func.func @top() -> () { 41 | %0 = memref.get_global @gv0 : memref<4x4xf32> 42 | %1 = memref.get_global @gv0 : memref<4x4xf32> 43 | %2 = memref.get_global @gv0 : memref<4x4xf32> 44 | 45 | call @matrix_multiply(%0, %1, %2) : (memref<4x4xf32>, memref<4x4xf32>, memref<4x4xf32>) -> () 46 | return 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /test/lit.cfg.py: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # -*- Python -*- 5 | 6 | import os 7 | import platform 8 | import re 9 | import subprocess 10 | import tempfile 11 | 12 | import lit.formats 13 | import lit.util 14 | 15 | from lit.llvm import llvm_config 16 | from lit.llvm.subst import ToolSubst 17 | from lit.llvm.subst import FindTool 18 | 19 | # Configuration file for the 'lit' test runner. 20 | 21 | # name: The name of this test suite. 22 | config.name = 'HETEROCL' 23 | 24 | config.test_format = lit.formats.ShTest(not llvm_config.use_lit_shell) 25 | 26 | # suffixes: A list of file extensions to treat as test files. 27 | config.suffixes = ['.mlir', '.py'] 28 | 29 | # test_source_root: The root path where tests are located. 30 | config.test_source_root = os.path.dirname(__file__) 31 | 32 | # test_exec_root: The root path where tests should be run. 33 | config.test_exec_root = os.path.join(config.standalone_obj_root, 'test') 34 | 35 | config.substitutions.append(('%PATH%', config.environment['PATH'])) 36 | config.substitutions.append(('%shlibext', config.llvm_shlib_ext)) 37 | 38 | llvm_config.with_system_environment( 39 | ['HOME', 'INCLUDE', 'LIB', 'TMP', 'TEMP']) 40 | 41 | llvm_config.use_default_substitutions() 42 | 43 | # excludes: A list of directories to exclude from the testsuite. The 'Inputs' 44 | # subdirectories contain auxiliary inputs for various tests in their parent 45 | # directories. 46 | config.excludes = ['lit.cfg.py', 'CMakeLists.txt', 'README.txt', 'LICENSE.txt'] 47 | 48 | # Unsupported tests 49 | config.excludes += ['test_llvm.py'] 50 | 51 | # test_source_root: The root path where tests are located. 52 | config.test_source_root = os.path.dirname(__file__) 53 | 54 | # test_exec_root: The root path where tests should be run. 55 | config.test_exec_root = os.path.join(config.standalone_obj_root, 'test') 56 | config.standalone_tools_dir = os.path.join(config.standalone_obj_root, 'bin') 57 | 58 | # Tweak the PATH to include the tools dir. 59 | llvm_config.with_environment('PATH', config.llvm_tools_dir, append_path=True) 60 | 61 | tool_dirs = [config.standalone_tools_dir, config.llvm_tools_dir] 62 | tools = [ 63 | 'hcl-opt', 64 | 'hcl-translate', 65 | ToolSubst('%PYTHON', config.python_executable, unresolved='ignore'), 66 | ] 67 | 68 | llvm_config.add_tool_substitutions(tools, tool_dirs) 69 | 70 | llvm_config.with_environment('PYTHONPATH', [ 71 | os.path.join(config.mlir_binary_dir, 'tools/hcl/python_packages/hcl_core'), 72 | ], append_path=True) 73 | llvm_config.with_environment('LLVM_BUILD_DIR', 74 | os.path.join(config.llvm_tools_dir, ".."), 75 | append_path=True) 76 | -------------------------------------------------------------------------------- /test/lit.site.cfg.py.in: -------------------------------------------------------------------------------- 1 | @LIT_SITE_CFG_IN_HEADER@ 2 | 3 | import sys 4 | 5 | config.host_triple = "@LLVM_HOST_TRIPLE@" 6 | config.target_triple = "@TARGET_TRIPLE@" 7 | config.llvm_src_root = "@LLVM_SOURCE_DIR@" 8 | config.llvm_obj_root = "@LLVM_BINARY_DIR@" 9 | config.llvm_tools_dir = "@LLVM_TOOLS_DIR@" 10 | config.llvm_lib_dir = "@LLVM_LIBS_DIR@" 11 | config.llvm_shlib_dir = "@SHLIBDIR@" 12 | config.llvm_shlib_ext = "@SHLIBEXT@" 13 | config.llvm_exe_ext = "@EXEEXT@" 14 | config.lit_tools_dir = "@LLVM_LIT_TOOLS_DIR@" 15 | config.mlir_binary_dir = "@MLIR_BINARY_DIR@" 16 | config.python_executable = "@Python3_EXECUTABLE@" 17 | config.enable_bindings_python = "@MLIR_ENABLE_BINDINGS_PYTHON@" 18 | config.gold_executable = "@GOLD_EXECUTABLE@" 19 | config.ld64_executable = "@LD64_EXECUTABLE@" 20 | config.enable_shared = @ENABLE_SHARED@ 21 | config.enable_assertions = @ENABLE_ASSERTIONS@ 22 | config.targets_to_build = "@TARGETS_TO_BUILD@" 23 | config.native_target = "@LLVM_NATIVE_ARCH@" 24 | config.llvm_bindings = "@LLVM_BINDINGS@".split(' ') 25 | config.host_os = "@HOST_OS@" 26 | config.host_cc = "@HOST_CC@" 27 | config.host_cxx = "@HOST_CXX@" 28 | config.enable_libcxx = "@LLVM_ENABLE_LIBCXX@" 29 | # Note: ldflags can contain double-quoted paths, so must use single quotes here. 30 | config.host_ldflags = '@HOST_LDFLAGS@' 31 | config.llvm_use_sanitizer = "@LLVM_USE_SANITIZER@" 32 | config.llvm_host_triple = '@LLVM_HOST_TRIPLE@' 33 | config.host_arch = "@HOST_ARCH@" 34 | config.standalone_src_root = "@CMAKE_SOURCE_DIR@" 35 | config.standalone_obj_root = "@CMAKE_BINARY_DIR@" 36 | 37 | # Support substitution of the tools_dir with user parameters. This is 38 | # used when we can't determine the tool dir at configuration time. 39 | try: 40 | config.llvm_tools_dir = config.llvm_tools_dir % lit_config.params 41 | config.llvm_lib_dir = config.llvm_lib_dir % lit_config.params 42 | config.llvm_shlib_dir = config.llvm_shlib_dir % lit_config.params 43 | except KeyError: 44 | e = sys.exc_info()[1] 45 | key, = e.args 46 | lit_config.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key,key)) 47 | 48 | 49 | import lit.llvm 50 | lit.llvm.initialize(lit_config, config) 51 | 52 | # Let the main config do the real work. 53 | lit_config.load_config(config, "@CMAKE_SOURCE_DIR@/test/lit.cfg.py") 54 | -------------------------------------------------------------------------------- /tools/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | add_subdirectory(hcl-opt) 5 | add_subdirectory(hcl-translate) -------------------------------------------------------------------------------- /tools/hcl-opt/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | set(LLVM_LINK_COMPONENTS 5 | Core 6 | Support 7 | nativecodegen 8 | OrcJIT 9 | ) 10 | get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS) 11 | get_property(conversion_libs GLOBAL PROPERTY MLIR_CONVERSION_LIBS) 12 | set(LIBS 13 | ${dialect_libs} 14 | ${conversion_libs} 15 | MLIRExecutionEngine 16 | MLIRLLVMCommonConversion 17 | MLIRLLVMDialect 18 | MLIRLLVMToLLVMIRTranslation 19 | MLIRTargetLLVMIRExport 20 | MLIRIR 21 | MLIROptLib 22 | MLIRHeteroCL 23 | MLIRHCLTransformOps 24 | MLIRHCLConversion 25 | MLIRHCLPasses 26 | ) 27 | add_llvm_executable(hcl-opt hcl-opt.cpp) 28 | 29 | llvm_update_compile_flags(hcl-opt) 30 | target_link_libraries(hcl-opt PRIVATE ${LIBS}) 31 | 32 | mlir_check_all_link_libraries(hcl-opt) 33 | -------------------------------------------------------------------------------- /tools/hcl-translate/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright HeteroCL authors. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | set(LLVM_LINK_COMPONENTS 5 | Support 6 | ) 7 | 8 | get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS) 9 | get_property(translation_libs GLOBAL PROPERTY MLIR_TRANSLATION_LIBS) 10 | 11 | add_llvm_executable(hcl-translate 12 | hcl-translate.cpp 13 | ) 14 | llvm_update_compile_flags(hcl-translate) 15 | 16 | if(OPENSCOP) 17 | target_link_libraries(hcl-translate 18 | PRIVATE 19 | ${dialect_libs} 20 | ${translation_libs} 21 | MLIRIR 22 | MLIRParser 23 | MLIRPass 24 | MLIRSPIRVDialect 25 | MLIRTranslateLib 26 | MLIRSupport 27 | MLIRHCLEmitHLSCpp 28 | MLIRHCLEmitOpenSCoP 29 | MLIRHeteroCL 30 | gmp 31 | ) 32 | else() 33 | target_link_libraries(hcl-translate 34 | PRIVATE 35 | ${dialect_libs} 36 | ${translation_libs} 37 | MLIRIR 38 | MLIRParser 39 | MLIRPass 40 | MLIRSPIRVDialect 41 | MLIRTranslateLib 42 | MLIRSupport 43 | MLIRHCLEmitHLSCpp 44 | MLIRHeteroCL 45 | ) 46 | endif() 47 | 48 | 49 | mlir_check_link_libraries(hcl-translate) 50 | -------------------------------------------------------------------------------- /tools/hcl-translate/hcl-translate.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright HeteroCL authors. All Rights Reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | //===----------------------------------------------------------------------===// 7 | // 8 | // This is a command line utility that translates a file from/to MLIR using one 9 | // of the registered translations. 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #include "hcl/Translation/EmitIntelHLS.h" 14 | #include "hcl/Translation/EmitVivadoHLS.h" 15 | #include "mlir/InitAllTranslations.h" 16 | #include "mlir/Support/LogicalResult.h" 17 | #include "mlir/Tools/mlir-translate/MlirTranslateMain.h" 18 | #ifdef OPENSCOP 19 | #include "hcl/Target/OpenSCoP/ExtractScopStmt.h" 20 | #endif 21 | 22 | #include "hcl/Dialect/HeteroCLDialect.h" 23 | 24 | int main(int argc, char **argv) { 25 | mlir::registerAllTranslations(); 26 | mlir::hcl::registerEmitVivadoHLSTranslation(); 27 | mlir::hcl::registerEmitIntelHLSTranslation(); 28 | #ifdef OPENSCOP 29 | mlir::hcl::registerToOpenScopExtractTranslation(); 30 | #endif 31 | 32 | return failed(mlir::mlirTranslateMain( 33 | argc, argv, "HeteroCL MLIR Dialect Translation Tool")); 34 | } 35 | --------------------------------------------------------------------------------