├── .gitignore ├── CMakeLists.txt ├── HEIR.sh ├── HEIR_full_bench ├── database │ ├── database-2.c │ ├── database-4.c │ └── database-8.c ├── euclid_dist │ ├── euclid_dist-16.c │ ├── euclid_dist-2048.c │ ├── euclid_dist-256.c │ ├── euclid_dist-4096.c │ ├── euclid_dist-512.c │ └── euclid_dist-64.c ├── fibonacci │ ├── fibonacci-16.c │ ├── fibonacci-32.c │ ├── fibonacci-4.c │ ├── fibonacci-64.c │ └── fibonacci-8.c ├── inner_product │ ├── inner_product-16.c │ ├── inner_product-2048.c │ ├── inner_product-256.c │ ├── inner_product-4096.c │ ├── inner_product-512.c │ └── inner_product-64.c ├── min_index │ ├── min_index-16.c │ ├── min_index-2.c │ ├── min_index-32.c │ ├── min_index-4.c │ └── min_index-8.c └── min_value │ ├── min_value-16.c │ ├── min_value-2.c │ ├── min_value-32.c │ ├── min_value-4.c │ └── min_value-8.c ├── HEIR_plot ├── Database │ ├── GenDatabaseResults.sh │ └── plot_database.py ├── EuclidDist │ ├── GenEuclidDistResults.sh │ └── plot_euclid.py ├── Fibonacci │ ├── GenFibonacciResults.sh │ └── plot_fibonacci.py ├── InnerProduct │ ├── GenInnerProductResults.sh │ └── plot_inner.py ├── MinIndex │ ├── GenMinIndexResults.sh │ └── plot_index.py ├── MinValue │ ├── GenMinValueResults.sh │ └── plot_value.py └── README.md ├── LISENCE ├── README.md ├── benchmarks ├── arithmetic │ ├── README.md │ ├── euclid_dist.c │ └── inner_product.c ├── e2e │ ├── README.md │ ├── database.c │ └── kmeans.c └── logic │ ├── README.md │ ├── fibonacci.c │ ├── min_index.c │ └── min_value.c ├── cmake └── modules │ ├── AddHEIR.cmake │ ├── CMakeLists.txt │ └── HEIRConfig.cmake.in ├── format_assistant ├── halo_transmitter.py └── polygeist_eliminator.py ├── include └── heir │ ├── CMakeLists.txt │ ├── IR │ ├── CMakeLists.txt │ └── FHE │ │ ├── CMakeLists.txt │ │ ├── HEIR.td │ │ └── HEIRDialect.h │ └── Passes │ ├── CMakeLists.txt │ ├── arith2heir │ └── LowerArithToHEIR.h │ ├── batching │ └── Batching.h │ ├── branch │ └── Branch.h │ ├── encrypt │ └── Encrypt.h │ ├── func2heir │ └── FuncToHEIR.h │ ├── genparm │ └── GenParm.h │ ├── heir2emitc │ └── LowerHEIRToEmitC.h │ ├── lwe2rlwe │ └── LWEToRLWE.h │ ├── memref2heir │ └── LowerMemrefToHEIR.h │ ├── nary │ └── Nary.h │ ├── slot2coeff │ └── SlotToCoeff.h │ ├── unfold │ └── BranchUnfold.h │ ├── unroll │ └── UnrollLoop.h │ └── vec2memref │ └── PromVecToMemref.h ├── lisences ├── HECO_LISENCE ├── Polygeist_LISENCE └── SEAL_LICENSE └── src ├── CMakeLists.txt ├── IR ├── CMakeLists.txt └── FHE │ ├── CMakeLists.txt │ └── HEIRDialect.cpp └── Passes ├── CMakeLists.txt ├── arith2heir ├── CMakeLists.txt ├── LowerArithToHEIR.cpp └── LowerArithToHEIR.td ├── batching ├── Batching.cpp └── CMakeLists.txt ├── branch ├── Branch.cpp └── CMakeLists.txt ├── encrypt ├── CMakeLists.txt ├── Encrypt.cpp └── Encrypt.td ├── func2heir ├── CMakeLists.txt ├── FuncToHEIR.cpp └── FuncToHEIR.td ├── genparm ├── CMakeLists.txt └── GenParm.cpp ├── heir2emitc ├── CMakeLists.txt ├── LowerHEIRToEmitC.cpp └── LowerHEIRToEmitC.td ├── lwe2rlwe ├── CMakeLists.txt └── LWEToRLWE.cpp ├── memref2heir ├── CMakeLists.txt ├── LowerMemrefToHEIR.cpp └── LowerMemrefToHEIR.td ├── nary ├── CMakeLists.txt └── Nary.cpp ├── slot2coeff ├── CMakeLists.txt └── SlotToCoeff.cpp ├── unfold ├── CMakeLists.txt └── Unfold.cpp ├── unroll ├── CMakeLists.txt └── UnrollLoop.cpp └── vec2memref ├── CMakeLists.txt ├── PromVecToMemref.cpp └── PromVecToMemref.td /.gitignore: -------------------------------------------------------------------------------- 1 | ## Misc 2 | .DS_Store 3 | .idea 4 | 5 | ## vscode stuff 6 | .vscode 7 | .history 8 | *.vsix 9 | 10 | ## CMake stuff 11 | build 12 | cmake-build-debug/ 13 | /test/CMakeFiles/ 14 | /cmake-build* 15 | 16 | ## Python 17 | __pycache__ 18 | *.egg-info 19 | *.pyc 20 | 21 | #Executables 22 | tools 23 | 24 | ######################################################################################## 25 | ## CMake gitignore from https://github.com/github/gitignore/blob/main/CMake.gitignore ## 26 | ######################################################################################## 27 | CMakeLists.txt.user 28 | CMakeCache.txt 29 | CMakeFiles 30 | CMakeScripts 31 | Testing 32 | Makefile 33 | cmake_install.cmake 34 | install_manifest.txt 35 | compile_commands.json 36 | CTestTestfile.cmake 37 | _deps 38 | 39 | #################################################################################### 40 | ## C++ gitignore from https://github.com/github/gitignore/blob/main/C++.gitignore ## 41 | #################################################################################### 42 | 43 | # Prerequisites 44 | *.d 45 | 46 | # Compiled Object files 47 | *.slo 48 | *.lo 49 | *.o 50 | *.obj 51 | 52 | # Precompiled Headers 53 | *.gch 54 | *.pch 55 | 56 | # Compiled Dynamic libraries 57 | *.so 58 | *.dylib 59 | *.dll 60 | 61 | # Fortran module files 62 | *.mod 63 | *.smod 64 | 65 | # Compiled Static libraries 66 | *.lai 67 | *.la 68 | *.a 69 | *.lib 70 | 71 | # Executables 72 | *.exe 73 | *.out 74 | *.app -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | 3 | ######################### 4 | # Project Configuration # 5 | ######################### 6 | 7 | # Only define a project when this CMakeLists.txt is in the "root" (i.e., this is a standtalone build) 8 | if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) 9 | project(HEIR 10 | VERSION 0.1 11 | DESCRIPTION "MLIR-based compiling platform for generalized Fully Homomorphic Encryption" 12 | LANGUAGES CXX C) 13 | set(HEIR_STANDALONE_BUILD TRUE) 14 | endif() 15 | 16 | ########################### 17 | # MLIR/LLVM Configuration # 18 | ########################### 19 | if(HEIR_STANDALONE_BUILD) 20 | 21 | set(CMAKE_BUILD_WITH_INSTALL_NAME_DIR ON) 22 | 23 | # Locate MLIR, which recursively locates LLVM 24 | find_package(MLIR REQUIRED CONFIG) 25 | message(STATUS "Using MLIRConfig.cmake in: ${MLIR_DIR}") 26 | message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") 27 | 28 | set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/bin) 29 | set(LLVM_LIBRARY_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/lib) 30 | 31 | list(APPEND CMAKE_MODULE_PATH "${MLIR_CMAKE_DIR}") 32 | list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") 33 | 34 | include(TableGen) 35 | include(AddLLVM) 36 | include(AddMLIR) 37 | include(HandleLLVMOptions) 38 | 39 | include_directories(${LLVM_INCLUDE_DIRS}) 40 | include_directories(${MLIR_INCLUDE_DIRS}) 41 | include_directories(${PROJECT_SOURCE_DIR}/include) 42 | include_directories(${PROJECT_BINARY_DIR}/include) 43 | link_directories(${LLVM_BUILD_LIBRARY_DIR}) 44 | add_definitions(${LLVM_DEFINITIONS}) 45 | 46 | #TODO (Implementation) Handling of unit-tests, e.g. like in CIRCT https://github.com/llvm/circt/blob/fe1ddfc6e3cd2af7d4fa333897d2a4da8d4521f4/CMakeLists.txt#L84-L121 47 | 48 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY 49 | "${CMAKE_CURRENT_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX}") 50 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin") 51 | 52 | else() # Not a standalone build 53 | #TODO Test out nested builds! 54 | message(WARNING "Non-Standalone build for HEIR is untested/unsupported.") 55 | endif() 56 | 57 | ###################### 58 | # HEIR Configuration # 59 | ###################### 60 | 61 | list(APPEND CMAKE_MODULE_PATH "${MLIR_MAIN_SRC_DIR}/cmake/modules") 62 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules") 63 | include(AddHEIR) 64 | 65 | # Installing the headers and docs needs to depend on generating any public 66 | # tablegen'd targets. 67 | add_custom_target(heir-headers) 68 | set_target_properties(heir-headers PROPERTIES FOLDER "Misc") 69 | add_custom_target(heir-doc) 70 | 71 | # Add MLIR and LLVM headers to the include path 72 | include_directories(${LLVM_INCLUDE_DIRS}) 73 | include_directories(${MLIR_INCLUDE_DIRS}) 74 | 75 | # Add HEIR files to the include path 76 | include_directories(${HEIR_MAIN_INCLUDE_DIR}) 77 | include_directories(${HEIR_INCLUDE_DIR}) 78 | 79 | ############################## 80 | # Compiler Setup (esp. MSVC) 81 | ############################## 82 | 83 | # Global flags aren't good CMAKE style, but these should work across pretty much all compilers 84 | set(CXXFLAGS "--coverage --pedantic-errors -Wall -WError") 85 | 86 | set(CMAKE_CXX_STANDARD 14 CACHE STRING "C++ standard to conform to") 87 | 88 | ################### 89 | # Directory Setup # 90 | ################### 91 | add_subdirectory(include/heir) 92 | add_subdirectory(src) 93 | 94 | install(DIRECTORY include 95 | DESTINATION include 96 | COMPONENT heir-headers 97 | FILES_MATCHING 98 | PATTERN "*.def" 99 | PATTERN "*.h" 100 | PATTERN "*.inc" 101 | PATTERN "*.td" 102 | PATTERN "*.sv" 103 | PATTERN "LICENSE.TXT" 104 | ) 105 | 106 | install(DIRECTORY ${HEIR_INCLUDE_DIR} 107 | DESTINATION include 108 | COMPONENT heir-headers 109 | FILES_MATCHING 110 | PATTERN "*.def" 111 | PATTERN "*.h" 112 | PATTERN "*.gen" 113 | PATTERN "*.inc" 114 | PATTERN "*.td" 115 | PATTERN "CMakeFiles" EXCLUDE 116 | PATTERN "config.h" EXCLUDE 117 | ) 118 | 119 | if (NOT LLVM_ENABLE_IDE) 120 | add_llvm_install_targets(install-heir-headers 121 | DEPENDS heir-headers 122 | COMPONENT heir-headers) 123 | endif() 124 | 125 | add_subdirectory(cmake/modules) 126 | 127 | # Set RPATH to $ORIGIN on all targets. 128 | function(set_rpath_all_targets dir) 129 | get_property(subdirectories DIRECTORY ${dir} PROPERTY SUBDIRECTORIES) 130 | foreach(subdir ${subdirectories}) 131 | set_rpath_all_targets(${subdir}) 132 | endforeach() 133 | 134 | get_directory_property(LCL_TARGETS DIRECTORY ${dir} BUILDSYSTEM_TARGETS) 135 | set_property(TARGET ${LCL_TARGETS} PROPERTY INSTALL_RPATH "$ORIGIN/../lib") 136 | endfunction() 137 | 138 | option(STANDALONE_INSTALL "Create an 'install' for packaging which doesn't \ 139 | require installation" off) 140 | if (STANDALONE_INSTALL) 141 | message(STATUS "Setting an $ORIGIN-based RPATH on all executables") 142 | set_rpath_all_targets(${CMAKE_CURRENT_SOURCE_DIR}) 143 | endif() -------------------------------------------------------------------------------- /HEIR.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Author: Zian Zhao 4 | # A script for evaluating benchmarks automatically 5 | 6 | # Check the number of parameters 7 | if [ $# -ne 1 ]; then 8 | echo "Please provide the path of the input file as the parameter!" 9 | exit 1 10 | fi 11 | 12 | # Get file path 13 | filePath=$1 14 | 15 | # Check whether the file exists 16 | if [ ! -f "$filePath" ]; then 17 | echo "File does not exists!" 18 | exit 1 19 | fi 20 | 21 | # Extract file name 22 | folderPath=$(dirname "$filePath") 23 | fileName=$(basename "$filePath") 24 | fileNameWithoutExtension=$(echo "$fileName" | cut -d. -f1) 25 | 26 | 27 | ./tools/cgeist "$filePath"\ 28 | -function=$fileNameWithoutExtension -S \ 29 | -raise-scf-to-affine \ 30 | --memref-fullrank -O0 \ 31 | >> "${folderPath}/${fileNameWithoutExtension}.mlir" 32 | 33 | ./tools/heir-opt "${folderPath}/${fileNameWithoutExtension}.mlir" \ 34 | --affine-loop-unroll="unroll-full unroll-num-reps=4" \ 35 | --arith-slot \ 36 | >> "${folderPath}/${fileNameWithoutExtension}_emitc.mlir" 37 | 38 | ./build/bin/emitc-translate "${folderPath}/${fileNameWithoutExtension}_emitc.mlir" \ 39 | --mlir-to-cpp \ 40 | >> "${folderPath}/${fileNameWithoutExtension}.cpp" 41 | 42 | rm "${folderPath}/${fileNameWithoutExtension}.mlir" 43 | rm "${folderPath}/${fileNameWithoutExtension}_emitc.mlir" -------------------------------------------------------------------------------- /HEIR_full_bench/database/database-2.c: -------------------------------------------------------------------------------- 1 | #define N 2 2 | float database(float data[N], float acc) 3 | { 4 | for (int i = 0; i < N; i++) { 5 | if (data[i] > 5) { 6 | acc += data[i]; 7 | } 8 | } 9 | return acc; 10 | } -------------------------------------------------------------------------------- /HEIR_full_bench/database/database-4.c: -------------------------------------------------------------------------------- 1 | #define N 4 2 | float database(float data[N], float acc) 3 | { 4 | for (int i = 0; i < N; i++) { 5 | if (data[i] > 5) { 6 | acc += data[i]; 7 | } 8 | } 9 | return acc; 10 | } -------------------------------------------------------------------------------- /HEIR_full_bench/database/database-8.c: -------------------------------------------------------------------------------- 1 | #define N 8 2 | float database(float data[N], float acc) 3 | { 4 | for (int i = 0; i < N; i++) { 5 | if (data[i] > 5) { 6 | acc += data[i]; 7 | } 8 | } 9 | return acc; 10 | } -------------------------------------------------------------------------------- /HEIR_full_bench/euclid_dist/euclid_dist-16.c: -------------------------------------------------------------------------------- 1 | #define N 16 2 | float euclid_dist(float a[N], float b[N]) 3 | { 4 | float result = (a[0] - b[0]) * (a[0] - b[0]); 5 | float temp; 6 | for (int i = 1; i < N; i++) { 7 | temp = a[i] - b[i]; 8 | result += temp * temp; 9 | } 10 | return result; 11 | } -------------------------------------------------------------------------------- /HEIR_full_bench/euclid_dist/euclid_dist-2048.c: -------------------------------------------------------------------------------- 1 | #define N 2048 2 | float euclid_dist(float a[N], float b[N]) 3 | { 4 | float result = (a[0] - b[0]) * (a[0] - b[0]); 5 | float temp; 6 | for (int i = 1; i < N; i++) { 7 | temp = a[i] - b[i]; 8 | result += temp * temp; 9 | } 10 | return result; 11 | } -------------------------------------------------------------------------------- /HEIR_full_bench/euclid_dist/euclid_dist-256.c: -------------------------------------------------------------------------------- 1 | #define N 256 2 | float euclid_dist(float a[N], float b[N]) 3 | { 4 | float result = (a[0] - b[0]) * (a[0] - b[0]); 5 | float temp; 6 | for (int i = 1; i < N; i++) { 7 | temp = a[i] - b[i]; 8 | result += temp * temp; 9 | } 10 | return result; 11 | } -------------------------------------------------------------------------------- /HEIR_full_bench/euclid_dist/euclid_dist-4096.c: -------------------------------------------------------------------------------- 1 | #define N 4096 2 | float euclid_dist(float a[N], float b[N]) 3 | { 4 | float result = (a[0] - b[0]) * (a[0] - b[0]); 5 | float temp; 6 | for (int i = 1; i < N; i++) { 7 | temp = a[i] - b[i]; 8 | result += temp * temp; 9 | } 10 | return result; 11 | } -------------------------------------------------------------------------------- /HEIR_full_bench/euclid_dist/euclid_dist-512.c: -------------------------------------------------------------------------------- 1 | #define N 512 2 | float euclid_dist(float a[N], float b[N]) 3 | { 4 | float result = (a[0] - b[0]) * (a[0] - b[0]); 5 | float temp; 6 | for (int i = 1; i < N; i++) { 7 | temp = a[i] - b[i]; 8 | result += temp * temp; 9 | } 10 | return result; 11 | } -------------------------------------------------------------------------------- /HEIR_full_bench/euclid_dist/euclid_dist-64.c: -------------------------------------------------------------------------------- 1 | #define N 64 2 | float euclid_dist(float a[N], float b[N]) 3 | { 4 | float result = (a[0] - b[0]) * (a[0] - b[0]); 5 | float temp; 6 | for (int i = 1; i < N; i++) { 7 | temp = a[i] - b[i]; 8 | result += temp * temp; 9 | } 10 | return result; 11 | } -------------------------------------------------------------------------------- /HEIR_full_bench/fibonacci/fibonacci-16.c: -------------------------------------------------------------------------------- 1 | #define iter 16 2 | float fibonacci(float pre, float cur, float count, float output) 3 | { 4 | float temp; 5 | for (int i = 0; i < iter; i++) { 6 | if (i < count) { 7 | temp = cur; 8 | cur = pre + cur; 9 | pre = temp; 10 | } 11 | output = cur; 12 | } 13 | return output; 14 | } -------------------------------------------------------------------------------- /HEIR_full_bench/fibonacci/fibonacci-32.c: -------------------------------------------------------------------------------- 1 | #define iter 32 2 | float fibonacci(float pre, float cur, float count, float output) 3 | { 4 | float temp; 5 | for (int i = 0; i < iter; i++) { 6 | if (i < count) { 7 | temp = cur; 8 | cur = pre + cur; 9 | pre = temp; 10 | } 11 | output = cur; 12 | } 13 | return output; 14 | } -------------------------------------------------------------------------------- /HEIR_full_bench/fibonacci/fibonacci-4.c: -------------------------------------------------------------------------------- 1 | #define iter 4 2 | float fibonacci(float pre, float cur, float count, float output) 3 | { 4 | float temp; 5 | for (int i = 0; i < iter; i++) { 6 | if (i < count) { 7 | temp = cur; 8 | cur = pre + cur; 9 | pre = temp; 10 | } 11 | output = cur; 12 | } 13 | return output; 14 | } -------------------------------------------------------------------------------- /HEIR_full_bench/fibonacci/fibonacci-64.c: -------------------------------------------------------------------------------- 1 | #define iter 64 2 | float fibonacci(float pre, float cur, float count, float output) 3 | { 4 | float temp; 5 | for (int i = 0; i < iter; i++) { 6 | if (i < count) { 7 | temp = cur; 8 | cur = pre + cur; 9 | pre = temp; 10 | } 11 | output = cur; 12 | } 13 | return output; 14 | } -------------------------------------------------------------------------------- /HEIR_full_bench/fibonacci/fibonacci-8.c: -------------------------------------------------------------------------------- 1 | #define iter 8 2 | float fibonacci(float pre, float cur, float count, float output) 3 | { 4 | float temp; 5 | for (int i = 0; i < iter; i++) { 6 | if (i < count) { 7 | temp = cur; 8 | cur = pre + cur; 9 | pre = temp; 10 | } 11 | output = cur; 12 | } 13 | return output; 14 | } -------------------------------------------------------------------------------- /HEIR_full_bench/inner_product/inner_product-16.c: -------------------------------------------------------------------------------- 1 | #define N 16 2 | float inner_product(float a[N], float b[N]) 3 | { 4 | float result; 5 | result = a[0] * b[0]; 6 | for (int i = 1; i < N; i++) { 7 | result += a[i] * b[i]; 8 | } 9 | return result; 10 | } -------------------------------------------------------------------------------- /HEIR_full_bench/inner_product/inner_product-2048.c: -------------------------------------------------------------------------------- 1 | #define N 2048 2 | float inner_product(float a[N], float b[N]) 3 | { 4 | float result; 5 | result = a[0] * b[0]; 6 | for (int i = 1; i < N; i++) { 7 | result += a[i] * b[i]; 8 | } 9 | return result; 10 | } -------------------------------------------------------------------------------- /HEIR_full_bench/inner_product/inner_product-256.c: -------------------------------------------------------------------------------- 1 | #define N 256 2 | float inner_product(float a[N], float b[N]) 3 | { 4 | float result; 5 | result = a[0] * b[0]; 6 | for (int i = 1; i < N; i++) { 7 | result += a[i] * b[i]; 8 | } 9 | return result; 10 | } -------------------------------------------------------------------------------- /HEIR_full_bench/inner_product/inner_product-4096.c: -------------------------------------------------------------------------------- 1 | #define N 4096 2 | float inner_product(float a[N], float b[N]) 3 | { 4 | float result; 5 | result = a[0] * b[0]; 6 | for (int i = 1; i < N; i++) { 7 | result += a[i] * b[i]; 8 | } 9 | return result; 10 | } -------------------------------------------------------------------------------- /HEIR_full_bench/inner_product/inner_product-512.c: -------------------------------------------------------------------------------- 1 | #define N 512 2 | float inner_product(float a[N], float b[N]) 3 | { 4 | float result; 5 | result = a[0] * b[0]; 6 | for (int i = 1; i < N; i++) { 7 | result += a[i] * b[i]; 8 | } 9 | return result; 10 | } -------------------------------------------------------------------------------- /HEIR_full_bench/inner_product/inner_product-64.c: -------------------------------------------------------------------------------- 1 | #define N 64 2 | float inner_product(float a[N], float b[N]) 3 | { 4 | float result; 5 | result = a[0] * b[0]; 6 | for (int i = 1; i < N; i++) { 7 | result += a[i] * b[i]; 8 | } 9 | return result; 10 | } -------------------------------------------------------------------------------- /HEIR_full_bench/min_index/min_index-16.c: -------------------------------------------------------------------------------- 1 | #define N 16 2 | float sgn(float input) 3 | { 4 | return input; 5 | } 6 | 7 | float min_index(float a[N], float min_value) 8 | { 9 | min_value = a[0]; 10 | for (int i = 1; i < N; i++) { 11 | if (min_value > a[i]) min_value = a[i]; 12 | } 13 | 14 | float min_index[N]; 15 | for (int i = 0; i < N; i++) { 16 | min_index[i] = a[i] - min_value; 17 | min_index[i] = sgn(min_index[i]); 18 | } 19 | 20 | return min_value; 21 | } -------------------------------------------------------------------------------- /HEIR_full_bench/min_index/min_index-2.c: -------------------------------------------------------------------------------- 1 | #define N 2 2 | float sgn(float input) 3 | { 4 | return input; 5 | } 6 | 7 | float min_index(float a[N], float min_value) 8 | { 9 | min_value = a[0]; 10 | for (int i = 1; i < N; i++) { 11 | if (min_value > a[i]) min_value = a[i]; 12 | } 13 | 14 | float min_index[N]; 15 | for (int i = 0; i < N; i++) { 16 | min_index[i] = a[i] - min_value; 17 | min_index[i] = sgn(min_index[i]); 18 | } 19 | 20 | return min_value; 21 | } -------------------------------------------------------------------------------- /HEIR_full_bench/min_index/min_index-32.c: -------------------------------------------------------------------------------- 1 | #define N 32 2 | float sgn(float input) 3 | { 4 | return input; 5 | } 6 | 7 | float min_index(float a[N], float min_value) 8 | { 9 | min_value = a[0]; 10 | for (int i = 1; i < N; i++) { 11 | if (min_value > a[i]) min_value = a[i]; 12 | } 13 | 14 | float min_index[N]; 15 | for (int i = 0; i < N; i++) { 16 | min_index[i] = a[i] - min_value; 17 | min_index[i] = sgn(min_index[i]); 18 | } 19 | 20 | return min_value; 21 | } -------------------------------------------------------------------------------- /HEIR_full_bench/min_index/min_index-4.c: -------------------------------------------------------------------------------- 1 | #define N 4 2 | float sgn(float input) 3 | { 4 | return input; 5 | } 6 | 7 | float min_index(float a[N], float min_value) 8 | { 9 | min_value = a[0]; 10 | for (int i = 1; i < N; i++) { 11 | if (min_value > a[i]) min_value = a[i]; 12 | } 13 | 14 | float min_index[N]; 15 | for (int i = 0; i < N; i++) { 16 | min_index[i] = a[i] - min_value; 17 | min_index[i] = sgn(min_index[i]); 18 | } 19 | 20 | return min_value; 21 | } -------------------------------------------------------------------------------- /HEIR_full_bench/min_index/min_index-8.c: -------------------------------------------------------------------------------- 1 | #define N 8 2 | float sgn(float input) 3 | { 4 | return input; 5 | } 6 | 7 | float min_index(float a[N], float min_value) 8 | { 9 | min_value = a[0]; 10 | for (int i = 1; i < N; i++) { 11 | if (min_value > a[i]) min_value = a[i]; 12 | } 13 | 14 | float min_index[N]; 15 | for (int i = 0; i < N; i++) { 16 | min_index[i] = a[i] - min_value; 17 | min_index[i] = sgn(min_index[i]); 18 | } 19 | 20 | return min_value; 21 | } -------------------------------------------------------------------------------- /HEIR_full_bench/min_value/min_value-16.c: -------------------------------------------------------------------------------- 1 | #define N 16 2 | float min_value(float a[N], float min_value) 3 | { 4 | min_value = a[0]; 5 | for (int i = 1; i < N; i++) { 6 | if (min_value > a[i]) min_value = a[i]; 7 | } 8 | 9 | return min_value; 10 | } -------------------------------------------------------------------------------- /HEIR_full_bench/min_value/min_value-2.c: -------------------------------------------------------------------------------- 1 | #define N 2 2 | float min_value(float a[N], float min_value) 3 | { 4 | min_value = a[0]; 5 | for (int i = 1; i < N; i++) { 6 | if (min_value > a[i]) min_value = a[i]; 7 | } 8 | 9 | return min_value; 10 | } -------------------------------------------------------------------------------- /HEIR_full_bench/min_value/min_value-32.c: -------------------------------------------------------------------------------- 1 | #define N 32 2 | float min_value(float a[N], float min_value) 3 | { 4 | min_value = a[0]; 5 | for (int i = 1; i < N; i++) { 6 | if (min_value > a[i]) min_value = a[i]; 7 | } 8 | 9 | return min_value; 10 | } -------------------------------------------------------------------------------- /HEIR_full_bench/min_value/min_value-4.c: -------------------------------------------------------------------------------- 1 | #define N 4 2 | float min_value(float a[N], float min_value) 3 | { 4 | min_value = a[0]; 5 | for (int i = 1; i < N; i++) { 6 | if (min_value > a[i]) min_value = a[i]; 7 | } 8 | 9 | return min_value; 10 | } -------------------------------------------------------------------------------- /HEIR_full_bench/min_value/min_value-8.c: -------------------------------------------------------------------------------- 1 | #define N 8 2 | float min_value(float a[N], float min_value) 3 | { 4 | min_value = a[0]; 5 | for (int i = 1; i < N; i++) { 6 | if (min_value > a[i]) min_value = a[i]; 7 | } 8 | 9 | return min_value; 10 | } -------------------------------------------------------------------------------- /HEIR_plot/Database/GenDatabaseResults.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CURRENT_DIR=$(cd $(dirname $0); pwd) 4 | 5 | # Transpiler Results 6 | cd /home/NDSS_Artifact/Transpiler 7 | bazel run //transpiler/examples/my_database/database2:database_tfhe_testbench >> $CURRENT_DIR/database.out 8 | bazel run //transpiler/examples/my_database/database4:database_tfhe_testbench >> $CURRENT_DIR/database.out 9 | bazel run //transpiler/examples/my_database/database8:database_tfhe_testbench >> $CURRENT_DIR/database.out 10 | # bazel run //transpiler/examples/my_database/database16:database_tfhe_testbench >> $CURRENT_DIR/database.out 11 | # bazel run //transpiler/examples/my_database/database32:database_tfhe_testbench >> $CURRENT_DIR/database.out 12 | 13 | echo "Transpiler Evaluation done" 14 | 15 | # HEIR Results 16 | fileList=( 17 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/database/database-2.c" 18 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/database/database-4.c" 19 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/database/database-8.c" 20 | # "/home/NDSS_Artifact/HEIR/HEIR_full_bench/database/database-16.c" 21 | # "/home/NDSS_Artifact/HEIR/HEIR_full_bench/database/database-32.c" 22 | ) 23 | 24 | for filePath in "${fileList[@]}"; do 25 | # Extract file name 26 | folderPath=$(dirname "$filePath") 27 | fileName=$(basename "$filePath") 28 | fileNameWithoutExtension=$(echo "$fileName" | cut -d. -f1) 29 | functionName=$(echo "$fileNameWithoutExtension" | cut -d- -f1) 30 | 31 | $CURRENT_DIR/../../tools/cgeist "$filePath"\ 32 | -function=$functionName -S \ 33 | -raise-scf-to-affine \ 34 | --memref-fullrank -O0 \ 35 | >> "${folderPath}/${fileNameWithoutExtension}.mlir" 36 | 37 | $CURRENT_DIR/../../tools/heir-opt "${folderPath}/${fileNameWithoutExtension}.mlir" \ 38 | --branch --affine-loop-unroll="unroll-full unroll-num-reps=4" \ 39 | --logic-emitc \ 40 | >> "${folderPath}/${fileNameWithoutExtension}_emitc.mlir" 41 | 42 | $CURRENT_DIR/../../tools/emitc-translate "${folderPath}/${fileNameWithoutExtension}_emitc.mlir" \ 43 | --mlir-to-cpp \ 44 | >> "${folderPath}/${fileNameWithoutExtension}.cpp" 45 | 46 | 47 | python "$CURRENT_DIR/../../format_assistant/halo_transmitter.py" \ 48 | -i "${folderPath}/${fileNameWithoutExtension}.cpp" \ 49 | -o "/home/NDSS_Artifact/HALO/ndss_plot/database/${fileNameWithoutExtension}.cpp" 50 | 51 | rm "${folderPath}/${fileNameWithoutExtension}.mlir" 52 | rm "${folderPath}/${fileNameWithoutExtension}_emitc.mlir" 53 | rm "${folderPath}/${fileNameWithoutExtension}.cpp" 54 | done 55 | 56 | cd /home/NDSS_Artifact/HALO 57 | cmake --build ./build --target all -j 58 | 59 | for filePath in "${fileList[@]}"; do 60 | folderPath=$(dirname "$filePath") 61 | fileName=$(basename "$filePath") 62 | fileNameWithoutExtension=$(echo "$fileName" | cut -d. -f1) 63 | 64 | ./build/bin/"heir_${fileNameWithoutExtension}" >> $CURRENT_DIR/database.out 65 | done 66 | 67 | echo "HEIR evaluation done" -------------------------------------------------------------------------------- /HEIR_plot/Database/plot_database.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import seaborn as sns 3 | import pandas as pd 4 | import math 5 | from matplotlib import rcParams 6 | import os 7 | 8 | def log_list(a): 9 | for i in range(len(a)): 10 | a[i] = math.log(a[i],10) 11 | return a 12 | 13 | labels = ['2', '4', '8'] 14 | 15 | 16 | current_file_path = os.path.abspath(__file__) 17 | current_directory = os.path.dirname(current_file_path) 18 | file_path = current_directory+"/database.out" 19 | transpiler = [] 20 | heir = [] 21 | 22 | try: 23 | with open(file_path, "r") as file: 24 | for line in file: 25 | if "Transpiler" in line: 26 | start_index = line.find("Time ") + len("Time ") 27 | end_index = line.find("ms", start_index) 28 | if start_index != -1 and end_index != -1: 29 | time_str = line[start_index:end_index].strip() 30 | transpiler.append(float(time_str) / 1000) 31 | elif "HEIR" in line: 32 | start_index = line.find("Time ") + len("Time ") 33 | end_index = line.find("ms", start_index) 34 | if start_index != -1 and end_index != -1: 35 | time_str = line[start_index:end_index].strip() 36 | heir.append(float(time_str) / 1000) 37 | 38 | except FileNotFoundError: 39 | print("Result File does not exist") 40 | 41 | 42 | width = 0.3 43 | x1_list = [] 44 | x2_list = [] 45 | label_list = [] 46 | for i in range(len(heir)): 47 | transpiler[i] = math.log10(transpiler[i]) 48 | heir[i] = math.log10(heir[i]) 49 | x1_list.append(i) 50 | x2_list.append(i + width) 51 | label_list.append(i + width + width/2) 52 | 53 | 54 | plt.ylabel('Latency (s)',fontdict={'size' : 20}) 55 | plt.xlabel('Length of the vector',fontdict={'size' : 20}) 56 | 57 | plt.bar(x1_list, transpiler, width=width, color='#87CEFA', align='edge',hatch='x', label='Transpiler') 58 | plt.bar(x2_list, heir, width=width, color='#1E90FF', align='edge', label='HEIR') 59 | plt.yticks([0, 1, 2, 3, 4],labels = ['$10^0$', '$10^1$', '$10^2$', '$10^3$', '$10^4$'], math_fontfamily='cm', size = 16) 60 | plt.xticks(label_list, labels, size = 16) 61 | 62 | 63 | plt.legend(prop = {'weight':'normal','size':12},loc='upper left') 64 | plt.tight_layout() 65 | plt.savefig(current_directory+'/database.pdf') 66 | # plt.show() 67 | -------------------------------------------------------------------------------- /HEIR_plot/EuclidDist/GenEuclidDistResults.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CURRENT_DIR=$(cd $(dirname $0); pwd) 4 | 5 | # EVA Results 6 | python /home/NDSS_Artifact/EVA/examples/euclid_dist/euclid_dist_16.py >> $CURRENT_DIR/eucliddist.out 7 | python /home/NDSS_Artifact/EVA/examples/euclid_dist/euclid_dist_64.py >> $CURRENT_DIR/eucliddist.out 8 | python /home/NDSS_Artifact/EVA/examples/euclid_dist/euclid_dist_256.py >> $CURRENT_DIR/eucliddist.out 9 | python /home/NDSS_Artifact/EVA/examples/euclid_dist/euclid_dist_512.py >> $CURRENT_DIR/eucliddist.out 10 | python /home/NDSS_Artifact/EVA/examples/euclid_dist/euclid_dist_2048.py >> $CURRENT_DIR/eucliddist.out 11 | python /home/NDSS_Artifact/EVA/examples/euclid_dist/euclid_dist_4096.py >> $CURRENT_DIR/eucliddist.out 12 | 13 | echo "EVA evaluation done" 14 | 15 | # HECO Results 16 | /home/NDSS_Artifact/SEAL/build/bin/heco_eucliddist_16 >> $CURRENT_DIR/eucliddist.out 17 | /home/NDSS_Artifact/SEAL/build/bin/heco_eucliddist_64 >> $CURRENT_DIR/eucliddist.out 18 | /home/NDSS_Artifact/SEAL/build/bin/heco_eucliddist_256 >> $CURRENT_DIR/eucliddist.out 19 | /home/NDSS_Artifact/SEAL/build/bin/heco_eucliddist_512 >> $CURRENT_DIR/eucliddist.out 20 | /home/NDSS_Artifact/SEAL/build/bin/heco_eucliddist_2048 >> $CURRENT_DIR/eucliddist.out 21 | /home/NDSS_Artifact/SEAL/build/bin/heco_eucliddist_4096 >> $CURRENT_DIR/eucliddist.out 22 | 23 | echo "HECO evaluation done" 24 | 25 | # HEIR Results 26 | fileList=( 27 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/euclid_dist/euclid_dist-16.c" 28 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/euclid_dist/euclid_dist-64.c" 29 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/euclid_dist/euclid_dist-256.c" 30 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/euclid_dist/euclid_dist-512.c" 31 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/euclid_dist/euclid_dist-2048.c" 32 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/euclid_dist/euclid_dist-4096.c" 33 | ) 34 | 35 | for filePath in "${fileList[@]}"; do 36 | # Extract file name 37 | folderPath=$(dirname "$filePath") 38 | fileName=$(basename "$filePath") 39 | fileNameWithoutExtension=$(echo "$fileName" | cut -d. -f1) 40 | functionName=$(echo "$fileNameWithoutExtension" | cut -d- -f1) 41 | 42 | $CURRENT_DIR/../../tools/cgeist "$filePath"\ 43 | -function=$functionName -S \ 44 | -raise-scf-to-affine \ 45 | --memref-fullrank -O0 \ 46 | >> "${folderPath}/${fileNameWithoutExtension}.mlir" 47 | 48 | $CURRENT_DIR/../../tools/heir-opt "${folderPath}/${fileNameWithoutExtension}.mlir" \ 49 | --affine-loop-unroll="unroll-full unroll-num-reps=4" \ 50 | --arith-emitc \ 51 | >> "${folderPath}/${fileNameWithoutExtension}_emitc.mlir" 52 | 53 | $CURRENT_DIR/../../tools/emitc-translate "${folderPath}/${fileNameWithoutExtension}_emitc.mlir" \ 54 | --mlir-to-cpp \ 55 | >> "${folderPath}/${fileNameWithoutExtension}.cpp" 56 | 57 | 58 | python "$CURRENT_DIR/../../format_assistant/halo_transmitter.py" \ 59 | -i "${folderPath}/${fileNameWithoutExtension}.cpp" \ 60 | -o "/home/NDSS_Artifact/HALO/ndss_plot/euclid_dist/${fileNameWithoutExtension}.cpp" 61 | 62 | rm "${folderPath}/${fileNameWithoutExtension}.mlir" 63 | rm "${folderPath}/${fileNameWithoutExtension}_emitc.mlir" 64 | rm "${folderPath}/${fileNameWithoutExtension}.cpp" 65 | done 66 | 67 | cd /home/NDSS_Artifact/HALO 68 | cmake --build ./build --target all -j 69 | 70 | for filePath in "${fileList[@]}"; do 71 | folderPath=$(dirname "$filePath") 72 | fileName=$(basename "$filePath") 73 | fileNameWithoutExtension=$(echo "$fileName" | cut -d. -f1) 74 | 75 | ./build/bin/"heir_${fileNameWithoutExtension}" >> $CURRENT_DIR/eucliddist.out 76 | done 77 | 78 | echo "HEIR evaluation done" -------------------------------------------------------------------------------- /HEIR_plot/EuclidDist/plot_euclid.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import seaborn as sns 3 | import pandas as pd 4 | import math 5 | from matplotlib import rcParams 6 | import os 7 | 8 | def log_list(a): 9 | for i in range(len(a)): 10 | a[i] = math.log(a[i],10) 11 | return a 12 | 13 | labels = ['16', '64', '256', '512', '2048', '4096'] 14 | 15 | 16 | current_file_path = os.path.abspath(__file__) 17 | current_directory = os.path.dirname(current_file_path) 18 | file_path = current_directory+"/eucliddist.out" 19 | eva = [] 20 | heco = [] 21 | heir = [] 22 | 23 | try: 24 | with open(file_path, "r") as file: 25 | for line in file: 26 | if "EVA" in line: 27 | start_index = line.find("Time: ") + len("Time: ") 28 | end_index = line.find("ms", start_index) 29 | if start_index != -1 and end_index != -1: 30 | time_str = line[start_index:end_index].strip() 31 | eva.append(float(time_str) / 1000) 32 | elif "HECO" in line: 33 | start_index = line.find("Time: ") + len("Time: ") 34 | end_index = line.find("ms", start_index) 35 | if start_index != -1 and end_index != -1: 36 | time_str = line[start_index:end_index].strip() 37 | heco.append(float(time_str) / 1000) 38 | elif "HEIR" in line: 39 | start_index = line.find("Time ") + len("Time ") 40 | end_index = line.find("ms", start_index) 41 | if start_index != -1 and end_index != -1: 42 | time_str = line[start_index:end_index].strip() 43 | heir.append(float(time_str) / 1000) 44 | 45 | except FileNotFoundError: 46 | print("Result File does not exist") 47 | 48 | 49 | width = 0.25 50 | x1_list = [] 51 | x2_list = [] 52 | x3_list = [] 53 | label_list = [] 54 | for i in range(len(eva)): 55 | eva[i] = math.log10(eva[i])+3 56 | heco[i] = math.log10(heco[i])+3 57 | heir[i] = math.log10(heir[i])+3 58 | x1_list.append(i) 59 | x2_list.append(i + width) 60 | label_list.append(i + width + width/2) 61 | x3_list.append(i + width + width) 62 | 63 | 64 | plt.ylabel('Latency (s)',fontdict={'size' : 20}) 65 | plt.xlabel('Length of the vector',fontdict={'size' : 20}) 66 | 67 | plt.bar(x1_list, eva, width=width, color='#EEDEB0', align='edge',hatch='-', label='EVA') 68 | plt.bar(x2_list, heco, width=width, color='#9B4400', align='edge',hatch='x', label='HECO') 69 | plt.bar(x3_list, heir, width=width, color='#1E90FF', align='edge', label='HEIR') 70 | plt.ylim(0, 5.1) 71 | plt.yticks([0, 1, 2, 3, 4],labels = ['$10^{-3}$', '$10^{-2}$', '$10^{-1}$', '$1$','$10^1$'], math_fontfamily='cm', size = 16) 72 | plt.xticks(label_list, labels, size = 16) 73 | 74 | 75 | plt.legend(prop = {'weight':'normal','size':12},loc='upper left') 76 | plt.tight_layout() 77 | plt.savefig(current_directory+'/eucliddist.pdf') 78 | # plt.show() 79 | -------------------------------------------------------------------------------- /HEIR_plot/Fibonacci/GenFibonacciResults.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ $# -ne 1 ]; then 4 | echo "Select to generate 'short' or 'full' version of experiment results" 5 | exit 1 6 | fi 7 | 8 | CURRENT_DIR=$(cd $(dirname $0); pwd) 9 | 10 | # Transpiler Results 11 | cd /home/NDSS_Artifact/Transpiler 12 | bazel run //transpiler/examples/my_fibonacci/fibonacci4:fibonacci_tfhe_testbench >> $CURRENT_DIR/fibonacci.out 13 | bazel run //transpiler/examples/my_fibonacci/fibonacci8:fibonacci_tfhe_testbench >> $CURRENT_DIR/fibonacci.out 14 | bazel run //transpiler/examples/my_fibonacci/fibonacci16:fibonacci_tfhe_testbench >> $CURRENT_DIR/fibonacci.out 15 | if [ "$1" == "full" ]; then 16 | bazel run //transpiler/examples/my_fibonacci/fibonacci32:fibonacci_tfhe_testbench >> $CURRENT_DIR/fibonacci.out 17 | bazel run //transpiler/examples/my_fibonacci/fibonacci64:fibonacci_tfhe_testbench >> $CURRENT_DIR/fibonacci.out 18 | fi 19 | 20 | echo "Transpiler Evaluation done" 21 | 22 | # HEIR Results 23 | fileList=( 24 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/fibonacci/fibonacci-4.c" 25 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/fibonacci/fibonacci-8.c" 26 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/fibonacci/fibonacci-16.c" 27 | ) 28 | 29 | if [ "$1" == "full" ]; then 30 | fileList=( 31 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/fibonacci/fibonacci-4.c" 32 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/fibonacci/fibonacci-8.c" 33 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/fibonacci/fibonacci-16.c" 34 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/fibonacci/fibonacci-32.c" 35 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/fibonacci/fibonacci-64.c" 36 | ) 37 | fi 38 | 39 | for filePath in "${fileList[@]}"; do 40 | # Extract file name 41 | folderPath=$(dirname "$filePath") 42 | fileName=$(basename "$filePath") 43 | fileNameWithoutExtension=$(echo "$fileName" | cut -d. -f1) 44 | functionName=$(echo "$fileNameWithoutExtension" | cut -d- -f1) 45 | 46 | $CURRENT_DIR/../../tools/cgeist "$filePath"\ 47 | -function=$functionName -S \ 48 | -raise-scf-to-affine \ 49 | --memref-fullrank -O0 \ 50 | >> "${folderPath}/${fileNameWithoutExtension}.mlir" 51 | 52 | $CURRENT_DIR/../../tools/heir-opt "${folderPath}/${fileNameWithoutExtension}.mlir" \ 53 | --branch --affine-loop-unroll="unroll-full unroll-num-reps=4" \ 54 | --logic-emitc \ 55 | >> "${folderPath}/${fileNameWithoutExtension}_emitc.mlir" 56 | 57 | $CURRENT_DIR/../../tools/emitc-translate "${folderPath}/${fileNameWithoutExtension}_emitc.mlir" \ 58 | --mlir-to-cpp \ 59 | >> "${folderPath}/${fileNameWithoutExtension}.cpp" 60 | 61 | 62 | python "$CURRENT_DIR/../../format_assistant/halo_transmitter.py" \ 63 | -i "${folderPath}/${fileNameWithoutExtension}.cpp" \ 64 | -o "/home/NDSS_Artifact/HALO/ndss_plot/fibonacci/${fileNameWithoutExtension}.cpp" 65 | 66 | rm "${folderPath}/${fileNameWithoutExtension}.mlir" 67 | rm "${folderPath}/${fileNameWithoutExtension}_emitc.mlir" 68 | rm "${folderPath}/${fileNameWithoutExtension}.cpp" 69 | done 70 | 71 | cd /home/NDSS_Artifact/HALO 72 | cmake --build ./build --target all -j 73 | 74 | for filePath in "${fileList[@]}"; do 75 | folderPath=$(dirname "$filePath") 76 | fileName=$(basename "$filePath") 77 | fileNameWithoutExtension=$(echo "$fileName" | cut -d. -f1) 78 | 79 | ./build/bin/"heir_${fileNameWithoutExtension}" >> $CURRENT_DIR/fibonacci.out 80 | done 81 | 82 | echo "HEIR evaluation done" -------------------------------------------------------------------------------- /HEIR_plot/Fibonacci/plot_fibonacci.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import seaborn as sns 3 | import pandas as pd 4 | import math 5 | from matplotlib import rcParams 6 | import os 7 | import sys 8 | 9 | def log_list(a): 10 | for i in range(len(a)): 11 | a[i] = math.log(a[i],10) 12 | return a 13 | 14 | args = sys.argv 15 | 16 | labels = ['4', '8', '16'] 17 | 18 | if args[1] == "full": 19 | labels = ['4', '8', '16', '32', '64'] 20 | 21 | 22 | current_file_path = os.path.abspath(__file__) 23 | current_directory = os.path.dirname(current_file_path) 24 | file_path = current_directory+"/fibonacci.out" 25 | transpiler = [] 26 | heir = [] 27 | 28 | try: 29 | with open(file_path, "r") as file: 30 | for line in file: 31 | if "Transpiler" in line: 32 | start_index = line.find("Time ") + len("Time ") 33 | end_index = line.find("ms", start_index) 34 | if start_index != -1 and end_index != -1: 35 | time_str = line[start_index:end_index].strip() 36 | transpiler.append(float(time_str) / 1000) 37 | elif "HEIR" in line: 38 | start_index = line.find("Time ") + len("Time ") 39 | end_index = line.find("ms", start_index) 40 | if start_index != -1 and end_index != -1: 41 | time_str = line[start_index:end_index].strip() 42 | heir.append(float(time_str) / 1000) 43 | 44 | except FileNotFoundError: 45 | print("Result File does not exist") 46 | 47 | 48 | width = 0.3 49 | x1_list = [] 50 | x2_list = [] 51 | label_list = [] 52 | for i in range(len(heir)): 53 | transpiler[i] = math.log10(transpiler[i]) 54 | heir[i] = math.log10(heir[i]) 55 | x1_list.append(i) 56 | x2_list.append(i + width) 57 | label_list.append(i + width + width/2) 58 | 59 | 60 | plt.ylabel('Latency (s)',fontdict={'size' : 20}) 61 | plt.xlabel('Length of the vector',fontdict={'size' : 20}) 62 | 63 | plt.bar(x1_list, transpiler, width=width, color='#87CEFA', align='edge',hatch='x', label='Transpiler') 64 | plt.bar(x2_list, heir, width=width, color='#1E90FF', align='edge', label='HEIR') 65 | plt.yticks([0, 1, 2, 3, 4],labels = ['$10^0$', '$10^1$', '$10^2$', '$10^3$', '$10^4$'], math_fontfamily='cm', size = 16) 66 | plt.xticks(label_list, labels, size = 16) 67 | 68 | 69 | plt.legend(prop = {'weight':'normal','size':12},loc='upper left') 70 | plt.tight_layout() 71 | plt.savefig(current_directory+'/fibonacci.pdf') 72 | # plt.show() 73 | -------------------------------------------------------------------------------- /HEIR_plot/InnerProduct/GenInnerProductResults.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CURRENT_DIR=$(cd $(dirname $0); pwd) 4 | 5 | # EVA Results 6 | python /home/NDSS_Artifact/EVA/examples/inner_product/inner_product_16.py >> $CURRENT_DIR/innerproduct.out 7 | python /home/NDSS_Artifact/EVA/examples/inner_product/inner_product_64.py >> $CURRENT_DIR/innerproduct.out 8 | python /home/NDSS_Artifact/EVA/examples/inner_product/inner_product_256.py >> $CURRENT_DIR/innerproduct.out 9 | python /home/NDSS_Artifact/EVA/examples/inner_product/inner_product_512.py >> $CURRENT_DIR/innerproduct.out 10 | python /home/NDSS_Artifact/EVA/examples/inner_product/inner_product_2048.py >> $CURRENT_DIR/innerproduct.out 11 | python /home/NDSS_Artifact/EVA/examples/inner_product/inner_product_4096.py >> $CURRENT_DIR/innerproduct.out 12 | 13 | echo "EVA evaluation done" 14 | 15 | # HECO Results 16 | /home/NDSS_Artifact/SEAL/build/bin/heco_innerproduct_16 >> $CURRENT_DIR/innerproduct.out 17 | /home/NDSS_Artifact/SEAL/build/bin/heco_innerproduct_64 >> $CURRENT_DIR/innerproduct.out 18 | /home/NDSS_Artifact/SEAL/build/bin/heco_innerproduct_256 >> $CURRENT_DIR/innerproduct.out 19 | /home/NDSS_Artifact/SEAL/build/bin/heco_innerproduct_512 >> $CURRENT_DIR/innerproduct.out 20 | /home/NDSS_Artifact/SEAL/build/bin/heco_innerproduct_2048 >> $CURRENT_DIR/innerproduct.out 21 | /home/NDSS_Artifact/SEAL/build/bin/heco_innerproduct_4096 >> $CURRENT_DIR/innerproduct.out 22 | 23 | echo "HECO evaluation done" 24 | 25 | # HEIR Results 26 | fileList=( 27 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/inner_product/inner_product-16.c" 28 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/inner_product/inner_product-64.c" 29 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/inner_product/inner_product-256.c" 30 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/inner_product/inner_product-512.c" 31 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/inner_product/inner_product-2048.c" 32 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/inner_product/inner_product-4096.c" 33 | ) 34 | 35 | for filePath in "${fileList[@]}"; do 36 | # Extract file name 37 | folderPath=$(dirname "$filePath") 38 | fileName=$(basename "$filePath") 39 | fileNameWithoutExtension=$(echo "$fileName" | cut -d. -f1) 40 | functionName=$(echo "$fileNameWithoutExtension" | cut -d- -f1) 41 | 42 | $CURRENT_DIR/../../tools/cgeist "$filePath"\ 43 | -function=$functionName -S \ 44 | -raise-scf-to-affine \ 45 | --memref-fullrank -O0 \ 46 | >> "${folderPath}/${fileNameWithoutExtension}.mlir" 47 | 48 | $CURRENT_DIR/../../tools/heir-opt "${folderPath}/${fileNameWithoutExtension}.mlir" \ 49 | --affine-loop-unroll="unroll-full unroll-num-reps=4" \ 50 | --arith-emitc \ 51 | >> "${folderPath}/${fileNameWithoutExtension}_emitc.mlir" 52 | 53 | $CURRENT_DIR/../../tools/emitc-translate "${folderPath}/${fileNameWithoutExtension}_emitc.mlir" \ 54 | --mlir-to-cpp \ 55 | >> "${folderPath}/${fileNameWithoutExtension}.cpp" 56 | 57 | 58 | python "$CURRENT_DIR/../../format_assistant/halo_transmitter.py" \ 59 | -i "${folderPath}/${fileNameWithoutExtension}.cpp" \ 60 | -o "/home/NDSS_Artifact/HALO/ndss_plot/inner_product/${fileNameWithoutExtension}.cpp" 61 | 62 | rm "${folderPath}/${fileNameWithoutExtension}.mlir" 63 | rm "${folderPath}/${fileNameWithoutExtension}_emitc.mlir" 64 | rm "${folderPath}/${fileNameWithoutExtension}.cpp" 65 | done 66 | 67 | cd /home/NDSS_Artifact/HALO 68 | cmake --build ./build --target all -j 69 | 70 | for filePath in "${fileList[@]}"; do 71 | folderPath=$(dirname "$filePath") 72 | fileName=$(basename "$filePath") 73 | fileNameWithoutExtension=$(echo "$fileName" | cut -d. -f1) 74 | 75 | ./build/bin/"heir_${fileNameWithoutExtension}" >> $CURRENT_DIR/innerproduct.out 76 | done 77 | 78 | echo "HEIR evaluation done" -------------------------------------------------------------------------------- /HEIR_plot/InnerProduct/plot_inner.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import seaborn as sns 3 | import pandas as pd 4 | import math 5 | from matplotlib import rcParams 6 | import os 7 | 8 | def log_list(a): 9 | for i in range(len(a)): 10 | a[i] = math.log(a[i],10) 11 | return a 12 | 13 | labels = ['16', '64', '256', '512', '2048', '4096'] 14 | 15 | 16 | current_file_path = os.path.abspath(__file__) 17 | current_directory = os.path.dirname(current_file_path) 18 | file_path = current_directory+"/innerproduct.out" 19 | eva = [] 20 | heco = [] 21 | heir = [] 22 | 23 | try: 24 | with open(file_path, "r") as file: 25 | for line in file: 26 | if "EVA" in line: 27 | start_index = line.find("Time: ") + len("Time: ") 28 | end_index = line.find("ms", start_index) 29 | if start_index != -1 and end_index != -1: 30 | time_str = line[start_index:end_index].strip() 31 | eva.append(float(time_str) / 1000) 32 | elif "HECO" in line: 33 | start_index = line.find("Time: ") + len("Time: ") 34 | end_index = line.find("ms", start_index) 35 | if start_index != -1 and end_index != -1: 36 | time_str = line[start_index:end_index].strip() 37 | heco.append(float(time_str) / 1000) 38 | elif "HEIR" in line: 39 | start_index = line.find("Time ") + len("Time ") 40 | end_index = line.find("ms", start_index) 41 | if start_index != -1 and end_index != -1: 42 | time_str = line[start_index:end_index].strip() 43 | heir.append(float(time_str) / 1000) 44 | 45 | except FileNotFoundError: 46 | print("Result File does not exist") 47 | 48 | 49 | width = 0.25 50 | x1_list = [] 51 | x2_list = [] 52 | x3_list = [] 53 | label_list = [] 54 | for i in range(len(eva)): 55 | eva[i] = math.log10(eva[i])+3 56 | heco[i] = math.log10(heco[i])+3 57 | heir[i] = math.log10(heir[i])+3 58 | x1_list.append(i) 59 | x2_list.append(i + width) 60 | label_list.append(i + width + width/2) 61 | x3_list.append(i + width + width) 62 | 63 | 64 | plt.ylabel('Latency (s)',fontdict={'size' : 20}) 65 | plt.xlabel('Length of the vector',fontdict={'size' : 20}) 66 | 67 | plt.bar(x1_list, eva, width=width, color='#EEDEB0', align='edge',hatch='-', label='EVA') 68 | plt.bar(x2_list, heco, width=width, color='#9B4400', align='edge',hatch='x', label='HECO') 69 | plt.bar(x3_list, heir, width=width, color='#1E90FF', align='edge', label='HEIR') 70 | plt.ylim(0, 5.1) 71 | plt.yticks([0, 1, 2, 3, 4],labels = ['$10^{-3}$', '$10^{-2}$', '$10^{-1}$', '$1$','$10^1$'], math_fontfamily='cm', size = 16) 72 | plt.xticks(label_list, labels, size = 16) 73 | 74 | 75 | plt.legend(prop = {'weight':'normal','size':12},loc='upper left') 76 | plt.tight_layout() 77 | plt.savefig(current_directory+'/innerproduct.pdf') 78 | # plt.show() 79 | -------------------------------------------------------------------------------- /HEIR_plot/MinIndex/GenMinIndexResults.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ $# -ne 1 ]; then 4 | echo "Select to generate 'short' or 'full' version of experiment results" 5 | exit 1 6 | fi 7 | 8 | CURRENT_DIR=$(cd $(dirname $0); pwd) 9 | 10 | # Transpiler Results 11 | cd /home/NDSS_Artifact/Transpiler 12 | bazel run //transpiler/examples/my_min_index/min_index2:min_index_tfhe_testbench >> $CURRENT_DIR/minindex.out 13 | bazel run //transpiler/examples/my_min_index/min_index4:min_index_tfhe_testbench >> $CURRENT_DIR/minindex.out 14 | bazel run //transpiler/examples/my_min_index/min_index8:min_index_tfhe_testbench >> $CURRENT_DIR/minindex.out 15 | if [ "$1" == "full" ]; then 16 | bazel run //transpiler/examples/my_min_index/min_index16:min_index_tfhe_testbench >> $CURRENT_DIR/minindex.out 17 | bazel run //transpiler/examples/my_min_index/min_index32:min_index_tfhe_testbench >> $CURRENT_DIR/minindex.out 18 | fi 19 | 20 | echo "Transpiler Evaluation done" 21 | 22 | # HEIR Results 23 | fileList=( 24 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/min_index/min_index-2.c" 25 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/min_index/min_index-4.c" 26 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/min_index/min_index-8.c" 27 | ) 28 | if [ "$1" == "full" ]; then 29 | fileList=( 30 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/min_index/min_index-2.c" 31 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/min_index/min_index-4.c" 32 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/min_index/min_index-8.c" 33 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/min_index/min_index-16.c" 34 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/min_index/min_index-32.c" 35 | ) 36 | fi 37 | 38 | for filePath in "${fileList[@]}"; do 39 | # Extract file name 40 | folderPath=$(dirname "$filePath") 41 | fileName=$(basename "$filePath") 42 | fileNameWithoutExtension=$(echo "$fileName" | cut -d. -f1) 43 | functionName=$(echo "$fileNameWithoutExtension" | cut -d- -f1) 44 | 45 | $CURRENT_DIR/../../tools/cgeist "$filePath"\ 46 | -function=$functionName -S \ 47 | -raise-scf-to-affine \ 48 | --memref-fullrank -O0 \ 49 | >> "${folderPath}/${fileNameWithoutExtension}.mlir" 50 | 51 | $CURRENT_DIR/../../tools/heir-opt "${folderPath}/${fileNameWithoutExtension}.mlir" \ 52 | --affine-loop-unroll="unroll-full unroll-num-reps=4" \ 53 | --logic-emitc \ 54 | >> "${folderPath}/${fileNameWithoutExtension}_emitc.mlir" 55 | 56 | $CURRENT_DIR/../../tools/emitc-translate "${folderPath}/${fileNameWithoutExtension}_emitc.mlir" \ 57 | --mlir-to-cpp \ 58 | >> "${folderPath}/${fileNameWithoutExtension}.cpp" 59 | 60 | 61 | python "$CURRENT_DIR/../../format_assistant/halo_transmitter.py" \ 62 | -i "${folderPath}/${fileNameWithoutExtension}.cpp" \ 63 | -o "/home/NDSS_Artifact/HALO/ndss_plot/min_index/${fileNameWithoutExtension}.cpp" 64 | 65 | rm "${folderPath}/${fileNameWithoutExtension}.mlir" 66 | rm "${folderPath}/${fileNameWithoutExtension}_emitc.mlir" 67 | rm "${folderPath}/${fileNameWithoutExtension}.cpp" 68 | done 69 | 70 | cd /home/NDSS_Artifact/HALO 71 | cmake --build ./build --target all -j 72 | 73 | for filePath in "${fileList[@]}"; do 74 | folderPath=$(dirname "$filePath") 75 | fileName=$(basename "$filePath") 76 | fileNameWithoutExtension=$(echo "$fileName" | cut -d. -f1) 77 | 78 | ./build/bin/"heir_${fileNameWithoutExtension}" >> $CURRENT_DIR/minindex.out 79 | done 80 | 81 | echo "HEIR evaluation done" -------------------------------------------------------------------------------- /HEIR_plot/MinIndex/plot_index.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import seaborn as sns 3 | import pandas as pd 4 | import math 5 | from matplotlib import rcParams 6 | import os 7 | import sys 8 | 9 | def log_list(a): 10 | for i in range(len(a)): 11 | a[i] = math.log(a[i],10) 12 | return a 13 | 14 | args = sys.argv 15 | 16 | labels = ['2', '4', '8'] 17 | 18 | if args[1] == "full": 19 | labels = ['2', '4', '8', '16', '32'] 20 | 21 | 22 | current_file_path = os.path.abspath(__file__) 23 | current_directory = os.path.dirname(current_file_path) 24 | file_path = current_directory+"/minindex.out" 25 | transpiler = [] 26 | heir = [] 27 | 28 | try: 29 | with open(file_path, "r") as file: 30 | for line in file: 31 | if "Transpiler" in line: 32 | start_index = line.find("Time ") + len("Time ") 33 | end_index = line.find("ms", start_index) 34 | if start_index != -1 and end_index != -1: 35 | time_str = line[start_index:end_index].strip() 36 | transpiler.append(float(time_str) / 1000) 37 | elif "HEIR" in line: 38 | start_index = line.find("Time ") + len("Time ") 39 | end_index = line.find("ms", start_index) 40 | if start_index != -1 and end_index != -1: 41 | time_str = line[start_index:end_index].strip() 42 | heir.append(float(time_str) / 1000) 43 | 44 | except FileNotFoundError: 45 | print("Result File does not exist") 46 | 47 | 48 | width = 0.3 49 | x1_list = [] 50 | x2_list = [] 51 | label_list = [] 52 | for i in range(len(heir)): 53 | transpiler[i] = math.log10(transpiler[i]) 54 | heir[i] = math.log10(heir[i]) 55 | x1_list.append(i) 56 | x2_list.append(i + width) 57 | label_list.append(i + width + width/2) 58 | 59 | 60 | plt.ylabel('Latency (s)',fontdict={'size' : 20}) 61 | plt.xlabel('Length of the vector',fontdict={'size' : 20}) 62 | 63 | plt.bar(x1_list, transpiler, width=width, color='#87CEFA', align='edge',hatch='x', label='Transpiler') 64 | plt.bar(x2_list, heir, width=width, color='#1E90FF', align='edge', label='HEIR') 65 | plt.yticks([0, 1, 2, 3, 4],labels = ['$10^0$', '$10^1$', '$10^2$', '$10^3$', '$10^4$'], math_fontfamily='cm', size = 16) 66 | plt.xticks(label_list, labels, size = 16) 67 | 68 | 69 | plt.legend(prop = {'weight':'normal','size':12},loc='upper left') 70 | plt.tight_layout() 71 | plt.savefig(current_directory+'/minindex.pdf') 72 | # plt.show() 73 | -------------------------------------------------------------------------------- /HEIR_plot/MinValue/GenMinValueResults.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ $# -ne 1 ]; then 4 | echo "Select to generate 'short' or 'full' version of experiment results" 5 | exit 1 6 | fi 7 | 8 | CURRENT_DIR=$(cd $(dirname $0); pwd) 9 | 10 | # Transpiler Results 11 | cd /home/NDSS_Artifact/Transpiler 12 | bazel run //transpiler/examples/my_min_value/min_value2:min_value_tfhe_testbench >> $CURRENT_DIR/minvalue.out 13 | bazel run //transpiler/examples/my_min_value/min_value4:min_value_tfhe_testbench >> $CURRENT_DIR/minvalue.out 14 | bazel run //transpiler/examples/my_min_value/min_value8:min_value_tfhe_testbench >> $CURRENT_DIR/minvalue.out 15 | if [ "$1" == "full" ]; then 16 | bazel run //transpiler/examples/my_min_value/min_value16:min_value_tfhe_testbench >> $CURRENT_DIR/minvalue.out 17 | bazel run //transpiler/examples/my_min_value/min_value32:min_value_tfhe_testbench >> $CURRENT_DIR/minvalue.out 18 | fi 19 | 20 | echo "Transpiler Evaluation done" 21 | 22 | # HEIR Results 23 | fileList=( 24 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/min_value/min_value-2.c" 25 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/min_value/min_value-4.c" 26 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/min_value/min_value-8.c" 27 | ) 28 | if [ "$1" == "full" ]; then 29 | fileList=( 30 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/min_value/min_value-2.c" 31 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/min_value/min_value-4.c" 32 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/min_value/min_value-8.c" 33 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/min_value/min_value-16.c" 34 | "/home/NDSS_Artifact/HEIR/HEIR_full_bench/min_value/min_value-32.c" 35 | ) 36 | fi 37 | 38 | for filePath in "${fileList[@]}"; do 39 | # Extract file name 40 | folderPath=$(dirname "$filePath") 41 | fileName=$(basename "$filePath") 42 | fileNameWithoutExtension=$(echo "$fileName" | cut -d. -f1) 43 | functionName=$(echo "$fileNameWithoutExtension" | cut -d- -f1) 44 | 45 | $CURRENT_DIR/../../tools/cgeist "$filePath"\ 46 | -function=$functionName -S \ 47 | -raise-scf-to-affine \ 48 | --memref-fullrank -O0 \ 49 | >> "${folderPath}/${fileNameWithoutExtension}.mlir" 50 | 51 | $CURRENT_DIR/../../tools/heir-opt "${folderPath}/${fileNameWithoutExtension}.mlir" \ 52 | --affine-loop-unroll="unroll-full unroll-num-reps=4" \ 53 | --logic-emitc \ 54 | >> "${folderPath}/${fileNameWithoutExtension}_emitc.mlir" 55 | 56 | $CURRENT_DIR/../../tools/emitc-translate "${folderPath}/${fileNameWithoutExtension}_emitc.mlir" \ 57 | --mlir-to-cpp \ 58 | >> "${folderPath}/${fileNameWithoutExtension}.cpp" 59 | 60 | 61 | python "$CURRENT_DIR/../../format_assistant/halo_transmitter.py" \ 62 | -i "${folderPath}/${fileNameWithoutExtension}.cpp" \ 63 | -o "/home/NDSS_Artifact/HALO/ndss_plot/min_value/${fileNameWithoutExtension}.cpp" 64 | 65 | rm "${folderPath}/${fileNameWithoutExtension}.mlir" 66 | rm "${folderPath}/${fileNameWithoutExtension}_emitc.mlir" 67 | rm "${folderPath}/${fileNameWithoutExtension}.cpp" 68 | done 69 | 70 | cd /home/NDSS_Artifact/HALO 71 | cmake --build ./build --target all -j 72 | 73 | for filePath in "${fileList[@]}"; do 74 | folderPath=$(dirname "$filePath") 75 | fileName=$(basename "$filePath") 76 | fileNameWithoutExtension=$(echo "$fileName" | cut -d. -f1) 77 | 78 | ./build/bin/"heir_${fileNameWithoutExtension}" >> $CURRENT_DIR/minvalue.out 79 | done 80 | 81 | echo "HEIR evaluation done" -------------------------------------------------------------------------------- /HEIR_plot/MinValue/plot_value.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import seaborn as sns 3 | import pandas as pd 4 | import math 5 | from matplotlib import rcParams 6 | import os 7 | import sys 8 | 9 | def log_list(a): 10 | for i in range(len(a)): 11 | a[i] = math.log(a[i],10) 12 | return a 13 | 14 | args = sys.argv 15 | 16 | labels = ['2', '4', '8'] 17 | 18 | if args[1] == "full": 19 | labels = ['2', '4', '8', '16', '32'] 20 | 21 | 22 | current_file_path = os.path.abspath(__file__) 23 | current_directory = os.path.dirname(current_file_path) 24 | file_path = current_directory+"/minvalue.out" 25 | transpiler = [] 26 | heir = [] 27 | 28 | try: 29 | with open(file_path, "r") as file: 30 | for line in file: 31 | if "Transpiler" in line: 32 | start_index = line.find("Time ") + len("Time ") 33 | end_index = line.find("ms", start_index) 34 | if start_index != -1 and end_index != -1: 35 | time_str = line[start_index:end_index].strip() 36 | transpiler.append(float(time_str) / 1000) 37 | elif "HEIR" in line: 38 | start_index = line.find("Time ") + len("Time ") 39 | end_index = line.find("ms", start_index) 40 | if start_index != -1 and end_index != -1: 41 | time_str = line[start_index:end_index].strip() 42 | heir.append(float(time_str) / 1000) 43 | 44 | except FileNotFoundError: 45 | print("Result File does not exist") 46 | 47 | 48 | width = 0.3 49 | x1_list = [] 50 | x2_list = [] 51 | label_list = [] 52 | for i in range(len(heir)): 53 | transpiler[i] = math.log10(transpiler[i]) 54 | heir[i] = math.log10(heir[i]) 55 | x1_list.append(i) 56 | x2_list.append(i + width) 57 | label_list.append(i + width + width/2) 58 | 59 | 60 | plt.ylabel('Latency (s)',fontdict={'size' : 20}) 61 | plt.xlabel('Length of the vector',fontdict={'size' : 20}) 62 | 63 | plt.bar(x1_list, transpiler, width=width, color='#87CEFA', align='edge',hatch='x', label='Transpiler') 64 | plt.bar(x2_list, heir, width=width, color='#1E90FF', align='edge', label='HEIR') 65 | plt.yticks([0, 1, 2, 3, 4],labels = ['$10^0$', '$10^1$', '$10^2$', '$10^3$', '$10^4$'], math_fontfamily='cm', size = 16) 66 | plt.xticks(label_list, labels, size = 16) 67 | 68 | 69 | plt.legend(prop = {'weight':'normal','size':12},loc='upper left') 70 | plt.tight_layout() 71 | plt.savefig(current_directory+'/minvalue.pdf') 72 | # plt.show() 73 | -------------------------------------------------------------------------------- /HEIR_plot/README.md: -------------------------------------------------------------------------------- 1 | # A Guide for Plots Generation 2 | In this directory, scripts are provided for the purpose of 3 | comparing with other FHE compilers and generating plots. 4 | 5 | ## 1. Compiling Benchmarks with other FHE compilers 6 | As HECO still faces challenges in integrating its IR code with the 7 | underlying FHE library, we manually implemented each benchmark on 8 | SEAL library using the generated IR. The source code for these 9 | benchmarks can be found in `SEAL/native/HECOBench`. Please follow 10 | the instructions in `HEIR/README.md` to bulld SEAL first for 11 | generating the executables of these benchmarks. 12 | 13 | 14 | The benchmark programs for the EVA compiler are located in 15 | `EVA/examples`. EVA can evaluate these benchmarks by executing 16 | the corresponding Python scripts. 17 | 18 | The benchmark programs for the Transpiler are located in 19 | `Transpiler/transpiler/examples`. To evaluate the benchmarks, 20 | you can execute the following instruction: 21 | ```sh 22 | # Take min_value (vector size = 2) program as an example 23 | cd Transpiler/ 24 | bazel run //transpiler/examples/my_min_value/min_value2:min_value_tfhe_testbench 25 | ``` 26 | 27 | **Note: Instead of evaluating the benchmarks one by one, please utilize 28 | the scripts provided in the following section to compare the 29 | performance among different FHE compilers.** 30 | 31 | ## 2. Generating Plots 32 | **Note that the complete input prgrams for HEIR benchmarks are 33 | located in `HEIR/HEIR_full_bench`. 34 | 35 | Before evaluating these benchmarks, please use the following 36 | instructions to build HALO and SEAL: 37 | ```sh 38 | # Build SEAL 39 | cd /home/NDSS_Artifact/SEAL/ 40 | cmake -S . -B build -DSEAL_USE_INTEL_HEXL=ON 41 | cmake --build build -j 42 | 43 | # Build HALO 44 | cd /home/NDSS_Artifact/HALO/ 45 | mkdir build && cd build 46 | cmake .. -DCMAKE_PREFIX_PATH=/home/NDSS_Artifact/SEAL/build/ \ 47 | -DCMAKE_BUILD_TYPE=Release 48 | cmake --build . --target all -j 49 | ``` 50 | 51 | ### 2.1. Arithmetic Circuit Evaluation 52 | To generate the plots for runtime latency comparison in evaluating 53 | InnerProduct, the runtime latency of different FHE compilers needs 54 | to be evaluated and logged in `innerproduct.out`. 55 | ```sh 56 | ./InnerProduct/GenInnerProductResults.sh 57 | ``` 58 | Next, generate the plot depicting the runtime latency evaluated in 59 | the previous step. 60 | ```sh 61 | python ./InnerProduct/plot_inner.py 62 | ``` 63 | 64 | Similarly, to generate plots for the runtime latency comparison in 65 | evaluating EuclidDist, please execute the following instructions. 66 | ```sh 67 | ./EuclidDist/GenEuclidDistResults.sh 68 | python ./EuclidDist/plot_euclid.py 69 | ``` 70 | ### 2.2. Logic Circuit Evaluation 71 | To generate the plots for the MinValue, MinIndex, and Fibonacci 72 | benchmarks, please follow the instructions below. 73 | ```sh 74 | ./MinValue/GenMinValueResults.sh full 75 | python ./MinValue/plot_value.py full 76 | 77 | ./MinIndex/GenMinIndexResults.sh full 78 | python ./MinIndex/plot_index.py full 79 | 80 | ./Fibonacci/GenFibonacciResults.sh full 81 | python ./Fibonacci/plot_fibonacci.py full 82 | ``` 83 | However, generating the full version of experiment results may take 84 | hours. To generate a shortened version of the comparison result, please 85 | follow the instructions below. 86 | ```sh 87 | ./MinValue/GenMinValueResults.sh short 88 | python ./MinValue/plot_value.py short 89 | 90 | ./MinIndex/GenMinIndexResults.sh short 91 | python ./MinIndex/plot_index.py short 92 | 93 | ./Fibonacci/GenFibonacciResults.sh short 94 | python ./Fibonacci/plot_fibonacci.py short 95 | ``` 96 | ### 2.3 Database evaluation 97 | Similarly, due to the significant runtime latency, only a condensed version 98 | of the comparison result is provied. Please refer to the instructions 99 | below. 100 | ```sh 101 | ./Database/GenDatabaseResults.sh 102 | python ./Database/plot_database.py 103 | ``` -------------------------------------------------------------------------------- /LISENCE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Beihang University. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # About HEIR 2 | HEIR is an end-to-end FHE compiler to compile high-level input 3 | C programs and emits to efficient FHE implementations. Currently, 4 | based on the arithmetic and Boolean nature of the C 5 | instructions, HEIR can transform these instructions into 6 | homomorphic operators supported in either Ring-LWE based schemes (CKKS) 7 | or LWE based schemes (TFHE). 8 | 9 | > **Note: 10 | > This repository only contains the IR part of HEIR, to evaluate the 11 | > benchmarks, please use the [Docker](https://hub.docker.com/repository/docker/zhaozian/heir/general) 12 | > version of HEIR. 13 | # Repository's Structure 14 | The repository is organized as follow: 15 | ``` 16 | cmake – configuration files for the CMake build system 17 | include – header (.h) and TableGen (.td) files 18 | └ IR – contains HEIR dialect definitions 19 | └ Passes – contains the definitions of the different transformations 20 | src – source files (.cpp) 21 | └ IR – implementations of additional dialect-specific functionality 22 | └ Passes – implementations of the different transformations 23 | └ tools – sources for the main commandline interface 24 | format_assistant – scripts for integrating Middle-End IR with Back-End FHE library 25 | tools – pre-built Front-End and Middle-End CLI 26 | HEIR_plot – scripts for results comparison and plots generation 27 | benchmarks – orignal version for artifact evaluation 28 | HEIR_full_bench – full input programs for plot generation 29 | ``` 30 | 31 | # Using HEIR 32 | ### Front-End 33 | HEIR uses Polygeist CLI `cgeist` as the Front-End to transform 34 | the input C program into `*.mlir` file. Please use the 35 | following default parameters to execute the tool. 36 | ```sh 37 | ./tools/cgeist $fileName$.c \ 38 | -function=$functionName$ -S \ 39 | -raise-scf-to-affine \ 40 | --memref-fullrank -O0 41 | ``` 42 | ### Middle-End 43 | In Middle-End, HEIR uses `heir-opt` CLI to transform the input 44 | MLIR program into programs with homomorphic operators 45 | reprsented in `emitc` dialect. There are three parameters for 46 | `heir-opt`: 47 | 48 | + **--branch**: Add this parameter when `if` insturction is 49 | called in the input C program. 50 | + **--affine-loop-unroll="unroll-full unroll-num-reps=4"**: 51 | Add this parameter to unroll all the `for` loop in the 52 | input program. 53 | + **--arith-emitc/--logic-emitc**: If the input program only includes arithmetic operations, use **--arith-emitc** for batching optimizations. Otherwise, use **--logic-emitc**. 54 | 55 | Next, HEIR uses `emitc-translate` to transform the MLIR file 56 | into a C++ file: 57 | ```sh 58 | ./tools/emitc-translate $fileName$.mlir --mlir-to-cpp 59 | ``` 60 | ### Back-End 61 | The integration between Middle-End and Back-End is not yet 62 | well-implemented. If you require an executable, please use 63 | `format_assistant/halo_transmitter.py` script and manual 64 | compilation & linking for now. 65 | 66 | # A Guide For HEIR Installation 67 | > **Note** 68 | > In this docker version, we pre-built the Front-End and Middle-End 69 | > executables in `./tools`, i.e. `cgeist`, `heir-opt` and `emitc-translate`. 70 | ## Build Polygeist Front-End 71 | Start with ``HEIR`` directory. 72 | 73 | Clone Polygeist from Github. 74 | ```sh 75 | cd .. 76 | git clone -b dev --recursive https://github.com/heir-compiler/Polygeist 77 | cd Polygeist 78 | ``` 79 | Using unified LLVM, MLIR, Clang, and Polygeist build. 80 | ```sh 81 | mkdir build 82 | cd build 83 | cmake -G Ninja ../llvm-project/llvm \ 84 | -DLLVM_ENABLE_PROJECTS="clang;mlir" \ 85 | -DLLVM_EXTERNAL_PROJECTS="polygeist" \ 86 | -DLLVM_EXTERNAL_POLYGEIST_SOURCE_DIR=.. \ 87 | -DLLVM_TARGETS_TO_BUILD="host" \ 88 | -DLLVM_ENABLE_ASSERTIONS=ON \ 89 | -DCMAKE_BUILD_TYPE=DEBUG 90 | ninja 91 | ``` 92 | 93 | ## Build HEIR Middle-End 94 | Start with ``HEIR`` directory. 95 | 96 | Clone llvm-15 from Github. Note that LLVM-15 used for HEIR Middle-End is not compatiable with LLVM for building Polygeist. 97 | ```sh 98 | cd .. 99 | git clone -b release/15.x https://github.com/llvm/llvm-project.git 100 | cd llvm-project 101 | ``` 102 | Build LLVM/MLIR. 103 | ```sh 104 | mkdir build && cd build 105 | cmake -G Ninja ../llvm -DLLVM_ENABLE_PROJECTS="mlir" -DLLVM_BUILD_EXAMPLES=ON -DLLVM_TARGETS_TO_BUILD="X86" -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_ASSERTIONS=ON -DLLVM_INSTALL_UTILS=ON 106 | ninja -j N 107 | ``` 108 | 109 | Build HEIR. 110 | ```sh 111 | cd ../../HEIR 112 | mkdir build && cd build 113 | cmake .. -DMLIR_DIR=/home/NDSS_Artifact/llvm-project/build/lib/cmake/mlir 114 | cmake --build . --target all 115 | ``` 116 | 117 | ## BUILD HALO Back-End 118 | Start with ``HEIR`` directory. 119 | 120 | We first build and install Microsoft SEAl to ``/home/NDSS_Artifact/mylibs/SEAL3.7``. 121 | ```sh 122 | cd .. 123 | git clone -b 3.7.1 https://github.com/microsoft/SEAL.git 124 | cd SEAL 125 | cmake -S . -B build -DCMAKE_INSTALL_PREFIX=/home/NDSS_Artifact/mylibs/SEAL3.7 -DSEAL_USE_INTEL_HEXL=ON 126 | cmake --build build 127 | sudo cmake --install build 128 | ``` 129 | Build HALO with Microsoft SEAL. 130 | ```sh 131 | cd ../HALO 132 | mkdir build && cd build 133 | cmake .. -DCMAKE_PREFIX_PATH=~/mylibs/SEAL3.7 -DCMAKE_INSTALL_PREFIX=~/mylibs/SEAL3.7 -DCMAKE_BUILD_TYPE=Release 134 | cmake --build . --target all -j 135 | ``` 136 | 137 | # A Guide For HEIR Experiment Evaluation (Original Version) 138 | This artifact included three experiments for arithmetic-circuit programs, logic-circuit programs and end-to-end hybrid-circuit programs. 139 | The concrete steps for evaluating these experiments are provided in ``benchmarks/arithmetic/README.md``, ``benchmarks/logic/README.md`` and ``benchmarks/e2e/README.md``. 140 | 141 | # A Guide for Plots Generation 142 | The concrete steps for evaluating these experiments are 143 | provided in ``HEIR_plot/README.md``. -------------------------------------------------------------------------------- /benchmarks/arithmetic/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Experment (E1): Arithmetic Experiments 3 | ## 1.1 Inner Product Evaluation. 4 | Execute the following instructions in ``HEIR/`` directory. 5 | 6 | First, we compile the original C program to C++ homomorphic APIs and plug it to HALO library. 7 | ```sh 8 | ./tools/cgeist ./benchmarks/arithmetic/inner_product.c \ 9 | -function=inner_product -S \ 10 | -raise-scf-to-affine \ 11 | --memref-fullrank -O0 \ 12 | >> ./benchmarks/arithmetic/inner_product.mlir 13 | ./tools/heir-opt ./benchmarks/arithmetic/inner_product.mlir \ 14 | --affine-loop-unroll="unroll-full=true" \ 15 | --arith-emitc \ 16 | >> ./benchmarks/arithmetic/inner_product_emitc.mlir 17 | ./tools/emitc-translate ./benchmarks/arithmetic/inner_product_emitc.mlir \ 18 | --mlir-to-cpp \ 19 | >> ./benchmarks/arithmetic/inner_product.cpp 20 | python ./format_assistant/halo_transmitter.py -i ./benchmarks/arithmetic/inner_product.cpp -o ../HALO/ndss_experiment/inner_product.cpp 21 | ``` 22 | Then, we execute the generated benchmark. 23 | ```sh 24 | cd ../HALO 25 | cmake --build ./build --config Release --target all 26 | ./build/bin/inner_product 27 | ``` 28 | 29 | ## 1.2 Euclidean distance evaluation. 30 | Execute the following instructions in ``HEIR/`` directory. 31 | 32 | First, we compile the original C program to C++ homomorphic APIs and plug it to HALO library. 33 | ```sh 34 | ./tools/cgeist ./benchmarks/arithmetic/euclid_dist.c \ 35 | -function=euclid_dist -S \ 36 | -raise-scf-to-affine \ 37 | --memref-fullrank -O0 \ 38 | >> ./benchmarks/arithmetic/euclid_dist.mlir 39 | ./tools/heir-opt ./benchmarks/arithmetic/euclid_dist.mlir \ 40 | --affine-loop-unroll="unroll-full=true" \ 41 | --arith-emitc \ 42 | >> ./benchmarks/arithmetic/euclid_dist_emitc.mlir 43 | ./tools/emitc-translate ./benchmarks/arithmetic/euclid_dist_emitc.mlir \ 44 | --mlir-to-cpp \ 45 | >> ./benchmarks/arithmetic/euclid_dist.cpp 46 | python ./format_assistant/halo_transmitter.py -i ./benchmarks/arithmetic/euclid_dist.cpp -o ../HALO/ndss_experiment/euclid_dist.cpp 47 | ``` 48 | Then, we execute the generated benchmark. 49 | ```sh 50 | cd ../HALO 51 | cmake --build ./build --config Release --target all 52 | ./build/bin/euclid_dist 53 | ``` -------------------------------------------------------------------------------- /benchmarks/arithmetic/euclid_dist.c: -------------------------------------------------------------------------------- 1 | float euclid_dist(float a[4], float b[4]) 2 | { 3 | float result = (a[0] - b[0]) * (a[0] - b[0]); 4 | float temp; 5 | for (int i = 1; i < 4; i++) { 6 | temp = a[i] - b[i]; 7 | result += temp * temp; 8 | } 9 | return result; 10 | } -------------------------------------------------------------------------------- /benchmarks/arithmetic/inner_product.c: -------------------------------------------------------------------------------- 1 | float inner_product(float a[4], float b[4]) 2 | { 3 | float result; 4 | result = a[0] * b[0]; 5 | for (int i = 1; i < 4; i++) { 6 | result += a[i] * b[i]; 7 | } 8 | return result; 9 | } -------------------------------------------------------------------------------- /benchmarks/e2e/README.md: -------------------------------------------------------------------------------- 1 | # Experiment (E3): End-To-End Applications 2 | ## 3.1 Database Filter-Aggregate Evaluation 3 | Execute the following instructions in ``HEIR/`` directory. 4 | 5 | First, we compile the original C program to C++ homomorphic APIs and plug it to HALO library. 6 | ```sh 7 | ./tools/cgeist ./benchmarks/e2e/database.c \ 8 | -function=database -S \ 9 | -raise-scf-to-affine \ 10 | --memref-fullrank -O0 \ 11 | >> ./benchmarks/e2e/database.mlir 12 | ./tools/heir-opt ./benchmarks/e2e/database.mlir \ 13 | --branch --affine-loop-unroll="unroll-full=true" \ 14 | --logic-emitc \ 15 | >> ./benchmarks/e2e/database_emitc.mlir 16 | ./tools/emitc-translate ./benchmarks/e2e/database_emitc.mlir \ 17 | --mlir-to-cpp \ 18 | >> ./benchmarks/e2e/database.cpp 19 | python ./format_assistant/halo_transmitter.py -i ./benchmarks/e2e/database.cpp -o ../HALO/ndss_experiment/database.cpp 20 | ``` 21 | Then, we execute the generated benchmark. 22 | ```sh 23 | cd ../HALO 24 | cmake --build ./build --config Release --target all 25 | ./build/bin/database 26 | ``` 27 | 28 | ## 3.2 K-Means Evaluation 29 | Execute the following instructions in ``HEIR/`` directory. 30 | 31 | First, we compile the original C program to C++ homomorphic APIs and plug it to HALO library. 32 | ```sh 33 | ./tools/cgeist ./benchmarks/e2e/kmeans.c \ 34 | -function=kmeans -S \ 35 | -raise-scf-to-affine \ 36 | --memref-fullrank -O0 \ 37 | >> ./benchmarks/e2e/kmeans.mlir 38 | python ./format_assistant/polygeist_eliminator.py -i ./benchmarks/e2e/kmeans.mlir 39 | ./tools/heir-opt ./benchmarks/e2e/kmeans.mlir \ 40 | --branch --affine-loop-unroll="unroll-full unroll-num-reps=4" \ 41 | --logic-emitc \ 42 | >> ./benchmarks/e2e/kmeans_emitc.mlir 43 | ./tools/emitc-translate ./benchmarks/e2e/kmeans_emitc.mlir \ 44 | --mlir-to-cpp \ 45 | >> ./benchmarks/e2e/kmeans.cpp 46 | python ./format_assistant/halo_transmitter.py -i ./benchmarks/e2e/kmeans.cpp -o ../HALO/ndss_experiment/kmeans.cpp 47 | ``` 48 | Then, we execute the generated benchmark. 49 | ```sh 50 | cd ../HALO 51 | cmake --build ./build --config Release --target all 52 | ./build/bin/kmeans 53 | ``` -------------------------------------------------------------------------------- /benchmarks/e2e/database.c: -------------------------------------------------------------------------------- 1 | float database(float data[4], float acc) 2 | { 3 | for (int i = 0; i < 4; i++) { 4 | if (data[i] > 5) { 5 | acc += data[i]; 6 | } 7 | } 8 | return acc; 9 | } -------------------------------------------------------------------------------- /benchmarks/e2e/kmeans.c: -------------------------------------------------------------------------------- 1 | #define DATANUM 5 2 | #define DATADIM 3 3 | #define CENTNUM 2 4 | 5 | float euclid_dist(float data[DATADIM], float cent[DATADIM]) 6 | { 7 | return data[0]; 8 | } 9 | 10 | float lut_abs(float a) 11 | { 12 | return a; 13 | } 14 | 15 | float lut_lsz(float a) 16 | { 17 | return a; 18 | } 19 | 20 | float inner_product(float a[DATADIM], float b[DATADIM]) 21 | { 22 | return a[0]; 23 | } 24 | 25 | float lut_inverse(float a) 26 | { 27 | return a; 28 | } 29 | 30 | float kmeans(float data[DATANUM][DATADIM], float cent[CENTNUM][DATADIM]) 31 | { 32 | float data_tran[DATADIM][DATANUM]; 33 | for (int i = 0; i < DATANUM; i++) { 34 | for (int j = 0; j < DATADIM; j++) { 35 | data_tran[j][i] = data[i][j]; 36 | } 37 | } 38 | 39 | float dist_matrix[DATANUM][CENTNUM]; 40 | for (int i = 0; i < DATANUM; i++) { 41 | for (int j = 0; j < CENTNUM; j++) { 42 | dist_matrix[i][j] = euclid_dist(data[i], cent[j]); 43 | } 44 | } 45 | 46 | // Compute Min-Index 47 | // 1. Compute Min_value 48 | // 2. Mi = Mi - min 49 | // 3. LUT(Mi < 0) 50 | float index_matrix[DATANUM][CENTNUM]; 51 | float min_value; 52 | float sub; 53 | // float add; 54 | float msb; 55 | for (int i = 0; i < DATANUM; i++) { 56 | // Compute min_value 57 | sub = dist_matrix[i][0] - dist_matrix[i][1]; 58 | msb = lut_lsz(sub); 59 | min_value = msb * dist_matrix[i][0] +(1 - msb) * dist_matrix[i][1]; 60 | // Mi = Mi - min_value 61 | index_matrix[i][0] = dist_matrix[i][0] + dist_matrix[i][0]; 62 | index_matrix[i][0] = index_matrix[i][0] - min_value; 63 | index_matrix[i][1] = dist_matrix[i][1] + dist_matrix[i][1]; 64 | index_matrix[i][1] = index_matrix[i][1] - min_value; 65 | // LUT(Mi < 0) 66 | index_matrix[i][0] = lut_lsz(index_matrix[i][0]); 67 | index_matrix[i][1] = lut_lsz(index_matrix[i][1]); 68 | } 69 | 70 | float index_column[CENTNUM][DATANUM]; 71 | for (int i = 0; i < DATANUM; i++) { 72 | for (int j = 0; j < CENTNUM; j++) { 73 | index_column[j][i] = index_matrix[i][j]; 74 | } 75 | } 76 | 77 | float cent_result[CENTNUM][DATADIM]; 78 | float inverse; 79 | for(int i = 0; i < CENTNUM; i++) { 80 | inverse = index_matrix[0][i]; 81 | for (int k = 1; k < DATANUM; k++) { 82 | inverse = inverse + index_matrix[k][i]; 83 | } 84 | inverse = lut_inverse(inverse); 85 | for (int j = 0; j < DATADIM; j++) { 86 | cent_result[i][j] = inner_product(data_tran[j], index_column[i]); 87 | cent_result[i][j] = inverse * cent_result[i][j]; 88 | } 89 | } 90 | 91 | return cent_result[1][1]; 92 | // return inverse; 93 | 94 | } -------------------------------------------------------------------------------- /benchmarks/logic/README.md: -------------------------------------------------------------------------------- 1 | # Experment (E2): Logic Experiments 2 | ## 2.1 Min Value Evaluation 3 | Execute the following instructions in ``HEIR/`` directory. 4 | 5 | First, we compile the original C program to C++ homomorphic APIs and plug it to HALO library. 6 | ```sh 7 | ./tools/cgeist ./benchmarks/logic/min_value.c \ 8 | -function=min_value -S \ 9 | -raise-scf-to-affine \ 10 | --memref-fullrank -O0 \ 11 | >> ./benchmarks/logic/min_value.mlir 12 | ./tools/heir-opt ./benchmarks/logic/min_value.mlir \ 13 | --affine-loop-unroll="unroll-full=true" \ 14 | --logic-emitc \ 15 | >> ./benchmarks/logic/min_value_emitc.mlir 16 | ./tools/emitc-translate ./benchmarks/logic/min_value_emitc.mlir \ 17 | --mlir-to-cpp \ 18 | >> ./benchmarks/logic/min_value.cpp 19 | python ./format_assistant/halo_transmitter.py -i ./benchmarks/logic/min_value.cpp -o ../HALO/ndss_experiment/min_value.cpp 20 | ``` 21 | Then, we execute the generated benchmark. 22 | ```sh 23 | cd ../HALO 24 | cmake --build ./build --config Release --target all 25 | ./build/bin/min_value 26 | ``` 27 | ## 2.2 Min Index Evaluation 28 | Execute the following instructions in ``HEIR/`` directory. 29 | 30 | First, we compile the original C program to C++ homomorphic APIs and plug it to HALO library. 31 | ```sh 32 | ./tools/cgeist ./benchmarks/logic/min_index.c \ 33 | -function=min_index -S \ 34 | -raise-scf-to-affine \ 35 | --memref-fullrank -O0 \ 36 | >> ./benchmarks/logic/min_index.mlir 37 | ./tools/heir-opt ./benchmarks/logic/min_index.mlir \ 38 | --affine-loop-unroll="unroll-full=true" \ 39 | --logic-emitc \ 40 | >> ./benchmarks/logic/min_index_emitc.mlir 41 | ./tools/emitc-translate ./benchmarks/logic/min_index_emitc.mlir \ 42 | --mlir-to-cpp \ 43 | >> ./benchmarks/logic/min_index.cpp 44 | python ./format_assistant/halo_transmitter.py -i ./benchmarks/logic/min_index.cpp -o ../HALO/ndss_experiment/min_index.cpp 45 | ``` 46 | Then, we execute the generated benchmark. 47 | ```sh 48 | cd ../HALO 49 | cmake --build ./build --config Release --target all 50 | ./build/bin/min_index 51 | ``` 52 | 53 | ## 2.3 Fibonacci Evaluation 54 | Execute the following instructions in ``HEIR/`` directory. 55 | 56 | First, we compile the original C program to C++ homomorphic APIs and plug it to HALO library. 57 | ```sh 58 | ./tools/cgeist ./benchmarks/logic/fibonacci.c \ 59 | -function=fibonacci -S \ 60 | -raise-scf-to-affine \ 61 | --memref-fullrank -O0 \ 62 | >> ./benchmarks/logic/fibonacci.mlir 63 | ./tools/heir-opt ./benchmarks/logic/fibonacci.mlir \ 64 | --branch --affine-loop-unroll="unroll-full=true" \ 65 | --logic-emitc \ 66 | >> ./benchmarks/logic/fibonacci_emitc.mlir 67 | ./tools/emitc-translate ./benchmarks/logic/fibonacci_emitc.mlir \ 68 | --mlir-to-cpp \ 69 | >> ./benchmarks/logic/fibonacci.cpp 70 | python ./format_assistant/halo_transmitter.py -i ./benchmarks/logic/fibonacci.cpp -o ../HALO/ndss_experiment/fibonacci.cpp 71 | ``` 72 | Then, we execute the generated benchmark. 73 | ```sh 74 | cd ../HALO 75 | cmake --build ./build --config Release --target all 76 | ./build/bin/fibonacci 77 | ``` -------------------------------------------------------------------------------- /benchmarks/logic/fibonacci.c: -------------------------------------------------------------------------------- 1 | float fibonacci(float pre, float cur, float count, float output) 2 | { 3 | float temp; 4 | for (int i = 0; i < 4; i++) { 5 | if (i < count) { 6 | temp = cur; 7 | cur = pre + cur; 8 | pre = temp; 9 | } 10 | output = cur; 11 | } 12 | return output; 13 | } -------------------------------------------------------------------------------- /benchmarks/logic/min_index.c: -------------------------------------------------------------------------------- 1 | float sgn(float input) 2 | { 3 | return input; 4 | } 5 | 6 | float min_index(float a[4], float min_value) 7 | { 8 | min_value = a[0]; 9 | for (int i = 1; i < 4; i++) { 10 | if (min_value > a[i]) min_value = a[i]; 11 | } 12 | 13 | float min_index[4]; 14 | for (int i = 0; i < 4; i++) { 15 | min_index[i] = a[i] - min_value; 16 | min_index[i] = sgn(min_index[i]); 17 | } 18 | 19 | return min_value; 20 | } -------------------------------------------------------------------------------- /benchmarks/logic/min_value.c: -------------------------------------------------------------------------------- 1 | float min_value(float a[4], float min_value) 2 | { 3 | min_value = a[0]; 4 | for (int i = 1; i < 4; i++) { 5 | if (min_value > a[i]) min_value = a[i]; 6 | } 7 | 8 | return min_value; 9 | } -------------------------------------------------------------------------------- /cmake/modules/AddHEIR.cmake: -------------------------------------------------------------------------------- 1 | # Authors: HECO 2 | # Modified by Zian Zhao 3 | # Copyright: 4 | # Copyright (c) 2020 ETH Zurich. 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # The above copyright notice and this permission notice shall be included in all 12 | # copies or substantial portions of the Software. 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | include_guard() 22 | 23 | function(add_heir_dialect dialect dialect_namespace) 24 | add_mlir_dialect(${ARGV}) 25 | add_dependencies(heir-headers MLIR${dialect}IncGen) 26 | endfunction() 27 | 28 | 29 | function(add_heir_library name) 30 | add_mlir_library(${ARGV}) 31 | add_heir_library_install(${name}) 32 | endfunction() 33 | 34 | # Adds a HEIR library target for installation. This should normally only be 35 | # called from add_heir_library(). 36 | function(add_heir_library_install name) 37 | install(TARGETS ${name} COMPONENT ${name} EXPORT HEIRTargets) 38 | set_property(GLOBAL APPEND PROPERTY HEIR_ALL_LIBS ${name}) 39 | set_property(GLOBAL APPEND PROPERTY HEIR_EXPORTS ${name}) 40 | endfunction() 41 | 42 | function(add_heir_dialect_library name) 43 | set_property(GLOBAL APPEND PROPERTY HEIR_DIALECT_LIBS ${name}) 44 | add_heir_library(${ARGV} DEPENDS heir-headers) 45 | endfunction() 46 | 47 | function(add_heir_conversion_library name) 48 | set_property(GLOBAL APPEND PROPERTY HEIR_CONVERSION_LIBS ${name}) 49 | add_heir_library(${ARGV} DEPENDS heir-headers) 50 | endfunction() 51 | -------------------------------------------------------------------------------- /cmake/modules/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Generate a list of CMake library targets so that other CMake projects can 2 | # link against them. 3 | set(HEIR_INSTALL_PACKAGE_DIR lib${LLVM_LIBDIR_SUFFIX}/cmake/heir) 4 | set(heir_cmake_builddir "${CMAKE_BINARY_DIR}/${HEIR_INSTALL_PACKAGE_DIR}") 5 | 6 | # Keep this in sync with mlir/cmake/CMakeLists.txt! 7 | set(MLIR_INSTALL_PACKAGE_DIR lib${LLVM_LIBDIR_SUFFIX}/cmake/mlir) 8 | set(mlir_cmake_builddir "${MLIR_BINARY_DIR}/${MLIR_INSTALL_PACKAGE_DIR}") 9 | 10 | # Keep this in sync with llvm/cmake/CMakeLists.txt! 11 | set(LLVM_INSTALL_PACKAGE_DIR lib${LLVM_LIBDIR_SUFFIX}/cmake/llvm) 12 | set(llvm_cmake_builddir "${LLVM_BINARY_DIR}/${LLVM_INSTALL_PACKAGE_DIR}") 13 | 14 | # Generate a list of CMake library targets so that other CMake projects can 15 | # link against them. LLVM calls its version of this file LLVMExports.cmake, but 16 | # the usual CMake convention seems to be ${Project}Targets.cmake. 17 | get_property(HEIR_EXPORTS GLOBAL PROPERTY HEIR_EXPORTS) 18 | export(TARGETS ${HEIR_EXPORTS} FILE ${heir_cmake_builddir}/HEIRTargets.cmake) 19 | 20 | get_property(HEIR_ALL_LIBS GLOBAL PROPERTY HEIR_ALL_LIBS) 21 | get_property(HEIR_DIALECT_LIBS GLOBAL PROPERTY HEIR_DIALECT_LIBS) 22 | get_property(HEIR_CONVERSION_LIBS GLOBAL PROPERTY HEIR_CONVERSION_LIBS) 23 | get_property(HEIR_TRANSLATION_LIBS GLOBAL PROPERTY HEIR_TRANSLATION_LIBS) 24 | get_property(HEIR_ANALYSIS_LIBS GLOBAL PROPERTY HEIR_ANALYSIS_LIBS) 25 | 26 | # Generate HEIRConfig.cmake for the build tree. 27 | set(HEIR_CONFIG_CMAKE_DIR "${heir_cmake_builddir}") 28 | set(HEIR_CONFIG_LLVM_CMAKE_DIR "${llvm_cmake_builddir}") 29 | set(HEIR_CONFIG_MLIR_CMAKE_DIR "${mlir_cmake_builddir}") 30 | set(HEIR_CONFIG_LIBRARY_DIRS "${HEIR_LIBRARY_DIR}") 31 | set(HEIR_CONFIG_BINARY_DIR "${HEIR_BINARY_DIR}") 32 | set(HEIR_CONFIG_TOOLS_DIR "${HEIR_TOOLS_DIR}") 33 | set(HEIR_CONFIG_INCLUDE_EXPORTS "include(\"\${HEIR_CMAKE_DIR}/HEIRTargets.cmake\")") 34 | set(HEIR_CONFIG_INCLUDE_DIRS 35 | "${HEIR_SOURCE_DIR}/include" 36 | "${HEIR_BINARY_DIR}/include" 37 | ) 38 | configure_file( 39 | ${CMAKE_CURRENT_SOURCE_DIR}/HEIRConfig.cmake.in 40 | ${heir_cmake_builddir}/HEIRConfig.cmake 41 | @ONLY) 42 | set(HEIR_CONFIG_CMAKE_DIR) 43 | set(HEIR_CONFIG_LLVM_CMAKE_DIR) 44 | set(HEIR_CONFIG_MLIR_CMAKE_DIR) 45 | set(HEIR_CONFIG_LIBRARY_DIRS) 46 | set(HEIR_CONFIG_BINARY_DIR) 47 | set(HEIR_CONFIG_TOOLS_DIR) 48 | set(HEIR_CONFIG_INCLUDE_EXPORTS) 49 | set(HEIR_CONFIG_INCLUDE_DIRS) 50 | 51 | # Generate HEIRConfig.cmake for the install tree. 52 | set(HEIR_CONFIG_CODE " 53 | # Compute the installation prefix from this HEIRConfig.cmake file location. 54 | get_filename_component(HEIR_INSTALL_PREFIX \"\${CMAKE_CURRENT_LIST_FILE}\" PATH)") 55 | # Construct the proper number of get_filename_component(... PATH) 56 | # calls to compute the installation prefix. 57 | string(REGEX REPLACE "/" ";" _count "${HEIR_INSTALL_PACKAGE_DIR}") 58 | foreach(p ${_count}) 59 | set(HEIR_CONFIG_CODE "${HEIR_CONFIG_CODE} 60 | get_filename_component(HEIR_INSTALL_PREFIX \"\${HEIR_INSTALL_PREFIX}\" PATH)") 61 | endforeach(p) 62 | set(HEIR_CONFIG_CMAKE_DIR "\${HEIR_INSTALL_PREFIX}/${HEIR_INSTALL_PACKAGE_DIR}") 63 | set(HEIR_CONFIG_LLVM_CMAKE_DIR "\${HEIR_INSTALL_PREFIX}/${LLVM_INSTALL_PACKAGE_DIR}") 64 | set(HEIR_CONFIG_MLIR_CMAKE_DIR "\${HEIR_INSTALL_PREFIX}/${MLIR_INSTALL_PACKAGE_DIR}") 65 | set(HEIR_CONFIG_LIBRARY_DIRS "\${HEIR_INSTALL_PREFIX}/lib") 66 | set(HEIR_CONFIG_BINARY_DIR "\${HEIR_INSTALL_PREFIX}") 67 | set(HEIR_CONFIG_TOOLS_DIR "\${HEIR_INSTALL_PREFIX}/bin") 68 | set(HEIR_CONFIG_INCLUDE_EXPORTS "include(\"\${HEIR_CMAKE_DIR}/HEIRTargets.cmake\")") 69 | set(HEIR_CONFIG_INCLUDE_DIRS 70 | "\${HEIR_INSTALL_PREFIX}/include" 71 | ) 72 | configure_file( 73 | ${CMAKE_CURRENT_SOURCE_DIR}/HEIRConfig.cmake.in 74 | ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/HEIRConfig.cmake 75 | @ONLY) 76 | set(HEIR_CONFIG_CODE) 77 | set(HEIR_CONFIG_CMAKE_DIR) 78 | set(HEIR_CONFIG_LLVM_CMAKE_DIR) 79 | set(HEIR_CONFIG_MLIR_CMAKE_DIR) 80 | set(HEIR_CONFIG_LIBRARY_DIRS) 81 | set(HEIR_CONFIG_BINARY_DIR) 82 | set(HEIR_CONFIG_TOOLS_DIR) 83 | set(HEIR_CONFIG_INCLUDE_EXPORTS) 84 | set(HEIR_CONFIG_INCLUDE_DIRS) 85 | 86 | if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY) 87 | # Not TOOLCHAIN ONLY, so install the HEIR parts as well 88 | # Include the cmake files so other tools can use heir-tblgen, etc. 89 | install(EXPORT HEIRTargets DESTINATION ${HEIR_INSTALL_PACKAGE_DIR} 90 | COMPONENT heir-cmake-exports) 91 | 92 | install(FILES 93 | ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/HEIRConfig.cmake 94 | ${CMAKE_CURRENT_SOURCE_DIR}/AddHEIR.cmake 95 | DESTINATION ${HEIR_INSTALL_PACKAGE_DIR} 96 | COMPONENT heir-cmake-exports) 97 | 98 | if(NOT LLVM_ENABLE_IDE) 99 | # Add a dummy target so this can be used with LLVM_DISTRIBUTION_COMPONENTS 100 | add_custom_target(heir-cmake-exports) 101 | add_llvm_install_targets(install-heir-cmake-exports 102 | COMPONENT heir-cmake-exports) 103 | endif() 104 | endif() -------------------------------------------------------------------------------- /cmake/modules/HEIRConfig.cmake.in: -------------------------------------------------------------------------------- 1 | # Authors: HECO 2 | # Modified by Zian Zhao 3 | # Copyright: 4 | # Copyright (c) 2020 ETH Zurich. 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # The above copyright notice and this permission notice shall be included in all 12 | # copies or substantial portions of the Software. 13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | # SOFTWARE. 20 | 21 | # This file allows users to call find_package(HEIR) and pick up our targets. 22 | 23 | @HEIR_CONFIG_CODE@ 24 | 25 | find_package(MLIR REQUIRED CONFIG 26 | HINTS "@HEIR_CONFIG_MLIR_CMAKE_DIR@") 27 | 28 | set(HEIR_EXPORTED_TARGETS "@HEIR_EXPORTS@") 29 | set(HEIR_CMAKE_DIR "@HEIR_CONFIG_CMAKE_DIR@") 30 | set(HEIR_BINARY_DIR "@HEIR_CONFIG_BINARY_DIR@") 31 | set(HEIR_INCLUDE_DIRS "@HEIR_CONFIG_INCLUDE_DIRS@") 32 | set(HEIR_LIBRARY_DIRS "@HEIR_CONFIG_LIBRARY_DIRS@") 33 | set(HEIR_TOOLS_DIR "@HEIR_CONFIG_TOOLS_DIR@") 34 | 35 | set_property(GLOBAL PROPERTY HEIR_ALL_LIBS "@HEIR_ALL_LIBS@") 36 | set_property(GLOBAL PROPERTY HEIR_DIALECT_LIBS "@HEIR_DIALECT_LIBS@") 37 | set_property(GLOBAL PROPERTY HEIR_CONVERSION_LIBS "@HEIR_CONVERSION_LIBS@") 38 | set_property(GLOBAL PROPERTY HEIR_TRANSLATION_LIBS "@HEIR_TRANSLATION_LIBS@") 39 | 40 | # Provide all our library targets to users. 41 | @HEIR_CONFIG_INCLUDE_EXPORTS@ 42 | 43 | # By creating these targets here, subprojects that depend on HEIR's 44 | # tablegen-generated headers can always depend on these targets whether building 45 | # in-tree with HEIR or not. 46 | if(NOT TARGET heir-tablegen-targets) 47 | add_custom_target(heir-tablegen-targets) 48 | endif() 49 | if(NOT TARGET heir-headers) 50 | add_custom_target(heir-headers) 51 | endif() 52 | if(NOT TARGET heir-generic-headers) 53 | add_custom_target(heir-generic-headers) 54 | endif() 55 | if(NOT TARGET heir-doc) 56 | add_custom_target(heir-doc) 57 | endif() -------------------------------------------------------------------------------- /format_assistant/halo_transmitter.py: -------------------------------------------------------------------------------- 1 | # Author: Zian Zhao 2 | import sys 3 | import getopt 4 | import re 5 | 6 | # Transmit the generated IR code into the HALO demo C++ files 7 | # Since HALO still has bugs in passing evaluation keys 8 | # we cannot directly include a external function to compute the benchmarks 9 | def main(argv): 10 | input_file = "" 11 | output_file = "" 12 | 13 | opts, args = getopt.getopt(argv[1:], "hi:o:", ["help", "input_file=", "output_file="]) 14 | 15 | for opt, arg in opts: 16 | if opt in ("-h", "--help"): 17 | print('poly_eliminator.py -i -o ') 18 | print('or: test_arg.py --input_file= --output_file=') 19 | sys.exit() 20 | elif opt in ("-i", "--input_file"): 21 | input_file = arg 22 | elif opt in ("-o", "--output_file"): 23 | output_file = arg 24 | print('Input File:', input_file) 25 | print('Output File:', output_file) 26 | 27 | 28 | f_in = open(input_file, 'r') 29 | 30 | f_out_read = open(output_file, 'r') 31 | out_lines = f_out_read.readlines() 32 | insert_line = 0 33 | for i, line in enumerate(out_lines): 34 | if "AutoTimer timer(&evaluation_time);" in line: 35 | insert_line = i 36 | break 37 | f_out_read.close() 38 | 39 | f_out_write = open(output_file, "w") 40 | 41 | in_lines = f_in.readlines() 42 | for line in in_lines: 43 | if "{" in line: 44 | continue 45 | if "return" in line: 46 | break 47 | if "lut" in line: 48 | str_index = line.find(')') 49 | line = line[:str_index] + ', fb_keys' + line[str_index:] 50 | elif "euclid" in line: 51 | str_index = line.find(')') 52 | line = line[:str_index] + ', repack_galois_keys, repack_key, relin_keys' + line[str_index:] 53 | elif "inner" in line: 54 | str_index = line.find(')') 55 | line = line[:str_index] + ', repack_galois_keys, repack_key, relin_keys' + line[str_index:] 56 | elif "lwe_multiply" in line: 57 | str_index = line.find(')') 58 | line = line[:str_index] + ', repack_galois_keys, repack_key, relin_keys' + line[str_index:] 59 | elif "rlwe_multily" in line: 60 | str_index = line.find(')') 61 | line = line[:str_index] + ', repack_galois_keys, repack_key, relin_keys' + line[str_index:] 62 | elif "encode" in line: 63 | str_index = line.find(', ') 64 | line = line[:str_index] + ', scale, lwe_parms' + line[str_index:] 65 | 66 | insert_line += 1 67 | out_lines.insert(insert_line, line) 68 | 69 | f_out_write.writelines(out_lines) 70 | 71 | f_in.close() 72 | f_out_write.close() 73 | 74 | 75 | if __name__ == "__main__": 76 | main(sys.argv) 77 | -------------------------------------------------------------------------------- /format_assistant/polygeist_eliminator.py: -------------------------------------------------------------------------------- 1 | # Author: Zian Zhao 2 | import sys 3 | import getopt 4 | import re 5 | 6 | # replace polygeist.SubIndexOp with heir.FHEVectorLoadOp 7 | # TODO: support polygeist dialect in heir and discard this script 8 | def main(argv): 9 | input_file = "" 10 | opts, args = getopt.getopt(argv[1:], "hi:", ["help", "input_file=", "output_file="]) 11 | 12 | for opt, arg in opts: 13 | if opt in ("-h", "--help"): 14 | print('poly_eliminator.py -i ') 15 | print('or: test_arg.py --input_file=') 16 | sys.exit() 17 | elif opt in ("-i", "--input_file"): 18 | input_file = arg 19 | print('Input File:', input_file) 20 | 21 | f_in = open(input_file, 'r') 22 | lines = f_in.readlines() 23 | 24 | str_poly = "polygeist.subindex" 25 | 26 | for i, line in enumerate(lines): 27 | if str_poly in line: 28 | res = line.split("\"" + str_poly)[0] 29 | out_type = line.split("-> memref")[1] 30 | in_type = line.split(": (")[1].split(", index")[0] 31 | memref = line.split("subindex\"(")[1].split(") : ")[0] 32 | memref, index = memref.split(", ") 33 | full_type = line.split(" : ")[1] 34 | 35 | str_heir = res + "\"heir.vector_load_init\"(" + memref + ", " + index + ") : (" + \ 36 | in_type + ", index) -> memref" + out_type 37 | lines[i] = str_heir 38 | 39 | f_in.close() 40 | 41 | f_out = open(input_file, 'w') 42 | 43 | f_out.writelines(lines) 44 | 45 | f_out.close() 46 | 47 | 48 | if __name__ == "__main__": 49 | main(sys.argv) 50 | -------------------------------------------------------------------------------- /include/heir/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(IR) 2 | add_subdirectory(Passes) -------------------------------------------------------------------------------- /include/heir/IR/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(FHE) -------------------------------------------------------------------------------- /include/heir/IR/FHE/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_heir_dialect(HEIR heir) -------------------------------------------------------------------------------- /include/heir/IR/FHE/HEIR.td: -------------------------------------------------------------------------------- 1 | //===- Ops.td - Toy dialect operation definitions ----------*- tablegen -*-===// 2 | //===----------------------------------------------------------------------===// 3 | // 4 | // Defines the operations of the HEIR dialect. 5 | // 6 | //===----------------------------------------------------------------------===// 7 | 8 | #ifndef HEIR_OPS 9 | #define HEIR_OPS 10 | 11 | include "mlir/IR/OpBase.td" 12 | include "mlir/IR/AttrTypeBase.td" 13 | include "mlir/Interfaces/SideEffectInterfaces.td" 14 | include "mlir/Dialect/Shape/IR/ShapeBase.td" 15 | include "mlir/Interfaces/CallInterfaces.td" 16 | include "mlir/Interfaces/CastInterfaces.td" 17 | include "mlir/Interfaces/ControlFlowInterfaces.td" 18 | include "mlir/Interfaces/InferTypeOpInterface.td" 19 | include "mlir/IR/OpAsmInterface.td" 20 | include "mlir/IR/SymbolInterfaces.td" 21 | include "mlir/Dialect/Arithmetic/IR/ArithmeticBase.td" 22 | // include "mlir/Dialect/Arith/IR/ArithBase.td" 23 | 24 | 25 | // Provide a definition of the 'heir' dialect in the ODS framework so that we 26 | // can define our operations. 27 | def HEIR_Dialect : Dialect { 28 | let name = "heir"; 29 | 30 | let description = [{ 31 | This dialect represents a common abstraction for all RLWE/LWE operations. 32 | }]; 33 | 34 | // let cppNamespace = "::heir::heir"; 35 | let cppNamespace = "::heir"; 36 | 37 | // We set this bit to generate a declaration of the `materializeConstant` 38 | // method so that we can materialize constants for our toy operations. 39 | // let hasConstantMaterializer = 1; 40 | let useDefaultTypePrinterParser = 1; 41 | } 42 | 43 | // def FHECmpPredicateAttr : I64EnumAttr< 44 | // "FHECmpPredicate", "", 45 | // [ 46 | // // I64EnumAttrCase<"AlwaysFalse", 0, "false">, 47 | // I64EnumAttrCase<"OEQ", 1, "oeq">, 48 | // I64EnumAttrCase<"OGT", 2, "ogt">, 49 | // I64EnumAttrCase<"OGE", 3, "oge">, 50 | // I64EnumAttrCase<"OLT", 4, "olt">, 51 | // I64EnumAttrCase<"OLE", 5, "ole">, 52 | // I64EnumAttrCase<"ONE", 6, "one">, 53 | // I64EnumAttrCase<"ORD", 7, "ord">, 54 | // I64EnumAttrCase<"UEQ", 8, "ueq">, 55 | // I64EnumAttrCase<"UGT", 9, "ugt">, 56 | // I64EnumAttrCase<"UGE", 10, "uge">, 57 | // I64EnumAttrCase<"ULT", 11, "ult">, 58 | // I64EnumAttrCase<"ULE", 12, "ule">, 59 | // I64EnumAttrCase<"UNE", 13, "une">, 60 | // I64EnumAttrCase<"UNO", 14, "uno">, 61 | // // I64EnumAttrCase<"AlwaysTrue", 15, "true">, 62 | // ]> { 63 | // let cppNamespace = "::heir"; 64 | // } 65 | 66 | // Base class for toy dialect operations. This operation inherits from the base 67 | // `Op` class in OpBase.td, and provides: 68 | // * The parent dialect of the operation. 69 | // * The mnemonic for the operation, or the name without the dialect prefix. 70 | // * A list of traits for the operation. 71 | class HEIR_Op traits = []> : 72 | Op { 73 | 74 | let assemblyFormat = [{ 75 | `(` operands `)` attr-dict `:` `(` type(operands) `)` `->` type(results) 76 | }]; 77 | } 78 | 79 | // Provide a definition for the HEIR StructType for use in ODS. This allows for 80 | // using StructType in a similar way to Tensor or MemRef. We use `DialectType` 81 | // to demarcate the StructType as belonging to the HEIR dialect. 82 | // def HEIR_StructType : 83 | // DialectType()">, 84 | // "HEIR struct type">; 85 | 86 | //===----------------------------------------------------------------------===// 87 | // HEIR Operations 88 | //===----------------------------------------------------------------------===// 89 | def String : TypeDef { 90 | 91 | let description = "A type for defining LUT function"; 92 | 93 | let mnemonic = "string"; 94 | 95 | let summary = "String"; 96 | } 97 | 98 | def Plain : TypeDef { 99 | 100 | let description = "A type for encoded Plaintext"; 101 | 102 | let mnemonic = "plain"; 103 | 104 | let summary = "Plain"; 105 | 106 | // let parameters = (ins 107 | // "Type":$plaintextType 108 | // ); 109 | } 110 | 111 | def Int : TypeDef { 112 | 113 | let description = "A type for Integer"; 114 | 115 | let mnemonic = "int"; 116 | 117 | let summary = "int"; 118 | } 119 | 120 | def Float : TypeDef { 121 | 122 | let description = "A type for Float"; 123 | 124 | let mnemonic = "float"; 125 | 126 | let summary = "float"; 127 | } 128 | 129 | def F64Vector : TypeDef { 130 | 131 | let description = "A type for vector of float"; 132 | 133 | let mnemonic = "f64vector"; 134 | 135 | let summary = "f64vector"; 136 | } 137 | 138 | def PlainVector : TypeDef { 139 | 140 | let description = "A type for vector of plain"; 141 | 142 | let mnemonic = "plainvector"; 143 | 144 | let summary = "plainvector"; 145 | } 146 | 147 | def LWECipher : TypeDef { 148 | 149 | let description = "A type for LWE Cipher"; 150 | 151 | let mnemonic = "lwecipher"; 152 | 153 | let summary = "lwecipher"; 154 | 155 | let parameters = (ins "Type":$plaintextType); 156 | 157 | let assemblyFormat = "`<` $plaintextType `>`"; 158 | } 159 | 160 | def RLWECipher : TypeDef { 161 | 162 | let description = "A type for RLWE Cipher"; 163 | 164 | let mnemonic = "rlwecipher"; 165 | 166 | let summary = "rlwecipher"; 167 | 168 | let parameters = (ins 169 | "Type":$plaintextType, 170 | "int":$size 171 | ); 172 | 173 | let assemblyFormat = "`<` $size `x` $plaintextType `>`"; 174 | } 175 | 176 | def RGSWCipher : TypeDef { 177 | 178 | let description = "A type for RGSW Cipher"; 179 | 180 | let mnemonic = "rgswcipher"; 181 | 182 | let summary = "rgswcipher"; 183 | } 184 | 185 | def LWECipherVector : TypeDef { 186 | 187 | let description = "A type for vector of LWE Cipher"; 188 | 189 | let mnemonic = "lweciphervec"; 190 | 191 | let summary = "lweciphervec"; 192 | 193 | let parameters = (ins 194 | "Type":$plaintextType, 195 | "int":$size 196 | ); 197 | 198 | let assemblyFormat = "`<` $size`x`$plaintextType `>`"; 199 | } 200 | 201 | def LWECipherMatrix: TypeDef { 202 | 203 | let description = "A type for matrix of LWE Cipher"; 204 | 205 | let mnemonic = "lweciphermat"; 206 | 207 | let summary = "lweciphermat"; 208 | 209 | let parameters = (ins 210 | "Type":$plaintextType, 211 | "int":$row, 212 | "int":$column 213 | ); 214 | 215 | let assemblyFormat = "`<` $row`x`$column`x`$plaintextType `>`"; 216 | } 217 | 218 | def RLWECipherVector: TypeDef { 219 | 220 | let description = "A type for vector of RLWE Cipher, corresponding to a plaintext matrix"; 221 | 222 | let mnemonic = "lweciphermat"; 223 | 224 | let summary = "lweciphermat"; 225 | 226 | let parameters = (ins 227 | "Type":$plaintextType, 228 | "int":$row, 229 | "int":$column 230 | ); 231 | 232 | let assemblyFormat = "`<` $row`x`$column`x`$plaintextType `>`"; 233 | } 234 | 235 | // Provide a definition of the types that are used within the HEIR dialect. 236 | def HEIR_Type : AnyTypeOf<[String, Int, Float, F64Vector, Plain, PlainVector, 237 | LWECipher, RLWECipher, RGSWCipher, LWECipherVector, 238 | LWECipherMatrix, RLWECipherVector]>; 239 | 240 | //===----------------------------------------------------------------------===// 241 | // HEIR Operations 242 | //===----------------------------------------------------------------------===// 243 | 244 | // We define a toy operation by inheriting from our base 'HEIR_Op' class above. 245 | // Here we provide the mnemonic and a list of traits for the operation. The 246 | // constant operation is marked as '' as it is a pure operation 247 | // and may be removed if dead. 248 | def FHEDefineOp : HEIR_Op<"define", 249 | [NoSideEffect]> { 250 | let summary = "Define a new ciphertext"; 251 | let description = [{ 252 | Convert variable assignment in C program to ciphertext definition in FHE porgram 253 | }]; 254 | 255 | // let arguments = (ins AnyType:$input); 256 | 257 | let results = (outs HEIR_Type:$output); 258 | } 259 | 260 | def FHEEncodeOp : HEIR_Op<"encode", 261 | [NoSideEffect]> { 262 | let summary = "LWE Encryption"; 263 | let description = [{ 264 | LWE Encryption fuction 265 | }]; 266 | 267 | let arguments = (ins F32Attr:$message); 268 | let results = (outs AnyType:$cipher); 269 | 270 | } 271 | 272 | def FHEExtractOp : HEIR_Op<"extract_init", 273 | [NoSideEffect]> { 274 | let summary = "Extract a single value from plain vector"; 275 | let description = [{ 276 | Extract a single value from plain vector. 277 | }]; 278 | 279 | let arguments = (ins AnyType:$vector, Variadic:$i); 280 | let results = (outs AnyType:$result); 281 | // let assemblyFormat = "$vector `[` $i `]` attr-dict `:` type($result)"; 282 | 283 | } 284 | 285 | def FHEExtractfinalOp : HEIR_Op<"extract", 286 | [NoSideEffect]> { 287 | let summary = "Extract a single value from plain vector"; 288 | let description = [{ 289 | Extract a single value from plain vector. 290 | }]; 291 | 292 | let arguments = (ins AnyTypeOf<[LWECipherVector,LWECipherMatrix,RLWECipher,RLWECipherVector]>:$vector, 293 | AnyAttr:$col, OptionalAttr:$row); 294 | let results = (outs LWECipher:$result); 295 | // let assemblyFormat = [{ 296 | // $vector `[` $i `]` attr-dict `:` type($result) 297 | // }]; 298 | 299 | } 300 | 301 | def FHEInsertOp : HEIR_Op<"insert_init", 302 | []> { 303 | let summary = "Insert a single value to plain vector"; 304 | let description = [{ 305 | Insert a single value to plain vector. 306 | }]; 307 | 308 | let arguments = (ins AnyType:$value, AnyType:$memref, Variadic:$index); 309 | // let results = (outs AnyType:$result); 310 | } 311 | 312 | 313 | def FHEInsertfinalOp : HEIR_Op<"insert", 314 | []> { 315 | let summary = "Insert a single value to plain vector"; 316 | let description = [{ 317 | Insert a single value to plain vector. 318 | }]; 319 | 320 | let arguments = (ins AnyType:$value, AnyType:$memref, AnyAttr:$col, OptionalAttr:$row); 321 | // let results = (outs AnyType:$result); 322 | } 323 | 324 | def LWEMulOp : HEIR_Op<"lwemul", 325 | [NoSideEffect]> { 326 | let summary = "LWECipher multiplication operation"; 327 | let description = [{ 328 | The "add" operation performs element-wise addition between two tensors. 329 | The shapes of the tensor operands are expected to match. 330 | }]; 331 | 332 | // let arguments = (ins LWECipher:$lhs, LWECipher:$rhs); 333 | let arguments = (ins 334 | // AnyType:$lhs, AnyType:$rhs 335 | Variadic:$x 336 | ); 337 | let results = (outs 338 | // Variadic:$output); 339 | AnyType:$output); 340 | } 341 | 342 | def RLWEMulOp : HEIR_Op<"rlwemul", 343 | [NoSideEffect]> { 344 | let summary = "LWECipher multiplication operation"; 345 | let description = [{ 346 | The "add" operation performs element-wise addition between two tensors. 347 | The shapes of the tensor operands are expected to match. 348 | }]; 349 | 350 | let arguments = (ins 351 | Variadic:$x 352 | ); 353 | let results = (outs 354 | AnyType:$output); 355 | } 356 | 357 | 358 | def LWEAddOp : HEIR_Op<"lweadd", 359 | [NoSideEffect]> { 360 | let summary = "LWECipher addition operation"; 361 | let description = [{ 362 | The "add" operation performs element-wise addition between two tensors. 363 | The shapes of the tensor operands are expected to match. 364 | }]; 365 | 366 | // let arguments = (ins LWECipher:$lhs, LWECipher:$rhs); 367 | let arguments = (ins 368 | // AnyType:$lhs, AnyType:$rhs 369 | Variadic:$x 370 | ); 371 | let results = (outs 372 | // Variadic:$output); 373 | AnyType:$output); 374 | 375 | } 376 | 377 | def LWESubOp : HEIR_Op<"lwesub", 378 | [NoSideEffect]> { 379 | let summary = "LWECipher addition operation"; 380 | let description = [{ 381 | The "sub" operation performs element-wise addition between two tensors. 382 | The shapes of the tensor operands are expected to match. 383 | }]; 384 | 385 | // let arguments = (ins LWECipher:$lhs, LWECipher:$rhs); 386 | let arguments = (ins 387 | // AnyType:$lhs, AnyType:$rhs 388 | Variadic:$x 389 | ); 390 | let results = (outs 391 | // Variadic:$output); 392 | AnyType:$output); 393 | 394 | } 395 | 396 | def FHERotateOp: HEIR_Op<"rotate", [NoSideEffect]> { 397 | let summary = "Rotate the RLWECipher in slot form."; 398 | 399 | let arguments = (ins 400 | AnyTypeOf<[RLWECipher, LWECipherVector]>:$cipher, 401 | SI32Attr:$i 402 | ); 403 | 404 | let results = (outs 405 | AnyTypeOf<[RLWECipher, LWECipherVector]>:$output 406 | ); 407 | 408 | let hasFolder = 1; 409 | } 410 | 411 | def FHEMaterializeOp: HEIR_Op<"materialize", [NoSideEffect]> { 412 | let summary = "No-op operation used to preserve consistency of type system during type conversion"; 413 | 414 | let arguments = (ins AnyType:$input); 415 | let results = (outs AnyType:$result); 416 | 417 | let hasFolder = 1; 418 | } 419 | 420 | def FHECmpOp: HEIR_Op<"compare", []> { 421 | let summary = "LWE comparing operation"; 422 | 423 | let arguments = (ins Arith_CmpFPredicateAttr:$predicate, 424 | AnyType:$lhs, 425 | AnyType:$rhs); 426 | 427 | let results = (outs AnyType:$result); 428 | 429 | // let hasFolder = 1; 430 | } 431 | 432 | def FHESelectOp: HEIR_Op<"select", []> { 433 | let summary = "Replace arith.select with this operation"; 434 | 435 | let arguments = (ins AnyType:$condition, 436 | AnyType:$true_value, 437 | AnyType:$false_value); 438 | 439 | let results = (outs AnyType:$result); 440 | } 441 | 442 | def FHERepackOp: HEIR_Op<"repack", []> { 443 | let summary = "Repack LWECiphers to a RLWECipher"; 444 | 445 | let arguments = (ins AnyType:$input); 446 | 447 | let results = (outs AnyType:$result); 448 | } 449 | 450 | def FHEVectorLoadOp: HEIR_Op<"vector_load_init", []> { 451 | let summary = "Replace polygeist.subindex to load a vector/slice from a matrix"; 452 | 453 | let arguments = (ins AnyType:$memref, AnyType:$indices); 454 | 455 | let results = (outs AnyType:$result); 456 | 457 | // let hasFolder = 1; 458 | 459 | } 460 | 461 | def FHEVectorLoadfinalOp: HEIR_Op<"vector_load", []> { 462 | let summary = "Same as FHEVectorOp, but replace Value Type indices with Attr Type"; 463 | 464 | let arguments = (ins AnyType:$memref, AnyAttr:$index); 465 | 466 | let results = (outs AnyType:$result); 467 | } 468 | 469 | def FHELUTForAddOp: HEIR_Op<"lut_half", []> { 470 | let summary = "LUT Operation for AddOp in Min Value"; 471 | 472 | let arguments = (ins AnyType:$input); 473 | 474 | let results = (outs AnyType:$result); 475 | } 476 | 477 | def FHELUTForSubOp: HEIR_Op<"lut_abshalf", []> { 478 | let summary = "LUT Operation for AddOp in Min Value"; 479 | 480 | let arguments = (ins AnyType:$input); 481 | 482 | let results = (outs AnyType:$result); 483 | } 484 | 485 | def FHELUTForLTOp: HEIR_Op<"lut_lt", []> { 486 | let summary = "LUT Opeartion for < 0"; 487 | 488 | let arguments = (ins AnyType:$input); 489 | 490 | let results = (outs AnyType:$result); 491 | } 492 | 493 | def FHELUTForGTOp: HEIR_Op<"lut_gt", []> { 494 | let summary = "LUT Opeartion for > 0"; 495 | 496 | let arguments = (ins AnyType:$input); 497 | 498 | let results = (outs AnyType:$result); 499 | } 500 | 501 | def FHELUTOp: HEIR_Op<"lut", []> { 502 | let summary = "LUT Opeartion without function evaluation"; 503 | 504 | let arguments = (ins AnyType:$input); 505 | 506 | let results = (outs AnyType:$result); 507 | } 508 | 509 | def FHEFuncCallOp: HEIR_Op<"call", []> { 510 | let summary = "Function call to replace Func::CallOp"; 511 | 512 | let description = [{ 513 | To replace Func::CallOp, since type conflict between function call 514 | and function definition is occured in FuncToHEIR pass. 515 | }]; 516 | 517 | let arguments = (ins 518 | Arg:$callee, 519 | Arg, "the order of operands and further attributes">:$args, 520 | Arg, "template arguments">:$template_args, 521 | Variadic:$operands 522 | ); 523 | 524 | let results = (outs AnyType); 525 | } 526 | 527 | #endif // HEIR_OPS -------------------------------------------------------------------------------- /include/heir/IR/FHE/HEIRDialect.h: -------------------------------------------------------------------------------- 1 | #ifndef HEIR_IR_HEIR_HEIRDIALECT_H 2 | #define HEIR_IR_HEIR_HEIRDIALECT_H 3 | 4 | #include "mlir/IR/Builders.h" 5 | #include "mlir/IR/BuiltinOps.h" 6 | #include "mlir/IR/BuiltinTypes.h" 7 | #include "mlir/IR/Dialect.h" 8 | #include "mlir/IR/OpDefinition.h" 9 | #include "mlir/IR/OpImplementation.h" 10 | #include "mlir/IR/PatternMatch.h" 11 | #include "mlir/Interfaces/CallInterfaces.h" 12 | #include "mlir/Interfaces/CastInterfaces.h" 13 | #include "mlir/Interfaces/ControlFlowInterfaces.h" 14 | #include "mlir/Interfaces/CopyOpInterface.h" 15 | #include "mlir/Interfaces/InferTypeOpInterface.h" 16 | #include "mlir/Interfaces/SideEffectInterfaces.h" 17 | 18 | // Include the C++ class declaration for this Dialect (no define necessary for this one) 19 | #include "heir/IR/FHE/HEIRDialect.h.inc" 20 | 21 | // Include the C++ class (and associated functions) declarations for this Dialect's types 22 | #define GET_TYPEDEF_CLASSES 23 | #include "heir/IR/FHE/HEIRTypes.h.inc" 24 | 25 | #include "mlir/Dialect/Arithmetic/IR/Arithmetic.h" 26 | 27 | // Include the C++ class (and associated functions) declarations for this Dialect's operations 28 | #define GET_OP_CLASSES 29 | #include "heir/IR/FHE/HEIR.h.inc" 30 | 31 | #endif // HEIR_IR_HEIR_HEIRDIALECT_H 32 | -------------------------------------------------------------------------------- /include/heir/Passes/CMakeLists.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heir-compiler/HEIR/d2e673e4374ed07b3c8791cbba71c6e08dd5ff08/include/heir/Passes/CMakeLists.txt -------------------------------------------------------------------------------- /include/heir/Passes/arith2heir/LowerArithToHEIR.h: -------------------------------------------------------------------------------- 1 | #ifndef HEIR_PASSES_ARITH2HEIR_LOWERARITHTOHEIR_H_ 2 | #define HEIR_PASSES_ARITH2HEIR_LOWERARITHTOHEIR_H_ 3 | 4 | #include "mlir/IR/BuiltinOps.h" 5 | #include "mlir/Pass/Pass.h" 6 | #include "mlir/Transforms/DialectConversion.h" 7 | #include "heir/IR/FHE/HEIRDialect.h" 8 | 9 | struct LowerArithToHEIRPass : public mlir::PassWrapper> 10 | { 11 | void getDependentDialects(mlir::DialectRegistry ®istry) const override; 12 | 13 | void runOnOperation() override; 14 | 15 | mlir::StringRef getArgument() const final 16 | { 17 | return "arith2heir"; 18 | } 19 | }; 20 | 21 | #endif // HEIR_PASSES_ARITH2HEIR_LOWERARITHTOHEIR_H_ 22 | -------------------------------------------------------------------------------- /include/heir/Passes/batching/Batching.h: -------------------------------------------------------------------------------- 1 | #ifndef HEIR_PASSES_BATCHING_H_ 2 | #define HEIR_PASSES_BATCHING_H_ 3 | 4 | #include "mlir/IR/BuiltinOps.h" 5 | #include "mlir/Pass/Pass.h" 6 | #include "mlir/Transforms/DialectConversion.h" 7 | #include "heir/IR/FHE/HEIRDialect.h" 8 | 9 | struct BatchingPass : public mlir::PassWrapper> 10 | { 11 | void getDependentDialects(mlir::DialectRegistry ®istry) const override; 12 | 13 | void runOnOperation() override; 14 | 15 | mlir::StringRef getArgument() const final 16 | { 17 | return "batching"; 18 | } 19 | }; 20 | 21 | #endif // HEIR_PASSES_BATCHING_H_ 22 | -------------------------------------------------------------------------------- /include/heir/Passes/branch/Branch.h: -------------------------------------------------------------------------------- 1 | #ifndef HEIR_PASSES_BRANCH_H_ 2 | #define HEIR_PASSES_BRANCH_H_ 3 | 4 | #include "mlir/IR/BuiltinOps.h" 5 | #include "mlir/Pass/Pass.h" 6 | #include "mlir/Transforms/DialectConversion.h" 7 | #include "heir/IR/FHE/HEIRDialect.h" 8 | 9 | struct BranchPass : public mlir::PassWrapper> 10 | { 11 | void getDependentDialects(mlir::DialectRegistry ®istry) const override; 12 | 13 | void runOnOperation() override; 14 | 15 | mlir::StringRef getArgument() const final 16 | { 17 | return "branch"; 18 | } 19 | }; 20 | 21 | #endif // HEIR_PASSES_BRANCH_H_ 22 | -------------------------------------------------------------------------------- /include/heir/Passes/encrypt/Encrypt.h: -------------------------------------------------------------------------------- 1 | #ifndef HEIR_ENCRYPT_TD 2 | #define HEIR_ENCRYPT_TD 3 | 4 | #include "mlir/IR/BuiltinOps.h" 5 | #include "mlir/Pass/Pass.h" 6 | 7 | struct EncryptPass : public mlir::PassWrapper> 8 | { 9 | void getDependentDialects(mlir::DialectRegistry ®istry) const override; 10 | 11 | void runOnOperation() override; 12 | 13 | mlir::StringRef getArgument() const final 14 | { 15 | return "encrypt"; 16 | } 17 | }; 18 | 19 | #endif // HEIR_ENCRYPT_TD 20 | -------------------------------------------------------------------------------- /include/heir/Passes/func2heir/FuncToHEIR.h: -------------------------------------------------------------------------------- 1 | #ifndef HEIR_PASSES_FUNC2HEIR_LOWERFUNCTOHEIR_H_ 2 | #define HEIR_PASSES_FUNC2HEIR_LOWERFUNCTOHEIR_H_ 3 | 4 | #include "mlir/IR/BuiltinOps.h" 5 | #include "mlir/Pass/Pass.h" 6 | #include "mlir/Transforms/DialectConversion.h" 7 | #include "heir/IR/FHE/HEIRDialect.h" 8 | 9 | struct FuncToHEIRPass : public mlir::PassWrapper> 10 | { 11 | void getDependentDialects(mlir::DialectRegistry ®istry) const override; 12 | 13 | void runOnOperation() override; 14 | 15 | mlir::StringRef getArgument() const final 16 | { 17 | return "func2heir"; 18 | } 19 | }; 20 | 21 | #endif // HEIR_PASSES_FUNC2HEIR_LOWERFUNCTOHEIR_H_ 22 | -------------------------------------------------------------------------------- /include/heir/Passes/genparm/GenParm.h: -------------------------------------------------------------------------------- 1 | #ifndef HEIR_PASSES_GENPARM_H_ 2 | #define HEIR_PASSES_GENPARM_H_ 3 | 4 | #include "mlir/IR/BuiltinOps.h" 5 | #include "mlir/Pass/Pass.h" 6 | #include "mlir/Transforms/DialectConversion.h" 7 | #include "heir/IR/FHE/HEIRDialect.h" 8 | 9 | struct GenerateParmPass : public mlir::PassWrapper> 10 | { 11 | void getDependentDialects(mlir::DialectRegistry ®istry) const override; 12 | 13 | void runOnOperation() override; 14 | 15 | mlir::StringRef getArgument() const final 16 | { 17 | return "genparm"; 18 | } 19 | }; 20 | 21 | #endif // HEIR_PASSES_GENPARM_H_ 22 | -------------------------------------------------------------------------------- /include/heir/Passes/heir2emitc/LowerHEIRToEmitC.h: -------------------------------------------------------------------------------- 1 | #ifndef HEIR_PASSES_HEIR2EMITC_LOWERHEIRTOEMITC_H_ 2 | #define HEIR_PASSES_HEIR2EMITC_LOWERHEIRTOEMITC_H_ 3 | 4 | #include "mlir/IR/BuiltinOps.h" 5 | #include "mlir/Pass/Pass.h" 6 | #include "mlir/Transforms/DialectConversion.h" 7 | #include "heir/IR/FHE/HEIRDialect.h" 8 | 9 | struct LowerHEIRToEmitCPass : public mlir::PassWrapper> 10 | { 11 | void getDependentDialects(mlir::DialectRegistry ®istry) const override; 12 | 13 | void runOnOperation() override; 14 | 15 | mlir::StringRef getArgument() const final 16 | { 17 | return "heir2emitc"; 18 | } 19 | }; 20 | 21 | #endif // HEIR_PASSES_HEIR2EMITC_LOWERHEIRTOEMITC_H_ 22 | -------------------------------------------------------------------------------- /include/heir/Passes/lwe2rlwe/LWEToRLWE.h: -------------------------------------------------------------------------------- 1 | #ifndef HEIR_PASSES_LWETORLWE_H_ 2 | #define HEIR_PASSES_LWETORLWE_H_ 3 | 4 | #include "mlir/IR/BuiltinOps.h" 5 | #include "mlir/Pass/Pass.h" 6 | #include "mlir/Transforms/DialectConversion.h" 7 | #include "heir/IR/FHE/HEIRDialect.h" 8 | 9 | struct LWEToRLWEPass : public mlir::PassWrapper> 10 | { 11 | void getDependentDialects(mlir::DialectRegistry ®istry) const override; 12 | 13 | void runOnOperation() override; 14 | 15 | mlir::StringRef getArgument() const final 16 | { 17 | return "lwe2rlwe"; 18 | } 19 | }; 20 | 21 | #endif // HEIR_PASSES_LWETORLWE_H_ 22 | -------------------------------------------------------------------------------- /include/heir/Passes/memref2heir/LowerMemrefToHEIR.h: -------------------------------------------------------------------------------- 1 | #ifndef HEIR_PASSES_MEMREF2HEIR_LOWERMEMREFTOHEIR_H_ 2 | #define HEIR_PASSES_MEMREF2HEIR_LOWERMEMREFTOHEIR_H_ 3 | 4 | #include "mlir/IR/BuiltinOps.h" 5 | #include "mlir/Pass/Pass.h" 6 | #include "mlir/Transforms/DialectConversion.h" 7 | #include "heir/IR/FHE/HEIRDialect.h" 8 | 9 | struct LowerMemrefToHEIRPass : public mlir::PassWrapper> 10 | { 11 | void getDependentDialects(mlir::DialectRegistry ®istry) const override; 12 | 13 | void runOnOperation() override; 14 | 15 | mlir::StringRef getArgument() const final 16 | { 17 | return "memref2heir"; 18 | } 19 | }; 20 | 21 | #endif // HEIR_PASSES_MEMREF2HEIR_LOWERMEMREFTOHEIR_H_ 22 | -------------------------------------------------------------------------------- /include/heir/Passes/nary/Nary.h: -------------------------------------------------------------------------------- 1 | #ifndef HEIR_PASSES_NARY_H_ 2 | #define HEIR_PASSES_NARY_H_ 3 | 4 | #include "mlir/IR/BuiltinOps.h" 5 | #include "mlir/Pass/Pass.h" 6 | #include "heir/IR/FHE/HEIRDialect.h" 7 | 8 | struct NaryPass : public mlir::PassWrapper> 9 | { 10 | void getDependentDialects(mlir::DialectRegistry ®istry) const override; 11 | void runOnOperation() override; 12 | 13 | mlir::StringRef getArgument() const final 14 | { 15 | return "nary"; 16 | } 17 | }; 18 | 19 | #endif // HEIR_PASSES_NARY_H_ 20 | -------------------------------------------------------------------------------- /include/heir/Passes/slot2coeff/SlotToCoeff.h: -------------------------------------------------------------------------------- 1 | #ifndef HEIR_PASSES_SLOTTOCOEFF_H_ 2 | #define HEIR_PASSES_SLOTTOCOEFF_H_ 3 | 4 | #include "mlir/IR/BuiltinOps.h" 5 | #include "mlir/Pass/Pass.h" 6 | #include "heir/IR/FHE/HEIRDialect.h" 7 | 8 | struct SlotToCoeffPass : public mlir::PassWrapper> 9 | { 10 | void getDependentDialects(mlir::DialectRegistry ®istry) const override; 11 | void runOnOperation() override; 12 | 13 | mlir::StringRef getArgument() const final 14 | { 15 | return "slot2coeff"; 16 | } 17 | }; 18 | 19 | #endif // HEIR_PASSES_SLOTTOCOEFF_H_ 20 | -------------------------------------------------------------------------------- /include/heir/Passes/unfold/BranchUnfold.h: -------------------------------------------------------------------------------- 1 | #ifndef HEIR_PASSES_BRANCHUNFOLD_H_ 2 | #define HEIR_PASSES_BRANCHUNFOLD_H_ 3 | 4 | #include "mlir/IR/BuiltinOps.h" 5 | #include "mlir/Pass/Pass.h" 6 | #include "mlir/Transforms/DialectConversion.h" 7 | #include "heir/IR/FHE/HEIRDialect.h" 8 | 9 | struct BranchUnfoldPass : public mlir::PassWrapper> 10 | { 11 | void getDependentDialects(mlir::DialectRegistry ®istry) const override; 12 | 13 | void runOnOperation() override; 14 | 15 | mlir::StringRef getArgument() const final 16 | { 17 | return "unfold"; 18 | } 19 | }; 20 | 21 | #endif // HEIR_PASSES_BRANCHUNFOLD_H_ 22 | -------------------------------------------------------------------------------- /include/heir/Passes/unroll/UnrollLoop.h: -------------------------------------------------------------------------------- 1 | #ifndef HEIR_PASSES_ARITH2HEIR_UNROLLLOOP_H_ 2 | #define HEIR_PASSES_ARITH2HEIR_UNROLLLOOP_H_ 3 | 4 | #include "mlir/IR/BuiltinOps.h" 5 | #include "mlir/Pass/Pass.h" 6 | #include "mlir/Transforms/DialectConversion.h" 7 | #include "heir/IR/FHE/HEIRDialect.h" 8 | 9 | struct UnrollLoopPass : public mlir::PassWrapper> 10 | { 11 | void getDependentDialects(mlir::DialectRegistry ®istry) const override; 12 | 13 | void runOnOperation() override; 14 | 15 | mlir::StringRef getArgument() const final 16 | { 17 | return "loop-unroll"; 18 | } 19 | }; 20 | 21 | #endif // HEIR_PASSES_ARITH2HEIR_UNROLLLOOP_H_ 22 | -------------------------------------------------------------------------------- /include/heir/Passes/vec2memref/PromVecToMemref.h: -------------------------------------------------------------------------------- 1 | #ifndef HEIR_PASSES_VEC2MEMREF_PROMVECTOMEMREF_H_ 2 | #define HEIR_PASSES_VEC2MEMREF_PROMVECTOMEMREF_H_ 3 | 4 | #include "mlir/IR/BuiltinOps.h" 5 | #include "mlir/Pass/Pass.h" 6 | #include "mlir/Transforms/DialectConversion.h" 7 | #include "heir/IR/FHE/HEIRDialect.h" 8 | 9 | struct PromVecToMemrefPass : public mlir::PassWrapper> 10 | { 11 | void getDependentDialects(mlir::DialectRegistry ®istry) const override; 12 | 13 | void runOnOperation() override; 14 | 15 | mlir::StringRef getArgument() const final 16 | { 17 | return "vec2memref"; 18 | } 19 | }; 20 | 21 | #endif // HEIR_PASSES_VEC2MEMREF_PROMVECTOMEMREF_H_ 22 | -------------------------------------------------------------------------------- /lisences/HECO_LISENCE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 ETH Zurich. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /lisences/Polygeist_LISENCE: -------------------------------------------------------------------------------- 1 | ============================================================================== 2 | The LLVM Project is under the Apache License v2.0 with LLVM Exceptions: 3 | As a project hoping to become part of LLVM, Enzyme is under the same license. 4 | ============================================================================== 5 | Apache License 6 | Version 2.0, January 2004 7 | http://www.apache.org/licenses/ 8 | 9 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 10 | 11 | 1. Definitions. 12 | 13 | "License" shall mean the terms and conditions for use, reproduction, 14 | and distribution as defined by Sections 1 through 9 of this document. 15 | 16 | "Licensor" shall mean the copyright owner or entity authorized by 17 | the copyright owner that is granting the License. 18 | 19 | "Legal Entity" shall mean the union of the acting entity and all 20 | other entities that control, are controlled by, or are under common 21 | control with that entity. For the purposes of this definition, 22 | "control" means (i) the power, direct or indirect, to cause the 23 | direction or management of such entity, whether by contract or 24 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 25 | outstanding shares, or (iii) beneficial ownership of such entity. 26 | 27 | "You" (or "Your") shall mean an individual or Legal Entity 28 | exercising permissions granted by this License. 29 | 30 | "Source" form shall mean the preferred form for making modifications, 31 | including but not limited to software source code, documentation 32 | source, and configuration files. 33 | 34 | "Object" form shall mean any form resulting from mechanical 35 | transformation or translation of a Source form, including but 36 | not limited to compiled object code, generated documentation, 37 | and conversions to other media types. 38 | 39 | "Work" shall mean the work of authorship, whether in Source or 40 | Object form, made available under the License, as indicated by a 41 | copyright notice that is included in or attached to the work 42 | (an example is provided in the Appendix below). 43 | 44 | "Derivative Works" shall mean any work, whether in Source or Object 45 | form, that is based on (or derived from) the Work and for which the 46 | editorial revisions, annotations, elaborations, or other modifications 47 | represent, as a whole, an original work of authorship. For the purposes 48 | of this License, Derivative Works shall not include works that remain 49 | separable from, or merely link (or bind by name) to the interfaces of, 50 | the Work and Derivative Works thereof. 51 | 52 | "Contribution" shall mean any work of authorship, including 53 | the original version of the Work and any modifications or additions 54 | to that Work or Derivative Works thereof, that is intentionally 55 | submitted to Licensor for inclusion in the Work by the copyright owner 56 | or by an individual or Legal Entity authorized to submit on behalf of 57 | the copyright owner. For the purposes of this definition, "submitted" 58 | means any form of electronic, verbal, or written communication sent 59 | to the Licensor or its representatives, including but not limited to 60 | communication on electronic mailing lists, source code control systems, 61 | and issue tracking systems that are managed by, or on behalf of, the 62 | Licensor for the purpose of discussing and improving the Work, but 63 | excluding communication that is conspicuously marked or otherwise 64 | designated in writing by the copyright owner as "Not a Contribution." 65 | 66 | "Contributor" shall mean Licensor and any individual or Legal Entity 67 | on behalf of whom a Contribution has been received by Licensor and 68 | subsequently incorporated within the Work. 69 | 70 | 2. Grant of Copyright License. Subject to the terms and conditions of 71 | this License, each Contributor hereby grants to You a perpetual, 72 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 73 | copyright license to reproduce, prepare Derivative Works of, 74 | publicly display, publicly perform, sublicense, and distribute the 75 | Work and such Derivative Works in Source or Object form. 76 | 77 | 3. Grant of Patent License. Subject to the terms and conditions of 78 | this License, each Contributor hereby grants to You a perpetual, 79 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 80 | (except as stated in this section) patent license to make, have made, 81 | use, offer to sell, sell, import, and otherwise transfer the Work, 82 | where such license applies only to those patent claims licensable 83 | by such Contributor that are necessarily infringed by their 84 | Contribution(s) alone or by combination of their Contribution(s) 85 | with the Work to which such Contribution(s) was submitted. If You 86 | institute patent litigation against any entity (including a 87 | cross-claim or counterclaim in a lawsuit) alleging that the Work 88 | or a Contribution incorporated within the Work constitutes direct 89 | or contributory patent infringement, then any patent licenses 90 | granted to You under this License for that Work shall terminate 91 | as of the date such litigation is filed. 92 | 93 | 4. Redistribution. You may reproduce and distribute copies of the 94 | Work or Derivative Works thereof in any medium, with or without 95 | modifications, and in Source or Object form, provided that You 96 | meet the following conditions: 97 | 98 | (a) You must give any other recipients of the Work or 99 | Derivative Works a copy of this License; and 100 | 101 | (b) You must cause any modified files to carry prominent notices 102 | stating that You changed the files; and 103 | 104 | (c) You must retain, in the Source form of any Derivative Works 105 | that You distribute, all copyright, patent, trademark, and 106 | attribution notices from the Source form of the Work, 107 | excluding those notices that do not pertain to any part of 108 | the Derivative Works; and 109 | 110 | (d) If the Work includes a "NOTICE" text file as part of its 111 | distribution, then any Derivative Works that You distribute must 112 | include a readable copy of the attribution notices contained 113 | within such NOTICE file, excluding those notices that do not 114 | pertain to any part of the Derivative Works, in at least one 115 | of the following places: within a NOTICE text file distributed 116 | as part of the Derivative Works; within the Source form or 117 | documentation, if provided along with the Derivative Works; or, 118 | within a display generated by the Derivative Works, if and 119 | wherever such third-party notices normally appear. The contents 120 | of the NOTICE file are for informational purposes only and 121 | do not modify the License. You may add Your own attribution 122 | notices within Derivative Works that You distribute, alongside 123 | or as an addendum to the NOTICE text from the Work, provided 124 | that such additional attribution notices cannot be construed 125 | as modifying the License. 126 | 127 | You may add Your own copyright statement to Your modifications and 128 | may provide additional or different license terms and conditions 129 | for use, reproduction, or distribution of Your modifications, or 130 | for any such Derivative Works as a whole, provided Your use, 131 | reproduction, and distribution of the Work otherwise complies with 132 | the conditions stated in this License. 133 | 134 | 5. Submission of Contributions. Unless You explicitly state otherwise, 135 | any Contribution intentionally submitted for inclusion in the Work 136 | by You to the Licensor shall be under the terms and conditions of 137 | this License, without any additional terms or conditions. 138 | Notwithstanding the above, nothing herein shall supersede or modify 139 | the terms of any separate license agreement you may have executed 140 | with Licensor regarding such Contributions. 141 | 142 | 6. Trademarks. This License does not grant permission to use the trade 143 | names, trademarks, service marks, or product names of the Licensor, 144 | except as required for reasonable and customary use in describing the 145 | origin of the Work and reproducing the content of the NOTICE file. 146 | 147 | 7. Disclaimer of Warranty. Unless required by applicable law or 148 | agreed to in writing, Licensor provides the Work (and each 149 | Contributor provides its Contributions) on an "AS IS" BASIS, 150 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 151 | implied, including, without limitation, any warranties or conditions 152 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 153 | PARTICULAR PURPOSE. You are solely responsible for determining the 154 | appropriateness of using or redistributing the Work and assume any 155 | risks associated with Your exercise of permissions under this License. 156 | 157 | 8. Limitation of Liability. In no event and under no legal theory, 158 | whether in tort (including negligence), contract, or otherwise, 159 | unless required by applicable law (such as deliberate and grossly 160 | negligent acts) or agreed to in writing, shall any Contributor be 161 | liable to You for damages, including any direct, indirect, special, 162 | incidental, or consequential damages of any character arising as a 163 | result of this License or out of the use or inability to use the 164 | Work (including but not limited to damages for loss of goodwill, 165 | work stoppage, computer failure or malfunction, or any and all 166 | other commercial damages or losses), even if such Contributor 167 | has been advised of the possibility of such damages. 168 | 169 | 9. Accepting Warranty or Additional Liability. While redistributing 170 | the Work or Derivative Works thereof, You may choose to offer, 171 | and charge a fee for, acceptance of support, warranty, indemnity, 172 | or other liability obligations and/or rights consistent with this 173 | License. However, in accepting such obligations, You may act only 174 | on Your own behalf and on Your sole responsibility, not on behalf 175 | of any other Contributor, and only if You agree to indemnify, 176 | defend, and hold each Contributor harmless for any liability 177 | incurred by, or claims asserted against, such Contributor by reason 178 | of your accepting any such warranty or additional liability. 179 | 180 | END OF TERMS AND CONDITIONS 181 | 182 | APPENDIX: How to apply the Apache License to your work. 183 | 184 | To apply the Apache License to your work, attach the following 185 | boilerplate notice, with the fields enclosed by brackets "[]" 186 | replaced with your own identifying information. (Don't include 187 | the brackets!) The text should be enclosed in the appropriate 188 | comment syntax for the file format. We also recommend that a 189 | file or class name and description of purpose be included on the 190 | same "printed page" as the copyright notice for easier 191 | identification within third-party archives. 192 | 193 | Copyright [yyyy] [name of copyright owner] 194 | 195 | Licensed under the Apache License, Version 2.0 (the "License"); 196 | you may not use this file except in compliance with the License. 197 | You may obtain a copy of the License at 198 | 199 | http://www.apache.org/licenses/LICENSE-2.0 200 | 201 | Unless required by applicable law or agreed to in writing, software 202 | distributed under the License is distributed on an "AS IS" BASIS, 203 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 204 | See the License for the specific language governing permissions and 205 | limitations under the License. 206 | 207 | ---- LLVM Exceptions to the Apache 2.0 License ---- 208 | 209 | As an exception, if, as a result of your compiling your source code, portions 210 | of this Software are embedded into an Object form of such source code, you 211 | may redistribute such embedded portions in such Object form without complying 212 | with the conditions of Sections 4(a), 4(b) and 4(d) of the License. 213 | 214 | In addition, if you combine or link compiled forms of this Software with 215 | software that is licensed under the GPLv2 ("Combined Software") and if a 216 | court of competent jurisdiction determines that the patent provision (Section 217 | 3), the indemnity provision (Section 9) or other Section of the License 218 | conflicts with the conditions of the GPLv2, you may retroactively and 219 | prospectively choose to deem waived or otherwise exclude such Section(s) of 220 | the License, but only in their entirety and only with respect to the Combined 221 | Software. 222 | 223 | ============================================================================== 224 | Software from third parties included in the LLVM Project: 225 | ============================================================================== 226 | The LLVM Project contains third party software which is under different license 227 | terms. All such code will be identified clearly using at least one of two 228 | mechanisms: 229 | 1) It will be in a separate directory tree with its own `LICENSE.txt` or 230 | `LICENSE` file at the top containing the specific license and restrictions 231 | which apply to that software, or 232 | 2) It will contain specific license and restriction terms at the top of every 233 | file. -------------------------------------------------------------------------------- /lisences/SEAL_LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(IR) 2 | add_subdirectory(Passes) 3 | add_subdirectory(tools) -------------------------------------------------------------------------------- /src/IR/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(FHE) -------------------------------------------------------------------------------- /src/IR/FHE/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_heir_dialect_library(HEIRHEIRDialect 2 | HEIRDialect.cpp 3 | 4 | ADDITIONAL_HEADER_DIRS 5 | ${PROJECT_SOURCE_DIR}/include/heir 6 | 7 | DEPENDS 8 | MLIRHEIRIncGen 9 | 10 | LINK_LIBS PUBLIC 11 | MLIRIR 12 | ) 13 | -------------------------------------------------------------------------------- /src/IR/FHE/HEIRDialect.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Authors: HECO 3 | Modified by Zian Zhao 4 | Copyright: 5 | Copyright (c) 2020 ETH Zurich. 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #include "heir/IR/FHE/HEIRDialect.h" 24 | #include "llvm/ADT/SmallString.h" 25 | #include "llvm/ADT/TypeSwitch.h" 26 | #include "mlir/Dialect/EmitC/IR/EmitC.h" 27 | #include "mlir/IR/DialectImplementation.h" 28 | #include "mlir/IR/PatternMatch.h" 29 | #include "mlir/IR/TypeSupport.h" 30 | #include "mlir/IR/Types.h" 31 | #include "mlir/Support/LLVM.h" 32 | 33 | using namespace mlir; 34 | using namespace heir; 35 | 36 | //===----------------------------------------------------------------------===// 37 | // TableGen'd Type definitions 38 | //===----------------------------------------------------------------------===// 39 | #define GET_TYPEDEF_CLASSES 40 | #include "heir/IR/FHE/HEIRTypes.cpp.inc" 41 | 42 | //===----------------------------------------------------------------------===// 43 | // TableGen'd Operation definitions 44 | //===----------------------------------------------------------------------===// 45 | #define GET_OP_CLASSES 46 | #include "heir/IR/FHE/HEIR.cpp.inc" 47 | 48 | /// simplifies away materialization(materialization(x)) to x if the types work 49 | ::mlir::OpFoldResult heir::FHEMaterializeOp::fold(::llvm::ArrayRef<::mlir::Attribute> operands) 50 | { 51 | if (auto m_op = input().getDefiningOp()) { 52 | if (m_op.input().getType() == result().getType()) 53 | return m_op.input(); 54 | if (auto mm_op = m_op.input().getDefiningOp()) { 55 | if (mm_op.input().getType() == result().getType()) 56 | return mm_op.input(); 57 | } 58 | } 59 | else if (input().getType() == result().getType()) { 60 | return input(); 61 | } 62 | return {}; 63 | 64 | 65 | } 66 | 67 | /// simplify rotate(cipher, 0) to cipher 68 | ::mlir::OpFoldResult heir::FHERotateOp::fold(::llvm::ArrayRef<::mlir::Attribute> operands) 69 | { 70 | if (i() == 0) 71 | return cipher(); 72 | 73 | return {}; 74 | } 75 | 76 | //===----------------------------------------------------------------------===// 77 | // FHE dialect definitions 78 | //===----------------------------------------------------------------------===// 79 | #include "heir/IR/FHE/HEIRDialect.cpp.inc" 80 | void HEIRDialect::initialize() 81 | { 82 | // Registers all the Types into the FHEDialect class 83 | addTypes< 84 | #define GET_TYPEDEF_LIST 85 | #include "heir/IR/FHE/HEIRTypes.cpp.inc" 86 | >(); 87 | 88 | // Registers all the Operations into the FHEDialect class 89 | addOperations< 90 | #define GET_OP_LIST 91 | #include "heir/IR/FHE/HEIR.cpp.inc" 92 | >(); 93 | } -------------------------------------------------------------------------------- /src/Passes/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(arith2heir) 2 | add_subdirectory(unroll) 3 | add_subdirectory(memref2heir) 4 | add_subdirectory(func2heir) 5 | add_subdirectory(heir2emitc) 6 | add_subdirectory(genparm) 7 | add_subdirectory(unfold) 8 | # add_subdirectory(encrypt) 9 | # add_subdirectory(vec2memref) 10 | add_subdirectory(batching) 11 | add_subdirectory(nary) 12 | add_subdirectory(slot2coeff) 13 | add_subdirectory(lwe2rlwe) 14 | add_subdirectory(branch) 15 | # add_subdirectory(tensor2rlwe) -------------------------------------------------------------------------------- /src/Passes/arith2heir/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(LLVM_TARGET_DEFINITIONS LowerArithToHEIR.td) 2 | mlir_tablegen(LowerArithToHEIR.cpp.inc -gen-rewriters) 3 | add_public_tablegen_target(arith2heir) 4 | 5 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 6 | 7 | 8 | add_heir_conversion_library(HEIRArithToHEIR 9 | LowerArithToHEIR.cpp 10 | 11 | #ADDITIONAL_HEADER_DIRS 12 | #Passes 13 | 14 | DEPENDS 15 | 16 | LINK_COMPONENTS 17 | Core 18 | 19 | LINK_LIBS PUBLIC 20 | HEIRHEIRDialect 21 | ) -------------------------------------------------------------------------------- /src/Passes/arith2heir/LowerArithToHEIR.td: -------------------------------------------------------------------------------- 1 | #ifndef HEIR_arith2heir_LOWERARITHTOHEIR_TD 2 | #define HEIR_arith2heir_LOWERARITHTOHEIR_TD 3 | 4 | include "mlir/IR/PatternBase.td" 5 | 6 | #endif // HEIR_arith2heir_LOWERARITHTOHEIR_TD -------------------------------------------------------------------------------- /src/Passes/batching/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_heir_conversion_library(HEIRBatching 2 | Batching.cpp 3 | 4 | #ADDITIONAL_HEADER_DIRS 5 | #Passes 6 | 7 | DEPENDS 8 | 9 | LINK_COMPONENTS 10 | Core 11 | 12 | LINK_LIBS PUBLIC 13 | HEIRHEIRDialect 14 | ) 15 | 16 | -------------------------------------------------------------------------------- /src/Passes/branch/Branch.cpp: -------------------------------------------------------------------------------- 1 | // Author: Zian Zhao 2 | #include 3 | #include "mlir/Transforms/DialectConversion.h" 4 | #include "mlir/Dialect/Affine/IR/AffineOps.h" 5 | #include "mlir/Dialect/Func/IR/FuncOps.h" 6 | #include "mlir/Dialect/SCF/IR/SCF.h" 7 | #include "mlir/Dialect/Tensor/IR/Tensor.h" 8 | #include "llvm/ADT/APSInt.h" 9 | 10 | #include "heir/Passes/branch/Branch.h" 11 | 12 | using namespace mlir; 13 | using namespace arith; 14 | using namespace heir; 15 | 16 | void BranchPass::getDependentDialects(mlir::DialectRegistry ®istry) const 17 | { 18 | registry.insert(); 23 | } 24 | 25 | typedef Value VectorValue; 26 | typedef llvm::SmallMapVector scalarBatchingMap; 27 | 28 | // To unfold scf::IfOp due to the data-independent nature of FHE computation 29 | LogicalResult ScfIfOperation(IRRewriter &rewriter, MLIRContext *context, scf::IfOp op) 30 | { 31 | rewriter.setInsertionPoint(op); 32 | 33 | Value originCondition = op.getCondition(); 34 | 35 | Block *thenBlock = op.thenBlock(); 36 | Block *elseBlock = op.elseBlock(); 37 | 38 | // Copy Operations 39 | // 1. ThenBranch 40 | Value thenResult; 41 | for (Operation &thenOp : thenBlock->getOperations()) { 42 | if (isa(thenOp)) { 43 | scf::YieldOp thenYieldOp = dyn_cast(thenOp); 44 | if (std::distance(thenBlock->begin(), thenBlock->end()) == 1) 45 | thenResult = thenYieldOp.getResults().front(); 46 | } 47 | else { 48 | Operation *newOp = thenOp.clone(); 49 | rewriter.insert(newOp); 50 | thenResult = newOp->getResults().front(); 51 | } 52 | } 53 | // 2. ElseBranch 54 | Value elseResult; 55 | for (Operation &elseOp : elseBlock->getOperations()) { 56 | if (isa(elseOp)) { 57 | scf::YieldOp elseYieldOp = dyn_cast(elseOp); 58 | elseResult = elseYieldOp.getResults().front(); 59 | } 60 | else { 61 | Operation *newOp = elseOp.clone(); 62 | rewriter.insert(newOp); 63 | elseResult = newOp->getResults().front(); 64 | } 65 | } 66 | 67 | // Unfold the two blocks 68 | rewriter.setInsertionPointAfter(op); 69 | auto matOp = rewriter.create(op.getLoc(), Float32Type::get(rewriter.getContext()), originCondition); 70 | auto thenMulOp = rewriter.create(matOp.getLoc(), matOp.getType(), matOp.getResult(), thenResult); 71 | APFloat f1(1.0f); 72 | auto constOp = rewriter.create(thenMulOp.getLoc(), f1, Float32Type::get(rewriter.getContext())); 73 | auto elseSubOp = rewriter.create(constOp.getLoc(), matOp.getType(), constOp.getResult(), matOp.getResult()); 74 | auto elseMulOp = rewriter.create(elseSubOp.getLoc(), matOp.getType(), elseSubOp.getResult(), elseResult); 75 | auto finalAddOp = rewriter.create(elseMulOp.getLoc(), matOp.getType(), thenMulOp.getResult(), elseMulOp.getResult()); 76 | auto finalLUTOp = rewriter.create(finalAddOp.getLoc(), finalAddOp.getType(), finalAddOp.getResult()); 77 | 78 | op->replaceAllUsesWith(finalLUTOp); 79 | 80 | op.erase(); 81 | 82 | 83 | return success(); 84 | 85 | } 86 | 87 | // Unfold the If-Else Blocks in a MLIR function 88 | void BranchPass::runOnOperation() 89 | { 90 | auto &block = getOperation()->getRegion(0).getBlocks().front(); 91 | IRRewriter rewriter(&getContext()); 92 | 93 | for (auto f : llvm::make_early_inc_range(block.getOps())) 94 | { 95 | if(f.walk([&](Operation *op) 96 | { 97 | if (scf::IfOp if_op = llvm::dyn_cast_or_null(op)) { 98 | if (ScfIfOperation(rewriter, &getContext(), if_op).failed()) 99 | return WalkResult::interrupt(); 100 | } 101 | return WalkResult(success()); }) 102 | .wasInterrupted()) 103 | signalPassFailure(); 104 | } 105 | 106 | } -------------------------------------------------------------------------------- /src/Passes/branch/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_heir_conversion_library(HEIRBranch 2 | Branch.cpp 3 | 4 | #ADDITIONAL_HEADER_DIRS 5 | #Passes 6 | 7 | DEPENDS 8 | 9 | LINK_COMPONENTS 10 | Core 11 | 12 | LINK_LIBS PUBLIC 13 | HEIRHEIRDialect 14 | ) 15 | -------------------------------------------------------------------------------- /src/Passes/encrypt/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_heir_conversion_library(HEIREncrypt 2 | Encrypt.cpp 3 | 4 | #ADDITIONAL_HEADER_DIRS 5 | #Passes 6 | 7 | DEPENDS 8 | 9 | LINK_COMPONENTS 10 | Core 11 | 12 | LINK_LIBS PUBLIC 13 | HEIRHEIRDialect 14 | ) 15 | 16 | -------------------------------------------------------------------------------- /src/Passes/encrypt/Encrypt.cpp: -------------------------------------------------------------------------------- 1 | // Author: Zian Zhao 2 | #include "heir/Passes/func2heir/FuncToHEIR.h" 3 | #include 4 | #include 5 | #include "mlir/Dialect/Affine/IR/AffineOps.h" 6 | #include "mlir/Dialect/Affine/Utils.h" 7 | #include "mlir/Dialect/Affine/LoopUtils.h" 8 | #include "mlir/Dialect/Func/IR/FuncOps.h" 9 | #include "mlir/Dialect/SCF/IR/SCF.h" 10 | #include "mlir/Dialect/Tensor/IR/Tensor.h" 11 | #include "mlir/Dialect/Arithmetic/IR/Arithmetic.h" 12 | #include "heir/Passes/encrypt/Encrypt.h" 13 | 14 | using namespace mlir; 15 | using namespace arith; 16 | using namespace heir; 17 | 18 | void EncryptPass::getDependentDialects(mlir::DialectRegistry ®istry) const 19 | { 20 | registry.insert(); 21 | registry.insert(); 22 | registry.insert(); 23 | registry.insert(); 24 | } 25 | 26 | // Based on the pattern in arith2heir pass, convert the MaterializeOp into 27 | // FHEEncryptOp to change a plaintext to ciphertext 28 | // TODO: Actually, we just need to encode it rather than encrypt it, but we face the 29 | // limitation of the undelying FHE library. 30 | class FHEEncryptConversionPattern final : public OpConversionPattern 31 | { 32 | public: 33 | using OpConversionPattern::OpConversionPattern; 34 | 35 | LogicalResult matchAndRewrite( 36 | FHEMaterializeOp op, typename FHEMaterializeOp::Adaptor adaptor, ConversionPatternRewriter &rewriter) const override 37 | { 38 | Value operand = op.getOperand(); 39 | if (operand.getType().dyn_cast_or_null()) { 40 | rewriter.replaceOpWithNewOp(op, op.getType(), operand); 41 | } 42 | 43 | return success(); 44 | } 45 | }; 46 | 47 | void EncryptPass::runOnOperation() 48 | { 49 | ConversionTarget target(getContext()); 50 | target.addLegalDialect(); 51 | target.addLegalDialect(); 52 | target.addLegalOp(); 53 | target.addIllegalOp(); 54 | 55 | 56 | IRRewriter rewriter(&getContext()); 57 | 58 | // MemRefToHEIR 59 | mlir::RewritePatternSet patterns(&getContext()); 60 | patterns.add(patterns.getContext()); 61 | 62 | if (mlir::failed(mlir::applyFullConversion(getOperation(), target, std::move(patterns)))) 63 | signalPassFailure(); 64 | 65 | } -------------------------------------------------------------------------------- /src/Passes/encrypt/Encrypt.td: -------------------------------------------------------------------------------- 1 | #ifndef HEIR_ENCRYPT_TD 2 | #define HEIR_ENCRYPT_TD 3 | 4 | include "mlir/IR/PatternBase.td" 5 | 6 | #endif // HEIR_ENCRYPT_TD -------------------------------------------------------------------------------- /src/Passes/func2heir/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_heir_conversion_library(HEIRFuncToHEIR 2 | FuncToHEIR.cpp 3 | 4 | #ADDITIONAL_HEADER_DIRS 5 | #Passes 6 | 7 | DEPENDS 8 | 9 | LINK_COMPONENTS 10 | Core 11 | 12 | LINK_LIBS PUBLIC 13 | HEIRHEIRDialect 14 | ) 15 | 16 | -------------------------------------------------------------------------------- /src/Passes/func2heir/FuncToHEIR.td: -------------------------------------------------------------------------------- 1 | #ifndef HEIR_func2heir_LOWERFUNCTOHEIR_TD 2 | #define HEIR_func2heir_LOWERFUNCTOHEIR_TD 3 | 4 | include "mlir/IR/PatternBase.td" 5 | 6 | #endif // HEIR_func2heir_LOWERFUNCTOHEIR_TD -------------------------------------------------------------------------------- /src/Passes/genparm/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_heir_conversion_library(HEIRGenParm 2 | GenParm.cpp 3 | 4 | #ADDITIONAL_HEADER_DIRS 5 | #Passes 6 | 7 | DEPENDS 8 | 9 | LINK_COMPONENTS 10 | Core 11 | 12 | LINK_LIBS PUBLIC 13 | HEIRHEIRDialect 14 | ) 15 | 16 | -------------------------------------------------------------------------------- /src/Passes/genparm/GenParm.cpp: -------------------------------------------------------------------------------- 1 | #include "heir/Passes/genparm/GenParm.h" 2 | #include 3 | #include 4 | #include "mlir/Dialect/Affine/IR/AffineOps.h" 5 | #include "mlir/Dialect/Affine/Utils.h" 6 | #include "mlir/Dialect/Affine/LoopUtils.h" 7 | #include "mlir/Dialect/Func/IR/FuncOps.h" 8 | #include "mlir/Dialect/SCF/IR/SCF.h" 9 | #include "mlir/Dialect/Tensor/IR/Tensor.h" 10 | #include "mlir/Dialect/Arithmetic/IR/Arithmetic.h" 11 | 12 | using namespace mlir; 13 | using namespace arith; 14 | using namespace heir; 15 | 16 | void GenerateParmPass::getDependentDialects(mlir::DialectRegistry ®istry) const 17 | { 18 | registry.insert(); 19 | registry.insert(); 20 | } 21 | 22 | // Generate the level of each ciphertext Value 23 | // TODO: Does not integrate to the IR pass 24 | size_t determinBootstrapLevel(Value bootOutput, unsigned int curLine) 25 | { 26 | std::vector uses_list; 27 | if (bootOutput.getUses().empty()) 28 | return 0; 29 | for (OpOperand &u : bootOutput.getUses()) { 30 | size_t localLevel = 0; 31 | auto *subOp = u.getOwner(); 32 | 33 | // 1. Result is stored to a matrix/vector, find the next extract op 34 | if (auto op = dyn_cast(subOp)) { 35 | // subOp->getName().print(llvm::outs()); 36 | // subOp->getLoc().print(llvm::outs()); 37 | // llvm::outs() << "\n"; 38 | 39 | APInt insRow = op.rowAttr().cast().getValue(); 40 | APInt insCol = op.colAttr().cast().getValue(); 41 | Value insVector = op.memref(); 42 | unsigned int insLine = LocationAttr(op.getLoc()).cast().getLine(); 43 | auto curBlock = subOp->getBlock(); 44 | 45 | // TODO: maybe we cannot call determinateBootstrapLevel() recurisively?? 46 | FHEExtractfinalOp nearExtOp; 47 | unsigned int nearExtDist = 99999; 48 | auto extractOps = curBlock->getOps(); 49 | for (FHEExtractfinalOp extractOp : extractOps) { 50 | APInt extRow = extractOp.rowAttr().cast().getValue(); 51 | APInt extCol = extractOp.colAttr().cast().getValue(); 52 | Value extVector = extractOp.vector(); 53 | unsigned int extLine = LocationAttr(extractOp.getLoc()).cast().getLine(); 54 | // Same slot in vector 55 | if (extRow == insRow && extCol == insCol && extVector == insVector 56 | && extLine > insLine && extLine - insLine < nearExtDist) { 57 | nearExtOp = extractOp; 58 | nearExtDist = extLine - insLine; 59 | } 60 | } 61 | FHEVectorLoadfinalOp nearVecLoadOp; 62 | unsigned int nearVecLoadDist = 99999; 63 | auto vecExtOps = curBlock->getOps(); 64 | for (FHEVectorLoadfinalOp vecExtOp : vecExtOps) { 65 | APInt extRow = vecExtOp.index().cast().getValue(); 66 | Value extVector = vecExtOp.memref(); 67 | unsigned int extLine = LocationAttr(vecExtOp.getLoc()).cast().getLine(); 68 | if (extRow == insRow && extVector == insVector 69 | && extLine > insLine && extLine - insLine < nearVecLoadDist) { 70 | nearVecLoadOp = vecExtOp; 71 | nearVecLoadDist = extLine - insLine; 72 | } 73 | } 74 | // Check if another store Op override the current result 75 | FHEInsertfinalOp nearInsertOp; 76 | unsigned int nearInsertDist = 99999; 77 | auto insertOps = curBlock->getOps(); 78 | for (FHEInsertfinalOp insertOp : insertOps) { 79 | APInt insertRow = insertOp.rowAttr().cast().getValue(); 80 | APInt insertCol = insertOp.colAttr().cast().getValue(); 81 | Value insertVector = insertOp.memref(); 82 | unsigned int insertLine = LocationAttr(insertOp.getLoc()).cast().getLine(); 83 | if (insertRow == insRow && insertCol == insCol && insertVector == insVector 84 | && insertLine > insLine && insertLine - insLine < nearInsertDist) { 85 | nearInsertOp = insertOp; 86 | nearInsertDist = insertLine - insLine; 87 | } 88 | } 89 | // Check if another store Op override the current result 90 | if (nearInsertDist < std::min(nearVecLoadDist, nearExtDist)) { 91 | llvm::outs() << "This FHEInsertfinalOp has been overrided by another Insert Op\n"; 92 | break; 93 | } 94 | else if (nearVecLoadDist < nearExtDist) { 95 | // llvm::outs() << "VecLoadOp is the next Op\n"; 96 | // nearVecLoadOp->getName().print(llvm::outs()); 97 | // nearVecLoadOp->getLoc().print(llvm::outs()); 98 | // llvm::outs() << "\n"; 99 | 100 | Value subOutput = nearVecLoadOp.getResult(); 101 | auto subLine = LocationAttr(nearVecLoadOp.getLoc()).cast().getLine(); 102 | localLevel += determinBootstrapLevel(subOutput, subLine); 103 | } 104 | else if (nearVecLoadDist > nearExtDist) { 105 | // llvm::outs() << "ExtractOp is the next Op\n"; 106 | // nearExtOp->getName().print(llvm::outs()); 107 | // nearExtOp->getLoc().print(llvm::outs()); 108 | // llvm::outs() << "\n"; 109 | 110 | Value subOutput = nearExtOp.getResult(); 111 | auto subLine = LocationAttr(nearExtOp.getLoc()).cast().getLine(); 112 | localLevel += determinBootstrapLevel(subOutput, subLine); 113 | } 114 | // No any subsequent Op after the current InsertOp 115 | else if (nearVecLoadDist == nearExtDist) { 116 | // subOp->getName().print(llvm::outs()); 117 | // subOp->getLoc().print(llvm::outs()); 118 | // llvm::outs() << "\n"; 119 | llvm::outs() << "!!!!!!!!!!!!!!!!!!!!No subsequent Op!!!!!!!!!!!!\n"; 120 | // break; 121 | } 122 | } 123 | 124 | // 2. Multiplications 125 | else if (auto op = dyn_cast(subOp)) { 126 | // subOp->getName().print(llvm::outs()); 127 | // subOp->getLoc().print(llvm::outs()); 128 | // llvm::outs() << "\n"; 129 | 130 | localLevel++; 131 | Value subOutput = op.getResult(); 132 | auto subLine = LocationAttr(op.getLoc()).cast().getLine(); 133 | localLevel += determinBootstrapLevel(subOutput, subLine); 134 | } 135 | else if (auto op = dyn_cast(subOp)) { 136 | // subOp->getName().print(llvm::outs()); 137 | // llvm::outs() << op.callee(); 138 | // subOp->getLoc().print(llvm::outs()); 139 | // llvm::outs() << "\n"; 140 | 141 | if (op.callee().str().find("lut") == 0) { 142 | // llvm::outs() << "callee name in col " << op.callee().str().find("lut"); 143 | llvm::outs() << "This is a LUT Function in line " 144 | << LocationAttr(op.getLoc()).cast().getLine() << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!11\n"; 145 | return 0; 146 | } 147 | 148 | if (op.callee().str().find("inner") == 0) { 149 | llvm::outs() << "!!!!!!!!!!!!!!!!!!!!!!inner_product!!!!!!!!!!!!!!!!!!\n"; 150 | localLevel++; 151 | } 152 | else if (op.callee().str().find("euclid") == 0) { 153 | llvm::outs() << "!!!!!!!!!!!!!!!!!!!!!!euclid_dist!!!!!!!!!!!!!!!!!!\n"; 154 | localLevel++; 155 | } 156 | Value subOutput = op.getResult(); 157 | auto subLine = LocationAttr(op.getLoc()).cast().getLine(); 158 | localLevel += determinBootstrapLevel(subOutput, subLine); 159 | } 160 | 161 | // 3. Other operators 162 | else if (auto op = dyn_cast(subOp)) { 163 | // subOp->getName().print(llvm::outs()); 164 | // subOp->getLoc().print(llvm::outs()); 165 | // llvm::outs() << "\n"; 166 | Value subOutput = op.getResult(); 167 | auto subLine = LocationAttr(op.getLoc()).cast().getLine(); 168 | localLevel += determinBootstrapLevel(subOutput, subLine); 169 | } 170 | else if (auto op = dyn_cast(subOp)) { 171 | // subOp->getName().print(llvm::outs()); 172 | // subOp->getLoc().print(llvm::outs()); 173 | // llvm::outs() << "\n"; 174 | Value subOutput = op.getResult(); 175 | auto subLine = LocationAttr(op.getLoc()).cast().getLine(); 176 | localLevel += determinBootstrapLevel(subOutput, subLine); 177 | } 178 | else if (auto op = dyn_cast(subOp)) { 179 | // subOp->getName().print(llvm::outs()); 180 | // subOp->getLoc().print(llvm::outs()); 181 | // llvm::outs() << "\n"; 182 | Value subOutput = op.getResult(); 183 | auto subLine = LocationAttr(op.getLoc()).cast().getLine(); 184 | localLevel += determinBootstrapLevel(subOutput, subLine); 185 | } 186 | else if (auto op = dyn_cast(subOp)) { 187 | // subOp->getName().print(llvm::outs()); 188 | // subOp->getLoc().print(llvm::outs()); 189 | // llvm::outs() << "\n"; 190 | Value subOutput = op.getResult(); 191 | auto subLine = LocationAttr(op.getLoc()).cast().getLine(); 192 | localLevel += determinBootstrapLevel(subOutput, subLine); 193 | } 194 | uses_list.push_back(localLevel); 195 | // else if (auto op = dyn_cast(subOp)) 196 | // return localLevel; 197 | // else return -1; throw error with other undifined Op. 198 | 199 | } 200 | auto finalLevel = *std::max_element(uses_list.begin(), uses_list.end()); 201 | return finalLevel; 202 | } 203 | 204 | 205 | /// In order to determine the parameters of fb_keys, we need to traverse the 206 | /// multiplication depth between two bootstrapping Op. However, for a value 207 | /// generated from LUT, it is often been stored to a vector/matrix firstly 208 | /// and extract(load) later for further computing. And we cannot find out the 209 | /// relation between a pair of insert/extract through def-use chain. 210 | /// Here, we *assume* heir.extract is always behind heir.store in terms of 211 | /// FileLineColLoc. But maybe in some complicated programs it is not always 212 | /// right? Maybe does not work for programs with large for loops 213 | void GenBootParms(FHEFuncCallOp op, IRRewriter &rewriter) 214 | { 215 | auto funcName = op.callee().str(); 216 | 217 | // Only operate on TFHE Bootstrapping Op 218 | if (funcName.find("lut") != std::string::npos) { 219 | auto curLine = LocationAttr(op.getLoc()).cast().getLine(); 220 | Value res = op.getResult(); 221 | size_t level = determinBootstrapLevel(res, curLine); 222 | 223 | llvm::outs() << "LUT in Line " << curLine << " has " << level << " level!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"; 224 | 225 | // Add an argument (fb_keys modulus) for LUT function 226 | auto val = APInt(8, level + 1, false); 227 | // auto typeName = IndexType() 228 | // auto a = IntegerAttr(mlir::detail::IntegerAttrStorage(IndexType(), val)); 229 | // auto indexOp = rewriter.create(op.getLoc(), level + 1); 230 | // auto newOp = rewriter.replaceOpWithNewOp(op, op.getResult().getType(), 231 | // op.callee(), ArrayAttr(), ArrayAttr(), op.getOperands()); 232 | auto indexOp = rewriter.create(op.getLoc(), op.getResult().getType(), 233 | op.callee(), ArrayAttr(), ArrayAttr(), op.getOperands()); 234 | // rewriter.eraseOp(op); 235 | indexOp.replaceAllUsesWith(res); 236 | 237 | // op.replaceAllUsesWith(newOp.getResult()); 238 | } 239 | 240 | 241 | } 242 | 243 | // Determine the level of the function arguments 244 | void GenArgLevel(Value arg, IRRewriter &rewriter) 245 | { 246 | 247 | unsigned int argLoc = LocationAttr(arg.getLoc()).cast().getLine(); 248 | size_t level = determinBootstrapLevel(arg, argLoc); 249 | llvm::outs() << "level = " << level << "\n"; 250 | } 251 | 252 | void GenerateParmPass::runOnOperation() 253 | { 254 | ConversionTarget target(getContext()); 255 | target.addLegalDialect(); 256 | target.addLegalDialect(); 257 | target.addLegalOp(); 258 | target.addLegalDialect(); 259 | 260 | IRRewriter rewriter(&getContext()); 261 | 262 | 263 | // Get the (default) block in the module's only region: 264 | auto &block = getOperation()->getRegion(0).getBlocks().front(); 265 | for (auto f : llvm::make_early_inc_range(block.getOps())) 266 | { 267 | // Bootstrapping Key Modulus Selection 268 | for (auto op : llvm::make_early_inc_range(f.getBody().getOps())) 269 | { 270 | GenBootParms(op, rewriter); 271 | } 272 | // Input cipher level selection 273 | auto arg = f.getArguments(); 274 | SmallVector funcArgVec{arg.begin(), arg.end()}; 275 | for (Value ArgI : arg) { 276 | ArgI.print(llvm::outs()); 277 | ArgI.getType().print(llvm::outs()); 278 | llvm::outs() << "\n"; 279 | // ArgI->cast(); 280 | GenArgLevel(ArgI, rewriter); 281 | } 282 | } 283 | 284 | } -------------------------------------------------------------------------------- /src/Passes/heir2emitc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_heir_conversion_library(HEIRHEIRToEmitC 2 | LowerHEIRToEmitC.cpp 3 | 4 | #ADDITIONAL_HEADER_DIRS 5 | #Passes 6 | 7 | DEPENDS 8 | 9 | LINK_COMPONENTS 10 | Core 11 | 12 | LINK_LIBS PUBLIC 13 | HEIRHEIRDialect 14 | ) -------------------------------------------------------------------------------- /src/Passes/heir2emitc/LowerHEIRToEmitC.td: -------------------------------------------------------------------------------- 1 | #ifndef HEIR_heir2emitc_LOWERHEIRTOEMITC_TD 2 | #define HEIR_heir2emitc_LOWERHEIRTOEMITC_TD 3 | 4 | include "mlir/IR/PatternBase.td" 5 | 6 | #endif // HEIR_heir2emitc_LOWERHEIRTOEMITC_TD -------------------------------------------------------------------------------- /src/Passes/lwe2rlwe/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_heir_conversion_library(HEIRLWEToRLWE 2 | LWEToRLWE.cpp 3 | 4 | #ADDITIONAL_HEADER_DIRS 5 | #Passes 6 | 7 | DEPENDS 8 | 9 | LINK_COMPONENTS 10 | Core 11 | 12 | LINK_LIBS PUBLIC 13 | HEIRHEIRDialect 14 | ) 15 | -------------------------------------------------------------------------------- /src/Passes/lwe2rlwe/LWEToRLWE.cpp: -------------------------------------------------------------------------------- 1 | // Author: Zian Zhao 2 | #include 3 | #include "mlir/Transforms/DialectConversion.h" 4 | #include "mlir/Dialect/Affine/IR/AffineOps.h" 5 | #include "mlir/Dialect/Func/IR/FuncOps.h" 6 | #include "mlir/Dialect/SCF/IR/SCF.h" 7 | #include "mlir/Dialect/Tensor/IR/Tensor.h" 8 | #include "llvm/ADT/APSInt.h" 9 | 10 | #include "heir/Passes/lwe2rlwe/LWEToRLWE.h" 11 | 12 | using namespace mlir; 13 | using namespace heir; 14 | 15 | void LWEToRLWEPass::getDependentDialects(mlir::DialectRegistry ®istry) const 16 | { 17 | registry.insert(); 21 | } 22 | 23 | // Transform the batched LWE addition operator into RLWE addition 24 | LogicalResult LWEAddToRLWEOperation(IRRewriter &rewriter, MLIRContext *context, LWEAddOp op, TypeConverter typeConverter) 25 | { 26 | rewriter.setInsertionPoint(op); 27 | 28 | auto dstType = typeConverter.convertType(op.getType()); 29 | if (!dstType) 30 | return failure(); 31 | 32 | llvm::SmallVector materialized_operands; 33 | for (Value o : op.getOperands()) 34 | { 35 | auto operandDstType = typeConverter.convertType(o.getType()); 36 | if (!operandDstType) 37 | return failure(); 38 | if (o.getType() != operandDstType) { 39 | auto new_operand = typeConverter.materializeTargetConversion(rewriter, op.getLoc(), operandDstType, o); 40 | assert(new_operand && "Type Conversion must not fail"); 41 | materialized_operands.push_back(new_operand); 42 | } 43 | else { 44 | materialized_operands.push_back(o); 45 | } 46 | } 47 | 48 | rewriter.replaceOpWithNewOp(op, dstType, materialized_operands); 49 | return success(); 50 | } 51 | 52 | // Transform the batched LWE substraction operator into RLWE substraction 53 | LogicalResult LWESubToRLWEOperation(IRRewriter &rewriter, MLIRContext *context, LWESubOp op, TypeConverter typeConverter) 54 | { 55 | rewriter.setInsertionPoint(op); 56 | 57 | auto dstType = typeConverter.convertType(op.getType()); 58 | if (!dstType) 59 | return failure(); 60 | 61 | llvm::SmallVector materialized_operands; 62 | for (Value o : op.getOperands()) 63 | { 64 | auto operandDstType = typeConverter.convertType(o.getType()); 65 | if (!operandDstType) 66 | return failure(); 67 | if (o.getType() != operandDstType) { 68 | auto new_operand = typeConverter.materializeTargetConversion(rewriter, op.getLoc(), operandDstType, o); 69 | assert(new_operand && "Type Conversion must not fail"); 70 | materialized_operands.push_back(new_operand); 71 | } 72 | else { 73 | materialized_operands.push_back(o); 74 | } 75 | } 76 | 77 | rewriter.replaceOpWithNewOp(op, dstType, materialized_operands); 78 | return success(); 79 | 80 | } 81 | 82 | // Transform the batched LWE multiplication operator into RLWE multiplication 83 | LogicalResult LWEMulToRLWEOperation(IRRewriter &rewriter, MLIRContext *context, LWEMulOp op, TypeConverter typeConverter) 84 | { 85 | rewriter.setInsertionPoint(op); 86 | 87 | auto dstType = typeConverter.convertType(op.getType()); 88 | if (!dstType) 89 | return failure(); 90 | 91 | llvm::SmallVector materialized_operands; 92 | for (Value o : op.getOperands()) 93 | { 94 | auto operandDstType = typeConverter.convertType(o.getType()); 95 | if (!operandDstType) 96 | return failure(); 97 | if (o.getType() != operandDstType) { 98 | auto new_operand = typeConverter.materializeTargetConversion(rewriter, op.getLoc(), operandDstType, o); 99 | assert(new_operand && "Type Conversion must not fail"); 100 | materialized_operands.push_back(new_operand); 101 | } 102 | else { 103 | materialized_operands.push_back(o); 104 | } 105 | } 106 | 107 | rewriter.replaceOpWithNewOp(op, dstType, materialized_operands); 108 | return success(); 109 | 110 | } 111 | 112 | // Tranform a program computed in pure LWE ciphertexts into RLWE ciphertexts 113 | // after batching optimizations 114 | void LWEToRLWEPass::runOnOperation() 115 | { 116 | auto type_converter = TypeConverter(); 117 | 118 | type_converter.addConversion([&](Type t) { 119 | if (t.isa()) 120 | { 121 | int size = -155; 122 | auto new_t = t.cast(); 123 | size = new_t.getSize(); 124 | return llvm::Optional(RLWECipherType::get(&getContext(), new_t.getPlaintextType(), size)); 125 | } 126 | else 127 | return llvm::Optional(t); 128 | }); 129 | type_converter.addTargetMaterialization([&] (OpBuilder &builder, Type t, ValueRange vs, Location loc) { 130 | if (auto ot = t.dyn_cast_or_null()) 131 | { 132 | assert(!vs.empty() && ++vs.begin() == vs.end() && "currently can only materalize single values"); 133 | auto old_type = vs.front().getType(); 134 | if (old_type.dyn_cast_or_null()) 135 | { 136 | return llvm::Optional(builder.create(loc, ot, vs)); 137 | } 138 | } 139 | return llvm::Optional(llvm::None); 140 | }); 141 | type_converter.addArgumentMaterialization([&] (OpBuilder &builder, Type t, ValueRange vs, Location loc) { 142 | if (auto ot = t.dyn_cast_or_null()) 143 | { 144 | assert(!vs.empty() && ++vs.begin() == vs.end() && "currently can only materalize single values"); 145 | auto old_type = vs.front().getType(); 146 | if (old_type.dyn_cast_or_null()) 147 | { 148 | return llvm::Optional(builder.create(loc, ot, vs)); 149 | } 150 | } 151 | return llvm::Optional(llvm::None); 152 | }); 153 | type_converter.addSourceMaterialization([&](OpBuilder &builder, Type t, ValueRange vs, Location loc) { 154 | if (auto bst = t.dyn_cast_or_null()) 155 | { 156 | assert(!vs.empty() && ++vs.begin() == vs.end() && "currently can only materialize single values"); 157 | auto old_type = vs.front().getType(); 158 | if (auto ot = old_type.dyn_cast_or_null()) 159 | return llvm::Optional(builder.create(loc, bst, vs)); 160 | } 161 | return llvm::Optional(llvm::None); 162 | }); 163 | 164 | 165 | auto &block = getOperation()->getRegion(0).getBlocks().front(); 166 | IRRewriter rewriter(&getContext()); 167 | 168 | for (auto f : llvm::make_early_inc_range(block.getOps())) 169 | { 170 | if (f.walk([&](Operation *op) 171 | { 172 | if (LWESubOp sub_op = llvm::dyn_cast_or_null(op)) { 173 | if (LWESubToRLWEOperation(rewriter, &getContext(), sub_op, type_converter).failed()) 174 | return WalkResult::interrupt(); 175 | } 176 | else if (LWEAddOp add_op = llvm::dyn_cast_or_null(op)) { 177 | if (LWEAddToRLWEOperation(rewriter, &getContext(), add_op, type_converter).failed()) 178 | return WalkResult::interrupt(); 179 | } 180 | else if (LWEMulOp mul_op = llvm::dyn_cast_or_null(op)) { 181 | if (LWEMulToRLWEOperation(rewriter, &getContext(), mul_op, type_converter).failed()) 182 | return WalkResult::interrupt(); 183 | } 184 | return WalkResult(success()); }) 185 | .wasInterrupted()) 186 | signalPassFailure(); 187 | 188 | // int argNum = f.getNumArguments(); 189 | // for (int i = 0; i < argNum; i++) { 190 | // Value arg = f.getArgument(i); 191 | // auto dstType = type_converter.convertType(arg.getType()); 192 | // arg.setType(dstType); 193 | // // Value new_arg = type_converter.materializeTargetConversion(rewriter, f.getLoc(), dstType, arg); 194 | // // arg.replaceAllUsesWith(new_arg); 195 | // } 196 | // Convert types of the function arguments 197 | func::FuncOp op = f; 198 | TypeConverter::SignatureConversion signatureConversion(op.getFunctionType().getNumInputs()); 199 | SmallVector newResultTypes; 200 | if (failed(type_converter.convertTypes(op.getFunctionType().getResults(), newResultTypes))) 201 | signalPassFailure(); 202 | if (type_converter.convertSignatureArgs(op.getFunctionType().getInputs(), signatureConversion).failed()) 203 | signalPassFailure(); 204 | auto new_functype = FunctionType::get(&getContext(), signatureConversion.getConvertedTypes(), newResultTypes); 205 | 206 | rewriter.startRootUpdate(op); 207 | op.setType(new_functype); 208 | for (auto it = op.getRegion().args_begin(); it != op.getRegion().args_end(); ++it) 209 | { 210 | auto arg = *it; 211 | auto oldType = arg.getType(); 212 | auto newType = type_converter.convertType(oldType); 213 | arg.setType(newType); 214 | if (newType != oldType) 215 | { 216 | rewriter.setInsertionPointToStart(&op.getBody().getBlocks().front()); 217 | auto m_op = type_converter.materializeSourceConversion(rewriter, arg.getLoc(), oldType, arg); 218 | arg.replaceAllUsesExcept(m_op, m_op.getDefiningOp()); 219 | } 220 | } 221 | rewriter.finalizeRootUpdate(op); 222 | } 223 | 224 | } -------------------------------------------------------------------------------- /src/Passes/memref2heir/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_heir_conversion_library(HEIRMemrefToHEIR 2 | LowerMemrefToHEIR.cpp 3 | 4 | #ADDITIONAL_HEADER_DIRS 5 | #Passes 6 | 7 | DEPENDS 8 | 9 | LINK_COMPONENTS 10 | Core 11 | 12 | LINK_LIBS PUBLIC 13 | HEIRHEIRDialect 14 | ) -------------------------------------------------------------------------------- /src/Passes/memref2heir/LowerMemrefToHEIR.cpp: -------------------------------------------------------------------------------- 1 | // Author: Zian Zhao 2 | #include "heir/Passes/memref2heir/LowerMemrefToHEIR.h" 3 | #include 4 | #include 5 | #include "mlir/Dialect/Affine/IR/AffineOps.h" 6 | #include "mlir/Dialect/Affine/Utils.h" 7 | #include "mlir/Dialect/Affine/LoopUtils.h" 8 | #include "mlir/Dialect/Func/IR/FuncOps.h" 9 | #include "mlir/Dialect/SCF/IR/SCF.h" 10 | #include "mlir/Dialect/Tensor/IR/Tensor.h" 11 | #include "mlir/Dialect/Arithmetic/IR/Arithmetic.h" 12 | 13 | using namespace mlir; 14 | using namespace arith; 15 | using namespace heir; 16 | 17 | void LowerMemrefToHEIRPass::getDependentDialects(mlir::DialectRegistry ®istry) const 18 | { 19 | registry.insert(); 20 | registry.insert(); 21 | registry.insert(); 22 | registry.insert(); 23 | } 24 | 25 | // Transform the AffineLoadOp into FHEExtractOp, convert memref type into LWECipherVec type 26 | class AffineLoadPattern final : public OpConversionPattern 27 | { 28 | public: 29 | using OpConversionPattern::OpConversionPattern; 30 | 31 | LogicalResult matchAndRewrite( 32 | AffineLoadOp op, typename AffineLoadOp::Adaptor adaptor, ConversionPatternRewriter &rewriter) const override 33 | { 34 | auto dstType = this->getTypeConverter()->convertType(op.getType()); 35 | if (!dstType) 36 | return failure(); 37 | 38 | if (auto st = dstType.dyn_cast_or_null()) 39 | { 40 | int size; 41 | Value batchedCipher; 42 | auto tt = op.getMemRef().getType().dyn_cast(); 43 | if (tt.hasStaticShape() && tt.getShape().size() == 1) { 44 | size = tt.getShape().front(); 45 | 46 | batchedCipher = typeConverter->materializeTargetConversion(rewriter, 47 | op.getMemRef().getLoc(), 48 | LWECipherVectorType::get(getContext(), 49 | st, size), 50 | op.getMemRef()); 51 | } 52 | 53 | else if (tt.hasStaticShape() && tt.getShape().size() == 2) { 54 | int row = tt.getShape().front(); 55 | int column = tt.getShape().back(); 56 | 57 | batchedCipher = typeConverter->materializeTargetConversion(rewriter, 58 | op.getMemRef().getLoc(), 59 | LWECipherMatrixType::get(getContext(), 60 | st, row, column), op.getMemRef()); 61 | } 62 | 63 | SmallVector indices(op.getMapOperands()); 64 | auto resultOperands = 65 | expandAffineMap(rewriter, op.getLoc(), op.getAffineMap(), indices); 66 | if (!resultOperands) 67 | return failure(); 68 | 69 | rewriter.replaceOpWithNewOp(op, dstType, batchedCipher, *resultOperands); 70 | } 71 | return success(); 72 | } 73 | }; 74 | 75 | // Transform the AffineLoadOp into FHEInsertOp, convert memref type into LWECipherVec type 76 | class AffineStorePattern final : public OpConversionPattern 77 | { 78 | public: 79 | using OpConversionPattern::OpConversionPattern; 80 | 81 | LogicalResult matchAndRewrite( 82 | AffineStoreOp op, typename AffineStoreOp::Adaptor adaptor, ConversionPatternRewriter &rewriter) const override 83 | { 84 | Type elementType = op.getMemRef().getType(); 85 | 86 | if (elementType.isa()) 87 | elementType = elementType.cast().getElementType(); 88 | if (auto st = elementType.dyn_cast_or_null()) { 89 | Value batchedCipher; 90 | auto tt = op.getMemRef().getType().dyn_cast(); 91 | if (tt.hasStaticShape() && tt.getShape().size() == 1) { 92 | auto size = tt.getShape().front(); 93 | batchedCipher = typeConverter->materializeTargetConversion(rewriter, 94 | op.getMemRef().getLoc(), 95 | LWECipherVectorType::get(getContext(), 96 | st, size), 97 | op.getMemRef()); 98 | } 99 | 100 | else if (tt.hasStaticShape() && tt.getShape().size() == 2) { 101 | int row = tt.getShape().front(); 102 | int column = tt.getShape().back(); 103 | batchedCipher = typeConverter->materializeTargetConversion(rewriter, 104 | op.getMemRef().getLoc(), 105 | LWECipherMatrixType::get(getContext(), 106 | st, row, column), op.getMemRef()); 107 | } 108 | 109 | SmallVector indices(op.getMapOperands()); 110 | auto resultOperands = 111 | expandAffineMap(rewriter, op.getLoc(), op.getAffineMap(), indices); 112 | if (!resultOperands) 113 | return failure(); 114 | 115 | rewriter.replaceOpWithNewOp(op, op.getValueToStore(), batchedCipher, *resultOperands); 116 | } 117 | 118 | return success(); 119 | } 120 | }; 121 | 122 | // For polygeist operator used to load a vector from a matrx, we replace this op 123 | // into FHEVectorLoadOp in polygeist_eliminator.py script 124 | // TODO: get rid of the scripts, define polygeist dialect in heir and replace these 125 | // ops by MLIR C++ passes 126 | class FHEVectorLoadPattern final : public OpConversionPattern 127 | { 128 | public: 129 | using OpConversionPattern::OpConversionPattern; 130 | 131 | LogicalResult matchAndRewrite( 132 | FHEVectorLoadOp op, typename FHEVectorLoadOp::Adaptor adaptor, ConversionPatternRewriter &rewriter) const override 133 | { 134 | auto dstType = typeConverter->convertType(op.getType()); 135 | if (!dstType) 136 | return failure(); 137 | 138 | auto memrefType = typeConverter->convertType(op.memref().getType()); 139 | auto new_memref = typeConverter->materializeTargetConversion(rewriter, op.memref().getLoc(), 140 | memrefType, op.memref()); 141 | 142 | auto cOp = op.indices().getDefiningOp(); 143 | if (!cOp) 144 | { 145 | emitError(op.getLoc(), 146 | "cannot find the definition of index in heir.extract_init op!"); 147 | return failure(); 148 | } 149 | auto indexAttr = cOp.getValue().cast(); 150 | 151 | rewriter.replaceOpWithNewOp(op, dstType, new_memref, indexAttr); 152 | 153 | return success(); 154 | 155 | } 156 | 157 | }; 158 | 159 | // Transform the vector/matrix related operations into homomorphic operators 160 | // and convert the data type of input/output from plaintext into LWECipher/LWECipherEVec 161 | void LowerMemrefToHEIRPass::runOnOperation() 162 | { 163 | auto type_converter = TypeConverter(); 164 | 165 | type_converter.addConversion([&](Type t) { 166 | if (t.isa()) 167 | { 168 | int size = -155; 169 | auto new_t = t.cast(); 170 | if (new_t.hasStaticShape() && new_t.getShape().size()==1) { 171 | size = new_t.getShape().front(); 172 | return llvm::Optional(LWECipherVectorType::get(&getContext(), new_t.getElementType(), size)); 173 | } 174 | else if (new_t.hasStaticShape() && new_t.getShape().size()==2) { 175 | int row = new_t.getShape().front(); 176 | int column = new_t.getShape().back(); 177 | return llvm::Optional(LWECipherMatrixType::get(&getContext(), new_t.getElementType(), row, column)); 178 | } 179 | else 180 | return llvm::Optional(t); 181 | } 182 | else 183 | return llvm::Optional(t); 184 | }); 185 | type_converter.addTargetMaterialization([&] (OpBuilder &builder, Type t, ValueRange vs, Location loc) { 186 | // // if (auto ot = t.dyn_cast_or_null()) 187 | // if (auto ot = t.dyn_cast_or_null()) 188 | // { 189 | // assert(!vs.empty() && ++vs.begin() == vs.end() && "currently can only materalize single values"); 190 | // auto old_type = vs.front().getType(); 191 | // // if (old_type.dyn_cast_or_null()) 192 | // if (old_type.dyn_cast_or_null()) 193 | // { 194 | // return llvm::Optional(builder.create(loc, ot, vs)); 195 | // } 196 | // } 197 | if (auto ot = t.dyn_cast_or_null()) 198 | { 199 | assert(!vs.empty() && ++vs.begin() == vs.end() && "currently can only materalize single values"); 200 | auto old_type = vs.front().getType(); 201 | if (old_type.dyn_cast_or_null()) 202 | { 203 | return llvm::Optional(builder.create(loc, ot, vs)); 204 | } 205 | } 206 | else if (auto ot = t.dyn_cast_or_null()) 207 | { 208 | assert(!vs.empty() && ++vs.begin() == vs.end() && "currently can only materalize single values"); 209 | auto old_type = vs.front().getType(); 210 | if (old_type.dyn_cast_or_null()) 211 | { 212 | return llvm::Optional(builder.create(loc, ot, vs)); 213 | } 214 | } 215 | return llvm::Optional(llvm::None); 216 | }); 217 | type_converter.addArgumentMaterialization([&] (OpBuilder &builder, Type t, ValueRange vs, Location loc) { 218 | // // if (auto ot = t.dyn_cast_or_null()) 219 | // if (auto ot = t.dyn_cast_or_null()) 220 | // { 221 | // assert(!vs.empty() && ++vs.begin() == vs.end() && "currently can only materalize single values"); 222 | // auto old_type = vs.front().getType(); 223 | // // if (old_type.dyn_cast_or_null()) 224 | // if (old_type.dyn_cast_or_null()) 225 | // { 226 | // return llvm::Optional(builder.create(loc, ot, vs)); 227 | // } 228 | // } 229 | if (auto ot = t.dyn_cast_or_null()) 230 | { 231 | assert(!vs.empty() && ++vs.begin() == vs.end() && "currently can only materalize single values"); 232 | auto old_type = vs.front().getType(); 233 | if (old_type.dyn_cast_or_null()) 234 | { 235 | return llvm::Optional(builder.create(loc, ot, vs)); 236 | } 237 | } 238 | else if (auto ot = t.dyn_cast_or_null()) 239 | { 240 | assert(!vs.empty() && ++vs.begin() == vs.end() && "currently can only materalize single values"); 241 | auto old_type = vs.front().getType(); 242 | if (old_type.dyn_cast_or_null()) 243 | { 244 | return llvm::Optional(builder.create(loc, ot, vs)); 245 | } 246 | } 247 | return llvm::Optional(llvm::None); 248 | }); 249 | type_converter.addSourceMaterialization([&](OpBuilder &builder, Type t, ValueRange vs, Location loc) { 250 | // // if (auto bst = t.dyn_cast_or_null()) 251 | // if (auto bst = t.dyn_cast_or_null()) 252 | // { 253 | // assert(!vs.empty() && ++vs.begin() == vs.end() && "currently can only materialize single values"); 254 | // auto old_type = vs.front().getType(); 255 | // // if (auto ot = old_type.dyn_cast_or_null()) 256 | // if (auto ot = old_type.dyn_cast_or_null()) 257 | // return llvm::Optional(builder.create(loc, bst, vs)); 258 | // } 259 | if (auto bst = t.dyn_cast_or_null()) 260 | { 261 | // Only support float type in C Program 262 | if (bst.getElementType().dyn_cast_or_null()) 263 | return llvm::Optional(llvm::None); 264 | 265 | assert(!vs.empty() && ++vs.begin() == vs.end() && "currently can only materialize single values"); 266 | auto old_type = vs.front().getType(); 267 | if (auto ot = old_type.dyn_cast_or_null()) 268 | return llvm::Optional(builder.create(loc, bst, vs)); 269 | else if (auto ot = old_type.dyn_cast_or_null()) 270 | return llvm::Optional(builder.create(loc, bst, vs)); 271 | } 272 | return llvm::Optional(llvm::None); 273 | }); 274 | 275 | ConversionTarget target(getContext()); 276 | target.addLegalDialect(); 277 | target.addLegalDialect(); 278 | target.addLegalOp(); 279 | // target.addIllegalOp(); 280 | 281 | IRRewriter rewriter(&getContext()); 282 | 283 | // MemRefToHEIR 284 | target.addIllegalOp(); 285 | target.addIllegalOp(); 286 | // target.addIllegalOp(); 287 | mlir::RewritePatternSet patterns(&getContext()); 288 | patterns.add< 289 | AffineLoadPattern, AffineStorePattern>(type_converter, patterns.getContext()); 290 | // ArithmeticNegPattern>(type_converter, patterns.getContext()); 291 | // ArithmeticNegPattern>(patterns.getContext()); 292 | 293 | if (mlir::failed(mlir::applyPartialConversion(getOperation(), target, std::move(patterns)))) 294 | signalPassFailure(); 295 | 296 | } -------------------------------------------------------------------------------- /src/Passes/memref2heir/LowerMemrefToHEIR.td: -------------------------------------------------------------------------------- 1 | #ifndef HEIR_memref2heir_LOWERMEMREFTOHEIR_TD 2 | #define HEIR_memref2heir_LOWERMEMREFTOHEIR_TD 3 | 4 | include "mlir/IR/PatternBase.td" 5 | 6 | #endif // HEIR_memref2heir_LOWERMEMREFTOHEIR_TD -------------------------------------------------------------------------------- /src/Passes/nary/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_heir_conversion_library(HEIRNary 2 | Nary.cpp 3 | 4 | #ADDITIONAL_HEADER_DIRS 5 | #Passes 6 | 7 | DEPENDS 8 | 9 | LINK_COMPONENTS 10 | Core 11 | 12 | LINK_LIBS PUBLIC 13 | HEIRHEIRDialect 14 | ) -------------------------------------------------------------------------------- /src/Passes/nary/Nary.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Authors: HECO 3 | Modified by Zian Zhao 4 | Copyright: 5 | Copyright (c) 2020 ETH Zurich. 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #include "heir/Passes/nary/Nary.h" 24 | #include 25 | #include 26 | #include "mlir/Dialect/Affine/IR/AffineOps.h" 27 | #include "mlir/Dialect/Func/IR/FuncOps.h" 28 | #include "mlir/Dialect/SCF/IR/SCF.h" 29 | #include "mlir/Dialect/Tensor/IR/Tensor.h" 30 | #include "mlir/Pass/Pass.h" 31 | #include "mlir/Transforms/DialectConversion.h" 32 | 33 | using namespace mlir; 34 | using namespace heir; 35 | 36 | void NaryPass::getDependentDialects(mlir::DialectRegistry ®istry) const 37 | { 38 | registry.insert< 39 | heir::HEIRDialect, mlir::AffineDialect, func::FuncDialect, mlir::scf::SCFDialect, mlir::tensor::TensorDialect>(); 40 | } 41 | 42 | // LWEAdd aggregation 43 | void collapseAdd(heir::LWEAddOp &op, IRRewriter &rewriter) 44 | { 45 | for (auto &use : llvm::make_early_inc_range(op.output().getUses())) 46 | { 47 | if (auto use_add = llvm::dyn_cast(*use.getOwner())) 48 | { 49 | rewriter.setInsertionPointAfter(use_add.getOperation()); 50 | llvm::SmallVector new_operands; 51 | for (auto s : use_add.x()) 52 | { 53 | if (s != op.output()) 54 | { 55 | new_operands.push_back(s); 56 | } 57 | } 58 | for (auto s : op.x()) 59 | { 60 | new_operands.push_back(s); 61 | } 62 | auto new_add = rewriter.create(use_add->getLoc(), use_add.output().getType(), new_operands); 63 | use_add.replaceAllUsesWith(new_add.getOperation()); 64 | } 65 | } 66 | } 67 | 68 | // LWESub aggregation 69 | void collapseSub(heir::LWESubOp &op, IRRewriter &rewriter) 70 | { 71 | for (auto &use : llvm::make_early_inc_range(op.output().getUses())) 72 | { 73 | if (auto use_sub = llvm::dyn_cast(*use.getOwner())) 74 | { 75 | rewriter.setInsertionPointAfter(use_sub.getOperation()); 76 | llvm::SmallVector new_operands; 77 | for (auto s : use_sub.x()) 78 | { 79 | if (s != op.output()) 80 | { 81 | new_operands.push_back(s); 82 | } 83 | } 84 | for (auto s : op.x()) 85 | { 86 | new_operands.push_back(s); 87 | } 88 | auto new_sub = rewriter.create(use_sub->getLoc(), use_sub.output().getType(), new_operands); 89 | use_sub.replaceAllUsesWith(new_sub.getOperation()); 90 | } 91 | } 92 | } 93 | 94 | // LWEMul aggregation 95 | void collapseMul(heir::LWEMulOp &op, IRRewriter &rewriter) 96 | { 97 | for (auto &use : llvm::make_early_inc_range(op.output().getUses())) 98 | { 99 | if (auto use_mul = llvm::dyn_cast(*use.getOwner())) 100 | { 101 | rewriter.setInsertionPointAfter(use_mul.getOperation()); 102 | llvm::SmallVector new_operands; 103 | for (auto s : use_mul.x()) 104 | { 105 | if (s != op.output()) 106 | { 107 | new_operands.push_back(s); 108 | } 109 | } 110 | for (auto s : op.x()) 111 | { 112 | new_operands.push_back(s); 113 | } 114 | auto new_mul = 115 | rewriter.create(use_mul->getLoc(), use_mul.output().getType(), new_operands); 116 | use_mul.replaceAllUsesWith(new_mul.getOperation()); 117 | } 118 | } 119 | } 120 | 121 | // add/sub/mult operation aggragation to get ready for batching optimizatins 122 | void NaryPass::runOnOperation() 123 | { 124 | ConversionTarget target(getContext()); 125 | target.addLegalDialect(); 126 | target.addIllegalOp(); 127 | 128 | // Get the (default) block in the module's only region: 129 | auto &block = getOperation()->getRegion(0).getBlocks().front(); 130 | IRRewriter rewriter(&getContext()); 131 | 132 | 133 | for (auto f : llvm::make_early_inc_range(block.getOps())) 134 | { 135 | for (auto op : llvm::make_early_inc_range(f.getBody().getOps())) 136 | { 137 | rewriter.setInsertionPointAfter(op.getOperation()); 138 | llvm::SmallVector operands = { op.getLhs(), op.getRhs() }; 139 | Value value = rewriter.create(op.getLoc(), op.getResult().getType(), operands); 140 | op.replaceAllUsesWith(value); 141 | rewriter.eraseOp(op.getOperation()); 142 | } 143 | } 144 | 145 | for (auto f : llvm::make_early_inc_range(block.getOps())) 146 | { 147 | for (auto op : llvm::make_early_inc_range(f.getBody().getOps())) 148 | { 149 | rewriter.setInsertionPointAfter(op.getOperation()); 150 | llvm::SmallVector operands = { op.getLhs(), op.getRhs() }; 151 | Value value = rewriter.create(op.getLoc(), op.getResult().getType(), operands); 152 | op.replaceAllUsesWith(value); 153 | rewriter.eraseOp(op.getOperation()); 154 | } 155 | } 156 | 157 | // Now, go through and actually start collapsing the operations! 158 | for (auto f : llvm::make_early_inc_range(block.getOps())) 159 | { 160 | for (auto op : llvm::make_early_inc_range(f.getBody().getOps())) 161 | { 162 | collapseAdd(op, rewriter); 163 | } 164 | } 165 | 166 | for (auto f : llvm::make_early_inc_range(block.getOps())) 167 | { 168 | for (auto op : llvm::make_early_inc_range(f.getBody().getOps())) 169 | { 170 | collapseSub(op, rewriter); 171 | } 172 | } 173 | 174 | for (auto f : llvm::make_early_inc_range(block.getOps())) 175 | { 176 | for (auto op : llvm::make_early_inc_range(f.getBody().getOps())) 177 | { 178 | collapseMul(op, rewriter); 179 | } 180 | } 181 | 182 | // TODO: Finally, clean up ops without uses (hard to do during above loop because of iter invalidation) 183 | // HACK: just canonicalize again for now ;) 184 | } 185 | 186 | // TODO: NOTE WE MUST ADD CSE MANUALLY! -------------------------------------------------------------------------------- /src/Passes/slot2coeff/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_heir_conversion_library(HEIRSlotToCoeff 2 | SlotToCoeff.cpp 3 | 4 | #ADDITIONAL_HEADER_DIRS 5 | #Passes 6 | 7 | DEPENDS 8 | 9 | LINK_COMPONENTS 10 | Core 11 | 12 | LINK_LIBS PUBLIC 13 | HEIRHEIRDialect 14 | ) -------------------------------------------------------------------------------- /src/Passes/slot2coeff/SlotToCoeff.cpp: -------------------------------------------------------------------------------- 1 | // Author: Zian Zhao 2 | #include 3 | #include "mlir/Transforms/DialectConversion.h" 4 | #include "mlir/Dialect/Affine/IR/AffineOps.h" 5 | #include "mlir/Dialect/Func/IR/FuncOps.h" 6 | #include "mlir/Dialect/SCF/IR/SCF.h" 7 | #include "mlir/Dialect/Tensor/IR/Tensor.h" 8 | #include "llvm/ADT/APSInt.h" 9 | 10 | #include "heir/Passes/slot2coeff/SlotToCoeff.h" 11 | 12 | using namespace mlir; 13 | using namespace heir; 14 | 15 | void SlotToCoeffPass::getDependentDialects(mlir::DialectRegistry ®istry) const 16 | { 17 | registry.insert(); 21 | } 22 | 23 | // coefficient-encoding optimization for inner_product and euclid_dist 24 | LogicalResult batchInnerProductOperation(IRRewriter &rewriter, MLIRContext *context, LWEAddOp op) 25 | { 26 | int numOperands = op.getNumOperands(); 27 | // Now we only support batching for vector length >= 4 28 | if (numOperands <= 2) { 29 | return success(); 30 | } 31 | 32 | // Check if the operation satisfies the structure of inner_product 33 | // 1. rotate 34 | int numRotateOp = 0; 35 | llvm::SmallVector rotOperands; 36 | std::vector rotIndices; 37 | Value originCipher; 38 | for (Value it : op.getOperands()) { 39 | if (FHERotateOp rot_op = it.getDefiningOp()) { 40 | numRotateOp++; 41 | rotOperands.push_back(it); 42 | rotIndices.push_back(rot_op.i()); 43 | if (numRotateOp > 1) { 44 | if (it.getDefiningOp().cipher() != rotOperands[0].getDefiningOp().cipher()) break; 45 | } 46 | } 47 | } 48 | if (numRotateOp != numOperands - 1) 49 | return success(); 50 | // If indices satisfy {-1, -2, -3, ...} 51 | auto vector_length = op.output().getType().dyn_cast_or_null().getSize(); 52 | for (int i = -1; i > -vector_length; i--) { 53 | auto it = std::find(rotIndices.begin(), rotIndices.end(), i); 54 | if (it == rotIndices.end()) return success(); 55 | } 56 | 57 | 58 | 59 | LWEMulOp rlweMulOp; 60 | for (Value it : op.getOperands()) { 61 | if (LWEMulOp mul_op = it.getDefiningOp()) { 62 | if (it != rotOperands[0].getDefiningOp().cipher()) break; 63 | originCipher = it; 64 | rlweMulOp = mul_op; 65 | } 66 | } 67 | 68 | op->replaceAllUsesWith(rlweMulOp); 69 | rewriter.setInsertionPoint(rlweMulOp); 70 | // auto newMulOp = rewriter.create(rlweMulOp.getLoc(), rlweMulOp.getType(), rlweMulOp.getOperands()); 71 | auto new_mul_op = rewriter.replaceOpWithNewOp(rlweMulOp, rlweMulOp.getType(), rlweMulOp.getOperands()); 72 | 73 | for (OpOperand & use : new_mul_op->getUses()) { 74 | Operation *userOp = use.getOwner(); 75 | if (FHEExtractfinalOp ex_op = dyn_cast(userOp)) { 76 | Value input = ex_op.vector(); 77 | auto vecSize = input.getType().dyn_cast().getSize(); 78 | auto indexAttr = IntegerAttr::get(IndexType::get(rewriter.getContext()), vecSize - 1); 79 | ex_op.colAttr(indexAttr); 80 | } 81 | } 82 | 83 | // For EuclidDist, compputing euclid_dist with three multiplications 84 | if (rlweMulOp.getOperand(0) == rlweMulOp.getOperand(1)) { 85 | if (LWESubOp subOp = rlweMulOp.getOperand(0).getDefiningOp()) { 86 | // llvm::outs() << "hello"; 87 | Value vec1 = subOp.getOperand(0); 88 | Value vec2 = subOp.getOperand(1); 89 | 90 | rewriter.setInsertionPoint(subOp); 91 | SmallVector v1MulOperands; 92 | v1MulOperands.push_back(vec1); 93 | v1MulOperands.push_back(vec1); 94 | auto v1MulOp = rewriter.create(subOp.getLoc(), vec1.getType(), v1MulOperands); 95 | SmallVector v2MulOperands; 96 | v2MulOperands.push_back(vec2); 97 | v2MulOperands.push_back(vec2); 98 | auto v2MulOp = rewriter.create(subOp.getLoc(), vec2.getType(), v2MulOperands); 99 | SmallVector v1v2MulOperands; 100 | v1v2MulOperands.push_back(vec1); 101 | v1v2MulOperands.push_back(vec2); 102 | auto v12MulOp = rewriter.create(subOp.getLoc(), vec1.getType(), v1v2MulOperands); 103 | SmallVector v12DoubleOperands; 104 | v12DoubleOperands.push_back(v12MulOp.output()); 105 | v12DoubleOperands.push_back(v12MulOp.output()); 106 | auto v12DoubleOp = rewriter.create(subOp.getLoc(), vec1.getType(), v12DoubleOperands); 107 | SmallVector v1v2AddOperands; 108 | v1v2AddOperands.push_back(v1MulOp.output()); 109 | v1v2AddOperands.push_back(v2MulOp.output()); 110 | auto v1v2AddOp = rewriter.create(subOp.getLoc(), vec1.getType(), v1v2AddOperands); 111 | SmallVector finalOperands; 112 | finalOperands.push_back(v1v2AddOp.output()); 113 | finalOperands.push_back(v12DoubleOp.output()); 114 | auto finalOp = rewriter.create(subOp.getLoc(), vec1.getType(), finalOperands); 115 | 116 | new_mul_op->replaceAllUsesWith(finalOp); 117 | 118 | } 119 | } 120 | 121 | 122 | // rewriter.eraseOp(op); 123 | 124 | return success(); 125 | } 126 | 127 | // several pattern can be optimized via coefficient-encoding instead of 128 | // slot-encoding, e.g., InnerProduct and EuclidDist 129 | // TODO: Add a new optimization for convolution 130 | void SlotToCoeffPass::runOnOperation() 131 | { 132 | // Get the (default) block in the module's only region: 133 | auto &block = getOperation()->getRegion(0).getBlocks().front(); 134 | IRRewriter rewriter(&getContext()); 135 | 136 | for (auto f : llvm::make_early_inc_range(block.getOps())) 137 | { 138 | if (f.walk([&](Operation *op) 139 | { 140 | 141 | if (LWEAddOp add_op = llvm::dyn_cast_or_null(op)) { 142 | if (batchInnerProductOperation(rewriter, &getContext(), add_op).failed()) 143 | return WalkResult::interrupt(); 144 | } 145 | return WalkResult(success()); }) 146 | .wasInterrupted()) 147 | signalPassFailure(); 148 | } 149 | } -------------------------------------------------------------------------------- /src/Passes/unfold/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_heir_conversion_library(HEIRUnfold 2 | Unfold.cpp 3 | 4 | #ADDITIONAL_HEADER_DIRS 5 | #Passes 6 | 7 | DEPENDS 8 | 9 | LINK_COMPONENTS 10 | Core 11 | 12 | LINK_LIBS PUBLIC 13 | HEIRHEIRDialect 14 | ) -------------------------------------------------------------------------------- /src/Passes/unroll/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_heir_conversion_library(HEIRUnrollLoop 2 | UnrollLoop.cpp 3 | 4 | #ADDITIONAL_HEADER_DIRS 5 | #Passes 6 | 7 | DEPENDS 8 | 9 | LINK_COMPONENTS 10 | Core 11 | 12 | LINK_LIBS PUBLIC 13 | HEIRHEIRDialect 14 | ) -------------------------------------------------------------------------------- /src/Passes/unroll/UnrollLoop.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Authors: HECO 3 | Modified by Zian Zhao 4 | Copyright: 5 | Copyright (c) 2020 ETH Zurich. 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | #include 23 | #include 24 | #include "mlir/Dialect/Affine/IR/AffineOps.h" 25 | #include "mlir/Dialect/Affine/Utils.h" 26 | #include "mlir/Dialect/Affine/LoopUtils.h" 27 | #include "mlir/Dialect/Func/IR/FuncOps.h" 28 | #include "mlir/Dialect/SCF/IR/SCF.h" 29 | #include "mlir/Dialect/Tensor/IR/Tensor.h" 30 | #include "mlir/Dialect/Arithmetic/IR/Arithmetic.h" 31 | #include "heir/Passes/unroll/UnrollLoop.h" 32 | 33 | using namespace mlir; 34 | using namespace arith; 35 | 36 | void UnrollLoopPass::getDependentDialects(mlir::DialectRegistry ®istry) const 37 | { 38 | registry.insert(); 39 | registry.insert(); 40 | registry.insert(); 41 | registry.insert(); 42 | } 43 | 44 | void unrollLoop(AffineForOp &op, IRRewriter &rewriter) 45 | { 46 | // First, let's recursively unroll all nested loops: 47 | for (auto nested_loop : op.getOps()) 48 | { 49 | unrollLoop(nested_loop, rewriter); 50 | } 51 | 52 | // TODO: Fix MLIR issues in mlir/Transforms/LoopUtils.h where the typedef for FuncOp is messing with the fwd 53 | // declaration of FuncOp 54 | if (loopUnrollFull(op).failed()) 55 | { 56 | emitError(op.getLoc(), "Failed to unroll loop"); 57 | } 58 | } 59 | 60 | // Unroll all the for loops in the input program, 61 | // but we do not actually use this pass because 62 | // perhaps there exists multiple nested for loops 63 | // for now, we use the built-in "affine-loop-unroll" pass 64 | void UnrollLoopPass::runOnOperation() 65 | { 66 | ConversionTarget target(getContext()); 67 | target.addLegalDialect(); 68 | target.addLegalDialect(); 69 | target.addLegalOp(); 70 | target.addLegalOp(); 71 | target.addLegalOp(); 72 | // target.addIllegalOp(); 73 | 74 | // Get the (default) block in the module's only region: 75 | auto &block = getOperation()->getRegion(0).getBlocks().front(); 76 | IRRewriter rewriter(&getContext()); 77 | 78 | // TODO: There's likely a much better way to do this that's not this kind of manual walk! 79 | for (auto f : llvm::make_early_inc_range(block.getOps())) 80 | { 81 | for (auto op : llvm::make_early_inc_range(f.getBody().getOps())) 82 | { 83 | unrollLoop(op, rewriter); 84 | } 85 | } 86 | 87 | } -------------------------------------------------------------------------------- /src/Passes/vec2memref/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_heir_conversion_library(HEIRVecToMemref 2 | PromVecToMemref.cpp 3 | 4 | #ADDITIONAL_HEADER_DIRS 5 | #Passes 6 | 7 | DEPENDS 8 | 9 | LINK_COMPONENTS 10 | Core 11 | 12 | LINK_LIBS PUBLIC 13 | HEIRHEIRDialect 14 | ) 15 | 16 | -------------------------------------------------------------------------------- /src/Passes/vec2memref/PromVecToMemref.td: -------------------------------------------------------------------------------- 1 | #ifndef HEIR_vec2memref_PROMVECTOMEMREF_TD 2 | #define HEIR_vec2memref_PROMVECTOMEMREF_TD 3 | 4 | include "mlir/IR/PatternBase.td" 5 | 6 | #endif // HEIR_vec2memref_PROMVECTOMEMREF_TD --------------------------------------------------------------------------------