├── .clang-format ├── .github └── workflows │ └── build.yml ├── .gitignore ├── CMakeLists.txt ├── Dockerfile ├── LICENSE ├── README.md ├── cmake └── FindAlive2.cmake ├── include ├── alive-interface.h ├── codegen.h ├── config.h ├── cost-command.h.in ├── cost.h ├── enumerator.h ├── expr.h ├── lexer.h ├── parse.h ├── removal-slice.h ├── slice.h ├── tokens.h ├── type.h └── utils.h ├── lib ├── alive-interface.cpp ├── codegen.cpp ├── config.cpp ├── cost.cpp ├── enumerator.cpp ├── expr.cpp ├── lexer.re ├── parse.cpp ├── slice.cpp ├── type.cpp └── utils.cpp ├── pass ├── online.cpp └── stat │ ├── CMakeLists.txt │ └── HelloWorld.cpp ├── scripts ├── cache-dump.in ├── cache-infer.in ├── get-cost.in ├── infer-cut.sh.in ├── minotaur-cc.in ├── opt-minotaur.sh.in └── slice-cc.in ├── tests ├── and0.syn.ll ├── and1.syn.ll ├── and2.syn.ll ├── and3.syn.ll ├── const │ ├── const0.syn.ll │ ├── const1.syn.ll │ ├── control0.ll │ ├── diff1.constsyn.ll │ ├── diff2.constsyn.ll │ ├── fadd1.constsyn.ll │ ├── fadd2.constsyn.ll │ ├── fcmp1.constsyn.ll │ ├── fcmp2.constsyn.ll │ ├── fmul1.constsyn.ll │ ├── fmul2.constsyn.ll │ ├── fmul3.constsyn.ll │ ├── fsub1.constsyn.ll │ ├── fsub2.constsyn.ll │ ├── shuffle1.constsyn.ll │ └── shuffle2.constsyn.ll ├── datamovements │ ├── extractelement0.syn.ll │ ├── extractelement1.syn.ll │ ├── extractelement2.syn.ll │ ├── extractelement3.syn.ll │ ├── insertelement0.syn.ll │ ├── insertelement1.syn.ll │ ├── insertelement10.syn.ll │ ├── insertelement11.syn.ll │ ├── insertelement2.syn.ll │ ├── insertelement3.syn.ll │ ├── insertelement4.syn.ll │ ├── insertelement5.syn.ll │ ├── insertelement6.syn.ll │ ├── insertelement7.syn.ll │ ├── insertelement8.syn.ll │ ├── insertelement9.syn.ll │ ├── shuffle1.syn.ll │ ├── shuffle2.syn.ll │ ├── shuffle3.syn.ll │ ├── shuffle4.syn.ll │ ├── shuffle5.syn.ll │ ├── shuffle6.syn.ll │ └── shuffle7.syn.ll ├── diff.constsyn.ll ├── divergence.ll ├── fcmp_or.syn.ll ├── fp │ ├── case1.syn.ll │ ├── case10.syn.ll │ ├── case11.syn.ll │ ├── case12.syn.ll │ ├── case13.syn.ll │ ├── case14.syn.ll │ ├── case15.syn.ll │ ├── case2.syn.ll │ ├── case3.syn.ll │ ├── case4.syn.skip.ll │ ├── case5.syn.ll │ ├── case6.syn.ll │ ├── case7.syn.ll │ ├── case8.syn.ll │ ├── case9.syn.ll │ ├── copysign0.syn.ll │ ├── copysign1.syn.ll │ ├── copysign2.syn.ll │ ├── fabs0.syn.ll │ ├── fabs1.syn.ll │ ├── fabs2.syn.ll │ ├── fabs3.syn.ll │ ├── fabs4.syn.ll │ ├── fabs5.syn.ll │ ├── fabs6.syn.ll │ ├── fabs7.syn.ll │ ├── fadd0.syn.ll │ ├── fadd1.syn.ll │ ├── fadd2.syn.ll │ ├── fcmp0.syn.ll │ ├── fcmp1.syn.ll │ ├── fcmp2.syn.ll │ ├── fcmp3.syn.ll │ ├── fmul0.syn.ll │ ├── fneg0.syn.skip.ll │ ├── fneg1.syn.ll │ ├── fpext0.syn.ll │ ├── fptrunc0.syn.ll │ ├── maximum0.syn.ll │ ├── maximum1.syn.ll │ ├── maximum2.syn.ll │ ├── maximum3.syn.ll │ ├── maxnum0.syn.ll │ ├── maxnum1.syn.ll │ ├── maxnum2.syn.ll │ ├── maxnum3.syn.ll │ ├── minimum0.syn.ll │ ├── minimum1.syn.ll │ ├── minimum2.syn.ll │ ├── minimum3.syn.ll │ ├── minnum0.syn.ll │ ├── minnum1.syn.ll │ ├── minnum2.syn.ll │ ├── minnum3.syn.ll │ ├── sitofp0.syn.ll │ ├── sitofp1.syn.ll │ ├── sitofp2.syn.ll │ ├── trunc0.syn.ll │ ├── uitofp0.syn.ll │ ├── uitofp1.syn.ll │ └── uitofp2.syn.ll ├── hacks │ ├── pmaddwd-merge.syn.ll │ ├── psll.syn.skip.ll │ ├── shuffle-ext-to-pmaddwd1.syn.ll │ ├── shuffle-ext-to-pmaddwd2.syn.ll │ ├── shuffle-ext-to-pmaddwd3.syn.ll │ └── shuffle-ext-to-pmaddwd4.syn.ll ├── icmp0.syn.ll ├── icmp1.syn.ll ├── issue_16.syn.ll ├── lit.cfg.py ├── lit │ ├── README.txt │ ├── lit.py │ └── lit │ │ ├── BooleanExpression.py │ │ ├── LitConfig.py │ │ ├── ProgressBar.py │ │ ├── ShCommands.py │ │ ├── ShUtil.py │ │ ├── Test.py │ │ ├── TestRunner.py │ │ ├── TestingConfig.py │ │ ├── __init__.py │ │ ├── discovery.py │ │ ├── formats │ │ ├── __init__.py │ │ ├── base.py │ │ └── minotaurtest.py │ │ ├── main.py │ │ ├── run.py │ │ └── util.py ├── memory │ ├── syn_mem1.syn.mem.ll │ ├── syn_mem2.syn.mem.ll │ ├── syn_mem3.syn.mem.ll │ ├── syn_mem4.syn.mem.ll │ ├── syn_mem5.syn.mem.ll │ ├── syn_mem6.syn.mem.ll │ └── syn_mem7.syn.mem.ll ├── nop1.syn.ll ├── nop2.syn.ll ├── nop3.syn.ll ├── nop4.syn.ll ├── nop5.syn.ll ├── nop6.syn.ll ├── nop7.syn.ll ├── nop8.syn.ll ├── or0.syn.ll ├── reverse1.syn.ll ├── reverse2.syn.ll ├── select0.syn.ll ├── select1.syn.ll ├── sub0.syn.ll ├── sub1.syn.ll ├── syn_add1.syn.ll ├── syn_add2.syn.ll ├── syn_add3.syn.ll ├── syn_add4.syn.ll ├── syn_ashr1.syn.ll ├── syn_ashr2.syn.ll ├── syn_const_bitmask0.syn.ll ├── syn_const_bitmask1.syn.ll ├── syn_const_control_flow.ll ├── syn_const_fsll0.skip.ll ├── syn_domtree_constraint1.syn.ll ├── syn_fneg.ll ├── syn_pavg1.syn.ll ├── syn_pavg2.syn.ll ├── syn_pavg3.syn.ll ├── syn_pmaddwd1.syn.ll ├── syn_psad_const1.ll ├── syn_sext0.syn.ll ├── syn_sext1.syn.ll ├── syn_sext2.syn.ll ├── syn_trunc0.syn.ll ├── syn_trunc1.syn.ll ├── syn_trunc2.syn.ll ├── syn_width_relax1.syn.ll ├── test02.ll ├── test04.ll ├── umax0.syn.ll ├── umin0.syn.ll ├── usub0.syn.ll ├── xor0.syn.ll ├── xor1.syn.ll ├── zext0.syn.ll ├── zext1.syn.ll ├── zext2.syn.ll ├── zext3.syn.ll ├── zext4.syn.ll ├── zext5.syn.ll ├── zext6.syn.ll ├── zext7.syn.ll └── zext8.syn.ll ├── tools ├── minotaur-cs.cpp └── minotaur-slice.cpp └── unit-tests └── parse-tests.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | BasedOnStyle: LLVM 4 | AllowShortFunctionsOnASingleLine: Empty 5 | ... 6 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | name: ${{ matrix.os }} ${{ matrix.compiler }} ${{ matrix.build_type }} ${{ matrix.cache }} 8 | runs-on: ${{ matrix.os }} 9 | 10 | strategy: 11 | matrix: 12 | os: [ubuntu-22.04] 13 | compiler: [g++-13, clang++-18, clang++-19] 14 | build_type: [Release, Debug] 15 | cache: ['', Redis] 16 | include: 17 | - os: macos-14 18 | compiler: clang++ 19 | build_type: Release 20 | - os: macos-14 21 | compiler: clang++ 22 | build_type: Debug 23 | 24 | steps: 25 | - name: Checkout code 26 | uses: actions/checkout@v4 27 | 28 | - name: Install dependencies (Linux) 29 | if: runner.os == 'Linux' 30 | run: | 31 | wget -O- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - 32 | if [[ ${{ matrix.compiler }} == "clang++-18" ]]; then 33 | sudo add-apt-repository "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-18 main" 34 | fi 35 | if [[ ${{ matrix.compiler }} == "clang++-19" ]]; then 36 | sudo add-apt-repository "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy main" 37 | fi 38 | sudo apt-get update 39 | sudo apt-get install z3 re2c ninja-build 40 | if [[ ${{ matrix.compiler }} == "clang++-18" ]]; then 41 | sudo apt-get install clang++-18 42 | fi 43 | if [[ ${{ matrix.compiler }} == "clang++-19" ]]; then 44 | sudo apt-get install clang++-19 45 | fi 46 | if [[ "${{ matrix.cache }}" == "Redis" ]]; then 47 | sudo apt-get install libhiredis-dev 48 | fi 49 | 50 | - name: Install dependencies (MacOS) 51 | if: runner.os == 'macOS' 52 | run: | 53 | brew install z3 re2c ninja 54 | 55 | - name: Compile 56 | run: ./.github/scripts/build.sh 57 | 58 | - name: Run Tests 59 | run: ninja check 60 | working-directory: build 61 | 62 | env: 63 | CMAKE_BUILD_TYPE: ${{ matrix.build_type }} 64 | CMAKE_CXX_COMPILER: ${{ matrix.compiler }} 65 | CMAKE_CXX_FLAGS: "-fsanitize=address,undefined" 66 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | build/ 3 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | include(ProcessorCount) 3 | 4 | project(Minotaur) 5 | 6 | if (NOT CMAKE_BUILD_TYPE) 7 | set(CMAKE_BUILD_TYPE Debug) 8 | endif() 9 | 10 | message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") 11 | 12 | set(CMAKE_CXX_STANDARD 20) 13 | set(CMAKE_CXX_EXTENSIONS OFF) 14 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 15 | 16 | set(CMAKE_CXX_FLAGS "-Wall -march=native -fPIC ${CMAKE_CXX_FLAGS}") 17 | set(CMAKE_CXX_FLAGS_DEBUG "-g -Og ${CMAKE_CXX_FLAGS_DEBUG}") 18 | set(CMAKE_CXX_FLAGS_RELEASE "-O3 ${CMAKE_CXX_FLAGS_RELEASE}") 19 | set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} -g ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") 20 | 21 | find_program(RE2C re2c) 22 | if (RE2C) 23 | message(STATUS "RE2C: ${RE2C}") 24 | else() 25 | message(SEND_ERROR "re2c executable not found") 26 | endif() 27 | add_custom_command(OUTPUT "${PROJECT_BINARY_DIR}/lexer/lexer.cpp" 28 | COMMAND ${CMAKE_COMMAND} -E make_directory "${PROJECT_BINARY_DIR}/lexer" 29 | COMMAND ${RE2C} ARGS "-d" "-b" "-T" "--no-generation-date" 30 | "-o" "${PROJECT_BINARY_DIR}/lexer/lexer.cpp" 31 | "${PROJECT_SOURCE_DIR}/lib/lexer.re" 32 | DEPENDS "lib/lexer.re") 33 | 34 | 35 | find_package(LLVM REQUIRED CONFIG) 36 | 37 | message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") 38 | message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") 39 | 40 | list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") 41 | include(AddLLVM) 42 | 43 | include_directories(${LLVM_INCLUDE_DIRS}) 44 | add_definitions(${LLVM_DEFINITIONS}) 45 | 46 | 47 | find_package(Git REQUIRED) 48 | add_custom_command( 49 | OUTPUT "${PROJECT_BINARY_DIR}/minotaur_gen.h.tmp" 50 | COMMAND "${CMAKE_COMMAND}" -E echo_append "#define MINOTAUR_VERSION_MACRO " > "${PROJECT_BINARY_DIR}/minotaur_gen.h.tmp" 51 | COMMAND "${GIT_EXECUTABLE}" describe --tags --dirty --always >> "${PROJECT_BINARY_DIR}/minotaur_gen.h.tmp" 52 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" 53 | VERBATIM 54 | ) 55 | add_custom_command( 56 | DEPENDS "${PROJECT_BINARY_DIR}/minotaur_gen.h.tmp" 57 | OUTPUT "${PROJECT_BINARY_DIR}/minotaur_gen.h" 58 | COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${PROJECT_BINARY_DIR}/minotaur_gen.h.tmp" "${PROJECT_BINARY_DIR}/minotaur_gen.h" 59 | COMMAND "${CMAKE_COMMAND}" -E remove -f "${PROJECT_BINARY_DIR}/minotaur_gen.h.tmp" 60 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" 61 | VERBATIM 62 | ) 63 | add_custom_target( 64 | generate_version ALL 65 | DEPENDS "${PROJECT_BINARY_DIR}/minotaur_gen.h" 66 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" 67 | ) 68 | 69 | include_directories(include) 70 | include_directories(${PROJECT_BINARY_DIR}) 71 | 72 | list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") 73 | 74 | find_package(Alive2) 75 | include_directories(${ALIVE2_SOURCE_DIR}) 76 | 77 | set(SYNTHESIZER_SRC 78 | "lib/alive-interface.cpp" 79 | "lib/enumerator.cpp" 80 | "lib/expr.cpp" 81 | "lib/codegen.cpp" 82 | "lib/parse.cpp" 83 | "lib/type.cpp" 84 | "${PROJECT_BINARY_DIR}/lexer/lexer.cpp" 85 | ) 86 | 87 | find_package(Z3 4.8.5 REQUIRED) 88 | 89 | find_path(HIREDIS_INCLUDE_DIR 90 | NAMES 91 | "hiredis/hiredis.h") 92 | 93 | find_library(HIREDIS_LIBRARY 94 | NAMES 95 | hiredis) 96 | 97 | include_directories(${HIREDIS_INCLUDE_DIR}/hiredis) 98 | 99 | llvm_map_components_to_libnames(LLVM_LIBS 100 | analysis core irreader passes scalaropts support transformutils targetparser) 101 | 102 | add_library(cost STATIC "lib/cost.cpp" 103 | "${PROJECT_BINARY_DIR}/cost-command.h") 104 | target_link_libraries(cost PRIVATE ${LLVM_LIBS}) 105 | 106 | add_library(utils STATIC "lib/utils.cpp") 107 | target_link_libraries(utils PRIVATE ${LLVM_LIBS} ${HIREDIS_LIBRARY}) 108 | 109 | add_library(config STATIC "lib/config.cpp" 110 | "${PROJECT_BINARY_DIR}/minotaur_gen.h") 111 | add_dependencies(config generate_version) 112 | 113 | add_library(slice STATIC "lib/slice.cpp") 114 | target_link_libraries(slice PRIVATE utils config) 115 | 116 | add_library(synthesizer STATIC ${SYNTHESIZER_SRC}) 117 | target_link_libraries(synthesizer PRIVATE utils cost config) 118 | 119 | add_llvm_library(online MODULE "pass/online.cpp") 120 | 121 | target_link_libraries(online 122 | PRIVATE synthesizer slice ${ALIVE_LIBS} ${Z3_LIBRARIES} ${LLVM_LIBS} 123 | $<$,$,9.0>>:stdc++fs>) 124 | 125 | 126 | add_llvm_executable(minotaur-cs "tools/minotaur-cs.cpp") 127 | 128 | target_link_libraries(minotaur-cs 129 | PRIVATE synthesizer ${ALIVE_LIBS} ${LLVM_LIBS} ${Z3_LIBRARIES} 130 | $<$,$,9.0>>:stdc++fs>) 131 | 132 | add_llvm_executable(minotaur-slice "tools/minotaur-slice.cpp") 133 | 134 | target_link_libraries(minotaur-slice 135 | PRIVATE slice ${ALIVE_LIBS} 136 | $<$,$,9.0>>:stdc++fs>) 137 | 138 | add_llvm_executable(parse-tests "unit-tests/parse-tests.cpp") 139 | set(GTEST_LIBS "-lgtest_main -lgtest -lpthread") 140 | target_link_libraries(parse-tests 141 | PRIVATE synthesizer ${GTEST_LIBS} ${Z3_LIBRARIES} 142 | $<$,$,9.0>>:stdc++fs>) 143 | 144 | if(APPLE) 145 | set_target_properties(online PROPERTIES 146 | LINK_FLAGS "-undefined dynamic_lookup" 147 | ) 148 | set_target_properties(minotaur-cs PROPERTIES 149 | LINK_FLAGS "-undefined dynamic_lookup" 150 | ) 151 | set_target_properties(minotaur-slice PROPERTIES 152 | LINK_FLAGS "-undefined dynamic_lookup" 153 | ) 154 | endif(APPLE) 155 | 156 | set(ONLINE_PASS ${CMAKE_BINARY_DIR}/online${CMAKE_SHARED_LIBRARY_SUFFIX}) 157 | 158 | configure_file( 159 | "${PROJECT_SOURCE_DIR}/include/cost-command.h.in" 160 | "${PROJECT_BINARY_DIR}/cost-command.h" 161 | @ONLY 162 | ) 163 | configure_file( 164 | "${PROJECT_SOURCE_DIR}/scripts/opt-minotaur.sh.in" 165 | "${PROJECT_BINARY_DIR}/opt-minotaur.sh" 166 | @ONLY 167 | ) 168 | configure_file( 169 | "${PROJECT_SOURCE_DIR}/scripts/infer-cut.sh.in" 170 | "${PROJECT_BINARY_DIR}/infer-cut.sh" 171 | @ONLY 172 | ) 173 | configure_file( 174 | "${PROJECT_SOURCE_DIR}/scripts/slice-cc.in" 175 | "${PROJECT_BINARY_DIR}/slice-cc" 176 | @ONLY 177 | ) 178 | configure_file( 179 | "${PROJECT_SOURCE_DIR}/scripts/slice-cc.in" 180 | "${PROJECT_BINARY_DIR}/slice-c++" 181 | @ONLY 182 | ) 183 | configure_file( 184 | "${PROJECT_SOURCE_DIR}/scripts/minotaur-cc.in" 185 | "${PROJECT_BINARY_DIR}/minotaur-cc" 186 | @ONLY 187 | ) 188 | configure_file( 189 | "${PROJECT_SOURCE_DIR}/scripts/minotaur-cc.in" 190 | "${PROJECT_BINARY_DIR}/minotaur-c++" 191 | @ONLY 192 | ) 193 | configure_file( 194 | "${PROJECT_SOURCE_DIR}/scripts/cache-dump.in" 195 | "${PROJECT_BINARY_DIR}/cache-dump" 196 | @ONLY 197 | ) 198 | configure_file( 199 | "${PROJECT_SOURCE_DIR}/scripts/cache-infer.in" 200 | "${PROJECT_BINARY_DIR}/cache-infer" 201 | @ONLY 202 | ) 203 | configure_file( 204 | "${PROJECT_SOURCE_DIR}/scripts/get-cost.in" 205 | "${PROJECT_BINARY_DIR}/get-cost" 206 | @ONLY 207 | ) 208 | 209 | if (NOT DEFINED TEST_NTHREADS) 210 | ProcessorCount(TEST_NTHREADS) 211 | if (TEST_NTHREADS EQUAL 0) 212 | set(TEST_NTHREADS 1) 213 | endif() 214 | endif() 215 | 216 | add_custom_target("check" 217 | COMMAND "python3" 218 | "${PROJECT_SOURCE_DIR}/tests/lit/lit.py" 219 | "-s" 220 | "${PROJECT_SOURCE_DIR}/tests" 221 | "-j${TEST_NTHREADS}" 222 | DEPENDS "online" 223 | USES_TERMINAL 224 | ) 225 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:23.04 2 | 3 | # We install some useful packages. 4 | RUN apt-get update -qq 5 | RUN DEBIAN_FRONTEND="noninteractive" apt-get -y install tzdata 6 | # Setup base dependencies: 7 | RUN apt-get install -y vim-tiny clang-format sudo python3 wget cmake g++ git clang linux-tools-generic ninja-build lldb 8 | 9 | # Setup project-specific dependencies: 10 | RUN apt-get -y install cmake ninja-build gcc-10 g++-10 redis redis-server libhiredis-dev libbsd-resource-perl libredis-perl re2c libgtest-dev z3 11 | 12 | RUN git clone --depth=1 https://github.com/zhengyang92/llvm.git $HOME/llvm 13 | RUN mkdir $HOME/llvm/build && cd $HOME/llvm/build && \ 14 | cmake -G Ninja -DLLVM_ENABLE_RTTI=ON -DLLVM_ENABLE_EH=ON -DBUILD_SHARED_LIBS=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_ENABLE_ASSERTIONS=ON -DLLVM_ENABLE_PROJECTS="llvm;clang" $HOME/llvm/llvm 15 | RUN cd $HOME/llvm/build && ninja # clang 16 | 17 | # To fetch and build the Alive2 with the semantic for intrinsics, use the following command. 18 | RUN git clone --depth=1 https://github.com/minotaur-toolkit/alive2-intrinsics.git $HOME/alive2-intrinsics 19 | RUN mkdir $HOME/alive2-intrinsics/build && cd $HOME/alive2-intrinsics/build && \ 20 | cmake -G Ninja -DLLVM_DIR=$HOME/llvm/build/lib/cmake/llvm -DBUILD_TV=1 -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo $HOME/alive2-intrinsics 21 | RUN cd $HOME/alive2-intrinsics/build && ninja 22 | 23 | # To build Minotaur, use the following command. 24 | RUN git clone --depth=1 https://github.com/minotaur-toolkit/minotaur.git $HOME/minotaur 25 | RUN mkdir $HOME/minotaur/build && cd $HOME/minotaur/build && \ 26 | cmake $HOME/minotaur -DALIVE2_SOURCE_DIR=$HOME/alive2-intrinsics -DALIVE2_BUILD_DIR=$HOME/alive2-intrinsics/build -DCMAKE_PREFIX_PATH=$HOME/llvm/build -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -G Ninja 27 | RUN cd $HOME/minotaur/build && ninja 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020-present The Minotaur Authors. 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Minotaur: A SIMD-Oriented Synthesizing Superoptimizer 2 | 3 | [![Build](https://github.com/minotaur-toolkit/minotaur/actions/workflows/build.yml/badge.svg)](https://github.com/minotaur-toolkit/minotaur/actions/workflows/build.yml) 4 | 5 | A description of how Minotaur works can be found in 6 | https://arxiv.org/abs/2306.00229. 7 | 8 | ## Build Minotaur using Docker 9 | 10 | To build the docker container use: 11 | 12 | docker build -t minotaur-dev -f Dockerfile . 13 | 14 | To run the container use: 15 | 16 | docker run -it minotaur-dev bash 17 | 18 | ## Build Minotaur from source code 19 | 20 | The project requires `cmake`, `ninja-build`, `gcc-10`, `g++-10`, 21 | `redis`, `redis-server`, `libhiredis-dev`, `libbsd-resource-perl`, 22 | `libredis-perl`, `libgtest-dev`, and `re2c` as dependencies. On 23 | Ubuntu/Debian, use 24 | 25 | sudo apt-get install cmake ninja-build gcc-10 g++-10 redis redis-server libhiredis-dev libbsd-resource-perl libredis-perl re2c libgtest-dev 26 | 27 | or on mac, use 28 | 29 | brew install cmake re2c z3 hiredis redis 30 | 31 | to install dependencies. 32 | 33 | The Alive2 requires a LLVM compiled with RTTI and exceptions enabled, 34 | use the following command to fetch and build LLVM. 35 | 36 | git clone git@github.com:zhengyang92/llvm $HOME/llvm 37 | mkdir $HOME/llvm/build && cd $HOME/llvm/build 38 | cmake -GNinja -DLLVM_ENABLE_RTTI=ON -DLLVM_ENABLE_EH=ON -DBUILD_SHARED_LIBS=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_ENABLE_ASSERTIONS=ON -DLLVM_ENABLE_PROJECTS="llvm;clang" ../llvm 39 | ninja 40 | 41 | To fetch and build the Alive2 with semantics for intrinsics, use the 42 | following command. 43 | 44 | git clone git@github.com:minotaur-toolkit/alive2-intrinsics $HOME/alive2-intrinsics 45 | mkdir $HOME/alive2-intrinsics/build && cd $HOME/alive2-intrinsics/build 46 | cmake -GNinja -DLLVM_DIR=$HOME/llvm/build/lib/cmake/llvm -DBUILD_TV=1 -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo .. 47 | ninja 48 | 49 | To build Minotaur, use the following command. 50 | 51 | git clone git@github.com:minotaur-toolkit/minotaur $HOME/minotaur 52 | mkdir $HOME/minotaur/build && cd $HOME/minotaur/build 53 | cmake .. -DALIVE2_SOURCE_DIR=$HOME/alive2-intrinsics -DALIVE2_BUILD_DIR=$HOME/alive2-intrinsics/build -DCMAKE_PREFIX_PATH=$HOME/llvm/build -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -G Ninja 54 | ninja 55 | 56 | To run the test suite, use 57 | 58 | ninja check 59 | 60 | ## Use Minotaur 61 | 62 | Minotaur can be invoked in two ways, it can be invoked online (during 63 | compilation), but also offline, in a mode where Minotaur extracts cuts 64 | into the redis cache but does not perform synthesis. In offline mode, 65 | a separate program called `cache-infer` retrieves cuts from the cache, 66 | runs synthesis on them, and stores any optimizations that it discovers 67 | back into the cache. Unlike the online mode, which runs synthesis 68 | tasks one after the other, offline mode can run all synthesis jobs in 69 | parallel. 70 | 71 | 72 | ### Online mode 73 | 74 | To run the Minotaur on llvm IR files in online mode, use the following 75 | command 76 | 77 | $HOME/llvm/build/bin/opt -load-pass-plugin $HOME/minotaur/build/online.so -passes="minotaur" 78 | 79 | For C/C++ programs, we have a drop-in replacement of C/C++ compiler. 80 | Users can call `minotaur-cc` or `minotaur-cxx` in the `build` 81 | directory to compile C/C++ programs. Minotaur pass is disabled by 82 | default; the pass can be enabled by setting environment variable 83 | `ENABLE_MINOTAUR`. 84 | 85 | export ENABLE_MINOTAUR=ON 86 | $HOME/minotaur/build/minotaur-cc [clang options] 87 | 88 | ### Offline mode 89 | 90 | #### Extract cuts from source 91 | 92 | To extract cuts, one can just set the environment variable 93 | `MINOTAUR_NO_INFER` and run the same command as above. 94 | 95 | For a single LLVM IR source, 96 | 97 | MINOTAUR_NO_INFER=ON $HOME/llvm/build/bin/opt -load-pass-plugin $HOME/minotaur/build/minotaur.so -passes="minotaur" 98 | 99 | For a single C/C++ source, 100 | 101 | ENABLE_MINOTAUR=ON MINOTAUR_NO_INFER=ON $HOME/minotaur/build/minotaur-cc [clang options] 102 | 103 | For a C/C++ project, simply set CC and CXX to `minotaur-cc` and `minotaur-cxx`, and run `configure` as usual. Set `ENABLE_MINOTAUR` and `MINOTAUR_NO_INFER` to `ON` for `make`. 104 | 105 | CC=$HOME/minotaur/build/minotaur-cc CXX=$HOME/minotaur/build/minotaur-cxx ./configure 106 | ENABLE_MINOTAUR=ON MINOTAUR_NO_INFER=ON make 107 | 108 | #### Run synthesis on cuts 109 | 110 | Run the `cache-infer` program to retrieve cuts from the cache and run 111 | synthesis on them. 112 | 113 | $HOME/minotaur/build/cache-infer 114 | 115 | After running `cache-infer`, the cache will be populated with the 116 | optimizations that Minotaur discovered. User can run the `opt`, 117 | `minotaur-cc`, `minotaur-cxx` or `make` again, to compile the program 118 | with the synthesized optimizations. 119 | 120 | ### Dump synthesized results from cache 121 | 122 | To dump synthesized results from cache, use `cache-dump`. 123 | 124 | $HOME/minotaur/build/cache-dump 125 | -------------------------------------------------------------------------------- /cmake/FindAlive2.cmake: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020-present, author: Zhengyang Liu (liuz@cs.utah.edu). 2 | # Distributed under the MIT license that can be found in the LICENSE file. 3 | 4 | if (ALIVE2_SOURCE_DIR) 5 | message(STATUS "alive2 source directory: ${ALIVE2_SOURCE_DIR}") 6 | else() 7 | message(SEND_ERROR "Alive2 source directory is not set. Use -DALIVE2_SOURCE_DIR to set the directory.") 8 | endif() 9 | 10 | if (ALIVE2_BUILD_DIR) 11 | find_library(ALIVE2_IR_LIBS ir PATHS "${ALIVE2_BUILD_DIR}" NO_DEFAULT_PATH) 12 | find_library(ALIVE2_LLVM_UTIL llvm_util PATHS "${ALIVE2_BUILD_DIR}" NO_DEFAULT_PATH) 13 | find_library(ALIVE2_SMT_LIBS smt PATHS "${ALIVE2_BUILD_DIR}" NO_DEFAULT_PATH) 14 | find_library(ALIVE2_TOOLS_LIBS tools PATHS "${ALIVE2_BUILD_DIR}" NO_DEFAULT_PATH) 15 | find_library(ALIVE2_UTIL_LIBS util PATHS "${ALIVE2_BUILD_DIR}" NO_DEFAULT_PATH) 16 | 17 | set(ALIVE_LIBS ${ALIVE2_IR_LIBS} ${ALIVE2_LLVM_UTIL} ${ALIVE2_SMT_LIBS} ${ALIVE2_TOOLS_LIBS} ${ALIVE2_UTIL_LIBS}) 18 | message(STATUS "Found alive libs: ${ALIVE_LIBS}") 19 | else() 20 | message(SEND_ERROR "Alive2 build directory is not set. Use -DALIVE2_BUILD_DIR to set the directory.") 21 | endif() 22 | -------------------------------------------------------------------------------- /include/alive-interface.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-present, author: Zhengyang Liu (liuz@cs.utah.edu). 2 | // Distributed under the MIT license that can be found in the LICENSE file. 3 | #pragma once 4 | 5 | #include "expr.h" 6 | #include "config.h" 7 | #include "ir/function.h" 8 | #include "smt/smt.h" 9 | #include "tools/transform.h" 10 | #include "util/config.h" 11 | 12 | #include "llvm/Analysis/TargetLibraryInfo.h" 13 | #include "llvm/IR/Argument.h" 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | namespace minotaur { 20 | 21 | static std::ostream NOP_OSTREAM(nullptr); 22 | 23 | class AliveEngine { 24 | private: 25 | llvm::TargetLibraryInfoWrapperPass &TLI; 26 | std::ostream *debug; 27 | 28 | util::Errors find_model(tools::Transform &t, 29 | std::unordered_map&); 30 | 31 | public: 32 | AliveEngine(llvm::TargetLibraryInfoWrapperPass &TLI, bool dpi) : TLI(TLI) { 33 | util::config::disable_undef_input = true; 34 | util::config::disable_poison_input = dpi; 35 | util::config::use_exact_fp = dpi; 36 | debug = config::debug_tv ? &std::cerr : &NOP_OSTREAM; 37 | } 38 | 39 | bool constantSynthesis(llvm::Function&, llvm::Function&, 40 | std::unordered_map&); 41 | bool compareFunctions(llvm::Function&, llvm::Function&); 42 | }; 43 | 44 | } -------------------------------------------------------------------------------- /include/codegen.h: -------------------------------------------------------------------------------- 1 | 2 | // Copyright (c) 2020-present, author: Zhengyang Liu (liuz@cs.utah.edu). 3 | // Distributed under the MIT license that can be found in the LICENSE file. 4 | #pragma once 5 | 6 | #include "alive-interface.h" 7 | #include "expr.h" 8 | 9 | #include "llvm/IR/Function.h" 10 | #include "llvm/Transforms/Utils/ValueMapper.h" 11 | 12 | #include 13 | #include 14 | 15 | namespace minotaur { 16 | 17 | class LLVMGen { 18 | std::unordered_set& IntrinsicDecls; 19 | llvm::IRBuilder<> b; 20 | llvm::Module *M; 21 | llvm::LLVMContext &C; 22 | public: 23 | LLVMGen(llvm::Instruction *I, 24 | std::unordered_set &IDs) 25 | : IntrinsicDecls(IDs), b(llvm::IRBuilder<>(I)), 26 | M(I->getModule()), C(I->getContext()) {}; 27 | llvm::Value *codeGen(Inst*, llvm::ValueToValueMapTy &VMap); 28 | llvm::Value *bitcastTo(llvm::Value*, llvm::Type*); 29 | 30 | private: 31 | llvm::Value *codeGenImpl(Inst*, llvm::ValueToValueMapTy&); 32 | }; 33 | 34 | } -------------------------------------------------------------------------------- /include/config.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-present, author: Zhengyang Liu (liuz@cs.utah.edu). 2 | // Distributed under the MIT license that can be found in the LICENSE file. 3 | #pragma once 4 | 5 | #include "llvm/Support/raw_ostream.h" 6 | #include 7 | #include 8 | 9 | namespace minotaur { 10 | namespace config { 11 | 12 | extern bool disable_poison_input; 13 | extern bool disable_undef_input; 14 | extern bool debug_slicer; 15 | extern bool debug_enumerator; 16 | extern bool debug_tv; 17 | extern bool debug_codegen; 18 | extern bool debug_parser; 19 | extern bool ignore_machine_cost; 20 | extern bool smt_verbose; 21 | extern bool disable_avx512; 22 | extern bool show_stats; 23 | extern bool return_first_solution; 24 | 25 | extern unsigned slice_to; 26 | extern unsigned slicer_max_depth; 27 | 28 | llvm::raw_ostream &dbg(); 29 | void set_debug(llvm::raw_ostream &os); 30 | 31 | extern const char minotaur_version[]; 32 | 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /include/cost-command.h.in: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-present, author: Zhengyang Liu (liuz@cs.utah.edu). 2 | // Distributed under the MIT license that can be found in the LICENSE file. 3 | #pragma once 4 | 5 | #include "string" 6 | 7 | constexpr const char *GET_COST_COMMAND="@CMAKE_BINARY_DIR@/get-cost"; -------------------------------------------------------------------------------- /include/cost.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-present, author: Zhengyang Liu (liuz@cs.utah.edu). 2 | // Distributed under the MIT license that can be found in the LICENSE file. 3 | 4 | #pragma once 5 | 6 | #include "expr.h" 7 | 8 | #include "llvm/IR/Function.h" 9 | 10 | namespace minotaur { 11 | unsigned get_machine_cost(llvm::Function *F); 12 | unsigned get_approx_cost (llvm::Function *F); 13 | } -------------------------------------------------------------------------------- /include/enumerator.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-present, author: Zhengyang Liu (liuz@cs.utah.edu). 2 | // Distributed under the MIT license that can be found in the LICENSE file. 3 | #pragma once 4 | 5 | #include "alive-interface.h" 6 | #include "ir/function.h" 7 | 8 | #include "expr.h" 9 | #include "llvm/Analysis/TargetLibraryInfo.h" 10 | #include "llvm/IR/Dominators.h" 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | namespace llvm { 17 | class Function; 18 | class TargetLibraryInfo; 19 | } 20 | 21 | namespace minotaur { 22 | 23 | using Sketch = std::pair>; 24 | 25 | class Enumerator { 26 | std::vector> exprs; 27 | 28 | std::vector values; 29 | 30 | void findInputs(llvm::Function&, 31 | llvm::Instruction*, 32 | llvm::DominatorTree&); 33 | bool getSketches(llvm::Value *V, 34 | std::vector&); 35 | public: 36 | std::vector solve(llvm::Function&, llvm::Instruction*); 37 | }; 38 | 39 | } 40 | -------------------------------------------------------------------------------- /include/lexer.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-present The Alive2 Authors. 2 | // Distributed under the MIT license that can be found in the LICENSE file. 3 | #pragma once 4 | 5 | #include 6 | #include 7 | 8 | namespace parse { 9 | 10 | enum token { 11 | #define TOKEN(x) x, 12 | #include "tokens.h" 13 | #undef TOKEN 14 | }; 15 | 16 | struct yylval_t { 17 | union { 18 | uint64_t num; 19 | std::string_view str; 20 | }; 21 | yylval_t() {} 22 | }; 23 | 24 | void yylex_init(std::string_view str); 25 | token yylex(); 26 | 27 | extern yylval_t yylval; 28 | extern unsigned yylineno; 29 | extern const char *const token_name[]; 30 | 31 | struct LexException { 32 | std::string str; 33 | unsigned lineno; 34 | 35 | LexException(std::string &&str, unsigned lineno) 36 | : str(std::move(str)), lineno(lineno) {} 37 | }; 38 | 39 | 40 | constexpr unsigned LEXER_READ_AHEAD = 20; 41 | 42 | } 43 | -------------------------------------------------------------------------------- /include/parse.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-present, author: Zhengyang Liu (liuz@cs.utah.edu). 2 | // Distributed under the MIT license that can be found in the LICENSE file. 3 | #pragma once 4 | #include "expr.h" 5 | #include "lexer.h" 6 | #include "llvm/IR/Function.h" 7 | 8 | namespace parse { 9 | 10 | struct ParseException { 11 | std::string str; 12 | unsigned lineno; 13 | 14 | ParseException(std::string &&str, unsigned lineno) 15 | : str(std::move(str)), lineno(lineno) {} 16 | }; 17 | 18 | class Parser { 19 | std::vector> exprs; 20 | llvm::Function &F; 21 | 22 | minotaur::Var *parse_var(); 23 | minotaur::ReservedConst *parse_const(); 24 | minotaur::Copy *parse_copy(); 25 | minotaur::UnaryOp *parse_unary(token); 26 | minotaur::BinaryOp *parse_binary(token); 27 | minotaur::ICmp *parse_icmp(token); 28 | minotaur::FCmp *parse_fcmp(token); 29 | minotaur::FakeShuffleInst *parse_shuffle(token); 30 | minotaur::IntConversion *parse_intconv(token); 31 | minotaur::FPConversion *parse_fpconv(token); 32 | minotaur::SIMDBinOpInst *parse_x86(std::string_view ops); 33 | minotaur::Select *parse_select(); 34 | minotaur::InsertElement *parse_insertelement(); 35 | minotaur::ExtractElement *parse_extractelement(); 36 | minotaur::Value* parse_expr(); 37 | 38 | public: 39 | Parser(llvm::Function &F) : F(F) {} 40 | std::vector parse(const llvm::Function&, std::string_view); 41 | }; 42 | 43 | 44 | 45 | } // end namespace minotaur -------------------------------------------------------------------------------- /include/removal-slice.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-present, author: Zhengyang Liu (liuz@cs.utah.edu). 2 | // Distributed under the MIT license that can be found in the LICENSE file. 3 | #include "llvm/Analysis/LoopInfo.h" 4 | #include "llvm/Analysis/MemoryDependenceAnalysis.h" 5 | #include "llvm/Analysis/PostDominators.h" 6 | #include "llvm/IR/DataLayout.h" 7 | #include "llvm/IR/Dominators.h" 8 | #include "llvm/IR/Function.h" 9 | #include "llvm/IR/LLVMContext.h" 10 | #include "llvm/IR/Module.h" 11 | #include "llvm/IR/Value.h" 12 | #include "llvm/Transforms/Utils/ValueMapper.h" 13 | 14 | #include 15 | #include 16 | 17 | namespace minotaur { 18 | 19 | class RemovalSlice { 20 | llvm::Function &VF; 21 | llvm::LLVMContext &Ctx; 22 | llvm::LoopInfo &LI; 23 | llvm::DominatorTree &DT; 24 | 25 | std::unique_ptr M; 26 | llvm::ValueToValueMapTy mapping; 27 | bool discarded_at_precheck = false; 28 | 29 | public: 30 | RemovalSlice(llvm::Function &VF, llvm::LoopInfo &LI, llvm::DominatorTree &DT) 31 | : VF(VF), Ctx(VF.getContext()), LI(LI), DT(DT) { 32 | 33 | for (auto &arg : VF.args()) { 34 | auto argTy = arg.getType(); 35 | if (argTy->isPPC_FP128Ty() || argTy->isX86_FP80Ty()) 36 | discarded_at_precheck = true; 37 | } 38 | 39 | M = std::make_unique("", Ctx); 40 | M->setDataLayout(VF.getParent()->getDataLayout()); 41 | } 42 | std::unique_ptr getNewModule() {return std::move(M); } 43 | llvm::ValueToValueMapTy& getValueMap() { return mapping; } 44 | std::optional> 45 | extractExpr(llvm::Value &V); 46 | }; 47 | 48 | } // namespace minotaur -------------------------------------------------------------------------------- /include/slice.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-present, author: Zhengyang Liu (liuz@cs.utah.edu). 2 | // Distributed under the MIT license that can be found in the LICENSE file. 3 | #include "llvm/Analysis/LoopInfo.h" 4 | #include "llvm/Analysis/MemoryDependenceAnalysis.h" 5 | #include "llvm/Analysis/PostDominators.h" 6 | #include "llvm/IR/Dominators.h" 7 | #include "llvm/IR/Function.h" 8 | #include "llvm/IR/Module.h" 9 | #include "llvm/IR/Value.h" 10 | #include "llvm/Passes/PassBuilder.h" 11 | #include "llvm/Transforms/Utils/ValueMapper.h" 12 | 13 | #include 14 | #include 15 | 16 | namespace minotaur { 17 | 18 | class Slice { 19 | llvm::Function &f; 20 | llvm::LoopInfo &LI; 21 | llvm::DominatorTree &DT; 22 | 23 | std::unique_ptr m; 24 | llvm::ValueToValueMapTy mapping; 25 | 26 | public: 27 | Slice(llvm::Function &f, llvm::LoopInfo &LI, llvm::DominatorTree &DT) 28 | : f(f), LI(LI), DT(DT) { 29 | m = std::make_unique("", f.getContext()); 30 | m->setDataLayout(f.getParent()->getDataLayout()); 31 | } 32 | std::unique_ptr getNewModule() {return std::move(m); } 33 | llvm::ValueToValueMapTy& getValueMap() { return mapping; } 34 | std::optional, 35 | llvm::Instruction*>> extractExpr(llvm::Value&); 36 | }; 37 | 38 | } // namespace minotaur -------------------------------------------------------------------------------- /include/tokens.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-present, author: Zhengyang Liu (liuz@cs.utah.edu). 2 | // Distributed under the MIT license that can be found in the LICENSE file. 3 | 4 | #include "lexer.h" 5 | TOKEN(END) 6 | TOKEN(COMMA) 7 | TOKEN(LPAREN) 8 | TOKEN(RPAREN) 9 | TOKEN(LCURLY) 10 | TOKEN(RCURLY) 11 | 12 | TOKEN(COPY) 13 | 14 | TOKEN(BITREVERSE) 15 | TOKEN(BSWAP) 16 | TOKEN(CTPOP) 17 | TOKEN(CTLZ) 18 | TOKEN(CTTZ) 19 | TOKEN(FNEG) 20 | TOKEN(FABS) 21 | TOKEN(FCEIL) 22 | TOKEN(FFLOOR) 23 | TOKEN(FRINT) 24 | TOKEN(FNEARBYINT) 25 | TOKEN(FROUND) 26 | TOKEN(FROUNDEVEN) 27 | TOKEN(FTRUNC) 28 | 29 | TOKEN(BAND) 30 | TOKEN(BOR) 31 | TOKEN(BXOR) 32 | TOKEN(ADD) 33 | TOKEN(SUB) 34 | TOKEN(MUL) 35 | TOKEN(SDIV) 36 | TOKEN(UDIV) 37 | TOKEN(LSHR) 38 | TOKEN(ASHR) 39 | TOKEN(SHL) 40 | TOKEN(SMAX) 41 | TOKEN(SMIN) 42 | TOKEN(UMAX) 43 | TOKEN(UMIN) 44 | TOKEN(FADD) 45 | TOKEN(FSUB) 46 | TOKEN(FMUL) 47 | TOKEN(FDIV) 48 | TOKEN(FMAXNUM) 49 | TOKEN(FMINNUM) 50 | TOKEN(FMAXIMUM) 51 | TOKEN(FMINIMUM) 52 | TOKEN(COPYSIGN) 53 | 54 | TOKEN(EQ) 55 | TOKEN(NE) 56 | TOKEN(ULT) 57 | TOKEN(ULE) 58 | TOKEN(UGT) 59 | TOKEN(UGE) 60 | TOKEN(SLT) 61 | TOKEN(SLE) 62 | TOKEN(SGT) 63 | TOKEN(SGE) 64 | 65 | TOKEN(FCMP_TRUE) 66 | TOKEN(FCMP_OEQ) 67 | TOKEN(FCMP_ONE) 68 | TOKEN(FCMP_OLT) 69 | TOKEN(FCMP_OLE) 70 | TOKEN(FCMP_OGT) 71 | TOKEN(FCMP_OGE) 72 | TOKEN(FCMP_ORD) 73 | TOKEN(FCMP_UEQ) 74 | TOKEN(FCMP_UNE) 75 | TOKEN(FCMP_ULT) 76 | TOKEN(FCMP_ULE) 77 | TOKEN(FCMP_UGT) 78 | TOKEN(FCMP_UGE) 79 | TOKEN(FCMP_UNO) 80 | TOKEN(FCMP_FALSE) 81 | 82 | TOKEN(SHUFFLE) 83 | TOKEN(BLEND) 84 | TOKEN(SELECT) 85 | TOKEN(INSERTELEMENT) 86 | TOKEN(EXTRACTELEMENT) 87 | 88 | TOKEN(X86BINARY) 89 | 90 | TOKEN(CONV_ZEXT) 91 | TOKEN(CONV_SEXT) 92 | TOKEN(CONV_TRUNC) 93 | 94 | TOKEN(CONV_FPTRUNC) 95 | TOKEN(CONV_FPEXT) 96 | TOKEN(CONV_FPTOUI) 97 | TOKEN(CONV_FPTOSI) 98 | TOKEN(CONV_UITOFP) 99 | TOKEN(CONV_SITOFP) 100 | 101 | TOKEN(VAR) 102 | TOKEN(CONST) 103 | TOKEN(LITERAL) 104 | 105 | TOKEN(NUM_STR) 106 | TOKEN(BITS) 107 | 108 | TOKEN(REGISTER) 109 | TOKEN(INT_TYPE) 110 | TOKEN(HALF) 111 | TOKEN(FLOAT) 112 | TOKEN(DOUBLE) 113 | TOKEN(FP128) 114 | TOKEN(VECTOR_TYPE_PREFIX) 115 | TOKEN(CSGT) -------------------------------------------------------------------------------- /include/type.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-present, author: Zhengyang Liu (liuz@cs.utah.edu). 2 | // Distributed under the MIT license that can be found in the LICENSE file. 3 | #pragma once 4 | 5 | #include "ir/instr.h" 6 | #include "llvm/IR/DerivedTypes.h" 7 | #include "llvm/IR/LLVMContext.h" 8 | #include "llvm/IR/Type.h" 9 | #include "llvm/Support/ErrorHandling.h" 10 | #include "llvm/Support/raw_ostream.h" 11 | 12 | namespace minotaur { 13 | 14 | class type { 15 | unsigned lane, bits; 16 | bool fp; 17 | type(unsigned l, unsigned b, bool f) : 18 | lane(l), bits(b), fp(f) {}; 19 | 20 | public: 21 | static type Scalar(unsigned bits, bool fp) { 22 | return type(1, bits, fp); 23 | } 24 | static type Integer(unsigned bits) { 25 | return Scalar(bits, false); 26 | } 27 | static type Vectorizable(unsigned lane, unsigned bits, bool fp) { 28 | return type(lane, bits, fp); 29 | } 30 | static type IntegerVectorizable(unsigned lane, unsigned bits) { 31 | return Vectorizable(lane, bits, false); 32 | } 33 | static type Null() { 34 | return type(0, 0, false); 35 | } 36 | static type Float() { 37 | return Scalar(32, true); 38 | } 39 | static type Double() { 40 | return Scalar(64, true); 41 | } 42 | static type Half() { 43 | return Scalar(16, true); 44 | } 45 | static type FP128() { 46 | return Scalar(128, true); 47 | } 48 | 49 | type(const type &t) 50 | : lane(t.getLane()), bits(t.getBits()), fp(t.isFP()) {} 51 | type(llvm::Type *t); 52 | 53 | bool isVector() const { return lane > 1; } 54 | bool isScalar() const { return lane == 1; } 55 | 56 | bool operator==(const type &rhs) const; 57 | bool same_width(const type &rhs) const; 58 | 59 | friend llvm::raw_ostream& operator<<(llvm::raw_ostream &os, const type &val); 60 | 61 | llvm::Type *toLLVM(llvm::LLVMContext&) const; 62 | 63 | unsigned getWidth() const; 64 | unsigned getLane() const; 65 | unsigned getBits() const; 66 | bool isFP() const; 67 | bool isValid() const; 68 | bool isBool() const; 69 | type getAsScalar() const; 70 | type getAsVector(unsigned lane) const; 71 | type getAsIntTy() const; 72 | }; 73 | 74 | type getIntrinsicRetTy(IR::X86IntrinBinOp::Op); 75 | type getIntrinsicOp0Ty(IR::X86IntrinBinOp::Op); 76 | type getIntrinsicOp1Ty(IR::X86IntrinBinOp::Op); 77 | 78 | std::vector getIntegerVectorTypes(type); 79 | 80 | } // namespace minotaur -------------------------------------------------------------------------------- /include/utils.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-present, author: Zhengyang Liu (liuz@cs.utah.edu). 2 | // Distributed under the MIT license that can be found in the LICENSE file. 3 | #pragma once 4 | #include 5 | #include "llvm/IR/Function.h" 6 | 7 | struct redisContext; 8 | 9 | namespace minotaur { 10 | void eliminate_dead_code(llvm::Function &F); 11 | 12 | bool hGet(const char* s, unsigned sz, std::string &Value, redisContext *c); 13 | void hSetRewrite(const char*, unsigned, const char *, unsigned, llvm::StringRef, 14 | redisContext *c, unsigned, unsigned, llvm::StringRef); 15 | void hSetNoSolution(const char*, unsigned, redisContext *c, llvm::StringRef); 16 | void removeUnusedDecls(std::unordered_set); 17 | } -------------------------------------------------------------------------------- /lib/config.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-present, author: Zhengyang Liu (liuz@cs.utah.edu). 2 | // Distributed under the MIT license that can be found in the LICENSE file. 3 | #include "config.h" 4 | #include "minotaur_gen.h" 5 | #include "llvm_util/utils.h" 6 | #include "llvm/Support/raw_ostream.h" 7 | #include 8 | 9 | #define xstr(s) str(s) 10 | #define str(s) #s 11 | 12 | static llvm::raw_ostream *debug_os = &llvm::nulls(); 13 | 14 | namespace minotaur{ 15 | namespace config { 16 | 17 | bool disable_poison_input = true; 18 | bool disable_undef_input = true; 19 | bool debug_slicer = false; 20 | bool debug_enumerator = false; 21 | bool debug_tv = false; 22 | bool debug_codegen = false; 23 | bool debug_parser = false; 24 | bool ignore_machine_cost = false; 25 | bool smt_verbose = false; 26 | bool disable_avx512 = true; 27 | bool show_stats = false; 28 | bool return_first_solution = false; 29 | 30 | unsigned slice_to; 31 | unsigned slicer_max_depth = 5; 32 | 33 | 34 | llvm::raw_ostream &dbg() { 35 | return *debug_os; 36 | } 37 | 38 | void set_debug(llvm::raw_ostream &os) { 39 | debug_os = &os; 40 | } 41 | 42 | const char minotaur_version[] = { 43 | xstr(MINOTAUR_VERSION_MACRO) 44 | }; 45 | 46 | } 47 | } 48 | 49 | -------------------------------------------------------------------------------- /lib/cost.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-present, author: Zhengyang Liu (liuz@cs.utah.edu). 2 | // Distributed under the MIT license that can be found in the LICENSE file. 3 | #include "cost.h" 4 | #include "utils.h" 5 | #include "cost-command.h" 6 | 7 | #include "llvm/ADT/ArrayRef.h" 8 | #include "llvm/IR/InstrTypes.h" 9 | #include "llvm/IR/Instructions.h" 10 | #include "llvm/IR/Module.h" 11 | #include "llvm/Support/Casting.h" 12 | #include "llvm/Support/FileSystem.h" 13 | #include "llvm/Support/Program.h" 14 | #include "llvm/Transforms/Utils/Cloning.h" 15 | #include "llvm/Transforms/Utils/ValueMapper.h" 16 | 17 | #include 18 | #include 19 | 20 | using namespace llvm; 21 | using namespace std; 22 | 23 | namespace minotaur { 24 | 25 | unsigned get_machine_cost(Function *F) { 26 | llvm::Module M("", F->getContext()); 27 | auto newF = Function::Create(F->getFunctionType(), F->getLinkage(), "foo", M); 28 | 29 | ValueToValueMapTy VMap; 30 | for (unsigned i = 0 ; i < F->arg_size() ; ++i) { 31 | VMap[F->getArg(i)] = newF->getArg(i); 32 | } 33 | 34 | for (auto &BB : *F) { 35 | for (auto &I : BB) { 36 | if (CallInst *CI = dyn_cast(&I)) { 37 | llvm::Function *callee = CI->getCalledFunction(); 38 | M.getOrInsertFunction(callee->getName(), callee->getFunctionType(), 39 | callee->getAttributes()); 40 | } 41 | } 42 | } 43 | 44 | SmallVector _; 45 | CloneFunctionInto(newF, F, VMap, CloneFunctionChangeType::DifferentModule, _); 46 | 47 | eliminate_dead_code(*newF); 48 | 49 | SmallString<64> InputPath; 50 | { 51 | int InputFD; 52 | if (std::error_code EC = 53 | sys::fs::createTemporaryFile("input", "ll", InputFD, InputPath)) { 54 | llvm::report_fatal_error("cannot open input buffer"); 55 | } 56 | 57 | std::string module_str; 58 | raw_string_ostream OS(module_str); 59 | M.print(OS, nullptr); 60 | 61 | raw_fd_ostream InputFile(InputFD, true,true); 62 | InputFile << module_str; 63 | InputFile.close(); 64 | ::close(InputFD); 65 | } 66 | 67 | SmallString<64> OutputPath; 68 | { 69 | int OutputFD; 70 | if (std::error_code EC = 71 | sys::fs::createTemporaryFile("output", "out", OutputFD, OutputPath)) { 72 | llvm::report_fatal_error("cannot open output buffer"); 73 | } 74 | ::close(OutputFD); 75 | } 76 | 77 | vector ArgPtrs = {"get-cost", InputPath}; 78 | optional Redirects[3] = { nullopt, 79 | StringRef(OutputPath), 80 | StringRef("/dev/null") }; 81 | 82 | int r = sys::ExecuteAndWait(GET_COST_COMMAND, ArgPtrs, nullopt, Redirects, 5); 83 | 84 | if (r) { 85 | llvm::errs()<<"error when analysizing cost\n"; 86 | return 0; 87 | } 88 | 89 | unsigned cycle; 90 | std::ifstream result((std::string(OutputPath))); 91 | result >> cycle; 92 | result.close(); 93 | 94 | return cycle; 95 | } 96 | 97 | unsigned get_approx_cost(llvm::Function *F) { 98 | unsigned cost = 0; 99 | for (auto &BB : *F) { 100 | for (auto &I : BB) { 101 | if (isa(&I)) { 102 | cost += 1; 103 | // reserved const 104 | } else if (CallInst *CI = dyn_cast(&I)) { 105 | auto CalledF = CI->getCalledFunction(); 106 | if (CalledF) { 107 | if (CalledF->getName().starts_with("__fksv")) { 108 | cost += 4; 109 | } else if (CalledF->isIntrinsic()){ 110 | if (CalledF->getIntrinsicID() == Intrinsic::minnum || 111 | CalledF->getIntrinsicID() == Intrinsic::minimum || 112 | CalledF->getIntrinsicID() == Intrinsic::maxnum || 113 | CalledF->getIntrinsicID() == Intrinsic::maximum) { 114 | cost += 30; 115 | } else { 116 | cost += 2; 117 | } 118 | } else { 119 | cost += 2; 120 | } 121 | } else { 122 | cost += 2; 123 | } 124 | } else if (Instruction *BO = dyn_cast(&I)) { 125 | auto opCode = BO->getOpcode(); 126 | if (opCode == Instruction::UDiv || opCode == Instruction::SDiv || 127 | opCode == Instruction::URem || opCode == Instruction::SRem) { 128 | cost += 10; 129 | } else if (opCode == Instruction::Mul) { 130 | cost += 4; 131 | } else if (opCode == Instruction::FAdd || opCode == Instruction::FSub || 132 | opCode == Instruction::FMul) { 133 | cost += 30; 134 | } else if (opCode == Instruction::FDiv || opCode == Instruction::FRem) { 135 | cost += 80; 136 | } else if (opCode == Instruction::FNeg) { 137 | cost += 2; 138 | } else if (opCode == Instruction::BitCast) { 139 | cost += 1; 140 | } else if (opCode == Instruction::Unreachable || 141 | opCode == Instruction::Ret) { 142 | cost += 0; 143 | } else if (opCode ==Instruction::Select) { 144 | cost += 4; 145 | } else if (opCode == Instruction::InsertElement || 146 | opCode == Instruction::ExtractElement || 147 | opCode == Instruction::ShuffleVector) { 148 | cost += 4; 149 | } else { 150 | cost += 2; 151 | } 152 | } else { 153 | cost += 2; 154 | } 155 | } 156 | } 157 | return cost; 158 | } 159 | 160 | } -------------------------------------------------------------------------------- /lib/lexer.re: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-present, author: Zhengyang Liu (liuz@cs.utah.edu). 2 | // Distributed under the MIT license that can be found in the LICENSE file. 3 | 4 | #include "lexer.h" 5 | #include "util/compiler.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | #define YYCTYPE unsigned char 15 | #define YYCURSOR yycursor 16 | #define YYLIMIT yylimit 17 | #define YYTEXT yytext 18 | #define YYMARKER yymarker 19 | #define YYLENGTH ((size_t)(YYCURSOR - YYTEXT)) 20 | #define YYFILL(n) do { if ((YYCURSOR + n) >= (YYLIMIT + YYMAXFILL)) \ 21 | { return END; } } while (0) 22 | 23 | static const YYCTYPE *YYCURSOR; 24 | static const YYCTYPE *YYLIMIT; 25 | static const YYCTYPE *YYTEXT; 26 | static const YYCTYPE *YYMARKER; 27 | static const YYCTYPE *tag1, *yyt1; 28 | 29 | #if 0 30 | # define YYRESTART() cout << "restart line: " << yylineno << '\n'; goto restart 31 | # define YYDEBUG(s, c) cout << "state: " << s << " char: " << c << '\n' 32 | #else 33 | # define YYRESTART() goto restart 34 | # define YYDEBUG(s, c) 35 | #endif 36 | 37 | /*!max:re2c */ 38 | static_assert(YYMAXFILL <= parse::LEXER_READ_AHEAD); 39 | 40 | namespace parse { 41 | 42 | unsigned yylineno; 43 | yylval_t yylval; 44 | 45 | const char *const token_name[] = { 46 | #define TOKEN(x) #x, 47 | #include "tokens.h" 48 | #undef TOKEN 49 | }; 50 | 51 | static void error(string &&str) { 52 | throw LexException("[Lex] " + std::move(str), yylineno); 53 | } 54 | 55 | static void COPY_STR(unsigned off = 0) { 56 | assert(off <= YYLENGTH); 57 | yylval.str = { (const char*)YYTEXT + off, YYLENGTH - off }; 58 | } 59 | 60 | void yylex_init(string_view str) { 61 | YYCURSOR = (const YYCTYPE*)str.data(); 62 | YYLIMIT = (const YYCTYPE*)str.data() + str.size(); 63 | yylineno = 1; 64 | } 65 | 66 | token yylex() { 67 | restart: 68 | if (YYCURSOR >= YYLIMIT) 69 | return END; 70 | YYTEXT = YYCURSOR; 71 | 72 | /*!re2c 73 | space = [ \t]; 74 | re2c:yyfill:check = 0; 75 | 76 | "\r"? "\n" { 77 | ++yylineno; 78 | YYRESTART(); 79 | } 80 | 81 | space+ { 82 | YYRESTART(); 83 | } 84 | 85 | "," { return COMMA; } 86 | 87 | 88 | "(" { return LPAREN; } 89 | ")" { return RPAREN; } 90 | 91 | "{" { return LCURLY; } 92 | "}" { return RCURLY; } 93 | 94 | "copy" { return COPY; } 95 | 96 | "bitreverse" { return BITREVERSE; } 97 | "bswap" { return BSWAP; } 98 | "ctpop" { return CTPOP; } 99 | "ctlz" { return CTLZ; } 100 | "cttz" { return CTTZ; } 101 | "fneg" { return FNEG; } 102 | "fabs" { return FABS; } 103 | "fceil" { return FCEIL; } 104 | "ffloor" { return FFLOOR; } 105 | "frint" { return FRINT; } 106 | "fnearbyint" { return FNEARBYINT; } 107 | "fround" { return FROUND; } 108 | "froundeven" { return FROUNDEVEN; } 109 | "ftrunc" { return FTRUNC; } 110 | 111 | "conv_fpext" { return CONV_FPEXT; } 112 | "conv_fptrunc" { return CONV_FPTRUNC; } 113 | "conv_uitofp" { return CONV_UITOFP; } 114 | "conv_sitofp" { return CONV_SITOFP; } 115 | "conv_fptoui" { return CONV_FPTOUI; } 116 | "conv_fptosi" { return CONV_FPTOSI; } 117 | 118 | "and" { return BAND; } 119 | "or" { return BOR; } 120 | "xor" { return BXOR; } 121 | 122 | "add" { return ADD; } 123 | "sub" { return SUB; } 124 | "mul" { return MUL; } 125 | "sdiv" { return SDIV; } 126 | "udiv" { return UDIV; } 127 | 128 | "lshr" { return LSHR; } 129 | "ashr" { return ASHR; } 130 | "shl" { return SHL; } 131 | 132 | "umax" { return UMAX; } 133 | "umin" { return UMIN; } 134 | "smax" { return SMAX; } 135 | "smin" { return SMIN; } 136 | 137 | "fadd" { return FADD; } 138 | "fsub" { return FSUB; } 139 | "fmul" { return FMUL; } 140 | "fdiv" { return FDIV; } 141 | 142 | "fmaxnum" { return FMAXNUM; } 143 | "fminnum" { return FMINNUM; } 144 | "fmaximum" { return FMAXIMUM; } 145 | "fminimum" { return FMINIMUM; } 146 | "copysign" { return COPYSIGN; } 147 | 148 | "icmp_eq" { return EQ; } 149 | "icmp_ne" { return NE; } 150 | "icmp_ult" { return ULT; } 151 | "icmp_ule" { return ULE; } 152 | "icmp_ugt" { return UGT; } 153 | "icmp_uge" { return UGE; } 154 | "icmp_slt" { return SLT; } 155 | "icmp_sle" { return SLE; } 156 | "icmp_sgt" { return SGT; } 157 | "icmp_sge" { return SGE; } 158 | 159 | "fcmp_t" { return FCMP_TRUE; } 160 | "fcmp_oeq" { return FCMP_OEQ; } 161 | "fcmp_ogt" { return FCMP_OGT; } 162 | "fcmp_oge" { return FCMP_OGE; } 163 | "fcmp_olt" { return FCMP_OLT; } 164 | "fcmp_ole" { return FCMP_OLE; } 165 | "fcmp_one" { return FCMP_ONE; } 166 | "fcmp_ord" { return FCMP_ORD; } 167 | "fcmp_ueq" { return FCMP_UEQ; } 168 | "fcmp_ugt" { return FCMP_UGT; } 169 | "fcmp_uge" { return FCMP_UGE; } 170 | "fcmp_ult" { return FCMP_ULT; } 171 | "fcmp_ule" { return FCMP_ULE; } 172 | "fcmp_une" { return FCMP_UNE; } 173 | "fcmp_uno" { return FCMP_UNO; } 174 | "fcmp_f" { return FCMP_FALSE; } 175 | 176 | "blend" { return BLEND; } 177 | "shuffle" { return SHUFFLE; } 178 | "select" { return SELECT; } 179 | "insertelement" { return INSERTELEMENT; } 180 | "extractelement" { return EXTRACTELEMENT; } 181 | 182 | "conv_zext" { return CONV_ZEXT; } 183 | "conv_sext" { return CONV_SEXT; } 184 | "conv_trunc" { return CONV_TRUNC; } 185 | 186 | "var" { return VAR; } 187 | "reservedconst" { return CONST; } 188 | 189 | "half" { return HALF; } 190 | "float" { return FLOAT; } 191 | "double" { return DOUBLE; } 192 | "fp128" { return FP128; } 193 | 194 | 195 | "x86_" [a-zA-Z0-9_]+ { COPY_STR(); return X86BINARY; } 196 | 197 | "%" [a-zA-Z0-9_.]+ { 198 | COPY_STR(); 199 | return REGISTER; 200 | } 201 | 202 | "i" [1-9][0-9]* { 203 | yylval.num = strtoull((char*)YYTEXT+1, nullptr, 10); 204 | return INT_TYPE; 205 | } 206 | 207 | "<" space* @tag1 [1-9][0-9]* space* "x" { 208 | yylval.num = strtoull((char*)tag1, nullptr, 10); 209 | return VECTOR_TYPE_PREFIX; 210 | } 211 | ">" { return CSGT; } 212 | 213 | "\|" @tag1 [<>0-9a-zA-Z- ,.\+]* "\|" { 214 | COPY_STR(); 215 | return LITERAL; 216 | } 217 | 218 | "b" "-"?[0-9]+ { 219 | yylval.num = strtoull((char*)YYTEXT + 1, nullptr, 10); 220 | return BITS; 221 | } 222 | 223 | "-"?[0-9]+ { 224 | COPY_STR(); 225 | return NUM_STR; 226 | } 227 | 228 | * { error("couldn't parse: '" + string((char*)YYTEXT, 16) + '\''); } 229 | */ 230 | 231 | UNREACHABLE(); 232 | } 233 | 234 | } 235 | -------------------------------------------------------------------------------- /lib/type.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-present, author: Zhengyang Liu (liuz@cs.utah.edu). 2 | // Distributed under the MIT license that can be found in the LICENSE file. 3 | #include "type.h" 4 | 5 | #include "ir/instr.h" 6 | #include "util/compiler.h" 7 | #include "llvm/ADT/StringExtras.h" 8 | #include "llvm/IR/DerivedTypes.h" 9 | #include "llvm/IR/Type.h" 10 | #include "llvm/Support/Error.h" 11 | #include "llvm/Support/ErrorHandling.h" 12 | #include 13 | 14 | using namespace std; 15 | using namespace llvm; 16 | 17 | namespace minotaur { 18 | 19 | type::type(llvm::Type *t) { 20 | if (t->isIntegerTy() || t->isIEEELikeFPTy()) { 21 | lane = 1; 22 | bits = t->getPrimitiveSizeInBits(); 23 | fp = t->isIEEELikeFPTy(); 24 | } else if (t->isVectorTy()) { 25 | if (isa(t)) 26 | report_fatal_error("scalable vector type not yet supported"); 27 | 28 | FixedVectorType *fty = cast(t); 29 | Type *elemty = fty->getElementType(); 30 | lane = fty->getNumElements(); 31 | bits = elemty->getPrimitiveSizeInBits(); 32 | if (elemty->isIntegerTy()) { 33 | fp = false; 34 | } else if (elemty->isIEEELikeFPTy()) { 35 | fp = true; 36 | } else { 37 | report_fatal_error("non-trivial vectors are not supported\n"); 38 | } 39 | } else { 40 | llvm::errs()<<"[expr] type: "<<*t<<"\n"; 41 | report_fatal_error("[expr] unrecognized type"); 42 | } 43 | } 44 | 45 | bool type::operator==(const type &rhs) const { 46 | return lane == rhs.lane && bits == rhs.bits && 47 | fp == rhs.fp; 48 | } 49 | 50 | bool type::same_width(const type &rhs) const { 51 | assert(valid()); 52 | return getWidth() == rhs.getWidth(); 53 | } 54 | 55 | static Type* getFloatingPointType(LLVMContext &C, unsigned bits) { 56 | switch (bits) { 57 | case 16: 58 | return Type::getHalfTy(C); 59 | case 32: 60 | return Type::getFloatTy(C); 61 | case 64: 62 | return Type::getDoubleTy(C); 63 | case 128: 64 | return Type::getFP128Ty(C); 65 | } 66 | UNREACHABLE(); 67 | } 68 | 69 | Type* type::toLLVM(LLVMContext &C) const { 70 | if (!isValid()) { 71 | report_fatal_error("invalid minotaur type"); 72 | } 73 | 74 | Type *Ty = nullptr; 75 | 76 | if (fp) { 77 | Ty = getFloatingPointType(C, bits); 78 | } else { 79 | Ty = Type::getIntNTy(C, bits); 80 | } 81 | 82 | if (isVector()) { 83 | Ty = FixedVectorType::get(Ty, lane); 84 | } 85 | 86 | return Ty; 87 | } 88 | 89 | unsigned type::getWidth() const { 90 | return lane * bits; 91 | } 92 | 93 | unsigned type::getLane() const { 94 | return lane; 95 | } 96 | 97 | unsigned type::getBits() const { 98 | return bits; 99 | } 100 | 101 | bool type::isFP() const { 102 | return fp; 103 | } 104 | 105 | bool type::isValid() const{ 106 | return lane != 0 && bits != 0; 107 | } 108 | 109 | bool type::isBool() const { 110 | return lane == 1 && bits == 1; 111 | } 112 | 113 | type type::getAsScalar() const { 114 | return type(1, bits, fp); 115 | } 116 | 117 | type type::getAsVector(unsigned lane) const { 118 | return type(lane, bits, fp); 119 | } 120 | 121 | type type::getAsIntTy() const { 122 | return fp ? type::Integer(getWidth()): type::IntegerVectorizable(lane, bits); 123 | } 124 | 125 | raw_ostream& operator<<(raw_ostream &os, const type &ty) { 126 | if (!ty.isValid()) { 127 | os<<"null"; 128 | return os; 129 | } 130 | if (ty.isVector()) 131 | os<<"<"<"; 154 | return os; 155 | } 156 | 157 | type getIntrinsicOp0Ty(IR::X86IntrinBinOp::Op op) { 158 | return type::IntegerVectorizable(IR::X86IntrinBinOp::shape_op0[op].first, 159 | IR::X86IntrinBinOp::shape_op0[op].second); 160 | } 161 | 162 | type getIntrinsicOp1Ty(IR::X86IntrinBinOp::Op op) { 163 | return type::IntegerVectorizable(IR::X86IntrinBinOp::shape_op1[op].first, 164 | IR::X86IntrinBinOp::shape_op1[op].second); 165 | } 166 | 167 | type getIntrinsicRetTy(IR::X86IntrinBinOp::Op op) { 168 | return type::IntegerVectorizable(IR::X86IntrinBinOp::shape_ret[op].first, 169 | IR::X86IntrinBinOp::shape_ret[op].second); 170 | } 171 | 172 | vector getIntegerVectorTypes(type ty) { 173 | unsigned width = ty.getWidth(); 174 | 175 | if (width % 8 != 0) { 176 | return { ty }; 177 | } 178 | 179 | vector bits{64, 32, 16, 8}; 180 | vector types; 181 | for (unsigned i = 0 ; i < 4 ; ++ i) { 182 | if (width % bits[i] == 0 && width >= bits[i]) { 183 | types.push_back(type::IntegerVectorizable(width/bits[i], bits[i])); 184 | } 185 | } 186 | return types; 187 | } 188 | 189 | } // namespace minotaur -------------------------------------------------------------------------------- /lib/utils.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-present, author: Zhengyang Liu (liuz@cs.utah.edu). 2 | // Distributed under the MIT license that can be found in the LICENSE file. 3 | #include "utils.h" 4 | 5 | #include "llvm/Transforms/Scalar/DCE.h" 6 | #include "llvm/Passes/PassBuilder.h" 7 | 8 | #include "hiredis.h" 9 | 10 | #include 11 | 12 | using namespace std; 13 | using namespace llvm; 14 | 15 | namespace minotaur { 16 | 17 | void eliminate_dead_code(Function &F) { 18 | FunctionAnalysisManager FAM; 19 | 20 | PassBuilder PB; 21 | PB.registerFunctionAnalyses(FAM); 22 | 23 | FunctionPassManager FPM; 24 | FPM.addPass(DCEPass()); 25 | FPM.run(F, FAM); 26 | } 27 | 28 | bool hGet(const char* s, unsigned sz, string &Value, redisContext *c) { 29 | redisReply *reply = (redisReply *)redisCommand(c, "HGET %b rewrite", s, sz); 30 | if (!reply || c->err) { 31 | report_fatal_error((StringRef)"redis error" + c->errstr); 32 | } 33 | if (reply->type == REDIS_REPLY_NIL) { 34 | freeReplyObject(reply); 35 | return false; 36 | } else if (reply->type == REDIS_REPLY_STRING) { 37 | Value = reply->str; 38 | freeReplyObject(reply); 39 | return true; 40 | } else { 41 | report_fatal_error((StringRef) 42 | "Redis protocol error for cache lookup, didn't expect reply type " + 43 | to_string(reply->type)); 44 | } 45 | } 46 | 47 | void hSetRewrite(const char *k, unsigned sz_k, 48 | const char *v, unsigned sz_v, 49 | StringRef rewrite, 50 | redisContext *c, 51 | unsigned costAfter, unsigned costBefore, StringRef FnName) { 52 | redisReply *reply = (redisReply *)redisCommand(c, 53 | "HSET %b rewrite %s costafter %s costbefore %s timestamp %s fn %s", 54 | k, sz_k, rewrite.data(), 55 | to_string(costAfter).c_str(), to_string(costBefore).c_str(), 56 | to_string((unsigned long)time(NULL)).c_str(), FnName.data()); 57 | if (!reply || c->err) 58 | report_fatal_error((StringRef)"Redis error: " + c->errstr); 59 | if (reply->type != REDIS_REPLY_INTEGER) { 60 | report_fatal_error((StringRef) 61 | "Redis protocol error for cache fill, didn't expect reply type " + 62 | to_string(reply->type)); 63 | } 64 | freeReplyObject(reply); 65 | } 66 | 67 | void hSetNoSolution(const char *k, unsigned sz_k, 68 | redisContext *c, 69 | StringRef FnName) { 70 | redisReply *reply = (redisReply *)redisCommand(c, 71 | "HSET %b rewrite timestamp %s fn %s", 72 | k, sz_k, to_string((unsigned long)time(NULL)).c_str(), FnName.data()); 73 | if (!reply || c->err) 74 | report_fatal_error((StringRef)"Redis error: " + c->errstr); 75 | if (reply->type != REDIS_REPLY_INTEGER) { 76 | report_fatal_error((StringRef) 77 | "Redis protocol error for cache fill, didn't expect reply type " + 78 | to_string(reply->type)); 79 | } 80 | // static profile 81 | reply = (redisReply *)redisCommand(c, "HINCRBY %b profile 1", k, sz_k); 82 | if (!reply || c->err) 83 | report_fatal_error((StringRef)"Redis error: " + c->errstr); 84 | if (reply->type != REDIS_REPLY_INTEGER) { 85 | report_fatal_error((StringRef) 86 | "Redis protocol error for cache fill, didn't expect reply type " + 87 | to_string(reply->type)); 88 | } 89 | freeReplyObject(reply); 90 | } 91 | 92 | void removeUnusedDecls(unordered_set IntrinsicDecls) { 93 | for (auto Intr : IntrinsicDecls) { 94 | if (Intr->isDeclaration() && Intr->use_empty()) { 95 | Intr->eraseFromParent(); 96 | } 97 | } 98 | } 99 | 100 | } -------------------------------------------------------------------------------- /pass/stat/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13.4) 2 | project(llvm-tutor-hello-world) 3 | 4 | #=============================================================================== 5 | # 1. LOAD LLVM CONFIGURATION 6 | #=============================================================================== 7 | # Set this to a valid LLVM installation dir 8 | set(LT_LLVM_INSTALL_DIR "" CACHE PATH "LLVM installation directory") 9 | 10 | # Add the location of LLVMConfig.cmake to CMake search paths (so that 11 | # find_package can locate it) 12 | list(APPEND CMAKE_PREFIX_PATH "${LT_LLVM_INSTALL_DIR}/lib/cmake/llvm/") 13 | 14 | # FIXME: This is a warkaround for #25. Remove once resolved and use 15 | find_package(LLVM REQUIRED CONFIG) 16 | 17 | # HelloWorld includes headers from LLVM - update the include paths accordingly 18 | include_directories(SYSTEM ${LLVM_INCLUDE_DIRS}) 19 | 20 | #=============================================================================== 21 | # 2. LLVM-TUTOR BUILD CONFIGURATION 22 | #=============================================================================== 23 | # Use the same C++ standard as LLVM does 24 | set(CMAKE_CXX_STANDARD 17 CACHE STRING "") 25 | 26 | # LLVM is normally built without RTTI. Be consistent with that. 27 | if(NOT LLVM_ENABLE_RTTI) 28 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") 29 | endif() 30 | 31 | #=============================================================================== 32 | # 3. ADD THE TARGET 33 | #=============================================================================== 34 | add_library(HelloWorld SHARED HelloWorld.cpp) 35 | 36 | # Allow undefined symbols in shared objects on Darwin (this is the default 37 | # behaviour on Linux) 38 | target_link_libraries(HelloWorld 39 | "$<$:-undefined dynamic_lookup>") 40 | -------------------------------------------------------------------------------- /pass/stat/HelloWorld.cpp: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // FILE: 3 | // HelloWorld.cpp 4 | // 5 | // DESCRIPTION: 6 | // Visits all functions in a module, prints their names and the number of 7 | // arguments via stderr. Strictly speaking, this is an analysis pass (i.e. 8 | // the functions are not modified). However, in order to keep things simple 9 | // there's no 'print' method here (every analysis pass should implement it). 10 | // 11 | // USAGE: 12 | // 2. New PM 13 | // opt -load-pass-plugin=libHelloWorld.dylib -passes="hello-world" `\` 14 | // -disable-output 15 | // 16 | // 17 | // License: MIT 18 | //============================================================================= 19 | #include "llvm/Passes/PassBuilder.h" 20 | #include "llvm/Passes/PassPlugin.h" 21 | #include "llvm/Support/raw_ostream.h" 22 | 23 | using namespace llvm; 24 | 25 | //----------------------------------------------------------------------------- 26 | // HelloWorld implementation 27 | //----------------------------------------------------------------------------- 28 | // No need to expose the internals of the pass to the outside world - keep 29 | // everything in an anonymous namespace. 30 | namespace { 31 | 32 | // This method implements what the pass does 33 | void visitor(Function &F) { 34 | errs() << F.getName() << " : "; 35 | auto DL = F.getParent()->getDataLayout(); 36 | long size = 0; 37 | for (auto &A : F.args()) { 38 | size += DL.getTypeSizeInBits(A.getType()); 39 | } 40 | errs() << size << "\n"; 41 | } 42 | 43 | // New PM implementation 44 | struct HelloWorld : PassInfoMixin { 45 | // Main entry point, takes IR unit to run the pass on (&F) and the 46 | // corresponding pass manager (to be queried if need be) 47 | PreservedAnalyses run(Function &F, FunctionAnalysisManager &) { 48 | visitor(F); 49 | return PreservedAnalyses::all(); 50 | } 51 | 52 | // Without isRequired returning true, this pass will be skipped for functions 53 | // decorated with the optnone LLVM attribute. Note that clang -O0 decorates 54 | // all functions with optnone. 55 | static bool isRequired() { return true; } 56 | }; 57 | 58 | } // namespace 59 | 60 | //----------------------------------------------------------------------------- 61 | // New PM Registration 62 | //----------------------------------------------------------------------------- 63 | llvm::PassPluginLibraryInfo getHelloWorldPluginInfo() { 64 | return {LLVM_PLUGIN_API_VERSION, "HelloWorld", LLVM_VERSION_STRING, 65 | [](PassBuilder &PB) { 66 | PB.registerPipelineParsingCallback( 67 | [](StringRef Name, FunctionPassManager &FPM, 68 | ArrayRef) { 69 | if (Name == "hello-world") { 70 | FPM.addPass(HelloWorld()); 71 | return true; 72 | } 73 | return false; 74 | }); 75 | }}; 76 | } 77 | 78 | // This is the core interface for pass plugins. It guarantees that 'opt' will 79 | // be able to recognize HelloWorld when added to the pass pipeline on the 80 | // command line, i.e. via '-passes=hello-world' 81 | extern "C" LLVM_ATTRIBUTE_WEAK ::llvm::PassPluginLibraryInfo 82 | llvmGetPassPluginInfo() { 83 | return getHelloWorldPluginInfo(); 84 | } 85 | 86 | -------------------------------------------------------------------------------- /scripts/cache-dump.in: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | # Copyright (c) 2020-present, author: Zhengyang Liu (liuz@cs.utah.edu). 4 | # Distributed under the MIT license that can be found in the LICENSE file. 5 | # borrowed from souper 6 | 7 | use warnings; 8 | use strict; 9 | use Redis; 10 | use Getopt::Long; 11 | use File::Temp; 12 | use Time::HiRes; 13 | 14 | my $llvmas = "@LLVM_BINARY_DIR@/bin/llvm-as"; 15 | my $llvmopt = "@LLVM_BINARY_DIR@/bin/opt"; 16 | 17 | sub runit ($) { 18 | my $cmd = shift; 19 | my $res = (system "$cmd"); 20 | return $? >> 8; 21 | } 22 | 23 | sub usage() { 24 | print <<'END'; 25 | Options: 26 | -dumpall dump all LHSs 27 | -tofiles dump all LHSs to files 28 | -sort=timestamp|costdiff|reduce|cutsize|profile sort optimizations 29 | -verbose 30 | END 31 | exit -1; 32 | } 33 | 34 | my $REDISPORT = 6379; 35 | my $DUMPALL = 0; 36 | my $TOFILES = 0; 37 | my $SORT = "timestamp"; 38 | my $VERBOSE = 0; 39 | my $UNIX = 0; 40 | 41 | GetOptions( 42 | "dumpall" => \$DUMPALL, 43 | "tofiles" => \$TOFILES, 44 | "redis-port=i" => \$REDISPORT, 45 | "sort=s" => \$SORT, 46 | "verbose" => \$VERBOSE, 47 | ) or usage(); 48 | usage() unless ($SORT eq "timestamp" || 49 | $SORT eq "costdiff" || 50 | $SORT eq "reduce" || 51 | $SORT eq "cutsize" || 52 | $SORT eq "profile"); 53 | 54 | my $noopt_count=0; 55 | 56 | my $r; 57 | if ($UNIX) { 58 | $r = Redis->new(sock => "@CMAKE_BINARY_DIR@/cache.sock"); 59 | } else { 60 | $r = Redis->new(server => "localhost:" . $REDISPORT); 61 | } 62 | $r->ping || die "no server?"; 63 | my @all_keys = $r->keys('*'); 64 | 65 | print "; Inspecting ".scalar(@all_keys)." Redis values\n"; 66 | 67 | sub parse($) { 68 | (my $opt) = @_; 69 | (my $fh, my $tmpfn) = File::Temp::tempfile(); 70 | print $fh $opt; 71 | $fh->flush(); 72 | open INF, "cat < $tmpfn 2>&1 |"; 73 | my $output = ""; 74 | my $success = 0; 75 | while (my $line = ) { 76 | $success = 1 if ($line =~ /success/); 77 | next if ($line =~ /^;/); 78 | $output .= $line; 79 | } 80 | close INF; 81 | close $fh; 82 | unlink $tmpfn; 83 | return $output; 84 | } 85 | 86 | my %toprint; 87 | my %ir; 88 | my %rewrite; 89 | my %costafter; 90 | my %costbefore; 91 | my %costdiff; 92 | my %reduce; 93 | my %timestamp; 94 | my %fn_name; 95 | my %profile; 96 | my %noopt; 97 | my %optbc; 98 | my %cutsize; 99 | 100 | if ($DUMPALL) { 101 | print "; Dumping all ".scalar(keys @all_keys)." rewrites\n"; 102 | my $count = 0; 103 | foreach my $opt (@all_keys) { 104 | my %h = $r->hgetall($opt); 105 | my $time = $h{"timestamp"}; 106 | my $fn = $h{"fn"}; 107 | my $profile = $h{"profile"}; 108 | my $rewrite = $h{"rewrite"}; 109 | my $ir = parse($opt); 110 | if ($TOFILES) { 111 | open(my $fh, ">", "dump_$count.ll"); 112 | print $fh $ir; 113 | $fh->flush(); 114 | close $fh; 115 | } else { 116 | print $ir, "\n"; 117 | print "rewrite: $rewrite\n"; 118 | print "timestamp: $time\n"; 119 | print "profile: $profile\n"; 120 | print "in fn: $fn\n"; 121 | print "\n------------------------------------------------------\n"; 122 | } 123 | $count = $count + 1; 124 | } 125 | exit(0); 126 | } 127 | 128 | foreach my $opt (@all_keys) { 129 | my %h = $r->hgetall($opt); 130 | 131 | my $rewrite = $h{"rewrite"}; 132 | $noopt{$opt} = $rewrite eq ""; 133 | 134 | if ($noopt{$opt}) { 135 | $noopt_count++; 136 | next; 137 | } 138 | 139 | my $time = $h{"timestamp"}; 140 | my $fn = $h{"fn"}; 141 | my $pf = $h{"profile"}; 142 | my $ca = $h{"costafter"}; 143 | my $cb = $h{"costbefore"}; 144 | if ($cb == 0) { 145 | $cb = 1; 146 | } 147 | if ($ca == 0) { 148 | $ca = 1; 149 | } 150 | 151 | $ir{$opt} = parse($opt); 152 | 153 | $toprint{$opt} = 1; 154 | $costafter{$opt} = $ca; 155 | $costbefore{$opt} = $cb; 156 | $costdiff{$opt} = $cb - $ca; 157 | $reduce{$opt} = ($cb - $ca * 1.0) / $cb; 158 | $rewrite{$opt} = $rewrite; 159 | $cutsize{$opt} = length($optbc{$opt}); 160 | $profile{$opt} = $pf; 161 | $fn_name{$opt} = $fn; 162 | $timestamp{$opt} = $time; 163 | } 164 | 165 | 166 | print "; Discarding ${noopt_count} not-optimizations leaving ". 167 | scalar(keys %toprint)." optimizations\n"; 168 | 169 | # print "\n\n"; 170 | 171 | sub bytimestamp { $timestamp{$b} <=> $timestamp{$a} } 172 | sub bycostdiff { $costdiff{$b} <=> $costdiff{$a} } 173 | sub byreduce { $reduce{$b} <=> $reduce{$a} } 174 | sub bycutsize { $cutsize{$b} <=> $cutsize{$a} } 175 | sub byprofile { $profile{$b} <=> $profile{$a} } 176 | 177 | my $byx; 178 | $byx = \&bytimestamp if ($SORT eq "timestamp"); 179 | $byx = \&bycostdiff if ($SORT eq "costdiff"); 180 | $byx = \&byreduce if ($SORT eq "reduce"); 181 | $byx = \&bycutsize if ($SORT eq "cutsize"); 182 | $byx = \&byprofile if ($SORT eq "profile"); 183 | 184 | 185 | my $count = 0; 186 | foreach my $opt (sort $byx keys %toprint) { 187 | my $ir = $ir{$opt}; 188 | my $time = $timestamp{$opt}; 189 | my $fn = $fn_name{$opt}; 190 | my $rewrite = $rewrite{$opt}; 191 | my $ca = $costafter{$opt}; 192 | my $cb = $costbefore{$opt}; 193 | my $pf = $profile{$opt}; 194 | 195 | if ($TOFILES) { 196 | open(my $fh, ">", "dump_$count.src.ll"); 197 | print $fh $ir, "\n"; 198 | $fh->flush(); 199 | close $fh; 200 | } else { 201 | print "; opt ---------------------------------------------------\n"; 202 | print $ir; 203 | print "; minotaur_rewrite: $rewrite \n"; 204 | print "; minotaur_cost-before: $cb\n"; 205 | print "; minotaur_cost-after: $ca\n"; 206 | print "; minotaur_timestamp: $time\n"; 207 | print "; minotaur_profile: $pf\n"; 208 | print "; minotaur_fn: $fn\n"; 209 | } 210 | $count = $count + 1; 211 | } 212 | 213 | # my $cnt = 0; 214 | # foreach my $opt (keys %toprint) { 215 | # $cnt += $sprofiles{$opt}; 216 | # } 217 | # print "; overall total static profile weight = $cnt\n"; 218 | # print "; $tagged were tagged by cache_infer, $untagged were not\n"; 219 | -------------------------------------------------------------------------------- /scripts/cache-infer.in: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | # Copyright (c) 2020-present, author: Zhengyang Liu (liuz@cs.utah.edu). 4 | # Distributed under the MIT license that can be found in the LICENSE file. 5 | # borrowed from souper 6 | 7 | use warnings; 8 | use strict; 9 | use Redis; 10 | use Getopt::Long; 11 | use File::Temp; 12 | use Time::HiRes; 13 | use BSD::Resource; 14 | 15 | eval { require Sys::CPU; Sys::CPU->import(); }; 16 | 17 | my $NPROCS = 40; 18 | $NPROCS = Sys::CPU::cpu_count() - 2 if defined(&Sys::CPU::cpu_count); 19 | 20 | sub usage() { 21 | print <<"END"; 22 | Options: 23 | -n number of CPUs to use (default=$NPROCS) 24 | -tag add this tag to cache entries, and skip entries with it 25 | -separate-files put each souper invocation's output into its own output file 26 | -souper-debug-level pass this integer debug level to Souper 27 | -verbose print extra output 28 | -unix talk to Redis using UNIX domain sockets 29 | END 30 | exit -1; 31 | } 32 | 33 | my $tag = "x"; 34 | my $VERBOSE = 0; 35 | my $SAVE_TEMPS=1; 36 | my $UNIX = 0; 37 | 38 | GetOptions( 39 | "n=i" => \$NPROCS, 40 | "tag=s" => \$tag, 41 | "verbose" => \$VERBOSE, 42 | "unix" => \$UNIX, 43 | "separate-files" => \$SAVE_TEMPS, 44 | ) or usage(); 45 | 46 | my $REDISPORT = 6379; 47 | 48 | my $minotaur = "@CMAKE_BINARY_DIR@/infer-cut.sh"; 49 | my $llvmdis = "@LLVM_BINARY_DIR@/bin/llvm-dis"; 50 | 51 | my $r; 52 | if ($UNIX) { 53 | $r = Redis->new(sock => "@CMAKE_BINARY_DIR@/cache.sock"); 54 | } else { 55 | $r = Redis->new(server => "localhost:" . $REDISPORT); 56 | } 57 | $r->ping || die "no server?"; 58 | my @all_keys = $r->keys('*'); 59 | 60 | sub infer($) { 61 | (my $opt) = @_; 62 | (my $fh, my $tmpfn) = File::Temp::tempfile(); 63 | print $fh $opt; 64 | $fh->flush(); 65 | 66 | my $pid = $$; 67 | my $ok = 0; 68 | 69 | my $OFN = "tmp_${pid}.log"; 70 | system "${minotaur} -S < $tmpfn > $OFN 2>&1"; 71 | #nclose $OF; 72 | unlink $tmpfn; 73 | exit 0; 74 | } 75 | 76 | my $num_running = 0; 77 | my $good = 0; 78 | my $fail = 0; 79 | 80 | sub wait_for_one() { 81 | my $xpid = wait(); 82 | die if $xpid == -1; 83 | $num_running--; 84 | my $result = $? >> 8; 85 | if ($result == 0) { 86 | $good++; 87 | } else { 88 | $fail++; 89 | } 90 | } 91 | 92 | my $status_cnt; 93 | my $status_opct; 94 | my $status_total; 95 | 96 | sub status() { 97 | print "."; 98 | $status_cnt++; 99 | my $pct = int(100.0 * $status_cnt/$status_total); 100 | if ($pct > $status_opct) { 101 | $status_opct = $pct; 102 | print "$pct %\n"; 103 | } 104 | } 105 | 106 | my $opid = $$; 107 | my $skip = 0; 108 | 109 | print "total expressions = ".scalar(@all_keys)."\n"; 110 | 111 | my $count = 1; 112 | 113 | my %toprint; 114 | my %ir; 115 | my %rewrite; 116 | my %timestamp; 117 | my %fn_name; 118 | my %noopt; 119 | 120 | foreach my $opt (@all_keys) { 121 | my %h = $r->hgetall($opt); 122 | 123 | my $result = $h{"rewrite"}; 124 | my $time = $h{"timestamp"}; 125 | my $fn = $h{"fn"}; 126 | 127 | #$ir{$opt} = infer($opt); 128 | $toprint{$opt} = 1; 129 | $fn_name{$opt} = $fn; 130 | $timestamp{$opt} = $time; 131 | } 132 | 133 | foreach my $opt (keys %toprint) { 134 | status() if $VERBOSE; 135 | my $ir = $ir{$opt}; 136 | # if (defined $result && $result eq $tag) { 137 | # $skip++; 138 | # next; 139 | # } 140 | wait_for_one() unless $num_running < $NPROCS; 141 | die unless $num_running < $NPROCS; 142 | print("\r\c[[Ksolving $count"); 143 | $count ++; 144 | my $pid = fork(); 145 | die unless $pid >= 0; 146 | if ($pid == 0) { 147 | #die "setrlimit RSS" unless setrlimit(RLIMIT_RSS, $RAM_LIMIT, $RAM_LIMIT); 148 | #die "setrlimit VMEM" unless setrlimit(RLIMIT_VMEM, $RAM_LIMIT, $RAM_LIMIT); 149 | infer ($opt); 150 | } 151 | # make sure we're in the parent 152 | die unless $$ == $opid; 153 | $num_running++; 154 | } 155 | 156 | wait_for_one() while ($num_running > 0); 157 | 158 | print "\n"; 159 | print "$good optimizations\n"; 160 | print "$fail not-optimizations\n"; 161 | print "$skip skipped due to tag match\n"; -------------------------------------------------------------------------------- /scripts/get-cost.in: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | set -o pipefail 5 | 6 | @LLVM_BINARY_DIR@/bin/clang -march=native -S -O2 -o - $@ | @LLVM_BINARY_DIR@/bin/llvm-mca --iterations 1 -mcpu=native | grep "Total uOps" | tr ' ' '\n' | tail -1 7 | -------------------------------------------------------------------------------- /scripts/infer-cut.sh.in: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | @LLVM_BINARY_DIR@/bin/opt -load-pass-plugin=@ONLINE_PASS@ \ 5 | $@ \ 6 | -passes="minotaur" \ 7 | -minotaur-enable-caching=true \ 8 | -minotaur-no-slice=true \ 9 | -minotaur-force-infer=true \ 10 | -S 11 | -------------------------------------------------------------------------------- /scripts/minotaur-cc.in: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | # Copyright (c) 2020-present, author: Zhengyang Liu (liuz@cs.utah.edu). 4 | # Distributed under the MIT license that can be found in the LICENSE file. 5 | 6 | use warnings; 7 | use strict; 8 | use File::Temp; 9 | 10 | if ($0 =~ /minotaur-cc$/) { 11 | unshift @ARGV, "@LLVM_BINARY_DIR@/bin/clang"; 12 | } elsif ($0 =~ /minotaur-c\+\+$/) { 13 | unshift @ARGV, "@LLVM_BINARY_DIR@/bin/clang++"; 14 | } else { 15 | die "Didn't expect minotuar-cc to be invoked as '$0'"; 16 | } 17 | 18 | foreach my $arg (@ARGV) { 19 | if ($arg eq "-help" || $arg eq "--help") { 20 | print < %1, 2 | define <4 x i32> @xnn_f16_f32_vcvt_ukernel__scalar_x2_(<8 x i16> %0) { 3 | vector.body: 4 | %1 = shufflevector <8 x i16> %0, <8 x i16> poison, <4 x i32> 5 | %2 = zext <4 x i16> %1 to <4 x i32> 6 | ret <4 x i32> %2 7 | 8 | sink: ; No predecessors! 9 | unreachable 10 | } -------------------------------------------------------------------------------- /tests/const/const0.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: ret i1 true 2 | define i1 @test39(i1 %cond, double %x) { 3 | ; CHECK-LABEL: @test39( 4 | ; CHECK-NEXT: ret i1 true 5 | ; 6 | %s = select i1 %cond, double %x, double 0x7FF0000000000000 ; RHS = +infty 7 | %cmp = fcmp ule double %x, %s 8 | ret i1 %cmp 9 | } -------------------------------------------------------------------------------- /tests/const/const1.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: ret i64 0 2 | define i64 @fold_ptrtoint_inbounds_nullgep_of_nonzero_inbounds_nullgep_zero_offset() { 3 | %1 = add i64 1234, 0 4 | %2 = sub i64 %1, 1234 5 | ret i64 %2 6 | } 7 | -------------------------------------------------------------------------------- /tests/const/control0.ll: -------------------------------------------------------------------------------- 1 | 2 | define i1 @src(i32 %0, i1 %_reservedc_0) { 3 | entry: 4 | %1 = add i32 %0, -1 5 | %2 = and i32 %0, 7 6 | %3 = icmp eq i32 %2, 0 7 | br i1 %3, label %do.body.prol.loopexit, label %sink 8 | 9 | do.body.prol.loopexit: ; preds = %entry 10 | %4 = icmp ult i32 %1, 7 11 | ret i1 %4 12 | 13 | sink: ; preds = %entry 14 | unreachable 15 | } 16 | 17 | 18 | define i1 @tgt(i32 %0, i1 %_reservedc_0) { 19 | entry: 20 | %1 = and i32 %0, 7 21 | %2 = icmp eq i32 %1, 0 22 | br i1 %2, label %do.body.prol.loopexit, label %sink 23 | 24 | do.body.prol.loopexit: ; preds = %entry 25 | ret i1 %_reservedc_0 26 | 27 | sink: ; preds = %entry 28 | unreachable 29 | } 30 | -------------------------------------------------------------------------------- /tests/const/diff1.constsyn.ll: -------------------------------------------------------------------------------- 1 | define <8 x i32> @src(<16 x i16> %wide.vec, <16 x i16> %_reservedc) { 2 | entry: 3 | %strided.vec = shufflevector <16 x i16> %wide.vec, <16 x i16> poison, <8 x i32> 4 | %strided.vec24 = shufflevector <16 x i16> %wide.vec, <16 x i16> poison, <8 x i32> 5 | %a = sext <8 x i16> %strided.vec to <8 x i32> 6 | %b = sext <8 x i16> %strided.vec24 to <8 x i32> 7 | %c = sub nsw <8 x i32> %a, %b 8 | ret <8 x i32> %c 9 | } 10 | 11 | 12 | define <8 x i32> @tgt(<16 x i16> %0, <16 x i16> %_reservedc) { 13 | entry: 14 | %intr = call <8 x i32> @llvm.x86.avx2.pmadd.wd(<16 x i16> %0, <16 x i16> %_reservedc) 15 | ret <8 x i32> %intr 16 | 17 | sink: ; No predecessors! 18 | unreachable 19 | } 20 | 21 | declare <8 x i32> @llvm.x86.avx2.pmadd.wd(<16 x i16>, <16 x i16>) 22 | 23 | -------------------------------------------------------------------------------- /tests/const/diff2.constsyn.ll: -------------------------------------------------------------------------------- 1 | define <8 x i32> @src(<16 x i16> %0, <16 x i16> %_reservedc) { 2 | entry: 3 | %1 = bitcast <16 x i16> %0 to <8 x i32> 4 | %2 = call <8 x i32> @llvm.x86.avx2.psrai.d(<8 x i32> %1, i32 16) 5 | %3 = call <8 x i32> @llvm.x86.avx2.pmadd.wd(<16 x i16> %0, <16 x i16> ) 6 | %4 = sub nsw <8 x i32> %3, %2 7 | ret <8 x i32> %4 8 | } 9 | 10 | define <8 x i32> @tgt(<16 x i16> %0, <16 x i16> %_reservedc) { 11 | entry: 12 | %intr = call <8 x i32> @llvm.x86.avx2.pmadd.wd(<16 x i16> %0, <16 x i16> %_reservedc) 13 | ret <8 x i32> %intr 14 | } 15 | 16 | 17 | declare <8 x i32> @llvm.x86.avx2.pmadd.wd(<16 x i16>, <16 x i16>) 18 | declare <8 x i32> @llvm.x86.avx2.psrai.d(<8 x i32>, i32) 19 | -------------------------------------------------------------------------------- /tests/const/fadd1.constsyn.ll: -------------------------------------------------------------------------------- 1 | define float @src(float %_reservedc) { 2 | entry: 3 | %add1 = fadd float 1.000000e+00, 1.000000e+00 4 | ret float %add1 5 | } 6 | 7 | define float @tgt(float %_reservedc) { 8 | entry: 9 | ret float %_reservedc 10 | } 11 | -------------------------------------------------------------------------------- /tests/const/fadd2.constsyn.ll: -------------------------------------------------------------------------------- 1 | define float @src(float %_reservedc) { 2 | entry: 3 | %add1 = fadd float 1.000000e+00, 0x7FF8000000000000 4 | ret float %add1 5 | } 6 | 7 | define float @tgt(float %_reservedc) { 8 | entry: 9 | ret float %_reservedc 10 | } 11 | -------------------------------------------------------------------------------- /tests/const/fcmp1.constsyn.ll: -------------------------------------------------------------------------------- 1 | define i1 @src(i1 %_reservedc) { 2 | entry: 3 | %add1 = fcmp ole float 1.000000e+00, 0.000000e+00 4 | ret i1 %add1 5 | } 6 | 7 | define i1 @tgt(i1 %_reservedc) { 8 | entry: 9 | ret i1 %_reservedc 10 | } 11 | -------------------------------------------------------------------------------- /tests/const/fcmp2.constsyn.ll: -------------------------------------------------------------------------------- 1 | define i1 @src(i1 %_reservedc) { 2 | entry: 3 | %add1 = fcmp ole float 0.000000e+00, 1.000000e+00 4 | ret i1 %add1 5 | } 6 | 7 | define i1 @tgt(i1 %_reservedc) { 8 | entry: 9 | ret i1 %_reservedc 10 | } 11 | -------------------------------------------------------------------------------- /tests/const/fmul1.constsyn.ll: -------------------------------------------------------------------------------- 1 | define float @src(float %_reservedc) { 2 | entry: 3 | %add1 = fmul float 1.000000e+00, 1.000000e+00 4 | ret float %add1 5 | } 6 | 7 | define float @tgt(float %_reservedc) { 8 | entry: 9 | ret float %_reservedc 10 | } 11 | -------------------------------------------------------------------------------- /tests/const/fmul2.constsyn.ll: -------------------------------------------------------------------------------- 1 | define float @src(float %_reservedc) { 2 | entry: 3 | %add1 = fmul float 0x7FF8000000000000, 0.000000e+00 4 | ret float %add1 5 | } 6 | 7 | define float @tgt(float %_reservedc) { 8 | entry: 9 | ret float %_reservedc 10 | } 11 | -------------------------------------------------------------------------------- /tests/const/fmul3.constsyn.ll: -------------------------------------------------------------------------------- 1 | define float @src(float %_reservedc) { 2 | entry: 3 | %add1 = fmul float 0x7FF8000000000000, 1.000000e+00 4 | ret float %add1 5 | } 6 | 7 | define float @tgt(float %_reservedc) { 8 | entry: 9 | ret float %_reservedc 10 | } 11 | -------------------------------------------------------------------------------- /tests/const/fsub1.constsyn.ll: -------------------------------------------------------------------------------- 1 | define float @src(float %_reservedc) { 2 | entry: 3 | %add1 = fsub float 1.000000e+00, 1.000000e+00 4 | ret float %add1 5 | } 6 | 7 | define float @tgt(float %_reservedc) { 8 | entry: 9 | ret float %_reservedc 10 | } 11 | -------------------------------------------------------------------------------- /tests/const/fsub2.constsyn.ll: -------------------------------------------------------------------------------- 1 | define float @src(float %_reservedc) { 2 | entry: 3 | %add1 = fsub float 1.000000e+00, 0x7FF8000000000000 4 | ret float %add1 5 | } 6 | 7 | define float @tgt(float %_reservedc) { 8 | entry: 9 | ret float %_reservedc 10 | } 11 | -------------------------------------------------------------------------------- /tests/const/shuffle1.constsyn.ll: -------------------------------------------------------------------------------- 1 | define <4 x i16> @src(<4 x i16> %a, <4 x i8> %_reservedc_113) { 2 | entry: 3 | %ext.1 = extractelement <4 x i16> %a, i32 0 4 | %ext.2 = extractelement <4 x i16> %a, i32 1 5 | %ext.3 = extractelement <4 x i16> %a, i32 2 6 | %ext.4 = extractelement <4 x i16> %a, i32 3 7 | %ins.1 = insertelement <4 x i16> undef, i16 %ext.1, i32 3 8 | %ins.2 = insertelement <4 x i16> %ins.1, i16 %ext.2, i32 2 9 | %ins.3 = insertelement <4 x i16> %ins.2, i16 %ext.3, i32 1 10 | %ins.4 = insertelement <4 x i16> %ins.3, i16 %ext.4, i32 0 11 | ret <4 x i16> %ins.4 12 | } 13 | 14 | define <4 x i16> @tgt(<4 x i16> %0, <4 x i8> %_reservedc_113) { 15 | entry: 16 | %sv = call <4 x i16> @__fksv.700(<4 x i16> %0, <4 x i16> poison, <4 x i8> %_reservedc_113) 17 | ret <4 x i16> %sv 18 | 19 | sink: ; No predecessors! 20 | unreachable 21 | } 22 | declare <4 x i16> @__fksv.700(<4 x i16>, <4 x i16>, <4 x i8>) 23 | -------------------------------------------------------------------------------- /tests/const/shuffle2.constsyn.ll: -------------------------------------------------------------------------------- 1 | define <4 x float> @src(<4 x float> %a, <4 x i8> %_reservedc_113) { 2 | entry: 3 | %ext.1 = extractelement <4 x float> %a, i32 0 4 | %ext.2 = extractelement <4 x float> %a, i32 1 5 | %ext.3 = extractelement <4 x float> %a, i32 2 6 | %ext.4 = extractelement <4 x float> %a, i32 3 7 | %ins.1 = insertelement <4 x float> undef, float %ext.1, i32 3 8 | %ins.2 = insertelement <4 x float> %ins.1, float %ext.2, i32 2 9 | %ins.3 = insertelement <4 x float> %ins.2, float %ext.3, i32 1 10 | %ins.4 = insertelement <4 x float> %ins.3, float %ext.4, i32 0 11 | ret <4 x float> %ins.4 12 | } 13 | 14 | define <4 x float> @tgt(<4 x float> %0, <4 x i8> %_reservedc_113) { 15 | entry: 16 | %sv = call <4 x float> @__fksv.700(<4 x float> %0, <4 x float> poison, <4 x i8> %_reservedc_113) 17 | ret <4 x float> %sv 18 | 19 | sink: ; No predecessors! 20 | unreachable 21 | } 22 | declare <4 x float> @__fksv.700(<4 x float>, <4 x float>, <4 x i8>) 23 | -------------------------------------------------------------------------------- /tests/datamovements/extractelement0.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: extractelement <2 x i133> %x, i32 0 2 | define i133 @extractelement_out_of_range(<2 x i133> %x, i32 %i) { 3 | %p = sub i32 %i, %i 4 | %E1 = extractelement <2 x i133> %x, i32 %p 5 | ret i133 %E1 6 | } -------------------------------------------------------------------------------- /tests/datamovements/extractelement1.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: extractelement <2 x i32> %x, i32 0 2 | define i32 @extractelement_out_of_range(<2 x i32> %x, i32 %i) { 3 | %p = sub i32 %i, %i 4 | %E1 = extractelement <2 x i32> %x, i32 %p 5 | ret i32 %E1 6 | } -------------------------------------------------------------------------------- /tests/datamovements/extractelement2.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: extractelement <2 x double> %x, i32 0 2 | define double @extractelement_out_of_range(<2 x double> %x, i32 %i) { 3 | %p = sub i32 %i, %i 4 | %E1 = extractelement <2 x double> %x, i32 %p 5 | ret double %E1 6 | } -------------------------------------------------------------------------------- /tests/datamovements/extractelement3.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: extractelement <6 x i32> %1, i16 0 2 | define i32 @shrinkExtractElt_i64_to_i32_0(<3 x i64> %x) { 3 | %e = extractelement <3 x i64> %x, i32 0 4 | %t = trunc i64 %e to i32 5 | ret i32 %t 6 | } -------------------------------------------------------------------------------- /tests/datamovements/insertelement0.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: and <2 x i3> %x, 2 | define <2 x i3> @extractelement_out_of_range(<2 x i3> %x, i32 %i) { 3 | %p = and <2 x i3> %x, 4 | %q = and <2 x i3> %p, 5 | ret <2 x i3> %q 6 | } -------------------------------------------------------------------------------- /tests/datamovements/insertelement1.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: and <2 x i8> %x, 2 | ; was expecting insertelement <2 x i8> %x, i8 0, i8 1 3 | define <2 x i8> @extractelement_out_of_range(<2 x i8> %x, i32 %i) { 4 | %p = and <2 x i8> %x, 5 | %q = and <2 x i8> %p, 6 | ret <2 x i8> %q 7 | } -------------------------------------------------------------------------------- /tests/datamovements/insertelement10.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: shufflevector <2 x i32> %1, <2 x i32> zeroinitializer, <4 x i32> 2 | define <4 x i32> @extractelement_out_of_range(<4 x i32> %x, i64 %i) { 3 | %f = trunc i64 %i to i32 4 | %g = lshr i64 %i, 32 5 | %h = trunc i64 %g to i32 6 | %b = insertelement <4 x i32> zeroinitializer, i32 %f, i32 0 7 | %c = insertelement <4 x i32> %b, i32 %h, i32 1 8 | ret <4 x i32> %c 9 | } -------------------------------------------------------------------------------- /tests/datamovements/insertelement11.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: shufflevector <2 x i32> %1, <2 x i32> , <4 x i32> 2 | define <4 x i32> @extractelement_out_of_range(<4 x i32> %x, i64 %i) { 3 | %f = trunc i64 %i to i32 4 | %g = lshr i64 %i, 32 5 | %h = trunc i64 %g to i32 6 | %b = insertelement <4 x i32> , i32 %f, i32 0 7 | %c = insertelement <4 x i32> %b, i32 %h, i32 1 8 | ret <4 x i32> %c 9 | } -------------------------------------------------------------------------------- /tests/datamovements/insertelement2.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: insertelement <2 x half> %x, half 0xH7C01, i16 0 2 | define <2 x half> @extractelement_out_of_range(<2 x half> %x, i32 %i) { 3 | %b = insertelement <2 x half> %x, half 0xH7C00, i32 0 4 | %c = insertelement <2 x half> %b, half 0xH7C01, i32 0 5 | ret <2 x half> %c 6 | } -------------------------------------------------------------------------------- /tests/datamovements/insertelement3.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: ret <2 x half> %x 2 | ; TODO: fixme 3 | define <2 x half> @extractelement_out_of_range(<2 x half> %x, i32 %i) { 4 | %b = insertelement <2 x half> %x, half 0xH7C00, i32 1 5 | %c = insertelement <2 x half> %b, half 0xH7C01, i32 4 6 | ret <2 x half> %c 7 | } -------------------------------------------------------------------------------- /tests/datamovements/insertelement4.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: insertelement <2 x half> %x, half %f, i16 1 2 | define <2 x half> @extractelement_out_of_range(<2 x half> %x, half %f) { 3 | %b = insertelement <2 x half> %x, half 0xH7C00, i32 1 4 | %c = insertelement <2 x half> %b, half %f, i32 1 5 | ret <2 x half> %c 6 | } -------------------------------------------------------------------------------- /tests/datamovements/insertelement5.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: insertelement <2 x half> %x, half 0xH7C00, i16 1 2 | define <2 x half> @extractelement_out_of_range(<2 x half> %x, half %f) { 3 | %b = insertelement <2 x half> %x, half %f, i32 1 4 | %c = insertelement <2 x half> %b, half 0xH7C00, i32 1 5 | ret <2 x half> %c 6 | } -------------------------------------------------------------------------------- /tests/datamovements/insertelement6.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: insertelement <2 x half> , half %f, i16 0 2 | define <2 x half> @extractelement_out_of_range(<2 x half> %x, half %f) { 3 | %b = insertelement <2 x half> undef, half %f, i32 0 4 | %c = insertelement <2 x half> %b, half 0xH7C00, i32 1 5 | ret <2 x half> %c 6 | } -------------------------------------------------------------------------------- /tests/datamovements/insertelement7.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: insertelement <2 x half> , half %f, i16 1 2 | define <2 x half> @extractelement_out_of_range(<2 x half> %x, half %f) { 3 | %b = insertelement <2 x half> poison, half %f, i32 1 4 | %c = insertelement <2 x half> %b, half 0xH7C00, i32 0 5 | ret <2 x half> %c 6 | } -------------------------------------------------------------------------------- /tests/datamovements/insertelement8.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: ret <2 x half> 2 | define <2 x half> @extractelement_out_of_range(<2 x half> %x, half %f) { 3 | %b = insertelement <2 x half> poison, half poison, i32 1 4 | %c = insertelement <2 x half> %b, half 0xH7C00, i32 0 5 | ret <2 x half> %c 6 | } -------------------------------------------------------------------------------- /tests/datamovements/insertelement9.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: insertelement <2 x i64> %1, i64 %i, i16 0 2 | define <4 x i32> @extractelement_out_of_range(<4 x i32> %x, i64 %i) { 3 | %f = trunc i64 %i to i32 4 | %g = lshr i64 %i, 32 5 | %h = trunc i64 %g to i32 6 | %b = insertelement <4 x i32> %x, i32 %f, i32 0 7 | %c = insertelement <4 x i32> %b, i32 %h, i32 1 8 | ret <4 x i32> %c 9 | } -------------------------------------------------------------------------------- /tests/datamovements/shuffle1.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: shl <4 x i32> %1, 2 | define <4 x i32> @rewrite(<8 x i16> %0) { 3 | vector.body: 4 | %1 = shufflevector <8 x i16> %0, <8 x i16> poison, <4 x i32> 5 | %2 = zext <4 x i16> %1 to <4 x i32> 6 | %3 = shl nuw <4 x i32> %2, 7 | ret <4 x i32> %3 8 | 9 | sink: ; No predecessors! 10 | unreachable 11 | } 12 | 13 | -------------------------------------------------------------------------------- /tests/datamovements/shuffle2.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: shufflevector <4 x i16> %a, <4 x i16> poison, <4 x i32> 2 | define <4 x i16> @syn_sv1(<4 x i16> %a) { 3 | entry: 4 | %ext.1 = extractelement <4 x i16> %a, i32 0 5 | %ext.2 = extractelement <4 x i16> %a, i32 1 6 | %ext.3 = extractelement <4 x i16> %a, i32 2 7 | %ext.4 = extractelement <4 x i16> %a, i32 3 8 | %ins.1 = insertelement <4 x i16> undef, i16 %ext.1, i32 3 9 | %ins.2 = insertelement <4 x i16> %ins.1, i16 %ext.2, i32 2 10 | %ins.3 = insertelement <4 x i16> %ins.2, i16 %ext.3, i32 1 11 | %ins.4 = insertelement <4 x i16> %ins.3, i16 %ext.4, i32 0 12 | ret <4 x i16> %ins.4 13 | } -------------------------------------------------------------------------------- /tests/datamovements/shuffle3.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: shufflevector 2 | define <3 x i16> @syn_sv2(<3 x i16> %a, <3 x i16> %b) { 3 | entry: 4 | %ext.1 = extractelement <3 x i16> %a, i32 0 5 | %ext.2 = extractelement <3 x i16> %b, i32 1 6 | %ext.3 = extractelement <3 x i16> %b, i32 1 7 | %ins.1 = insertelement <3 x i16> poison, i16 %ext.1, i32 1 8 | %ins.2 = insertelement <3 x i16> %ins.1, i16 %ext.2, i32 0 9 | %ins.3 = insertelement <3 x i16> %ins.2, i16 %ext.3, i32 2 10 | ret <3 x i16> %ins.3 11 | } -------------------------------------------------------------------------------- /tests/datamovements/shuffle4.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: shufflevector 2 | define <2 x i16> @syn_sv3(<2 x i16> %a, <2 x i16> %b) { 3 | entry: 4 | %ext.1 = extractelement <2 x i16> %a, i32 0 5 | %ext.2 = extractelement <2 x i16> %b, i32 1 6 | %ins.1 = insertelement <2 x i16> undef, i16 %ext.1, i32 1 7 | %ins.2 = insertelement <2 x i16> %ins.1, i16 %ext.2, i32 0 8 | ret <2 x i16> %ins.2 9 | } 10 | 11 | -------------------------------------------------------------------------------- /tests/datamovements/shuffle5.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: xor <4 x i1> 2 | define i4 @slice(<4 x i32> %0) { 3 | if.then32: 4 | %1 = icmp eq <4 x i32> %0, 5 | %2 = icmp ne <4 x i32> %0, 6 | %3 = shufflevector <4 x i1> %1, <4 x i1> %2, <4 x i32> 7 | %4 = bitcast <4 x i1> %3 to i4 8 | ret i4 %4 9 | } 10 | 11 | 12 | -------------------------------------------------------------------------------- /tests/datamovements/shuffle6.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: shufflevector <4 x half> %a, <4 x half> poison, <4 x i32> 2 | define <4 x half> @syn_sv1(<4 x half> %a) { 3 | entry: 4 | %ext.1 = extractelement <4 x half> %a, i32 0 5 | %ext.2 = extractelement <4 x half> %a, i32 1 6 | %ext.3 = extractelement <4 x half> %a, i32 2 7 | %ext.4 = extractelement <4 x half> %a, i32 3 8 | %ins.1 = insertelement <4 x half> undef, half %ext.1, i32 3 9 | %ins.2 = insertelement <4 x half> %ins.1, half %ext.2, i32 2 10 | %ins.3 = insertelement <4 x half> %ins.2, half %ext.3, i32 1 11 | %ins.4 = insertelement <4 x half> %ins.3, half %ext.4, i32 0 12 | ret <4 x half> %ins.4 13 | } -------------------------------------------------------------------------------- /tests/datamovements/shuffle7.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: shufflevector <16 x i16> %0, <16 x i16> zeroinitializer 2 | define <4 x i32> @xnn_f16_f32_vcvt_ukernel__scalar_x4_(<16 x i16> %0) { 3 | vector.body: 4 | %1 = shufflevector <16 x i16> %0, <16 x i16> poison, <4 x i32> 5 | %2 = zext <4 x i16> %1 to <4 x i32> 6 | %3 = shl nuw <4 x i32> %2, 7 | ret <4 x i32> %3 8 | 9 | sink: ; No predecessors! 10 | unreachable 11 | } -------------------------------------------------------------------------------- /tests/diff.constsyn.ll: -------------------------------------------------------------------------------- 1 | define <8 x i32> @src(<16 x i16> %wide.vec, <16 x i16> %_reservedc) { 2 | entry: 3 | %strided.vec = shufflevector <16 x i16> %wide.vec, <16 x i16> poison, <8 x i32> 4 | %strided.vec24 = shufflevector <16 x i16> %wide.vec, <16 x i16> poison, <8 x i32> 5 | %a = sext <8 x i16> %strided.vec to <8 x i32> 6 | %b = sext <8 x i16> %strided.vec24 to <8 x i32> 7 | %c = sub nsw <8 x i32> %a, %b 8 | ret <8 x i32> %c 9 | } 10 | 11 | 12 | define <8 x i32> @tgt(<16 x i16> %0, <16 x i16> %_reservedc) { 13 | entry: 14 | %intr = call <8 x i32> @llvm.x86.avx2.pmadd.wd(<16 x i16> %0, <16 x i16> %_reservedc) 15 | ret <8 x i32> %intr 16 | 17 | sink: ; No predecessors! 18 | unreachable 19 | } 20 | 21 | declare <8 x i32> @llvm.x86.avx2.pmadd.wd(<16 x i16>, <16 x i16>) -------------------------------------------------------------------------------- /tests/divergence.ll: -------------------------------------------------------------------------------- 1 | ; Function Attrs: alwaysinline nounwind readnone 2 | define <16 x i32> @divergence(<16 x i32> %a, <16 x i32> %b, i1 %j) #2 { 3 | br i1 %j, label %t1, label %f1 4 | t1: 5 | %a1 = call <16 x i32> @llvm.x86.avx512.mask.padd.d.512(<16 x i32> %a, <16 x i32> %b, <16 x i32> zeroinitializer, i16 43690) 6 | br label %mid 7 | f1: 8 | %a2 = call <16 x i32> @llvm.x86.avx512.mask.padd.d.512(<16 x i32> %a, <16 x i32> %b, <16 x i32> zeroinitializer, i16 21845) 9 | br label %mid 10 | mid: 11 | %ret_1 = phi <16 x i32> [%a1, %t1], [%a2, %f1] 12 | %not_j = icmp eq i1 %j, 0 13 | br i1 %not_j, label %t2, label %f2 14 | t2: 15 | %b1 = call <16 x i32> @llvm.x86.avx512.mask.padd.d.512(<16 x i32> %a, <16 x i32> %b, <16 x i32> zeroinitializer, i16 43690) 16 | br label %final 17 | f2: 18 | %b2 = call <16 x i32> @llvm.x86.avx512.mask.padd.d.512(<16 x i32> %a, <16 x i32> %b, <16 x i32> zeroinitializer, i16 21845) 19 | br label %final 20 | final: 21 | %ret_2 = phi <16 x i32> [%b1, %t2], [%b2, %f2] 22 | %ret = add <16 x i32> %ret_1, %ret_2 23 | ret <16 x i32> %ret 24 | } 25 | 26 | declare <16 x i32> @llvm.x86.avx512.mask.padd.d.512(<16 x i32>, <16 x i32>, <16 x i32>, i16) 27 | 28 | -------------------------------------------------------------------------------- /tests/fcmp_or.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: fcmp oge double %0, %1 2 | define i1 @auto_gen_8_retval(double %0, double %1) { 3 | %3 = fcmp oge double %0, %1 4 | %4 = fcmp ogt double %0, %1 5 | %5 = or i1 %3, %4 6 | ret i1 %5 7 | } 8 | -------------------------------------------------------------------------------- /tests/fp/case1.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: rewrite: (var <1 x float> %1) 2 | define float @src(float %0) { 3 | entry: 4 | %1 = fmul float %0, 0.000000e+00 5 | %2 = fmul float %1, 3.000000e+00 6 | ret float %2 7 | } -------------------------------------------------------------------------------- /tests/fp/case10.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: fcmp oge float %0, 0.000000e+00 2 | define i1 @src(float %0) { 3 | if.end35: 4 | %1 = fmul float %0, 2.000000e+00 5 | %2 = fcmp oge float %1, 0.000000e+00 6 | ret i1 %2 7 | } -------------------------------------------------------------------------------- /tests/fp/case11.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: fcmp oge double %0, 0x4058FFFFF0000000 2 | define i1 @src(double %0) { 3 | if.end155: 4 | %1 = fptrunc double %0 to float 5 | %2 = fcmp oge float %1, 1.000000e+02 6 | ret i1 %2 7 | } -------------------------------------------------------------------------------- /tests/fp/case12.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: fcmp ole float %0, 0x3FE12878E0000000 2 | define i1 @src(float %0) { 3 | %t1 = fmul float %0, 0x3FF0CCCCC0000000 4 | %t2 = fcmp olt float %t1, 0x3FE20418A0000000 5 | ret i1 %t2 6 | } -------------------------------------------------------------------------------- /tests/fp/case13.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: fptosi float %0 to i64 2 | define i64 @src(float %0) { 3 | if.end27: 4 | %1 = fptosi float %0 to i32 5 | %2 = sext i32 %1 to i64 6 | ret i64 %2 7 | 8 | sink: ; No predecessors! 9 | unreachable 10 | } -------------------------------------------------------------------------------- /tests/fp/case14.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: and i32 %1, -2147483648 2 | define i32 @src(float %0) { 3 | if.then83: 4 | %1 = tail call float @llvm.fabs.f32(float %0) 5 | %2 = bitcast float %0 to i32 6 | %3 = bitcast float %1 to i32 7 | %4 = xor i32 %3, %2 8 | ret i32 %4 9 | } 10 | declare float @llvm.fabs.f32(float) -------------------------------------------------------------------------------- /tests/fp/case15.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: (conv 2 | define i32 @src(half %0) { 3 | if.end27: 4 | %1 = fptoui half %0 to i16 5 | %2 = zext i16 %1 to i32 6 | ret i32 %2 7 | 8 | sink: ; No predecessors! 9 | unreachable` 10 | } -------------------------------------------------------------------------------- /tests/fp/case2.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: rewrite: (fadd <2 x double> (var <2 x double> %3) (reservedconst <2 x double> <2 x double> )) 2 | define <2 x double> @src(double %0, double %1, i1 %2, i1 %3, i1 %4) { 3 | if.end: 4 | %5 = fadd double %1, -1.0 5 | %6 = insertelement <2 x double> poison, double %0, i64 0 6 | %7 = insertelement <2 x double> %6, double %5, i64 1 7 | %8 = fadd <2 x double> %7, 8 | ret <2 x double> %8 9 | } 10 | -------------------------------------------------------------------------------- /tests/fp/case3.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: fcmp ogt half %0, %1 2 | define i1 @src(half %0, half %1) { 3 | if.then: 4 | %2 = fsub half %0, %1 5 | %3 = fcmp ogt half %2, 0.000000e+00 6 | ret i1 %3 7 | } 8 | -------------------------------------------------------------------------------- /tests/fp/case4.syn.skip.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: fcmp uno double %0, %1 2 | define i1 @src(double %0, double %1, double %2, double %3, double %4, double %5, i1 %6, i1 %7, i8 %8) { 3 | entry: 4 | %t1 = fcmp uno double %0, 0.000000e+00 5 | %t2 = fcmp uno double %1, 0.000000e+00 6 | %t3 = select i1 %t1, i1 true, i1 %t2 7 | ret i1 %t3 8 | } -------------------------------------------------------------------------------- /tests/fp/case5.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: fcmp oge double %0, 1.280000e+02 2 | declare double @llvm.floor.f64(double) 3 | 4 | define i1 @src(double %0, i1 %1) { 5 | %t2 = fmul double %0, 7.812500e-03 6 | %t3 = call double @llvm.floor.f64(double %t2) 7 | %t4 = fcmp ogt double %t3, 0.000000e+00 8 | ret i1 %t4 9 | 10 | } -------------------------------------------------------------------------------- /tests/fp/case6.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: fcmp oeq float %0, 0.000000e+00 2 | define i1 @src(float %0) { 3 | if.end192: 4 | %1 = fcmp oge float %0, 0.000000e+00 5 | %2 = fneg float %0 6 | %3 = select i1 %1, float %0, float %2 7 | %4 = fcmp oeq float %3, 0.000000e+00 8 | ret i1 %4 9 | } 10 | 11 | -------------------------------------------------------------------------------- /tests/fp/case7.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: select i1 %0, float 1.000000e+00, float -1.000000e+00 2 | define float @src(i1 %0) { 3 | if.else285: 4 | %t2 = select i1 %0, float -1.000000e+00, float 1.000000e+00 5 | %t3 = fneg float %t2 6 | ret float %t3 7 | } -------------------------------------------------------------------------------- /tests/fp/case8.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: xor i1 %t5, %t7 2 | define i1 @src(float %0, float %1, i1 %2, i1 %3, i1 %4) { 3 | %t5 = fcmp ult float %0, 0.000000e+00 4 | %t6 = select i1 %t5, float -1.000000e+00, float 1.000000e+00 5 | %t7 = fcmp ult float %1, 0.000000e+00 6 | %t8 = select i1 %t7, float -1.000000e+00, float 1.000000e+00 7 | %t9 = fcmp une float %t6, %t8 8 | ret i1 %t9 9 | } 10 | -------------------------------------------------------------------------------- /tests/fp/case9.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: select i1 %c2, float %t5, float %t6 2 | define float @src(float %0, float %1, i1 %c1, i1 %c2) { 3 | if.else: 4 | %t4 = fneg float %1 5 | %t5 = select i1 %c1, float %1, float %t4 6 | %t6 = select i1 %c1, float %t4, float %1 7 | %t7 = select i1 %c2, float %t6, float %t5 8 | %t8 = fneg float %t7 9 | ret float %t8 10 | 11 | sink: ; No predecessors! 12 | unreachable 13 | } -------------------------------------------------------------------------------- /tests/fp/copysign0.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: call float @llvm.copysign.f32(float %x, float %y) 2 | define float @fabs_mag(float %x, float %y) { 3 | ; CHECK-LABEL: @fabs_mag( 4 | ; CHECK-NEXT: [[R:%.*]] = call float @llvm.copysign.f32(float [[X:%.*]], float [[Y:%.*]]) 5 | ; CHECK-NEXT: ret float [[R]] 6 | ; 7 | %a = call float @llvm.fabs.f32(float %x) 8 | %r = call float @llvm.copysign.f32(float %a, float %y) 9 | ret float %r 10 | } 11 | 12 | declare float @llvm.fabs.f32(float) 13 | declare float @llvm.copysign.f32(float, float) -------------------------------------------------------------------------------- /tests/fp/copysign1.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: call float @llvm.copysign.f32(float %x, float %y) 2 | define float @fneg_mag(float %x, float %y) { 3 | %n = fneg float %x 4 | %r = call float @llvm.copysign.f32(float %n, float %y) 5 | ret float %r 6 | } 7 | 8 | declare float @llvm.copysign.f32(float, float) -------------------------------------------------------------------------------- /tests/fp/copysign2.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: call float @llvm.copysign.f32(float 1.000000e+00, float %x) 2 | define float @copysign1(float %x) { 3 | %i = bitcast float %x to i32 4 | %ispos = icmp sgt i32 %i, -1 5 | %r = select i1 %ispos, float 1.0, float -1.0 6 | ret float %r 7 | } -------------------------------------------------------------------------------- /tests/fp/fabs0.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: call float @llvm.fabs.f32(float %x) 2 | define float @select_fneg(i1 %c, float %x) { 3 | %n = fneg float %x 4 | %s = select i1 %c, float %n, float %x 5 | %fabs = call float @llvm.fabs.f32(float %s) 6 | ret float %fabs 7 | } 8 | 9 | declare float @llvm.fabs.f32(float) -------------------------------------------------------------------------------- /tests/fp/fabs1.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: ret float %mul 2 | define float @square_nnan_fabs_intrinsic_f32(float %x) { 3 | %mul = fmul nnan float %x, %x 4 | %fabsf = call float @llvm.fabs.f32(float %mul) 5 | ret float %fabsf 6 | } 7 | 8 | declare float @llvm.fabs.f32(float) -------------------------------------------------------------------------------- /tests/fp/fabs2.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: ret float %sq 2 | define float @square_fabs_shrink_call2(float %x) { 3 | ; CHECK-LABEL: @square_fabs_shrink_call2( 4 | ; CHECK-NEXT: [[SQ:%.*]] = fmul float [[X:%.*]], [[X]] 5 | ; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[SQ]]) 6 | ; CHECK-NEXT: ret float [[TMP1]] 7 | ; 8 | %sq = fmul float %x, %x 9 | %ext = fpext float %sq to double 10 | %fabs = call double @llvm.fabs.f64(double %ext) 11 | %trunc = fptrunc double %fabs to float 12 | ret float %trunc 13 | } 14 | 15 | declare double @llvm.fabs.f64(double) -------------------------------------------------------------------------------- /tests/fp/fabs3.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: ret float 0.000000e+00 2 | define float @fabs_select_constant_neg0(i32 %c) { 3 | %cmp = icmp eq i32 %c, 0 4 | %select = select i1 %cmp, float -0.0, float 0.0 5 | %fabs = call float @llvm.fabs.f32(float %select) 6 | ret float %fabs 7 | } 8 | 9 | declare float @llvm.fabs.f32(float) -------------------------------------------------------------------------------- /tests/fp/fabs4.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: ret float %select 2 | define float @fabs_select_constant_negative_negative(i32 %c) { 3 | %cmp = icmp eq i32 %c, 0 4 | %select = select i1 %cmp, float 1.0, float 2.0 5 | %fabs = call float @llvm.fabs.f32(float %select) 6 | ret float %fabs 7 | } 8 | 9 | declare float @llvm.fabs.f32(float) -------------------------------------------------------------------------------- /tests/fp/fabs5.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: select i1 %cmp, float 1.000000e+00, float 2.000000e+00 2 | define float @fabs_select_constant_negative_negative(i32 %c) { 3 | %cmp = icmp eq i32 %c, 0 4 | %select = select i1 %cmp, float -1.0, float -2.0 5 | %fabs = call float @llvm.fabs.f32(float %select) 6 | ret float %fabs 7 | } 8 | 9 | declare float @llvm.fabs.f32(float) -------------------------------------------------------------------------------- /tests/fp/fabs6.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: select i1 %cmp, double 1.000000e+00, double 2.000000e+00 2 | define double @fabs_select_constant_negative_negative(i32 %c) { 3 | %cmp = icmp eq i32 %c, 0 4 | %select = select i1 %cmp, double -1.0, double -2.0 5 | %fabs = call double @llvm.fabs.f64(double %select) 6 | ret double %fabs 7 | } 8 | 9 | declare double @llvm.fabs.f64(double) -------------------------------------------------------------------------------- /tests/fp/fabs7.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: %sel = select i1 %cmp, fp128 0xL00000000000000004000000000000000, fp128 0xL00000D00000000004000000000000000 2 | define fp128 @fabs_select_constant_negative_negative(i32 %c) { 3 | %cmp = icmp eq i32 %c, 0 4 | %select = select i1 %cmp, fp128 0xL0000000000000000C000000000000000, fp128 0xL00000D0000000000C000000000000000 5 | %fabs = call fp128 @llvm.fabs.f128(fp128 %select) 6 | ret fp128 %fabs 7 | } 8 | 9 | declare fp128 @llvm.fabs.f128(fp128) -------------------------------------------------------------------------------- /tests/fp/fadd0.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: fsub half %y, %x 2 | define half @fneg_op0(half %x, half %y) { 3 | %neg = fsub half -0.0, %x 4 | %add = fadd half %neg, %y 5 | ret half %add 6 | } 7 | -------------------------------------------------------------------------------- /tests/fp/fadd1.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: fadd half %a, %b 2 | declare half @llvm.minimum.f16(half %Val0, half %Val1) 3 | declare half @llvm.maximum.f16(half %Val0, half %Val1) 4 | 5 | define half @test(half %a, half %b) { 6 | entry: 7 | %min = call half @llvm.minimum.f16(half %a, half %b) 8 | %max = call half @llvm.maximum.f16(half %a, half %b) 9 | %res = fadd half %min, %max 10 | ret half %res 11 | } 12 | -------------------------------------------------------------------------------- /tests/fp/fadd2.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: fadd float %x, 0.000000e+00 2 | define float @test(float %x) nounwind { 3 | %t1 = fpext float %x to double 4 | %t3 = fadd double %t1, 0.000000e+00 5 | %t34 = fptrunc double %t3 to float 6 | ret float %t34 7 | } -------------------------------------------------------------------------------- /tests/fp/fcmp0.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: fcmp oeq float %0, 0.000000e+00 2 | define i1 @src(float %0) { 3 | if.end192: 4 | %1 = fcmp oge float %0, 0.000000e+00 5 | %2 = fneg float %0 6 | %3 = select i1 %1, float %0, float %2 7 | %4 = fcmp oeq float %3, 0.000000e+00 8 | ret i1 %4 9 | 10 | sink: ; No predecessors! 11 | unreachable 12 | } -------------------------------------------------------------------------------- /tests/fp/fcmp1.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: fcmp oge double %0, 0x4058FFFFF0000000 2 | define i1 @src(double %0) { 3 | if.end155: 4 | %1 = fptrunc double %0 to float 5 | %2 = fcmp oge float %1, 1.000000e+02 6 | ret i1 %2 7 | 8 | sink: ; No predecessors! 9 | unreachable 10 | } -------------------------------------------------------------------------------- /tests/fp/fcmp2.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: fcmp oge double %0, 0x4062BFFFF0000000 2 | define i1 @src(double %0) { 3 | if.end155: 4 | %1 = fptrunc double %0 to float 5 | %2 = fcmp oge float %1, 1.500000e+02 6 | ret i1 %2 7 | 8 | sink: ; No predecessors! 9 | unreachable 10 | } -------------------------------------------------------------------------------- /tests/fp/fcmp3.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: fcmp oge double %0, 0xC07AB00010000000 2 | define i1 @src(double %0) { 3 | if.end155: 4 | %1 = fptrunc double %0 to float 5 | %2 = fcmp oge float %1, -4.270000e02 6 | ret i1 %2 7 | 8 | sink: ; No predecessors! 9 | unreachable 10 | } -------------------------------------------------------------------------------- /tests/fp/fmul0.syn.ll: -------------------------------------------------------------------------------- 1 | define half @test2(half %x, half %y) nounwind { 2 | ; CHECK-LABEL: @test2( 3 | ; CHECK-NEXT: [[T56:%.*]] = fmul half [[X:%.*]], [[Y:%.*]] 4 | ; CHECK-NEXT: ret half [[T56]] 5 | ; 6 | %t1 = fpext half %x to float 7 | %t23 = fpext half %y to float 8 | %t5 = fmul float %t1, %t23 9 | %t56 = fptrunc float %t5 to half 10 | ret half %t56 11 | } -------------------------------------------------------------------------------- /tests/fp/fneg0.syn.skip.ll: -------------------------------------------------------------------------------- 1 | define half @src(half %x, half %y) { 2 | %s = fsub half -0.0, %x 3 | ret half %s 4 | } -------------------------------------------------------------------------------- /tests/fp/fneg1.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: fsub float -0.000000e+00, %x 2 | define float @test4(float %x) nounwind { 3 | ; CHECK-LABEL: @test4( 4 | ; CHECK-NEXT: [[T34:%.*]] = fneg float [[X:%.*]] 5 | ; CHECK-NEXT: ret float [[T34]] 6 | ; 7 | %t1 = fpext float %x to double 8 | %t2 = fsub double -0.000000e+00, %t1 9 | %t34 = fptrunc double %t2 to float 10 | ret float %t34 11 | } -------------------------------------------------------------------------------- /tests/fp/fpext0.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: fpext half %a to float 2 | define float @test8(half %a) nounwind { 3 | %y = fpext half %a to double 4 | %z = fptrunc double %y to float 5 | ret float %z 6 | } -------------------------------------------------------------------------------- /tests/fp/fptrunc0.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: fptrunc float %0 to half 2 | define half @test7(float %a) nounwind { 3 | %y = fpext float %a to double 4 | %z = fptrunc double %y to half 5 | ret half %z 6 | } -------------------------------------------------------------------------------- /tests/fp/maximum0.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: call half @llvm.maximum.f16(half %x, half 0xH3C00) 2 | define half @maximum_f16_1_maximum_p0_val(half %x) { 3 | %y = call half @llvm.maximum.f16(half 0.0, half %x) 4 | %z = call half @llvm.maximum.f16(half %y, half 1.0) 5 | ret half %z 6 | } 7 | 8 | 9 | 10 | declare half @llvm.maximum.f16(half %Val0, half %Val1) 11 | -------------------------------------------------------------------------------- /tests/fp/maximum1.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: call float @llvm.maximum.f32(float %x, float 1.000000e+00) 2 | define float @maximum_f32_1_maximum_p0_val(float %x) { 3 | %y = call float @llvm.maximum.f32(float 0.0, float %x) 4 | %z = call float @llvm.maximum.f32(float %y, float 1.0) 5 | ret float %z 6 | } 7 | 8 | declare float @llvm.maximum.f32(float %Val0, float %Val1) 9 | -------------------------------------------------------------------------------- /tests/fp/maximum2.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: call <2 x float> @llvm.maximum.v2f32(<2 x float> %x, <2 x float> ) 2 | define <2 x float> @maximum_f32_1_maximum_p0_val(<2 x float> %x) { 3 | %y = call <2 x float> @llvm.maximum.v2f32(<2 x float> , <2 x float> %x) 4 | %z = call <2 x float> @llvm.maximum.v2f32(<2 x float> %y, <2 x float> ) 5 | ret <2 x float> %z 6 | } 7 | 8 | 9 | 10 | declare <2 x float> @llvm.maximum.v2f32(<2 x float> %Val0, <2 x float> %Val1) 11 | -------------------------------------------------------------------------------- /tests/fp/maximum3.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: call half @llvm.maximum.f16(half %x, half %y) 2 | define half @reduce_precision(half %x, half %y) { 3 | %x.ext = fpext half %x to float 4 | %y.ext = fpext half %y to float 5 | %maximum = call float @llvm.maximum.f32(float %x.ext, float %y.ext) 6 | %trunc = fptrunc float %maximum to half 7 | ret half %trunc 8 | } 9 | 10 | declare float @llvm.maximum.f32(float, float) -------------------------------------------------------------------------------- /tests/fp/maxnum0.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: call half @llvm.maxnum.f16(half %x, half 0xH3C00) 2 | define half @maximum_f16_1_maxnum_p0_val(half %x) { 3 | %y = call half @llvm.maxnum.f16(half 0.0, half %x) 4 | %z = call half @llvm.maxnum.f16(half %y, half 1.0) 5 | ret half %z 6 | } 7 | 8 | 9 | 10 | declare half @llvm.maxnum.f16(half %Val0, half %Val1) 11 | -------------------------------------------------------------------------------- /tests/fp/maxnum1.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: call float @llvm.maxnum.f32(float %x, float 1.000000e+00) 2 | define float @maxnum_f32_1_maxnum_p0_val(float %x) { 3 | %y = call float @llvm.maxnum.f32(float 0.0, float %x) 4 | %z = call float @llvm.maxnum.f32(float %y, float 1.0) 5 | ret float %z 6 | } 7 | 8 | 9 | 10 | declare float @llvm.maxnum.f32(float %Val0, float %Val1) 11 | -------------------------------------------------------------------------------- /tests/fp/maxnum2.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: call <2 x float> @llvm.maxnum.v2f32(<2 x float> %x, <2 x float> ) 2 | define <2 x float> @maxnum_f32_1_maxnum_p0_val(<2 x float> %x) { 3 | %y = call <2 x float> @llvm.maxnum.v2f32(<2 x float> , <2 x float> %x) 4 | %z = call <2 x float> @llvm.maxnum.v2f32(<2 x float> %y, <2 x float> ) 5 | ret <2 x float> %z 6 | } 7 | 8 | 9 | 10 | declare <2 x float> @llvm.maxnum.v2f32(<2 x float> %Val0, <2 x float> %Val1) 11 | -------------------------------------------------------------------------------- /tests/fp/maxnum3.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: call half @llvm.maxnum.f16(half %x, half %y) 2 | define half @reduce_precision(half %x, half %y) { 3 | %x.ext = fpext half %x to float 4 | %y.ext = fpext half %y to float 5 | %maxnum = call float @llvm.maxnum.f32(float %x.ext, float %y.ext) 6 | %trunc = fptrunc float %maxnum to half 7 | ret half %trunc 8 | } 9 | 10 | declare float @llvm.maxnum.f32(float, float) -------------------------------------------------------------------------------- /tests/fp/minimum0.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: call half @llvm.minimum.f16(half 0xH0000, half %x) 2 | define half @minimum_f16_1_minimum_p0_val(half %x) { 3 | %y = call half @llvm.minimum.f16(half 0.0, half %x) 4 | %z = call half @llvm.minimum.f16(half %y, half 1.0) 5 | ret half %z 6 | } 7 | 8 | 9 | 10 | declare half @llvm.minimum.f16(half %Val0, half %Val1) 11 | -------------------------------------------------------------------------------- /tests/fp/minimum1.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: call float @llvm.minimum.f32(float 0.000000e+00, float %x) 2 | define float @minimum_f32_1_minimum_p0_val(float %x) { 3 | %y = call float @llvm.minimum.f32(float 0.0, float %x) 4 | %z = call float @llvm.minimum.f32(float %y, float 1.0) 5 | ret float %z 6 | } 7 | 8 | declare float @llvm.minimum.f32(float %Val0, float %Val1) 9 | -------------------------------------------------------------------------------- /tests/fp/minimum2.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: call <2 x float> @llvm.minimum.v2f32(<2 x float> %x, <2 x float> zeroinitializer) 2 | define <2 x float> @minimum_f32_1_minimum_p0_val(<2 x float> %x) { 3 | %y = call <2 x float> @llvm.minimum.v2f32(<2 x float> , <2 x float> %x) 4 | %z = call <2 x float> @llvm.minimum.v2f32(<2 x float> %y, <2 x float> ) 5 | ret <2 x float> %z 6 | } 7 | 8 | 9 | 10 | declare <2 x float> @llvm.minimum.v2f32(<2 x float> %Val0, <2 x float> %Val1) 11 | -------------------------------------------------------------------------------- /tests/fp/minimum3.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: call half @llvm.minimum.f16(half %x, half %y) 2 | define half @reduce_precision(half %x, half %y) { 3 | %x.ext = fpext half %x to float 4 | %y.ext = fpext half %y to float 5 | %minimum = call float @llvm.minimum.f32(float %x.ext, float %y.ext) 6 | %trunc = fptrunc float %minimum to half 7 | ret half %trunc 8 | } 9 | 10 | declare float @llvm.minimum.f32(float, float) -------------------------------------------------------------------------------- /tests/fp/minnum0.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: call half @llvm.minnum.f16(half 0xH0000, half %x) 2 | define half @maximum_f16_1_minnum_p0_val(half %x) { 3 | %y = call half @llvm.minnum.f16(half 0.0, half %x) 4 | %z = call half @llvm.minnum.f16(half %y, half 1.0) 5 | ret half %z 6 | } 7 | 8 | 9 | 10 | declare half @llvm.minnum.f16(half %Val0, half %Val1) 11 | -------------------------------------------------------------------------------- /tests/fp/minnum1.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: call float @llvm.minnum.f32(float 0.000000e+00, float %x) 2 | define float @minnum_f32_1_minnum_p0_val(float %x) { 3 | %y = call float @llvm.minnum.f32(float 0.0, float %x) 4 | %z = call float @llvm.minnum.f32(float %y, float 1.0) 5 | ret float %z 6 | } 7 | 8 | 9 | 10 | declare float @llvm.minnum.f32(float %Val0, float %Val1) 11 | -------------------------------------------------------------------------------- /tests/fp/minnum2.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: call <2 x float> @llvm.minnum.v2f32(<2 x float> %x, <2 x float> zeroinitializer) 2 | define <2 x float> @minnum_f32_1_minnum_p0_val(<2 x float> %x) { 3 | %y = call <2 x float> @llvm.minnum.v2f32(<2 x float> , <2 x float> %x) 4 | %z = call <2 x float> @llvm.minnum.v2f32(<2 x float> %y, <2 x float> ) 5 | ret <2 x float> %z 6 | } 7 | 8 | 9 | 10 | declare <2 x float> @llvm.minnum.v2f32(<2 x float> %Val0, <2 x float> %Val1) 11 | -------------------------------------------------------------------------------- /tests/fp/minnum3.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: call half @llvm.minnum.f16(half %x, half %y) 2 | define half @reduce_precision(half %x, half %y) { 3 | %x.ext = fpext half %x to float 4 | %y.ext = fpext half %y to float 5 | %minnum = call float @llvm.minnum.f32(float %x.ext, float %y.ext) 6 | %trunc = fptrunc float %minnum to half 7 | ret half %trunc 8 | } 9 | 10 | declare float @llvm.minnum.f32(float, float) -------------------------------------------------------------------------------- /tests/fp/sitofp0.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: sitofp i24 %i to fp128 2 | define fp128 @ItoFtoF_u24_f32_f128(i24 %i) { 3 | ; CHECK-LABEL: @ItoFtoF_u24_f32_f128( 4 | ; CHECK-NEXT: [[R:%.*]] = uitofp i24 [[I:%.*]] to fp128 5 | ; CHECK-NEXT: ret fp128 [[R]] 6 | ; 7 | %x = sitofp i24 %i to float 8 | %r = fpext float %x to fp128 9 | ret fp128 %r 10 | } 11 | -------------------------------------------------------------------------------- /tests/fp/sitofp1.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: sitofp <2 x i23> %i to <2 x fp128> 2 | define <2 x fp128> @ItoFtoF_u24_f32_f128(<2 x i23> %i) { 3 | ; CHECK-LABEL: @ItoFtoF_u24_f32_f128( 4 | ; CHECK-NEXT: [[R:%.*]] = uitofp i24 [[I:%.*]] to fp128 5 | ; CHECK-NEXT: ret fp128 [[R]] 6 | ; 7 | %x = sitofp <2 x i23> %i to <2 x float> 8 | %r = fpext <2 x float> %x to <2 x fp128> 9 | ret <2 x fp128> %r 10 | } 11 | -------------------------------------------------------------------------------- /tests/fp/sitofp2.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: sitofp i32 %i to double 2 | define double @FtoItoFtoF_f32_s32_f32_f64(float %f) { 3 | %i = fptosi float %f to i32 4 | %x = sitofp i32 %i to float 5 | %r = fpext float %x to double 6 | ret double %r 7 | } -------------------------------------------------------------------------------- /tests/fp/trunc0.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: store volatile double 1.000000e+00, ptr %P, align 8 2 | ; CHECK-NEXT: store volatile double -1.000000e+00, ptr %P, align 8 3 | 4 | define void @trunc(ptr %P) { 5 | %B = tail call double @llvm.trunc.f64(double 1.5) nounwind 6 | store volatile double %B, ptr %P 7 | %C = tail call double @llvm.trunc.f64(double -1.5) nounwind 8 | store volatile double %C, ptr %P 9 | ret void 10 | } 11 | 12 | declare double @llvm.trunc.f64(double %Val) -------------------------------------------------------------------------------- /tests/fp/uitofp0.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: uitofp i24 %i to fp128 2 | define fp128 @ItoFtoF_u24_f32_f128(i24 %i) { 3 | ; CHECK-LABEL: @ItoFtoF_u24_f32_f128( 4 | ; CHECK-NEXT: [[R:%.*]] = uitofp i24 [[I:%.*]] to fp128 5 | ; CHECK-NEXT: ret fp128 [[R]] 6 | ; 7 | %x = uitofp i24 %i to float 8 | %r = fpext float %x to fp128 9 | ret fp128 %r 10 | } 11 | -------------------------------------------------------------------------------- /tests/fp/uitofp1.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: uitofp <2 x i23> %i to <2 x fp128> 2 | define <2 x fp128> @ItoFtoF_u24_f32_f128(<2 x i23> %i) { 3 | ; CHECK-LABEL: @ItoFtoF_u24_f32_f128( 4 | ; CHECK-NEXT: [[R:%.*]] = uitofp i24 [[I:%.*]] to fp128 5 | ; CHECK-NEXT: ret fp128 [[R]] 6 | ; 7 | %x = uitofp <2 x i23> %i to <2 x float> 8 | %r = fpext <2 x float> %x to <2 x fp128> 9 | ret <2 x fp128> %r 10 | } 11 | -------------------------------------------------------------------------------- /tests/fp/uitofp2.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: uitofp i24 %i to double 2 | define double @ItoFtoF_u24_f32_f128(i24 %i) { 3 | %x = uitofp i24 %i to float 4 | %r = fpext float %x to double 5 | ret double %r 6 | } -------------------------------------------------------------------------------- /tests/hacks/pmaddwd-merge.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: 2 | 3 | ; long duration test case 4 | 5 | define <8 x i32> @sliced_(<16 x i16> %0) { 6 | entry: 7 | %1 = call <8 x i32> @llvm.x86.avx2.pmadd.wd(<16 x i16> %0, <16 x i16> ) 8 | %2 = call <8 x i32> @llvm.x86.avx2.pmadd.wd(<16 x i16> %0, <16 x i16> ) 9 | %3 = sub nsw <8 x i32> %2, %1 10 | ret <8 x i32> %3 11 | } 12 | 13 | declare <8 x i32> @llvm.x86.avx2.pmadd.wd(<16 x i16>, <16 x i16>) -------------------------------------------------------------------------------- /tests/hacks/psll.syn.skip.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: pslli 2 | define <2 x i64> @sliced_(i32 %0) { entry: 3 | %1 = and i32 %0, 7 4 | %2 = icmp eq i32 %1, 7 5 | %3 = select i1 %2, i32 6, i32 %1 6 | %4 = icmp eq i32 %1, 0 7 | %5 = select i1 %4, i32 1, i32 %3 8 | %6 = add nsw i32 %5, -1 9 | %7 = insertelement <2 x i32> poison, i32 %5, i32 0 10 | %8 = insertelement <2 x i32> %7, i32 %6, i32 1 11 | %9 = zext <2 x i32> %8 to <2 x i64> 12 | %10 = shl <2 x i64> , %9 13 | ret <2 x i64> %10 14 | } 15 | -------------------------------------------------------------------------------- /tests/hacks/shuffle-ext-to-pmaddwd1.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: changed 2 | define <8 x i32> @sliced_b(<16 x i16> %0) { 3 | entry: 4 | %1 = shufflevector <16 x i16> %0, <16 x i16> poison, <8 x i32> 5 | %2 = sext <8 x i16> %1 to <8 x i32> 6 | ret <8 x i32> %2 7 | } 8 | -------------------------------------------------------------------------------- /tests/hacks/shuffle-ext-to-pmaddwd2.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: 2 | define <8 x i32> @sliced_b(<16 x i16> %0) { 3 | entry: 4 | %1 = shufflevector <16 x i16> %0, <16 x i16> poison, <8 x i32> 5 | %2 = sext <8 x i16> %1 to <8 x i32> 6 | ret <8 x i32> %2 7 | } 8 | -------------------------------------------------------------------------------- /tests/hacks/shuffle-ext-to-pmaddwd3.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: 2 | define <8 x i32> @sliced_b(<16 x i16> %0) { 3 | entry: 4 | %1 = shufflevector <16 x i16> %0, <16 x i16> poison, <8 x i32> 5 | %2 = sext <8 x i16> %1 to <8 x i32> 6 | ret <8 x i32> %2 7 | } 8 | -------------------------------------------------------------------------------- /tests/hacks/shuffle-ext-to-pmaddwd4.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: 2 | define <8 x i32> @sliced_b(<16 x i16> %0) { 3 | entry: 4 | %1 = shufflevector <16 x i16> %0, <16 x i16> poison, <8 x i32> 5 | %2 = sext <8 x i16> %1 to <8 x i32> 6 | ret <8 x i32> %2 7 | } 8 | -------------------------------------------------------------------------------- /tests/icmp0.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: icmp sle i32 %0, %1 2 | define i1 @sggrqf__cmp106(i32 %0, i32 %1) { 3 | if.end92: 4 | %2 = sub nsw i32 %0, %1 5 | %3 = icmp slt i32 %2, 1 6 | ret i1 %3 7 | 8 | sink: ; No predecessors! 9 | unreachable 10 | } 11 | -------------------------------------------------------------------------------- /tests/icmp1.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: icmp eq i8 %x, 0 2 | define i1 @syn_icmp_1(i8 %x) { 3 | %ia = zext i8 %x to i16 4 | %ib = icmp eq i16 0, %ia 5 | ret i1 %ib 6 | } 7 | -------------------------------------------------------------------------------- /tests/issue_16.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: icmp ugt i64 %0, -4503599627370497 2 | define i1 @rewrite(i64 %0) { 3 | if.end25: 4 | %1 = lshr i64 %0, 52 5 | %2 = trunc i64 %1 to i32 6 | %3 = icmp eq i32 %2, 4095 7 | ret i1 %3 8 | 9 | sink: ; No predecessors! 10 | unreachable 11 | } 12 | -------------------------------------------------------------------------------- /tests/lit.cfg.py: -------------------------------------------------------------------------------- 1 | import os 2 | import lit.formats 3 | 4 | config.name = 'Minotaur' 5 | config.test_format = lit.formats.MinotaurTest() 6 | config.test_source_root = os.path.dirname(__file__) 7 | -------------------------------------------------------------------------------- /tests/lit/README.txt: -------------------------------------------------------------------------------- 1 | =============================== 2 | lit - A Software Testing Tool 3 | =============================== 4 | 5 | lit is a portable tool for executing LLVM and Clang style test suites, 6 | summarizing their results, and providing indication of failures. lit is designed 7 | to be a lightweight testing tool with as simple a user interface as possible. 8 | 9 | ===================== 10 | Contributing to lit 11 | ===================== 12 | 13 | Please browse the Test Suite > lit category in LLVM's Bugzilla for ideas on 14 | what to work on. 15 | 16 | Before submitting patches, run the test suite to ensure nothing has regressed: 17 | 18 | # From within your LLVM source directory. 19 | utils/lit/lit.py \ 20 | --path /path/to/your/llvm/build/bin \ 21 | utils/lit/tests 22 | 23 | Note that lit's tests depend on 'not' and 'FileCheck', LLVM utilities. 24 | You will need to have built LLVM tools in order to run lit's test suite 25 | successfully. 26 | 27 | You'll also want to confirm that lit continues to work when testing LLVM. 28 | Follow the instructions in http://llvm.org/docs/TestingGuide.html to run the 29 | regression test suite: 30 | 31 | make check-llvm 32 | 33 | And be sure to run the llvm-lit wrapper script as well: 34 | 35 | /path/to/your/llvm/build/bin/llvm-lit utils/lit/tests 36 | 37 | Finally, make sure lit works when installed via setuptools: 38 | 39 | python utils/lit/setup.py install 40 | lit --path /path/to/your/llvm/build/bin utils/lit/tests 41 | 42 | -------------------------------------------------------------------------------- /tests/lit/lit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | 4 | from lit.main import main 5 | 6 | if __name__=='__main__': 7 | main() 8 | -------------------------------------------------------------------------------- /tests/lit/lit/LitConfig.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | import inspect 3 | import os 4 | import sys 5 | 6 | import lit.Test 7 | import lit.formats 8 | import lit.TestingConfig 9 | import lit.util 10 | 11 | # LitConfig must be a new style class for properties to work 12 | class LitConfig(object): 13 | """LitConfig - Configuration data for a 'lit' test runner instance, shared 14 | across all tests. 15 | 16 | The LitConfig object is also used to communicate with client configuration 17 | files, it is always passed in as the global variable 'lit' so that 18 | configuration files can access common functionality and internal components 19 | easily. 20 | """ 21 | 22 | def __init__(self, progname, path, quiet, 23 | useValgrind, valgrindLeakCheck, valgrindArgs, 24 | noExecute, debug, isWindows, singleProcess, 25 | params, config_prefix = None, 26 | maxIndividualTestTime = 0, 27 | maxFailures = None, 28 | parallelism_groups = {}, 29 | echo_all_commands = False): 30 | # The name of the test runner. 31 | self.progname = progname 32 | # The items to add to the PATH environment variable. 33 | self.path = [str(p) for p in path] 34 | self.quiet = bool(quiet) 35 | self.useValgrind = bool(useValgrind) 36 | self.valgrindLeakCheck = bool(valgrindLeakCheck) 37 | self.valgrindUserArgs = list(valgrindArgs) 38 | self.noExecute = noExecute 39 | self.debug = debug 40 | self.singleProcess = singleProcess 41 | self.isWindows = bool(isWindows) 42 | self.params = dict(params) 43 | self.bashPath = None 44 | 45 | # Configuration files to look for when discovering test suites. 46 | self.config_prefix = config_prefix or 'lit' 47 | self.suffixes = ['cfg.py', 'cfg'] 48 | self.config_names = ['%s.%s' % (self.config_prefix,x) for x in self.suffixes] 49 | self.site_config_names = ['%s.site.%s' % (self.config_prefix,x) for x in self.suffixes] 50 | self.local_config_names = ['%s.local.%s' % (self.config_prefix,x) for x in self.suffixes] 51 | 52 | self.numErrors = 0 53 | self.numWarnings = 0 54 | 55 | self.valgrindArgs = [] 56 | if self.useValgrind: 57 | self.valgrindArgs = ['valgrind', '-q', '--run-libc-freeres=no', 58 | '--tool=memcheck', '--trace-children=yes', 59 | '--error-exitcode=123'] 60 | if self.valgrindLeakCheck: 61 | self.valgrindArgs.append('--leak-check=full') 62 | else: 63 | # The default is 'summary'. 64 | self.valgrindArgs.append('--leak-check=no') 65 | self.valgrindArgs.extend(self.valgrindUserArgs) 66 | 67 | self.maxIndividualTestTime = maxIndividualTestTime 68 | self.maxFailures = maxFailures 69 | self.parallelism_groups = parallelism_groups 70 | self.echo_all_commands = echo_all_commands 71 | 72 | @property 73 | def maxIndividualTestTime(self): 74 | """ 75 | Interface for getting maximum time to spend executing 76 | a single test 77 | """ 78 | return self._maxIndividualTestTime 79 | 80 | @maxIndividualTestTime.setter 81 | def maxIndividualTestTime(self, value): 82 | """ 83 | Interface for setting maximum time to spend executing 84 | a single test 85 | """ 86 | if not isinstance(value, int): 87 | self.fatal('maxIndividualTestTime must set to a value of type int.') 88 | self._maxIndividualTestTime = value 89 | if self.maxIndividualTestTime > 0: 90 | # The current implementation needs psutil to set 91 | # a timeout per test. Check it's available. 92 | # See lit.util.killProcessAndChildren() 93 | try: 94 | import psutil # noqa: F401 95 | except ImportError: 96 | self.fatal("Setting a timeout per test requires the" 97 | " Python psutil module but it could not be" 98 | " found. Try installing it via pip or via" 99 | " your operating system's package manager.") 100 | elif self.maxIndividualTestTime < 0: 101 | self.fatal('The timeout per test must be >= 0 seconds') 102 | 103 | def load_config(self, config, path): 104 | """load_config(config, path) - Load a config object from an alternate 105 | path.""" 106 | if self.debug: 107 | self.note('load_config from %r' % path) 108 | config.load_from_path(path, self) 109 | return config 110 | 111 | def getBashPath(self): 112 | """getBashPath - Get the path to 'bash'""" 113 | if self.bashPath is not None: 114 | return self.bashPath 115 | 116 | self.bashPath = lit.util.which('bash', os.pathsep.join(self.path)) 117 | if self.bashPath is None: 118 | self.bashPath = lit.util.which('bash') 119 | 120 | if self.bashPath is None: 121 | self.bashPath = '' 122 | 123 | return self.bashPath 124 | 125 | def getToolsPath(self, dir, paths, tools): 126 | if dir is not None and os.path.isabs(dir) and os.path.isdir(dir): 127 | if not lit.util.checkToolsPath(dir, tools): 128 | return None 129 | else: 130 | dir = lit.util.whichTools(tools, paths) 131 | 132 | # bash 133 | self.bashPath = lit.util.which('bash', dir) 134 | if self.bashPath is None: 135 | self.bashPath = '' 136 | 137 | return dir 138 | 139 | def _write_message(self, kind, message): 140 | # Get the file/line where this message was generated. 141 | f = inspect.currentframe() 142 | # Step out of _write_message, and then out of wrapper. 143 | f = f.f_back.f_back 144 | file,line,_,_,_ = inspect.getframeinfo(f) 145 | location = '%s:%d' % (file, line) 146 | 147 | sys.stderr.write('%s: %s: %s: %s\n' % (self.progname, location, 148 | kind, message)) 149 | 150 | def note(self, message): 151 | self._write_message('note', message) 152 | 153 | def warning(self, message): 154 | self._write_message('warning', message) 155 | self.numWarnings += 1 156 | 157 | def error(self, message): 158 | self._write_message('error', message) 159 | self.numErrors += 1 160 | 161 | def fatal(self, message): 162 | self._write_message('fatal', message) 163 | sys.exit(2) 164 | -------------------------------------------------------------------------------- /tests/lit/lit/ShCommands.py: -------------------------------------------------------------------------------- 1 | class Command: 2 | def __init__(self, args, redirects): 3 | self.args = list(args) 4 | self.redirects = list(redirects) 5 | 6 | def __repr__(self): 7 | return 'Command(%r, %r)' % (self.args, self.redirects) 8 | 9 | def __eq__(self, other): 10 | if not isinstance(other, Command): 11 | return False 12 | 13 | return ((self.args, self.redirects) == 14 | (other.args, other.redirects)) 15 | 16 | def toShell(self, file): 17 | for arg in self.args: 18 | if "'" not in arg: 19 | quoted = "'%s'" % arg 20 | elif '"' not in arg and '$' not in arg: 21 | quoted = '"%s"' % arg 22 | else: 23 | raise NotImplementedError('Unable to quote %r' % arg) 24 | file.write(quoted) 25 | 26 | # For debugging / validation. 27 | import ShUtil 28 | dequoted = list(ShUtil.ShLexer(quoted).lex()) 29 | if dequoted != [arg]: 30 | raise NotImplementedError('Unable to quote %r' % arg) 31 | 32 | for r in self.redirects: 33 | if len(r[0]) == 1: 34 | file.write("%s '%s'" % (r[0][0], r[1])) 35 | else: 36 | file.write("%s%s '%s'" % (r[0][1], r[0][0], r[1])) 37 | 38 | class GlobItem: 39 | def __init__(self, pattern): 40 | self.pattern = pattern 41 | 42 | def __repr__(self): 43 | return self.pattern 44 | 45 | def __eq__(self, other): 46 | if not isinstance(other, Command): 47 | return False 48 | 49 | return (self.pattern == other.pattern) 50 | 51 | def resolve(self, cwd): 52 | import glob 53 | import os 54 | if os.path.isabs(self.pattern): 55 | abspath = self.pattern 56 | else: 57 | abspath = os.path.join(cwd, self.pattern) 58 | results = glob.glob(abspath) 59 | return [self.pattern] if len(results) == 0 else results 60 | 61 | class Pipeline: 62 | def __init__(self, commands, negate=False, pipe_err=False): 63 | self.commands = commands 64 | self.negate = negate 65 | self.pipe_err = pipe_err 66 | 67 | def __repr__(self): 68 | return 'Pipeline(%r, %r, %r)' % (self.commands, self.negate, 69 | self.pipe_err) 70 | 71 | def __eq__(self, other): 72 | if not isinstance(other, Pipeline): 73 | return False 74 | 75 | return ((self.commands, self.negate, self.pipe_err) == 76 | (other.commands, other.negate, self.pipe_err)) 77 | 78 | def toShell(self, file, pipefail=False): 79 | if pipefail != self.pipe_err: 80 | raise ValueError('Inconsistent "pipefail" attribute!') 81 | if self.negate: 82 | file.write('! ') 83 | for cmd in self.commands: 84 | cmd.toShell(file) 85 | if cmd is not self.commands[-1]: 86 | file.write('|\n ') 87 | 88 | class Seq: 89 | def __init__(self, lhs, op, rhs): 90 | assert op in (';', '&', '||', '&&') 91 | self.op = op 92 | self.lhs = lhs 93 | self.rhs = rhs 94 | 95 | def __repr__(self): 96 | return 'Seq(%r, %r, %r)' % (self.lhs, self.op, self.rhs) 97 | 98 | def __eq__(self, other): 99 | if not isinstance(other, Seq): 100 | return False 101 | 102 | return ((self.lhs, self.op, self.rhs) == 103 | (other.lhs, other.op, other.rhs)) 104 | 105 | def toShell(self, file, pipefail=False): 106 | self.lhs.toShell(file, pipefail) 107 | file.write(' %s\n' % self.op) 108 | self.rhs.toShell(file, pipefail) 109 | -------------------------------------------------------------------------------- /tests/lit/lit/ShUtil.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | import itertools 3 | 4 | import lit.util 5 | from lit.ShCommands import Command, GlobItem, Pipeline, Seq 6 | 7 | class ShLexer: 8 | def __init__(self, data, win32Escapes = False): 9 | self.data = data 10 | self.pos = 0 11 | self.end = len(data) 12 | self.win32Escapes = win32Escapes 13 | 14 | def eat(self): 15 | c = self.data[self.pos] 16 | self.pos += 1 17 | return c 18 | 19 | def look(self): 20 | return self.data[self.pos] 21 | 22 | def maybe_eat(self, c): 23 | """ 24 | maybe_eat(c) - Consume the character c if it is the next character, 25 | returning True if a character was consumed. """ 26 | if self.data[self.pos] == c: 27 | self.pos += 1 28 | return True 29 | return False 30 | 31 | def lex_arg_fast(self, c): 32 | # Get the leading whitespace free section. 33 | chunk = self.data[self.pos - 1:].split(None, 1)[0] 34 | 35 | # If it has special characters, the fast path failed. 36 | if ('|' in chunk or '&' in chunk or 37 | '<' in chunk or '>' in chunk or 38 | "'" in chunk or '"' in chunk or 39 | ';' in chunk or '\\' in chunk): 40 | return None 41 | 42 | self.pos = self.pos - 1 + len(chunk) 43 | return GlobItem(chunk) if '*' in chunk or '?' in chunk else chunk 44 | 45 | def lex_arg_slow(self, c): 46 | if c in "'\"": 47 | str = self.lex_arg_quoted(c) 48 | else: 49 | str = c 50 | unquoted_glob_char = False 51 | quoted_glob_char = False 52 | while self.pos != self.end: 53 | c = self.look() 54 | if c.isspace() or c in "|&;": 55 | break 56 | elif c in '><': 57 | # This is an annoying case; we treat '2>' as a single token so 58 | # we don't have to track whitespace tokens. 59 | 60 | # If the parse string isn't an integer, do the usual thing. 61 | if not str.isdigit(): 62 | break 63 | 64 | # Otherwise, lex the operator and convert to a redirection 65 | # token. 66 | num = int(str) 67 | tok = self.lex_one_token() 68 | assert isinstance(tok, tuple) and len(tok) == 1 69 | return (tok[0], num) 70 | elif c == '"' or c == "'": 71 | self.eat() 72 | quoted_arg = self.lex_arg_quoted(c) 73 | if '*' in quoted_arg or '?' in quoted_arg: 74 | quoted_glob_char = True 75 | str += quoted_arg 76 | elif not self.win32Escapes and c == '\\': 77 | # Outside of a string, '\\' escapes everything. 78 | self.eat() 79 | if self.pos == self.end: 80 | lit.util.warning( 81 | "escape at end of quoted argument in: %r" % self.data) 82 | return str 83 | str += self.eat() 84 | elif c in '*?': 85 | unquoted_glob_char = True 86 | str += self.eat() 87 | else: 88 | str += self.eat() 89 | # If a quote character is present, lex_arg_quoted will remove the quotes 90 | # and append the argument directly. This causes a problem when the 91 | # quoted portion contains a glob character, as the character will no 92 | # longer be treated literally. If glob characters occur *only* inside 93 | # of quotes, then we can handle this by not globbing at all, and if 94 | # glob characters occur *only* outside of quotes, we can still glob just 95 | # fine. But if a glob character occurs both inside and outside of 96 | # quotes this presents a problem. In practice this is such an obscure 97 | # edge case that it doesn't seem worth the added complexity to support. 98 | # By adding an assertion, it means some bot somewhere will catch this 99 | # and flag the user of a non-portable test (which could almost certainly 100 | # be re-written to work correctly without triggering this). 101 | assert not (quoted_glob_char and unquoted_glob_char) 102 | return GlobItem(str) if unquoted_glob_char else str 103 | 104 | def lex_arg_quoted(self, delim): 105 | str = '' 106 | while self.pos != self.end: 107 | c = self.eat() 108 | if c == delim: 109 | return str 110 | elif c == '\\' and delim == '"': 111 | # Inside a '"' quoted string, '\\' only escapes the quote 112 | # character and backslash, otherwise it is preserved. 113 | if self.pos == self.end: 114 | lit.util.warning( 115 | "escape at end of quoted argument in: %r" % self.data) 116 | return str 117 | c = self.eat() 118 | if c == '"': # 119 | str += '"' 120 | elif c == '\\': 121 | str += '\\' 122 | else: 123 | str += '\\' + c 124 | else: 125 | str += c 126 | lit.util.warning("missing quote character in %r" % self.data) 127 | return str 128 | 129 | def lex_arg_checked(self, c): 130 | pos = self.pos 131 | res = self.lex_arg_fast(c) 132 | end = self.pos 133 | 134 | self.pos = pos 135 | reference = self.lex_arg_slow(c) 136 | if res is not None: 137 | if res != reference: 138 | raise ValueError("Fast path failure: %r != %r" % ( 139 | res, reference)) 140 | if self.pos != end: 141 | raise ValueError("Fast path failure: %r != %r" % ( 142 | self.pos, end)) 143 | return reference 144 | 145 | def lex_arg(self, c): 146 | return self.lex_arg_fast(c) or self.lex_arg_slow(c) 147 | 148 | def lex_one_token(self): 149 | """ 150 | lex_one_token - Lex a single 'sh' token. """ 151 | 152 | c = self.eat() 153 | if c == ';': 154 | return (c,) 155 | if c == '|': 156 | if self.maybe_eat('|'): 157 | return ('||',) 158 | return (c,) 159 | if c == '&': 160 | if self.maybe_eat('&'): 161 | return ('&&',) 162 | if self.maybe_eat('>'): 163 | return ('&>',) 164 | return (c,) 165 | if c == '>': 166 | if self.maybe_eat('&'): 167 | return ('>&',) 168 | if self.maybe_eat('>'): 169 | return ('>>',) 170 | return (c,) 171 | if c == '<': 172 | if self.maybe_eat('&'): 173 | return ('<&',) 174 | if self.maybe_eat('>'): 175 | return ('<<',) 176 | return (c,) 177 | 178 | return self.lex_arg(c) 179 | 180 | def lex(self): 181 | while self.pos != self.end: 182 | if self.look().isspace(): 183 | self.eat() 184 | else: 185 | yield self.lex_one_token() 186 | 187 | ### 188 | 189 | class ShParser: 190 | def __init__(self, data, win32Escapes = False, pipefail = False): 191 | self.data = data 192 | self.pipefail = pipefail 193 | self.tokens = ShLexer(data, win32Escapes = win32Escapes).lex() 194 | 195 | def lex(self): 196 | for item in self.tokens: 197 | return item 198 | return None 199 | 200 | def look(self): 201 | token = self.lex() 202 | if token is not None: 203 | self.tokens = itertools.chain([token], self.tokens) 204 | return token 205 | 206 | def parse_command(self): 207 | tok = self.lex() 208 | if not tok: 209 | raise ValueError("empty command!") 210 | if isinstance(tok, tuple): 211 | raise ValueError("syntax error near unexpected token %r" % tok[0]) 212 | 213 | args = [tok] 214 | redirects = [] 215 | while 1: 216 | tok = self.look() 217 | 218 | # EOF? 219 | if tok is None: 220 | break 221 | 222 | # If this is an argument, just add it to the current command. 223 | if isinstance(tok, (str, GlobItem)): 224 | args.append(self.lex()) 225 | continue 226 | 227 | # Otherwise see if it is a terminator. 228 | assert isinstance(tok, tuple) 229 | if tok[0] in ('|',';','&','||','&&'): 230 | break 231 | 232 | # Otherwise it must be a redirection. 233 | op = self.lex() 234 | arg = self.lex() 235 | if not arg: 236 | raise ValueError("syntax error near token %r" % op[0]) 237 | redirects.append((op, arg)) 238 | 239 | return Command(args, redirects) 240 | 241 | def parse_pipeline(self): 242 | negate = False 243 | 244 | commands = [self.parse_command()] 245 | while self.look() == ('|',): 246 | self.lex() 247 | commands.append(self.parse_command()) 248 | return Pipeline(commands, negate, self.pipefail) 249 | 250 | def parse(self): 251 | lhs = self.parse_pipeline() 252 | 253 | while self.look(): 254 | operator = self.lex() 255 | assert isinstance(operator, tuple) and len(operator) == 1 256 | 257 | if not self.look(): 258 | raise ValueError( 259 | "missing argument to operator %r" % operator[0]) 260 | 261 | # FIXME: Operator precedence!! 262 | lhs = Seq(lhs, operator[0], self.parse_pipeline()) 263 | 264 | return lhs 265 | 266 | -------------------------------------------------------------------------------- /tests/lit/lit/TestingConfig.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | 5 | class TestingConfig: 6 | """" 7 | TestingConfig - Information on the tests inside a suite. 8 | """ 9 | 10 | @staticmethod 11 | def fromdefaults(litConfig): 12 | """ 13 | fromdefaults(litConfig) -> TestingConfig 14 | 15 | Create a TestingConfig object with default values. 16 | """ 17 | # Set the environment based on the command line arguments. 18 | environment = { 19 | 'PATH' : os.pathsep.join(litConfig.path + 20 | [os.environ.get('PATH','')]), 21 | 'LLVM_DISABLE_CRASH_REPORT' : '1', 22 | } 23 | 24 | pass_vars = ['LIBRARY_PATH', 'LD_LIBRARY_PATH', 'SYSTEMROOT', 'TERM', 25 | 'CLANG', 'LD_PRELOAD', 'ASAN_OPTIONS', 'UBSAN_OPTIONS', 26 | 'LSAN_OPTIONS', 'ADB', 'ANDROID_SERIAL', 27 | 'SANITIZER_IGNORE_CVE_2016_2143', 'TMPDIR', 'TMP', 'TEMP', 28 | 'TEMPDIR', 'AVRLIT_BOARD', 'AVRLIT_PORT', 29 | 'FILECHECK_DUMP_INPUT_ON_FAILURE'] 30 | for var in pass_vars: 31 | val = os.environ.get(var, '') 32 | # Check for empty string as some variables such as LD_PRELOAD cannot be empty 33 | # ('') for OS's such as OpenBSD. 34 | if val: 35 | environment[var] = val 36 | 37 | if sys.platform == 'win32': 38 | environment.update({ 39 | 'INCLUDE' : os.environ.get('INCLUDE',''), 40 | 'PATHEXT' : os.environ.get('PATHEXT',''), 41 | 'PYTHONUNBUFFERED' : '1', 42 | 'TEMP' : os.environ.get('TEMP',''), 43 | 'TMP' : os.environ.get('TMP',''), 44 | }) 45 | 46 | # Set the default available features based on the LitConfig. 47 | available_features = [] 48 | if litConfig.useValgrind: 49 | available_features.append('valgrind') 50 | if litConfig.valgrindLeakCheck: 51 | available_features.append('vg_leak') 52 | 53 | return TestingConfig(None, 54 | name = '', 55 | suffixes = set(), 56 | test_format = None, 57 | environment = environment, 58 | substitutions = [], 59 | unsupported = False, 60 | test_exec_root = None, 61 | test_source_root = None, 62 | excludes = [], 63 | available_features = available_features, 64 | pipefail = True) 65 | 66 | def load_from_path(self, path, litConfig): 67 | """ 68 | load_from_path(path, litConfig) 69 | 70 | Load the configuration module at the provided path into the given config 71 | object. 72 | """ 73 | 74 | # Load the config script data. 75 | data = None 76 | f = open(path) 77 | try: 78 | data = f.read() 79 | except: 80 | litConfig.fatal('unable to load config file: %r' % (path,)) 81 | f.close() 82 | 83 | # Execute the config script to initialize the object. 84 | cfg_globals = dict(globals()) 85 | cfg_globals['config'] = self 86 | cfg_globals['lit_config'] = litConfig 87 | cfg_globals['__file__'] = path 88 | try: 89 | exec(compile(data, path, 'exec'), cfg_globals, None) 90 | if litConfig.debug: 91 | litConfig.note('... loaded config %r' % path) 92 | except SystemExit: 93 | e = sys.exc_info()[1] 94 | # We allow normal system exit inside a config file to just 95 | # return control without error. 96 | if e.args: 97 | raise 98 | except: 99 | import traceback 100 | litConfig.fatal( 101 | 'unable to parse config file %r, traceback: %s' % ( 102 | path, traceback.format_exc())) 103 | 104 | self.finish(litConfig) 105 | 106 | def __init__(self, parent, name, suffixes, test_format, 107 | environment, substitutions, unsupported, 108 | test_exec_root, test_source_root, excludes, 109 | available_features, pipefail, limit_to_features = [], 110 | is_early = False, parallelism_group = ""): 111 | self.parent = parent 112 | self.name = str(name) 113 | self.suffixes = set(suffixes) 114 | self.test_format = test_format 115 | self.environment = dict(environment) 116 | self.substitutions = list(substitutions) 117 | self.unsupported = unsupported 118 | self.test_exec_root = test_exec_root 119 | self.test_source_root = test_source_root 120 | self.excludes = set(excludes) 121 | self.available_features = set(available_features) 122 | self.pipefail = pipefail 123 | # This list is used by TestRunner.py to restrict running only tests that 124 | # require one of the features in this list if this list is non-empty. 125 | # Configurations can set this list to restrict the set of tests to run. 126 | self.limit_to_features = set(limit_to_features) 127 | # Whether the suite should be tested early in a given run. 128 | self.is_early = bool(is_early) 129 | self.parallelism_group = parallelism_group 130 | 131 | def finish(self, litConfig): 132 | """finish() - Finish this config object, after loading is complete.""" 133 | 134 | self.name = str(self.name) 135 | self.suffixes = set(self.suffixes) 136 | self.environment = dict(self.environment) 137 | self.substitutions = list(self.substitutions) 138 | if self.test_exec_root is not None: 139 | # FIXME: This should really only be suite in test suite config 140 | # files. Should we distinguish them? 141 | self.test_exec_root = str(self.test_exec_root) 142 | if self.test_source_root is not None: 143 | # FIXME: This should really only be suite in test suite config 144 | # files. Should we distinguish them? 145 | self.test_source_root = str(self.test_source_root) 146 | self.excludes = set(self.excludes) 147 | 148 | @property 149 | def root(self): 150 | """root attribute - The root configuration for the test suite.""" 151 | if self.parent is None: 152 | return self 153 | else: 154 | return self.parent.root 155 | 156 | class SubstituteCaptures: 157 | """ 158 | Helper class to indicate that the substitutions contains backreferences. 159 | 160 | This can be used as the following in lit.cfg to mark subsitutions as having 161 | back-references:: 162 | 163 | config.substutions.append(('\b[^ ]*.cpp', SubstituteCaptures('\0.txt'))) 164 | 165 | """ 166 | def __init__(self, substitution): 167 | self.substitution = substitution 168 | 169 | def replace(self, pattern, replacement): 170 | return self.substitution 171 | 172 | def __str__(self): 173 | return self.substitution 174 | 175 | def __len__(self): 176 | return len(self.substitution) 177 | 178 | def __getitem__(self, item): 179 | return self.substitution.__getitem__(item) 180 | 181 | -------------------------------------------------------------------------------- /tests/lit/lit/__init__.py: -------------------------------------------------------------------------------- 1 | """'lit' Testing Tool""" 2 | 3 | __author__ = 'Daniel Dunbar' 4 | __email__ = 'daniel@minormatter.com' 5 | __versioninfo__ = (0, 8, 0) 6 | __version__ = '.'.join(str(v) for v in __versioninfo__) + 'dev' 7 | 8 | __all__ = [] 9 | 10 | from .main import main 11 | -------------------------------------------------------------------------------- /tests/lit/lit/formats/__init__.py: -------------------------------------------------------------------------------- 1 | from lit.formats.base import ( # noqa: F401 2 | TestFormat, 3 | FileBasedTest, 4 | OneCommandPerFileTest 5 | ) 6 | 7 | from lit.formats.minotaurtest import MinotaurTest 8 | -------------------------------------------------------------------------------- /tests/lit/lit/formats/base.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | import os 3 | 4 | import lit.Test 5 | import lit.util 6 | 7 | class TestFormat(object): 8 | pass 9 | 10 | ### 11 | 12 | class FileBasedTest(TestFormat): 13 | def getTestsInDirectory(self, testSuite, path_in_suite, 14 | litConfig, localConfig): 15 | source_path = testSuite.getSourcePath(path_in_suite) 16 | for filename in os.listdir(source_path): 17 | # Ignore dot files and excluded tests. 18 | if (filename.startswith('.') or 19 | filename in localConfig.excludes): 20 | continue 21 | 22 | filepath = os.path.join(source_path, filename) 23 | if not os.path.isdir(filepath): 24 | base,ext = os.path.splitext(filename) 25 | if ext in localConfig.suffixes: 26 | yield lit.Test.Test(testSuite, path_in_suite + (filename,), 27 | localConfig) 28 | 29 | ### 30 | 31 | import re 32 | import tempfile 33 | 34 | class OneCommandPerFileTest(TestFormat): 35 | # FIXME: Refactor into generic test for running some command on a directory 36 | # of inputs. 37 | 38 | def __init__(self, command, dir, recursive=False, 39 | pattern=".*", useTempInput=False): 40 | if isinstance(command, str): 41 | self.command = [command] 42 | else: 43 | self.command = list(command) 44 | if dir is not None: 45 | dir = str(dir) 46 | self.dir = dir 47 | self.recursive = bool(recursive) 48 | self.pattern = re.compile(pattern) 49 | self.useTempInput = useTempInput 50 | 51 | def getTestsInDirectory(self, testSuite, path_in_suite, 52 | litConfig, localConfig): 53 | dir = self.dir 54 | if dir is None: 55 | dir = testSuite.getSourcePath(path_in_suite) 56 | 57 | for dirname,subdirs,filenames in os.walk(dir): 58 | if not self.recursive: 59 | subdirs[:] = [] 60 | 61 | subdirs[:] = [d for d in subdirs 62 | if (d != '.svn' and 63 | d not in localConfig.excludes)] 64 | 65 | for filename in filenames: 66 | if (filename.startswith('.') or 67 | not self.pattern.match(filename) or 68 | filename in localConfig.excludes): 69 | continue 70 | 71 | path = os.path.join(dirname,filename) 72 | suffix = path[len(dir):] 73 | if suffix.startswith(os.sep): 74 | suffix = suffix[1:] 75 | test = lit.Test.Test( 76 | testSuite, path_in_suite + tuple(suffix.split(os.sep)), 77 | localConfig) 78 | # FIXME: Hack? 79 | test.source_path = path 80 | yield test 81 | 82 | def createTempInput(self, tmp, test): 83 | raise NotImplementedError('This is an abstract method.') 84 | 85 | def execute(self, test, litConfig): 86 | if test.config.unsupported: 87 | return (lit.Test.UNSUPPORTED, 'Test is unsupported') 88 | 89 | cmd = list(self.command) 90 | 91 | # If using temp input, create a temporary file and hand it to the 92 | # subclass. 93 | if self.useTempInput: 94 | tmp = tempfile.NamedTemporaryFile(suffix='.cpp') 95 | self.createTempInput(tmp, test) 96 | tmp.flush() 97 | cmd.append(tmp.name) 98 | elif hasattr(test, 'source_path'): 99 | cmd.append(test.source_path) 100 | else: 101 | cmd.append(test.getSourcePath()) 102 | 103 | out, err, exitCode = lit.util.executeCommand(cmd) 104 | 105 | diags = out + err 106 | if not exitCode and not diags.strip(): 107 | return lit.Test.PASS,'' 108 | 109 | # Try to include some useful information. 110 | report = """Command: %s\n""" % ' '.join(["'%s'" % a 111 | for a in cmd]) 112 | if self.useTempInput: 113 | report += """Temporary File: %s\n""" % tmp.name 114 | report += "--\n%s--\n""" % open(tmp.name).read() 115 | report += """Output:\n--\n%s--""" % diags 116 | 117 | return lit.Test.FAIL, report 118 | -------------------------------------------------------------------------------- /tests/lit/lit/formats/minotaurtest.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-present The Alive2 Authors. 2 | # MIT license that can be found in the LICENSE file. 3 | 4 | import lit.TestRunner 5 | import lit.util 6 | from .base import TestFormat 7 | import os, re, signal, string, subprocess 8 | 9 | ok_string = 'Transformation seems to be correct!' 10 | 11 | def executeCommand(command): 12 | p = subprocess.Popen(command, 13 | stdout=subprocess.PIPE, 14 | stderr=subprocess.PIPE) 15 | out,err = p.communicate() 16 | exitCode = p.wait() 17 | 18 | # Detect Ctrl-C in subprocess. 19 | if exitCode == -signal.SIGINT: 20 | raise KeyboardInterrupt 21 | 22 | # Ensure the resulting output is always of string type. 23 | try: 24 | out = str(out.decode('ascii')) 25 | except: 26 | out = str(out) 27 | try: 28 | err = str(err.decode('ascii')) 29 | except: 30 | err = str(err) 31 | return out, err, exitCode 32 | 33 | def is_timeout(str): 34 | return str.find('ERROR: Timeout') > 0 35 | 36 | def id_check(fn, cmd, args): 37 | out, err, exitCode = executeCommand(cmd + args + ["-always-verify"]) 38 | str = out + err 39 | if not is_timeout(str) and (exitCode != 0 or str.find(ok_string) < 0): 40 | raise Exception(fn + ' identity check fail: ' + str) 41 | 42 | 43 | def readFile(path): 44 | fd = open(path, 'r') 45 | return fd.read() 46 | 47 | 48 | class MinotaurTest(TestFormat): 49 | def __init__(self): 50 | self.regex_errs = re.compile(r";\s*(ERROR:.*)") 51 | self.regex_xfail = re.compile(r";\s*XFAIL:\s*(.*)") 52 | self.regex_args = re.compile(r"(?:;|//)\s*TEST-ARGS:(.*)") 53 | self.regex_check = re.compile(r"(?:;|//)\s*CHECK:(.*)") 54 | self.regex_check_not = re.compile(r"(?:;|//)\s*CHECK-NOT:(.*)") 55 | self.regex_errs_out = re.compile("ERROR:.*") 56 | 57 | def getTestsInDirectory(self, testSuite, path_in_suite, 58 | litConfig, localConfig): 59 | source_path = testSuite.getSourcePath(path_in_suite) 60 | for filename in os.listdir(source_path): 61 | filepath = os.path.join(source_path, filename) 62 | if not filename.startswith('.') and \ 63 | not os.path.isdir(filepath) and \ 64 | filename.endswith('.syn.ll'): 65 | yield lit.Test.Test(testSuite, path_in_suite + (filename,), localConfig) 66 | 67 | 68 | def execute(self, test, litConfig): 69 | test = test.getSourcePath() 70 | 71 | opt_tv = test.endswith('.syn.ll') 72 | if opt_tv: 73 | cmd = ['./opt-minotaur.sh', '-S'] 74 | if not os.path.isfile('opt-minotaur.sh'): 75 | return lit.Test.UNSUPPORTED, '' 76 | 77 | input = readFile(test) 78 | 79 | # add test-specific args 80 | m = self.regex_args.search(input) 81 | if m != None: 82 | cmd += m.group(1).split() 83 | 84 | cmd.append(test) 85 | 86 | out, err, exitCode = executeCommand(cmd) 87 | output = out + err 88 | 89 | xfail = self.regex_xfail.search(input) 90 | if xfail != None and output.find(xfail.group(1)) != -1: 91 | return lit.Test.XFAIL, '' 92 | 93 | if is_timeout(output): 94 | return lit.Test.PASS, '' 95 | 96 | chk = self.regex_check.search(input) 97 | if chk != None and output.find(chk.group(1).strip()) == -1: 98 | return lit.Test.FAIL, output 99 | 100 | chk_not = self.regex_check_not.search(input) 101 | if chk_not != None and output.find(chk_not.group(1).strip()) != -1: 102 | return lit.Test.FAIL, output 103 | 104 | expect_err = self.regex_errs.search(input) 105 | if expect_err is None and xfail is None and chk is None and chk_not is None: 106 | # If there's no other test, correctness of the transformation should be 107 | # checked. 108 | if exitCode == 0 and output.find(ok_string) != -1 and \ 109 | self.regex_errs_out.search(output) is None: 110 | return lit.Test.PASS, '' 111 | return lit.Test.FAIL, output 112 | 113 | if expect_err != None and output.find(expect_err.group(1)) == -1: 114 | return lit.Test.FAIL, output 115 | 116 | return lit.Test.PASS, '' 117 | -------------------------------------------------------------------------------- /tests/memory/syn_mem1.syn.mem.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: ret i32 128 2 | define i32 @src() { 3 | %p = alloca i32 4 | store i32 128, i32* %p 5 | %v = load i32, i32* %p 6 | ret i32 %v 7 | } 8 | -------------------------------------------------------------------------------- /tests/memory/syn_mem2.syn.mem.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: -8376322 2 | define i24 @src() { 3 | %p = alloca <2 x i12> 4 | store <2 x i12> , <2 x i12>* %p 5 | %p2 = bitcast <2 x i12>* %p to i24* 6 | %v = load i24, i24* %p2 7 | ret i24 %v 8 | } 9 | -------------------------------------------------------------------------------- /tests/memory/syn_mem3.syn.mem.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: 75520970237766904317954 2 | target datalayout="E" 3 | define i128 @src() { 4 | %p = alloca <2 x i64> 5 | store <2 x i64> , <2 x i64>* %p 6 | %p2 = bitcast <2 x i64>* %p to i128* 7 | %v = load i128, i128* %p2 8 | ret i128 %v 9 | } 10 | -------------------------------------------------------------------------------- /tests/memory/syn_mem4.syn.mem.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: 37815825351104580816894 2 | target datalayout="e" 3 | define i128 @src() { 4 | %p = alloca <2 x i64> 5 | store <2 x i64> , <2 x i64>* %p 6 | %p2 = bitcast <2 x i64>* %p to i128* 7 | %v = load i128, i128* %p2 8 | ret i128 %v 9 | } 10 | -------------------------------------------------------------------------------- /tests/memory/syn_mem5.syn.mem.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: 37852718839251999920126 2 | target datalayout="e" 3 | define i128 @src() { 4 | %p = alloca <2 x i64> 5 | store <2 x i64> , <2 x i64>* %p 6 | store <2 x i64> , <2 x i64>* %p 7 | %p2 = bitcast <2 x i64>* %p to i128* 8 | %v = load i128, i128* %p2 9 | ret i128 %v 10 | } 11 | -------------------------------------------------------------------------------- /tests/memory/syn_mem6.syn.mem.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: load 2 | target datalayout="e" 3 | define i64 @src(i1 %foo) { 4 | entry: 5 | %p = alloca <2 x i64> 6 | br i1 %foo, label %t, label %f 7 | t: 8 | store <2 x i64> , <2 x i64>* %p 9 | br label %ret 10 | f: 11 | store <2 x i64> , <2 x i64>* %p 12 | br label %ret 13 | ret: 14 | %p2 = bitcast <2 x i64>* %p to i128* 15 | %v = load i128, i128* %p2 16 | %r = trunc i128 %v to i64 17 | ret i64 %r 18 | } 19 | -------------------------------------------------------------------------------- /tests/memory/syn_mem7.syn.mem.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: -2 2 | target datalayout="e" 3 | define i8 @src(i1 %foo) { 4 | entry: 5 | %p = alloca <2 x i64> 6 | %sel = select i1 %foo, <2 x i64> , <2 x i64> 7 | store <2 x i64> %sel, <2 x i64>* %p 8 | %p2 = bitcast <2 x i64>* %p to i128* 9 | %v = load i128, i128* %p2 10 | %r = trunc i128 %v to i8 11 | ret i8 %r 12 | } 13 | -------------------------------------------------------------------------------- /tests/nop1.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: ret i4 %x 2 | define i4 @syn_nop_1(i4 %x, i4 %y) { 3 | %ia = sub i4 %x, 7 4 | %ib = add i4 %ia, 7 5 | ret i4 %ib 6 | } 7 | -------------------------------------------------------------------------------- /tests/nop2.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: ret i233 %x 2 | define i233 @syn_nop_2(i233 %x, i233 %y) { 3 | %ia = sub i233 %x, 7 4 | %ib = add i233 %ia, 7 5 | ret i233 %ib 6 | } 7 | -------------------------------------------------------------------------------- /tests/nop3.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: ret <2 x i4> %x 2 | define <2 x i4> @syn_nop_3(<2 x i4> %x, <2 x i4> %y) { 3 | %ia = sub <2 x i4> %x, 4 | %ib = add <2 x i4> %ia, 5 | ret <2 x i4> %ib 6 | } 7 | -------------------------------------------------------------------------------- /tests/nop4.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: ret <4 x i64> %a 2 | define <4 x i64> @syn_add_4(<4 x i64> %a) { 3 | entry: 4 | %ext.1 = extractelement <4 x i64> %a, i32 0 5 | %ext.2 = extractelement <4 x i64> %a, i32 1 6 | %ext.3 = extractelement <4 x i64> %a, i32 2 7 | %ext.4 = extractelement <4 x i64> %a, i32 3 8 | %ins.1 = insertelement <4 x i64> undef, i64 %ext.1, i32 0 9 | %ins.2 = insertelement <4 x i64> %ins.1, i64 %ext.2, i32 1 10 | %ins.3 = insertelement <4 x i64> %ins.2, i64 %ext.3, i32 2 11 | %ins.4 = insertelement <4 x i64> %ins.3, i64 %ext.4, i32 3 12 | ret <4 x i64> %ins.4 13 | } 14 | -------------------------------------------------------------------------------- /tests/nop5.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: ret <4 x i64> %a 2 | define <4 x i64> @syn_add_4(<4 x i64> %a) { 3 | entry: 4 | %ext.1 = extractelement <4 x i64> %a, i32 0 5 | %ext.2 = extractelement <4 x i64> %a, i32 1 6 | %ext.3 = extractelement <4 x i64> %a, i32 2 7 | %ext.4 = extractelement <4 x i64> %a, i32 3 8 | %ins.1 = insertelement <4 x i64> undef, i64 %ext.1, i32 0 9 | %ins.2 = insertelement <4 x i64> %ins.1, i64 %ext.3, i32 2 10 | %ins.3 = insertelement <4 x i64> %ins.2, i64 %ext.2, i32 1 11 | %ins.4 = insertelement <4 x i64> %ins.3, i64 %ext.4, i32 3 12 | ret <4 x i64> %ins.4 13 | } 14 | -------------------------------------------------------------------------------- /tests/nop6.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: call <16 x i16> @llvm.x86.avx2.psign.w(<16 x i16> %a, <16 x i16> %b) 2 | define <16 x i16> @syn_nop_psign_1(<16 x i16> %a, <16 x i16> %b) { 3 | %x1 = call <16 x i16> @llvm.x86.avx2.psign.w(<16 x i16> %a, <16 x i16> %b) #2 4 | %y1 = call <16 x i16> @llvm.x86.avx2.psign.w(<16 x i16> %x1, <16 x i16> %b) #2 5 | %z1 = call <16 x i16> @llvm.x86.avx2.psign.w(<16 x i16> %y1, <16 x i16> %b) #2 6 | ret <16 x i16> %z1 7 | } 8 | 9 | declare <16 x i16> @llvm.x86.avx2.psign.w(<16 x i16>, <16 x i16>) nounwind readnone 10 | -------------------------------------------------------------------------------- /tests/nop7.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: ret i32 %x 2 | define i32 @test34(i32 %x, i32 %y) { 3 | %cmp = icmp sgt i32 %x, %y 4 | %cond = select i1 %cmp, i32 %x, i32 %y 5 | %cmp5 = icmp sgt i32 %cond, %x 6 | %retval = select i1 %cmp5, i32 %x, i32 %cond 7 | ret i32 %retval 8 | } -------------------------------------------------------------------------------- /tests/nop8.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: ret i32 %x 2 | define i32 @test33(i32 %x, i32 %y) { 3 | %cmp = icmp sgt i32 %x, %y 4 | %cond = select i1 %cmp, i32 %y, i32 %x 5 | %cmp5 = icmp sgt i32 %cond, %x 6 | %retval = select i1 %cmp5, i32 %cond, i32 %x 7 | ret i32 %retval 8 | } -------------------------------------------------------------------------------- /tests/or0.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: 2 | define <2 x i32> @select_icmp_slt0_xor_vec(<2 x i32> %x) { 3 | %cmp = icmp slt <2 x i32> %x, zeroinitializer 4 | %xor = xor <2 x i32> %x, 5 | %x.xor = select <2 x i1> %cmp, <2 x i32> %x, <2 x i32> %xor 6 | ret <2 x i32> %x.xor 7 | } 8 | -------------------------------------------------------------------------------- /tests/reverse1.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: call <16 x i8> @llvm.x86.ssse3.pshuf.b.128(<16 x i8> %v, <16 x i8> ) 2 | 3 | ; backend is able to turn the script into pshuf, anyway 4 | declare <4 x i32> @llvm.fshl.v4i32(<4 x i32>, <4 x i32>, <4 x i32>) #17 5 | 6 | declare <8 x i16> @llvm.bswap.v8i16(<8 x i16>) #17 7 | 8 | declare <8 x i32> @llvm.fshl.v8i32(<8 x i32>, <8 x i32>, <8 x i32>) #17 9 | 10 | ; Function Attrs: norecurse nounwind readnone uwtable willreturn mustprogress 11 | define <16 x i8> @_Z12reverse_sse2Dv2_x(<16 x i8> %v) { 12 | entry: 13 | %0 = bitcast <16 x i8> %v to <4 x i32> 14 | %permil = shufflevector <4 x i32> %0, <4 x i32> poison, <4 x i32> 15 | %or.i1415 = tail call <4 x i32> @llvm.fshl.v4i32(<4 x i32> %permil, <4 x i32> %permil, <4 x i32> ) 16 | %1 = bitcast <4 x i32> %or.i1415 to <8 x i16> 17 | %or.i16 = tail call <8 x i16> @llvm.bswap.v8i16(<8 x i16> %1) 18 | %or.i = bitcast <8 x i16> %or.i16 to <16 x i8> 19 | ret <16 x i8> %or.i 20 | } 21 | 22 | -------------------------------------------------------------------------------- /tests/reverse2.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: llvm.x86.ssse3.pshuf.b.128 2 | declare <4 x i32> @llvm.fshl.v4i32(<4 x i32>, <4 x i32>, <4 x i32>) #17 3 | 4 | declare <8 x i16> @llvm.bswap.v8i16(<8 x i16>) #17 5 | 6 | declare <8 x i32> @llvm.fshl.v8i32(<8 x i32>, <8 x i32>, <8 x i32>) #17 7 | 8 | ; Function Attrs: norecurse nounwind readnone uwtable willreturn mustprogress 9 | define <16 x i8> @_Z12reverse_sse2Dv2_x(<16 x i8> %v) { 10 | entry: 11 | %0 = bitcast <16 x i8> %v to <4 x i32> 12 | %permil = shufflevector <4 x i32> %0, <4 x i32> poison, <4 x i32> 13 | %or.i1415 = tail call <4 x i32> @llvm.fshl.v4i32(<4 x i32> %permil, <4 x i32> %permil, <4 x i32> ) 14 | %1 = bitcast <4 x i32> %or.i1415 to <8 x i16> 15 | %or.i16 = tail call <8 x i16> @llvm.bswap.v8i16(<8 x i16> %1) 16 | %or.i = bitcast <8 x i16> %or.i16 to <16 x i8> 17 | ret <16 x i8> %or.i 18 | } 19 | 20 | -------------------------------------------------------------------------------- /tests/select0.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: select i1 %cmp, i32 1, i32 6 2 | define i32 @test52(i32 %n, i32 %m) { 3 | %cmp = icmp sgt i32 %n, %m 4 | %. = select i1 %cmp, i32 1, i32 3 5 | %add = add nsw i32 %., 3 6 | %storemerge = select i1 %cmp, i32 %., i32 %add 7 | ret i32 %storemerge 8 | } -------------------------------------------------------------------------------- /tests/select1.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: select i1 %cmp2, i32 16777215, i32 0 2 | define i32 @pr61361(i32 %arg) { 3 | ; CHECK-LABEL: @pr61361( 4 | ; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[ARG:%.*]], 0 5 | ; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[CMP2]], i32 16777215, i32 0 6 | ; CHECK-NEXT: ret i32 [[SEL2]] 7 | ; 8 | %cmp1 = icmp eq i32 %arg, 1 9 | %sel1 = select i1 %cmp1, i32 0, i32 33554431 10 | %cmp2 = icmp eq i32 %arg, 0 11 | %sel2 = select i1 %cmp2, i32 %sel1, i32 0 12 | %ashr = ashr i32 %sel2, 1 13 | ret i32 %ashr 14 | } 15 | -------------------------------------------------------------------------------- /tests/sub0.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: sub <2 x i32> zeroinitializer, %x 2 | define <2 x i32> @PR27817_nsw_vec(<2 x i32> %x) { 3 | ; CHECK-LABEL: @PR27817_nsw_vec( 4 | ; CHECK-NEXT: [[SUB:%.*]] = sub <2 x i32> zeroinitializer, [[X:%.*]] 5 | ; CHECK-NEXT: ret <2 x i32> [[SUB]] 6 | ; 7 | %cmp = icmp eq <2 x i32> %x, 8 | %sub = sub nsw <2 x i32> zeroinitializer, %x 9 | %sel = select <2 x i1> %cmp, <2 x i32> , <2 x i32> %sub 10 | ret <2 x i32> %sel 11 | } 12 | -------------------------------------------------------------------------------- /tests/sub1.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: sub <4 x i8> %x, %y 2 | define <4 x i8> @syn_add_3(<4 x i8> %x, <4 x i8> %y) { 3 | %a = and <4 x i8> %x, 4 | %b = and <4 x i8> %y, 5 | %sum1 = sub <4 x i8> %a, %b 6 | %c = and <4 x i8> %x, 7 | %d = and <4 x i8> %y, 8 | %sum2 = sub <4 x i8> %c, %d 9 | %sum = add <4 x i8> %sum1, %sum2 10 | ret <4 x i8> %sum 11 | } 12 | -------------------------------------------------------------------------------- /tests/syn_add1.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: add i4 %x, -3 2 | define i4 @syn_add_1(i4 %x, i4 %y) { 3 | %ia = sub i4 %x, 7 4 | %ib = add i4 %ia, 4 5 | ret i4 %ib 6 | } 7 | -------------------------------------------------------------------------------- /tests/syn_add2.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: add i233 %x, -3 2 | define i233 @syn_add_2(i233 %x, i233 %y) { 3 | %ia = sub i233 %x, 7 4 | %ib = add i233 %ia, 4 5 | ret i233 %ib 6 | } 7 | -------------------------------------------------------------------------------- /tests/syn_add3.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: add <2 x i8> %x, 2 | define <2 x i8> @syn_add_3(<2 x i8> %x, <2 x i8> %y) { 3 | %ia = sub <2 x i8> %x, 4 | %ib = add <2 x i8> %ia, 5 | ret <2 x i8> %ib 6 | } 7 | -------------------------------------------------------------------------------- /tests/syn_add4.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: sub <4 x i64> , %a 2 | define <4 x i64> @syn_add_4(<4 x i64> %a, <4 x i64> %b, <4 x i64> %c) { 3 | entry: 4 | %add.i = add <4 x i64> %a, 5 | %x = add <4 x i64> %add.i, 6 | %y = add <4 x i64> %x, 7 | %z = sub <4 x i64> , %y 8 | ret <4 x i64> %z 9 | } 10 | -------------------------------------------------------------------------------- /tests/syn_ashr1.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: lshr <16 x i16> %x, 2 | define <16 x i16> @syn_ashr_1(<16 x i16> %x, <16 x i16> %y) { 3 | %ia = udiv <16 x i16> %x, 4 | %ib = udiv <16 x i16> %ia, 5 | ret <16 x i16> %ib 6 | } 7 | -------------------------------------------------------------------------------- /tests/syn_ashr2.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: lshr <16 x i16> %x, 2 | define <16 x i16> @syn_ashr_1(<16 x i16> %x, <16 x i16> %y) { 3 | %ia = udiv <16 x i16> %x, 4 | %ib = udiv <16 x i16> %ia, 5 | ret <16 x i16> %ib 6 | } 7 | -------------------------------------------------------------------------------- /tests/syn_const_bitmask0.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: 16776960 2 | 3 | define i32 @mask(i32 %x) { 4 | %shr = lshr i32 %x, 8 5 | %shl = shl i32 %shr, 16 6 | %shr.2 = lshr i32 %shl, 8 7 | ret i32 %shr.2 8 | } 9 | 10 | -------------------------------------------------------------------------------- /tests/syn_const_bitmask1.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: 72057594037927680 2 | target triple = "x86_64-apple-macosx10.15.0" 3 | 4 | define i64 @mask(i64 %x) { 5 | %shr = lshr i64 %x, 8 6 | %shl = shl i64 %shr, 16 7 | %shr.2 = lshr i64 %shl, 8 8 | ret i64 %shr.2 9 | } 10 | 11 | -------------------------------------------------------------------------------- /tests/syn_const_control_flow.ll: -------------------------------------------------------------------------------- 1 | 2 | define i1 @src(i32 %0) { 3 | entry: 4 | %1 = add i32 %0, -1 5 | %2 = and i32 %0, 7 6 | %3 = icmp eq i32 %2, 0 7 | br i1 %3, label %do.body.prol.loopexit, label %sink 8 | 9 | do.body.prol.loopexit: ; preds = %entry 10 | %4 = icmp ult i32 %1, 7 11 | %5 = add i1 %3, %4 12 | ret i1 %5 13 | 14 | sink: ; preds = %entry 15 | unreachable 16 | } 17 | 18 | 19 | -------------------------------------------------------------------------------- /tests/syn_const_fsll0.skip.ll: -------------------------------------------------------------------------------- 1 | ; SKIP 2 | ; was expecting ret i32 59 3 | target triple = "x86_64-apple-macosx10.15.0" 4 | 5 | define i32 @tgt() { 6 | %v = call i32 @ffsl(i64 9223372036854775808) 7 | %ret = sub i32 %v, 5 8 | ret i32 %ret 9 | } 10 | 11 | declare i32 @ffsl(i64) nounwind willreturn 12 | 13 | -------------------------------------------------------------------------------- /tests/syn_domtree_constraint1.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: add i4 %x, -3 2 | define i4 @syn_add_1(i4 %x, i4 %y, i1 %bool) { 3 | %ia = sub i4 %x, 7 4 | br i1 %bool, label %tru, label %fal 5 | tru: 6 | %ib = add i4 %ia, 4 7 | %ic = mul i4 %ib, 2 8 | br label %final 9 | fal: 10 | br label %final 11 | final: 12 | %if = add i4 %ia, 4 13 | %iff = mul i4 %if, 2 14 | ret i4 %iff 15 | } 16 | -------------------------------------------------------------------------------- /tests/syn_fneg.ll: -------------------------------------------------------------------------------- 1 | define half @src(half noundef %x, half noundef %y) { 2 | %s = fsub half -0.0, %x 3 | ret half %s 4 | } 5 | 6 | define half @tgt(half noundef %x, half noundef %y) { 7 | %s = fneg half %x 8 | ret half %s 9 | } 10 | 11 | declare void @fn(half) 12 | -------------------------------------------------------------------------------- /tests/syn_pavg1.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: call <16 x i16> @llvm.x86.avx2.pavg.w 2 | 3 | ; LLVM Codegen(llc) is able to identify the pattern and emit pavgs. check 4 | ; detectAVGPattern() in lib/Target/X86/X86ISelLowering.cpp. however, codegen 5 | ; fails to identify the pattern if the source is altered. See syn_pavg3.syn.ll. 6 | 7 | define <16 x i16> @syn_pavg_0(<16 x i16> %a, <16 x i16> %b) { 8 | entry: 9 | %za = zext <16 x i16> %a to <16 x i17> 10 | %zb = zext <16 x i16> %b to <16 x i17> 11 | %add = add <16 x i17> %za, %zb 12 | %add_1 = add <16 x i17> %add, 13 | %sh = lshr <16 x i17> %add_1, 14 | %ret = trunc <16 x i17> %sh to <16 x i16> 15 | ret <16 x i16> %ret 16 | } 17 | -------------------------------------------------------------------------------- /tests/syn_pavg2.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: call <16 x i16> @llvm.x86.avx2.pavg.w 2 | declare <8 x i16> @llvm.x86.sse2.pavg.w(<8 x i16>, <8 x i16>) nounwind readnone 3 | 4 | define <16 x i16> @__avg_up_uint16(<16 x i16>, <16 x i16>) nounwind readnone { 5 | 6 | %a0 = shufflevector <16 x i16> %0, <16 x i16> undef, 7 | <8 x i32> 8 | %b0 = shufflevector <16 x i16> %0, <16 x i16> undef, 9 | <8 x i32> 10 | 11 | 12 | %a1 = shufflevector <16 x i16> %1, <16 x i16> undef, 13 | <8 x i32> 14 | %b1 = shufflevector <16 x i16> %1, <16 x i16> undef, 15 | <8 x i32> 16 | 17 | %r0 = call <8 x i16> @llvm.x86.sse2.pavg.w(<8 x i16> %a0, <8 x i16> %a1) 18 | %r1 = call <8 x i16> @llvm.x86.sse2.pavg.w(<8 x i16> %b0, <8 x i16> %b1) 19 | 20 | %r = shufflevector <8 x i16> %r0, <8 x i16> %r1, 21 | <16 x i32> 23 | 24 | ret <16 x i16> %r 25 | } 26 | 27 | -------------------------------------------------------------------------------- /tests/syn_pavg3.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: call <16 x i16> @llvm.x86.avx2.pavg.w 2 | ; run llc will result in stupid code 3 | define <16 x i16> @syn_pavg_0(<16 x i16> %a, <16 x i16> %b) { 4 | entry: 5 | %za = and <16 x i16> %a, 6 | %zb = and <16 x i16> %b, 7 | %add = add <16 x i16> %za, %zb 8 | %add_1 = add <16 x i16> %add, 9 | %sh = lshr <16 x i16> %add_1, 10 | ret <16 x i16> %sh 11 | } -------------------------------------------------------------------------------- /tests/syn_pmaddwd1.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: call <8 x i32> @llvm.x86.avx2.pmadd.wd 2 | ; https://godbolt.org/z/7nTjYEKh9 3 | define <8 x i32> @src(<16 x i16> %wide.vec) { 4 | entry: 5 | %strided.vec = shufflevector <16 x i16> %wide.vec, <16 x i16> poison, <8 x i32> 6 | %strided.vec24 = shufflevector <16 x i16> %wide.vec, <16 x i16> poison, <8 x i32> 7 | %a = sext <8 x i16> %strided.vec to <8 x i32> 8 | %b = sext <8 x i16> %strided.vec24 to <8 x i32> 9 | %c = sub nsw <8 x i32> %a, %b 10 | ret <8 x i32> %c 11 | } 12 | -------------------------------------------------------------------------------- /tests/syn_psad_const1.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: 2 | define <2 x i64> @src(<16 x i16> %wide.vec) { 3 | %c = call <2 x i64> @llvm.x86.sse2.psad.bw(<16 x i8> , <16 x i8> ) 4 | ret <2 x i64> %c 5 | } 6 | 7 | 8 | declare <2 x i64> @llvm.x86.sse2.psad.bw(<16 x i8>, <16 x i8>) nounwind readnone -------------------------------------------------------------------------------- /tests/syn_sext0.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: sext <2 x i8> %a to <2 x i16> 2 | define <2 x i16> @syn_sv2(<2 x i8> %a) { 3 | entry: 4 | %zx = sext <2 x i8> %a to <2 x i16> 5 | %and = and <2 x i16> %zx, 6 | ret <2 x i16> %and 7 | } -------------------------------------------------------------------------------- /tests/syn_sext1.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: sext <3 x i8> %a to <3 x i16> 2 | define <3 x i16> @syn_sv2(<3 x i8> %a) { 3 | entry: 4 | %zx = sext <3 x i8> %a to <3 x i16> 5 | %and = and <3 x i16> %zx, 6 | ret <3 x i16> %and 7 | } -------------------------------------------------------------------------------- /tests/syn_sext2.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: sext i8 %a to i16 2 | define i16 @syn_sv2(i8 %a) { 3 | entry: 4 | %zx = sext i8 %a to i16 5 | %and = and i16 %zx, 65535 6 | ret i16 %and 7 | } -------------------------------------------------------------------------------- /tests/syn_trunc0.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: trunc <2 x i16> %a to <2 x i8> 2 | define <2 x i8> @syn_sv2(<2 x i16> %a) { 3 | entry: 4 | %and = and <2 x i16> %a, 5 | %t = trunc <2 x i16> %and to <2 x i8> 6 | ret <2 x i8> %t 7 | } -------------------------------------------------------------------------------- /tests/syn_trunc1.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: trunc <3 x i16> %a to <3 x i8> 2 | define <3 x i8> @syn_sv2(<3 x i16> %a) { 3 | entry: 4 | %and = and <3 x i16> %a, 5 | %t = trunc <3 x i16> %and to <3 x i8> 6 | ret <3 x i8> %t 7 | } -------------------------------------------------------------------------------- /tests/syn_trunc2.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: trunc i16 %a to i8 2 | define i8 @syn_sv2(i16 %a) { 3 | entry: 4 | %and = and i16 %a, 255 5 | %t = trunc i16 %and to i8 6 | ret i8 %t 7 | } -------------------------------------------------------------------------------- /tests/syn_width_relax1.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: changed 2 | define <2 x i16> @syn_add_3(<2 x i16> %w, <2 x i16> %u) { 3 | %x = bitcast <2 x i16> %w to <4 x i8> 4 | %y = bitcast <2 x i16> %u to <4 x i8> 5 | %a = and <4 x i8> %x, 6 | %b = and <4 x i8> %y, 7 | %sum1 = add <4 x i8> %a, %b 8 | %c = and <4 x i8> %x, 9 | %d = and <4 x i8> %y, 10 | %sum2 = add <4 x i8> %c, %d 11 | %sum = add <4 x i8> %sum1, %sum2 12 | %ret = bitcast <4 x i8> %sum to <2 x i16> 13 | ret <2 x i16> %ret 14 | } 15 | -------------------------------------------------------------------------------- /tests/test02.ll: -------------------------------------------------------------------------------- 1 | define dso_local <4 x i64> @test_mm_hsub_epi32(<4 x i64> %a, <4 x i64> %b, <4 x i64> %c) local_unnamed_addr #0 { 2 | entry: 3 | %0 = bitcast <4 x i64> %a to <16 x i16> 4 | %1 = bitcast <4 x i64> %c to <16 x i16> 5 | %2 = bitcast <4 x i64> %b to <16 x i16> 6 | %add.i = add <16 x i16> %1, %0 7 | %add.i4 = add <16 x i16> %1, %2 8 | %3 = tail call <16 x i16> @llvm.x86.avx2.pavg.w(<16 x i16> %add.i, <16 x i16> %add.i4) #2 9 | %4 = tail call <16 x i16> @llvm.x86.avx2.pavg.w(<16 x i16> %0, <16 x i16> %2) #2 10 | %sub = sub <16 x i16> %3, %4 11 | %5 = bitcast <16 x i16> %sub to <4 x i64> 12 | ret <4 x i64> %5 13 | } 14 | 15 | declare <16 x i16> @llvm.x86.avx2.pavg.w(<16 x i16>, <16 x i16>) nounwind readnone 16 | -------------------------------------------------------------------------------- /tests/test04.ll: -------------------------------------------------------------------------------- 1 | define dso_local <32 x i8> @test_mm_hsub_epi32(<32 x i8> %a) local_unnamed_addr #0 { 2 | entry: 3 | %fst = extractelement <32 x i8> %a, i32 0 4 | %snd = extractelement <32 x i8> %a, i32 1 5 | %new = insertelement <32 x i8> %a, i8 %snd, i32 0 6 | %new2 = insertelement <32 x i8> %new, i8 %fst, i32 1 7 | %new3 = insertelement <32 x i8> %new2, i8 0, i32 4 8 | ret <32 x i8> %new3 9 | } 10 | -------------------------------------------------------------------------------- /tests/umax0.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: call i32 @llvm.umax.i32(i32 %x, i32 1) 2 | define i32 @clamp_umin_use(i32 %x) { 3 | %cmp = icmp eq i32 %x, 0 4 | call void @use1(i1 %cmp) 5 | %sel = select i1 %cmp, i32 1, i32 %x 6 | ret i32 %sel 7 | } 8 | 9 | declare void @use1(i1) -------------------------------------------------------------------------------- /tests/umin0.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: call <2 x i8> @llvm.umin.v2i8(<2 x i8> %x, <2 x i8> ) 2 | define <2 x i8> @clamp_umaxval(<2 x i8> %x) { 3 | %cmp = icmp eq <2 x i8> %x, 4 | %sel = select <2 x i1> %cmp, <2 x i8> , <2 x i8> %x 5 | ret <2 x i8> %sel 6 | } -------------------------------------------------------------------------------- /tests/usub0.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: zeroinitializer 2 | declare <2 x i8> @llvm.usub.sat.v2i8(<2 x i8>, <2 x i8>) #0 3 | 4 | define <2 x i8> @test_vector_usub_overflow_y2(<2 x i8> %0) { 5 | %2 = call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> %0, <2 x i8> ) 6 | %3 = call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> %2, <2 x i8> ) 7 | ret <2 x i8> %3 8 | } 9 | -------------------------------------------------------------------------------- /tests/xor0.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: xor i64 %1, -9223372036854775808 2 | define <2 x float> @src(<2 x float> %0) { 3 | entry: 4 | %1 = fneg <2 x float> %0 5 | %2 = shufflevector <2 x float> %0, <2 x float> %1, <2 x i32> 6 | ret <2 x float> %2 7 | 8 | sink: ; No predecessors! 9 | unreachable 10 | } 11 | -------------------------------------------------------------------------------- /tests/xor1.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: changed 2 | define i1 @test5(i1 %C) { 3 | %V = select i1 %C, i1 false, i1 true 4 | ret i1 %V 5 | } -------------------------------------------------------------------------------- /tests/zext0.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: zext <2 x i8> %a to <2 x i16> 2 | define <2 x i16> @syn_sv2(<2 x i8> %a) { 3 | entry: 4 | %zx = zext <2 x i8> %a to <2 x i16> 5 | %and = and <2 x i16> %zx, 6 | ret <2 x i16> %and 7 | } -------------------------------------------------------------------------------- /tests/zext1.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: zext <3 x i8> %a to <3 x i16> 2 | define <3 x i16> @syn_sv2(<3 x i8> %a) { 3 | entry: 4 | %zx = zext <3 x i8> %a to <3 x i16> 5 | %and = and <3 x i16> %zx, 6 | ret <3 x i16> %and 7 | } -------------------------------------------------------------------------------- /tests/zext2.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: zext i8 %a to i16 2 | define i16 @syn_sv2(i8 %a) { 3 | entry: 4 | %zx = zext i8 %a to i16 5 | %and = and i16 %zx, 255 6 | ret i16 %and 7 | } -------------------------------------------------------------------------------- /tests/zext3.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: zext <2 x i8> %a to <2 x i16> 2 | define <2 x i16> @syn_sv2(<2 x i8> %a) { 3 | entry: 4 | %zx = sext <2 x i8> %a to <2 x i16> 5 | %and = and <2 x i16> %zx, 6 | ret <2 x i16> %and 7 | } -------------------------------------------------------------------------------- /tests/zext4.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: zext <3 x i8> %a to <3 x i16> 2 | define <3 x i16> @syn_sv2(<3 x i8> %a) { 3 | entry: 4 | %zx = sext <3 x i8> %a to <3 x i16> 5 | %and = and <3 x i16> %zx, 6 | ret <3 x i16> %and 7 | } -------------------------------------------------------------------------------- /tests/zext5.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: zext i8 %a to i16 2 | define i16 @syn_sv2(i8 %a) { 3 | entry: 4 | %zx = sext i8 %a to i16 5 | %and = and i16 %zx, 255 6 | ret i16 %and 7 | } -------------------------------------------------------------------------------- /tests/zext6.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: zext i1 %C to i32 2 | define i32 @test6(i1 %C) { 3 | %V = select i1 %C, i32 1, i32 0 4 | ret i32 %V 5 | } -------------------------------------------------------------------------------- /tests/zext7.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: zext i16 %x to i32 2 | define i32 @test58(i16 %x) { 3 | %tobool = icmp ne i16 %x, 1 4 | %conv = zext i16 %x to i32 5 | %cond = select i1 %tobool, i32 %conv, i32 1 6 | ret i32 %cond 7 | } -------------------------------------------------------------------------------- /tests/zext8.syn.ll: -------------------------------------------------------------------------------- 1 | ; CHECK: zext i16 %x to i32 2 | define i32 @test56(i16 %x) { 3 | %tobool = icmp eq i16 %x, 0 4 | %conv = zext i16 %x to i32 5 | %cond = select i1 %tobool, i32 0, i32 %conv 6 | ret i32 %cond 7 | } 8 | -------------------------------------------------------------------------------- /tools/minotaur-cs.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-present, author: Zhengyang Liu (liuz@cs.utah.edu). 2 | // Distributed under the MIT license that can be found in the LICENSE file. 3 | #include "alive-interface.h" 4 | #include "expr.h" 5 | 6 | #include "ir/type.h" 7 | #include "ir/instr.h" 8 | #include "ir/function.h" 9 | #include "ir/globals.h" 10 | #include "smt/smt.h" 11 | #include "smt/solver.h" 12 | #include "tools/transform.h" 13 | #include "util/config.h" 14 | #include "util/symexec.h" 15 | #include "util/errors.h" 16 | #include "llvm_util/llvm2alive.h" 17 | #include "llvm/ADT/STLExtras.h" 18 | #include "llvm/Analysis/ScalarEvolutionExpressions.h" 19 | #include "llvm/Analysis/TargetLibraryInfo.h" 20 | #include "llvm/Bitcode/BitcodeReader.h" 21 | #include "llvm/IR/LLVMContext.h" 22 | #include "llvm/IR/Function.h" 23 | #include "llvm/IRReader/IRReader.h" 24 | #include "llvm/Support/CommandLine.h" 25 | #include "llvm/Support/PrettyStackTrace.h" 26 | #include "llvm/Support/Signals.h" 27 | #include "llvm/Support/SourceMgr.h" 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | using namespace tools; 34 | using namespace util; 35 | using namespace std; 36 | 37 | using namespace llvm; 38 | 39 | static cl::OptionCategory minotaur_cs("minotaur-cs options"); 40 | 41 | static cl::opt opt_file( 42 | cl::Positional, cl::desc("bitcode_file"), cl::Required, 43 | cl::value_desc("filename"), cl::cat(minotaur_cs)); 44 | 45 | static cl::opt opt_debug( 46 | "dbg", cl::desc("Alive: print debugging info"), 47 | cl::cat(minotaur_cs), cl::init(false)); 48 | 49 | static cl::opt opt_disable_undef("disable-undef-input", 50 | cl::init(true), cl::cat(minotaur_cs), 51 | cl::desc("Alive: Assume inputs are not undef (default=true)")); 52 | 53 | static cl::opt opt_disable_poison("disable-poison-input", 54 | cl::init(true), cl::cat(minotaur_cs), 55 | cl::desc("Alive: Assume inputs are not poison (default=true)")); 56 | 57 | static cl::opt opt_smt_verbose( 58 | "smt-verbose", cl::desc("Alive: SMT verbose mode"), 59 | cl::cat(minotaur_cs), cl::init(false)); 60 | 61 | static cl::opt opt_smt_stats( 62 | "smt-stats", cl::desc("Alive: show SMT statistics"), 63 | cl::cat(minotaur_cs), cl::init(false)); 64 | 65 | static cl::opt opt_smt_to( 66 | "smt-to", cl::desc("Timeout for SMT queries (default=10000)"), 67 | cl::cat(minotaur_cs), 68 | cl::init(10000), cl::value_desc("ms")); 69 | 70 | static ExitOnError ExitOnErr; 71 | 72 | // adapted from llvm-dis.cpp 73 | static std::unique_ptr openInputFile(LLVMContext &Context, 74 | string InputFilename) { 75 | auto MB = 76 | ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(InputFilename))); 77 | SMDiagnostic Diag; 78 | auto M = getLazyIRModule(std::move(MB), Diag, Context, 79 | /*ShouldLazyLoadMetadata=*/true); 80 | if (!M) { 81 | Diag.print("", errs(), false); 82 | return 0; 83 | } 84 | ExitOnErr(M->materializeAll()); 85 | return M; 86 | } 87 | 88 | static Function *findFunction(Module &M, const string &FName) { 89 | for (auto &F : M) { 90 | if (F.isDeclaration()) 91 | continue; 92 | if (FName.compare(F.getName()) != 0) 93 | continue; 94 | return &F; 95 | } 96 | return nullptr; 97 | } 98 | 99 | int main(int argc, char **argv) { 100 | sys::PrintStackTraceOnErrorSignal(argv[0]); 101 | PrettyStackTraceProgram X(argc, argv); 102 | EnableDebugBuffering = true; 103 | llvm_shutdown_obj llvm_shutdown; // Call llvm_shutdown() on exit. 104 | LLVMContext Context; 105 | 106 | cl::ParseCommandLineOptions(argc, argv, 107 | "Minotaur stand-alone Constant Synthesizer\n"); 108 | 109 | smt::set_query_timeout(to_string(opt_smt_to)); 110 | smt::solver_print_queries(opt_smt_verbose); 111 | config::disable_undef_input = opt_disable_undef; 112 | config::disable_poison_input = opt_disable_poison; 113 | config::debug = opt_debug; 114 | 115 | auto M = openInputFile(Context, opt_file); 116 | if (!M.get()) 117 | report_fatal_error( 118 | Twine("could not read bitcode from '" + opt_file + "'")); 119 | 120 | auto targetTriple = Triple(M.get()->getTargetTriple()); 121 | TargetLibraryInfoWrapperPass TLI(targetTriple); 122 | 123 | auto SRC = findFunction(*M, "src"); 124 | if (!SRC) 125 | report_fatal_error("could not find function in src"); 126 | 127 | auto TGT = findFunction(*M, "tgt"); 128 | if (!TGT) 129 | report_fatal_error("could not find function in tgt"); 130 | 131 | auto check_name = [](Argument &A) { 132 | return A.getName().starts_with("_reservedc"); 133 | }; 134 | if (!any_of(SRC->args(), check_name)) 135 | report_fatal_error("could not find reservedconst argument in src"); 136 | if (!any_of(TGT->args(), check_name)) 137 | report_fatal_error("could not find reservedconst argument in tgt"); 138 | 139 | minotaur::config::debug_tv = true; 140 | unordered_map constMap; 141 | minotaur::AliveEngine AE(TLI, true); 142 | try { 143 | AE.constantSynthesis(*SRC, *TGT, constMap); 144 | } catch (AliveException e) { 145 | std::cerr< opt_file(cl::Positional, cl::desc("bitcode_file"), 28 | cl::Required, cl::value_desc("filename"), 29 | cl::cat(minotaur_slice)); 30 | 31 | static cl::opt dump_files("dump-files", 32 | llvm::cl::desc("if enabled, dump the sliced bitcode to files"), 33 | llvm::cl::init(false), llvm::cl::cat(minotaur_slice)); 34 | 35 | static llvm::ExitOnError ExitOnErr; 36 | 37 | // adapted from llvm-dis.cpp 38 | static std::unique_ptr openInputFile(LLVMContext &Context, 39 | string InputFilename) { 40 | auto MB = ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(InputFilename))); 41 | llvm::SMDiagnostic Diag; 42 | auto M = getLazyIRModule(std::move(MB), Diag, Context, 43 | /*ShouldLazyLoadMetadata=*/true); 44 | if (!M) { 45 | Diag.print("", llvm::errs(), false); 46 | return 0; 47 | } 48 | ExitOnErr(M->materializeAll()); 49 | return M; 50 | } 51 | 52 | int main(int argc, char **argv) { 53 | llvm::sys::PrintStackTraceOnErrorSignal(argv[0]); 54 | llvm::PrettyStackTraceProgram X(argc, argv); 55 | llvm::EnableDebugBuffering = true; 56 | llvm::llvm_shutdown_obj llvm_shutdown; // Call llvm_shutdown() on exit. 57 | llvm::LLVMContext Context; 58 | 59 | config::debug_slicer = true; 60 | 61 | llvm::cl::ParseCommandLineOptions(argc, argv, "Minotaur Program Slicer\n"); 62 | 63 | auto M = openInputFile(Context, opt_file); 64 | 65 | for (auto &F : *M) { 66 | if (F.isDeclaration()) 67 | continue; 68 | 69 | llvm::PassBuilder PB; 70 | llvm::FunctionAnalysisManager FAM; 71 | PB.registerFunctionAnalyses(FAM); 72 | 73 | //FAM.registerPass(llvm::LoopInfo()); 74 | LoopInfo &LI = FAM.getResult(F); 75 | DominatorTree &DT = FAM.getResult(F); 76 | //MemoryDependenceResults &MD = FAM.getResult(F); 77 | 78 | unsigned count = 0; 79 | for (auto &BB : F) { 80 | for (auto &I : BB) { 81 | Slice S(F, LI, DT); 82 | if (I.getType()->isVoidTy()) 83 | continue; 84 | S.extractExpr(I); 85 | 86 | if (!dump_files) 87 | continue; 88 | 89 | std::error_code EC; 90 | string filename = "slice_" + string(F.getName()) + 91 | "_" + to_string(count++) + ".bc"; 92 | llvm::raw_fd_ostream OS(filename, EC, sys::fs::OpenFlags::OF_None); 93 | //WriteBitcodeToFile(*S.getNewModule(), OS); 94 | OS.flush(); 95 | } 96 | } 97 | } 98 | 99 | return 0; 100 | } -------------------------------------------------------------------------------- /unit-tests/parse-tests.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-present, author: Zhengyang Liu (liuz@cs.utah.edu). 2 | // Distributed under the MIT license that can be found in the LICENSE file. 3 | 4 | #include "gtest/gtest.h" 5 | #include "parse.h" 6 | 7 | #include 8 | 9 | using namespace std; 10 | using namespace minotaur; 11 | 12 | #if 0 13 | 14 | TEST(ParseTest, RoundTrip) { 15 | std::string Tests[] = { 16 | "(add <1 x i32> (var b4 %0) (var b4 %0))", 17 | "(sub <1 x i8> (var b4 %0) (var b4 %0))", 18 | "(sub <1 x i8> (var b4 %0) (const i4 6))", 19 | "(sub <2 x i8> (var b16 %0) (var b16 %0))", 20 | "(sub <2 x i8> (var b16 %0) (var b16 %1))", 21 | "(sub <2 x i8> (var b16 %0) (const <2 x i4> {6,8}))", 22 | "(and <1 x i64> (var b64 %8) (const i64 18446744073709551612))", 23 | "(copy (const <4 x i32> {1,0,2,3}))", 24 | "(icmp_ult (var b32 %0) (const i32 3) b1)", 25 | "(shuffle <32 x i32> (var b64 %0) (const <32 x i8> {0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1}))", 26 | "(blend <32 x i32> (var b64 %0) (var b64 %0) (const <32 x i8> {0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1}))", 27 | "(conv_zext (var b8 %0) <1 x i8> <1 x i64>)", 28 | "(conv_sext (var b8 %0) <1 x i8> <1 x i64>)", 29 | "(conv_trunc (var b8 %0) <1 x i64> <1 x i8>)", 30 | "(x86_sse2_pmadd_wd (var b128 %0) (var b128 %0))" 31 | }; 32 | 33 | for (const auto &T : Tests) { 34 | vector> exprs; 35 | minotaur::Inst *I = nullptr; 36 | try { 37 | Parse p; 38 | I = parse::parse(T, exprs); 39 | } catch (parse::ParseException E) { 40 | cerr<print(rs); 45 | rs.flush(); 46 | EXPECT_EQ(rs.str(), T); 47 | } 48 | } 49 | #endif --------------------------------------------------------------------------------