diff --git a/.travis.yml b/.travis.yml index 9d473ab70..01c29cbf3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,27 +3,50 @@ dist: trusty sudo: required compiler: clang +addons: + apt: + packages: + - git + - cmake + - python-yaml + - python-psutil + - unzip + - libz-dev + - libedit-dev + +cache: + directories: + - $HOME/build/smackers/boogie + - $HOME/build/smackers/corral + - $HOME/build/smackers/symbooglix + - $HOME/build/smackers/lockpwn + env: global: - COMPILER_NAME=clang COMPILER=clang++ CXX=clang++ CC=clang matrix: - TRAVIS_ENV="--exhaustive --folder=basic" + - TRAVIS_ENV="--exhaustive --folder=data" - TRAVIS_ENV="--exhaustive --folder=ntdrivers-simplified" - TRAVIS_ENV="--exhaustive --folder=bits" - TRAVIS_ENV="--exhaustive --folder=float" - TRAVIS_ENV="--exhaustive --folder=locks" - TRAVIS_ENV="--exhaustive --folder=contracts" + - TRAVIS_ENV="--exhaustive --folder=simd" - TRAVIS_ENV="--exhaustive --folder=memory-safety" - TRAVIS_ENV="--exhaustive --folder=pthread" + - TRAVIS_ENV="--exhaustive --folder=strings" before_install: - sudo rm -rf /usr/local/clang-3.5.0 - sudo add-apt-repository "deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-3.9 main" - wget -O - http://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - + - sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF + - echo "deb http://download.mono-project.com/repo/ubuntu trusty main" | sudo tee /etc/apt/sources.list.d/mono-official.list - sudo apt-get update install: - - sudo apt-get install -y clang-3.9 llvm-3.9 + - sudo apt-get install -y clang-3.9 llvm-3.9 mono-complete - sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-3.9 20 - sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-3.9 20 - sudo update-alternatives --install /usr/bin/llvm-config llvm-config /usr/bin/llvm-config-3.9 20 @@ -38,4 +61,3 @@ script: - clang --version - clang++ --version - ./bin/build.sh - diff --git a/CMakeLists.txt b/CMakeLists.txt index aeec6ef7c..731dc3251 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,6 +21,8 @@ if (NOT WIN32 OR MSYS OR CYGWIN) string(REPLACE "-DNDEBUG" "" LLVM_CXXFLAGS "${LLVM_CXXFLAGS}") string(REPLACE "-Wno-maybe-uninitialized" "" LLVM_CXXFLAGS "${LLVM_CXXFLAGS}") string(REPLACE "-fuse-ld=gold" "" LLVM_CXXFLAGS "${LLVM_CXXFLAGS}") + string(REPLACE "--no-keep-files-mapped" "" LLVM_CXXFLAGS "${LLVM_CXXFLAGS}") + string(REPLACE "--no-map-whole-files" "" LLVM_CXXFLAGS "${LLVM_CXXFLAGS}") string(REPLACE "-Wl," "" LLVM_CXXFLAGS "${LLVM_CXXFLAGS}") string(REPLACE "-gsplit-dwarf" "" LLVM_CXXFLAGS "${LLVM_CXXFLAGS}") string(REGEX REPLACE "-O[0-9]" "" CMAKE_CXX_FLAGS "${LLVM_CXXFLAGS}") @@ -172,9 +174,11 @@ add_library(smackTranslator STATIC include/smack/VerifierCodeMetadata.h include/smack/SimplifyLibCalls.h include/smack/SmackRep.h + include/smack/VectorOperations.h include/smack/MemorySafetyChecker.h - include/smack/SignedIntegerOverflowChecker.h - include/smack/SplitAggregateLoadStore.h + include/smack/IntegerOverflowChecker.h + include/smack/NormalizeLoops.h + include/smack/SplitAggregateValue.h lib/smack/AddTiming.cpp lib/smack/BoogieAst.cpp lib/smack/BplFilePrinter.cpp @@ -192,9 +196,11 @@ add_library(smackTranslator STATIC lib/smack/VerifierCodeMetadata.cpp lib/smack/SimplifyLibCalls.cpp lib/smack/SmackRep.cpp + lib/smack/VectorOperations.cpp lib/smack/MemorySafetyChecker.cpp - lib/smack/SignedIntegerOverflowChecker.cpp - lib/smack/SplitAggregateLoadStore.cpp + lib/smack/IntegerOverflowChecker.cpp + lib/smack/NormalizeLoops.cpp + lib/smack/SplitAggregateValue.cpp ) add_executable(llvm2bpl @@ -211,6 +217,7 @@ INSTALL(TARGETS llvm2bpl INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/bin/boogie ${CMAKE_CURRENT_SOURCE_DIR}/bin/corral + ${CMAKE_CURRENT_SOURCE_DIR}/bin/symbooglix ${CMAKE_CURRENT_SOURCE_DIR}/bin/lockpwn ${CMAKE_CURRENT_SOURCE_DIR}/bin/smack ${CMAKE_CURRENT_SOURCE_DIR}/bin/smack-doctor @@ -223,5 +230,5 @@ INSTALL(FILES INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/share/smack DESTINATION share USE_SOURCE_PERMISSIONS - FILES_MATCHING PATTERN "*.py" PATTERN "*.h" PATTERN "*.c" PATTERN "Makefile" + FILES_MATCHING PATTERN "*.py" PATTERN "*.h" PATTERN "*.c" PATTERN "Makefile" PATTERN "*.rs" PATTERN "*.f90" PATTERN "*.di" ) diff --git a/Doxyfile b/Doxyfile index 20d5ae219..ee3c75f72 100644 --- a/Doxyfile +++ b/Doxyfile @@ -5,7 +5,7 @@ #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = smack -PROJECT_NUMBER = 1.9.0 +PROJECT_NUMBER = 1.9.1 PROJECT_BRIEF = "A bounded software verifier." PROJECT_LOGO = OUTPUT_DIRECTORY = docs diff --git a/LICENSE b/LICENSE index 18b4dcd40..cdc39c560 100644 --- a/LICENSE +++ b/LICENSE @@ -1,8 +1,8 @@ The MIT License -Copyright (c) 2008-2017 Zvonimir Rakamaric (zvonimir@cs.utah.edu), +Copyright (c) 2008-2018 Zvonimir Rakamaric (zvonimir@cs.utah.edu), Michael Emmi (michael.emmi@gmail.com) -Modified work Copyright (c) 2013-2017 Montgomery Carter, +Modified work Copyright (c) 2013-2018 Montgomery Carter, Pantazis Deligiannis, Dietrich Geisler, Arvind Haran, @@ -51,6 +51,6 @@ tools and packages, which come with their own licenses: - LLVM, clang, LLVM runtime (http://llvm.org/) - mono (http://www.mono-project.com/) - Boogie (https://github.com/boogie-org/boogie/) -- Corral (http://corral.codeplex.com/) +- Corral (https://github.com/boogie-org/corral/) - Z3 (https://github.com/Z3Prover/z3/) diff --git a/README.md b/README.md index 758140829..0367ec47d 100644 --- a/README.md +++ b/README.md @@ -13,14 +13,14 @@ bitwise operations. Under the hood, SMACK is a translator from the [LLVM](http://www.llvm.org) compiler's popular intermediate representation (IR) into the -[Boogie](http://boogie.codeplex.com) intermediate verification language (IVL). +[Boogie](https://github.com/boogie-org/boogie) intermediate verification language (IVL). Sourcing LLVM IR exploits an increasing number of compiler front-ends, optimizations, and analyses. Currently SMACK only supports the C language via the [Clang](http://clang.llvm.org) compiler, though we are working on providing support for additional languages. Targeting Boogie exploits a canonical platform which simplifies the implementation of algorithms for verification, model checking, and abstract interpretation. Currently, SMACK leverages the -[Boogie](http://boogie.codeplex.com) and [Corral](http://corral.codeplex.com) +[Boogie](https://github.com/boogie-org/boogie) and [Corral](https://github.com/boogie-org/corral) verifiers. See below for system requirements, installation, usage, and everything else. diff --git a/bin/boogie b/bin/boogie index 291ecdc68..1ea15b4fb 100755 --- a/bin/boogie +++ b/bin/boogie @@ -1,2 +1,6 @@ #!/bin/bash +if [ -z "$BOOGIE" ] ; then + echo "The required BOOGIE environment variable is not set. See SMACK documentation for details." + exit 1 +fi $BOOGIE "$@" diff --git a/bin/build.sh b/bin/build.sh index e5f2b840c..fc75a23c7 100755 --- a/bin/build.sh +++ b/bin/build.sh @@ -15,20 +15,26 @@ # - Z3 # - Boogie # - Corral +# - Symbooglix # - lockpwn # ################################################################################ # Set these flags to control various installation options INSTALL_DEPENDENCIES=1 -BUILD_Z3=1 +INSTALL_Z3=1 BUILD_BOOGIE=1 BUILD_CORRAL=1 +BUILD_SYMBOOGLIX=1 BUILD_LOCKPWN=1 BUILD_SMACK=1 TEST_SMACK=1 BUILD_LLVM=0 # LLVM is typically installed from packages (see below) -BUILD_MONO=0 +BUILD_MONO=0 # mono is typically installed from packages (see below) + +# Support for more programming languages +INSTALL_OBJECTIVEC=0 +INSTALL_RUST=0 # PATHS SMACK_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )" @@ -36,6 +42,7 @@ ROOT="$( cd "${SMACK_DIR}" && cd .. && pwd )" Z3_DIR="${ROOT}/z3" BOOGIE_DIR="${ROOT}/boogie" CORRAL_DIR="${ROOT}/corral" +SYMBOOGLIX_DIR="${ROOT}/symbooglix" LOCKPWN_DIR="${ROOT}/lockpwn" MONO_DIR="${ROOT}/mono" LLVM_DIR="${ROOT}/llvm" @@ -50,7 +57,7 @@ INSTALL_PREFIX= CONFIGURE_INSTALL_PREFIX= CMAKE_INSTALL_PREFIX= -# Partial list of dependnecies; the rest are added depending on the platform +# Partial list of dependencies; the rest are added depending on the platform DEPENDENCIES="git cmake python-yaml python-psutil unzip wget" shopt -s extglob @@ -138,6 +145,23 @@ function get-platform { esac } +# ================================================================ +# Check if git repo is up to date. +# ================================================================ +function upToDate { + if [ ! -d "$1/.git" ] ; then + return 1 + else + cd $1 + hash=$(git rev-parse --short=10 HEAD) + if [ "$TRAVIS" != "true" ] || [ $hash == $2 ] ; then + return 0 + else + return 1 + fi + fi +} + function puts { echo -e "\033[35m*** SMACK BUILD: ${1} ***\033[0m" } @@ -157,7 +181,7 @@ puts "Detected distribution: $distro" # Set platform-dependent flags case "$distro" in linux-opensuse*) - Z3_DOWNLOAD_LINK="https://github.com/Z3Prover/z3/releases/download/z3-${Z3_VERSION}/z3-${Z3_VERSION}-x64-debian-8.2.zip" + Z3_DOWNLOAD_LINK="https://github.com/Z3Prover/z3/releases/download/z3-${Z3_VERSION}/z3-${Z3_VERSION}-x64-debian-8.10.zip" DEPENDENCIES+=" llvm-clang llvm-devel gcc-c++ mono-complete make" DEPENDENCIES+=" ncurses-devel zlib-devel" ;; @@ -181,7 +205,7 @@ linux-ubuntu-12*) linux-cygwin*) BUILD_LLVM=1 - BUILD_Z3=0 + INSTALL_Z3=0 BUILD_BOOGIE=0 BUILD_CORRAL=0 ;; @@ -214,8 +238,7 @@ do done -if [ ${INSTALL_DEPENDENCIES} -eq 1 ] -then +if [ ${INSTALL_DEPENDENCIES} -eq 1 ] && [ "$TRAVIS" != "true" ] ; then puts "Installing required packages" case "$distro" in @@ -239,13 +262,16 @@ then ;; esac + if [ ${INSTALL_OBJECTIVEC} -eq 1 ] ; then + sudo apt-get install -y gobjc gnustep gnustep-make gnustep-common gnustep-devel + fi + # Adding LLVM repository sudo add-apt-repository "deb http://apt.llvm.org/${UBUNTU_CODENAME}/ llvm-toolchain-${UBUNTU_CODENAME}-${LLVM_SHORT_VERSION} main" ${WGET} -O - http://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - # Adding MONO repository - sudo add-apt-repository "deb http://download.mono-project.com/repo/debian wheezy main" sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF -# echo "deb http://download.mono-project.com/repo/debian wheezy main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list + echo "deb http://download.mono-project.com/repo/ubuntu trusty main" | sudo tee /etc/apt/sources.list.d/mono-official.list sudo apt-get update sudo apt-get install -y ${DEPENDENCIES} sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-${LLVM_SHORT_VERSION} 30 @@ -279,8 +305,7 @@ then fi -if [ ${BUILD_MONO} -eq 1 ] -then +if [ ${BUILD_MONO} -eq 1 ] ; then puts "Building mono" git clone git://github.com/mono/mono.git ${MONO_DIR} @@ -299,8 +324,7 @@ then make sudo make install - if [[ ${INSTALL_PREFIX} ]] - then + if [[ ${INSTALL_PREFIX} ]] ; then echo export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${INSTALL_PREFIX}/lib >> ${SMACKENV} source ${SMACKENV} fi @@ -309,8 +333,7 @@ then fi -if [ ${BUILD_LLVM} -eq 1 ] -then +if [ ${BUILD_LLVM} -eq 1 ] ; then puts "Building LLVM" mkdir -p ${LLVM_DIR}/src/{tools/clang,projects/compiler-rt} @@ -333,74 +356,119 @@ then fi -if [ ${BUILD_Z3} -eq 1 ] -then - puts "Installing Z3" +if [ ${INSTALL_OBJECTIVEC} -eq 1 ] ; then + puts "Installing Objective-C" - ${WGET} ${Z3_DOWNLOAD_LINK} -O z3-downloaded.zip - unzip -o z3-downloaded.zip -d z3-extracted - mv -f --backup=numbered z3-extracted/z3-* ${Z3_DIR} - rm -rf z3-downloaded.zip z3-extracted + # The version numbers here will have to change by OS + sudo ln -s /usr/lib/gcc/x86_64-linux-gnu/4.8/include/objc /usr/local/include/objc + echo ". /usr/share/GNUstep/Makefiles/GNUstep.sh" >> ${SMACKENV} - puts "Installed Z3" -fi + puts "Installed Objective-C" +fi +if [ ${INSTALL_RUST} -eq 1 ] ; then + puts "Installing Rust" -if [ ${BUILD_BOOGIE} -eq 1 ] -then - puts "Building Boogie" + ${WGET} https://static.rust-lang.org/dist/${RUST_VERSION}/rust-nightly-x86_64-unknown-linux-gnu.tar.gz -O rust.tar.gz + tar xf rust.tar.gz + cd rust-nightly-x86_64-unknown-linux-gnu + sudo ./install.sh + cd .. + + puts "Installed Rust" +fi - if [ ! -d "$BOOGIE_DIR" ] ; then - git clone https://github.com/boogie-org/boogie.git ${BOOGIE_DIR} +if [ ${INSTALL_Z3} -eq 1 ] ; then + if [ ! -d "$Z3_DIR" ] ; then + puts "Installing Z3" + mkdir -p ${Z3_DIR} + ${WGET} ${Z3_DOWNLOAD_LINK} -O z3-downloaded.zip + unzip -o z3-downloaded.zip -d z3-extracted + mv -f --backup=numbered z3-extracted/z3-*/* ${Z3_DIR} + rm -rf z3-downloaded.zip z3-extracted + puts "Installed Z3" + else + puts "Z3 already installed" fi - cd ${BOOGIE_DIR} - git reset --hard ${BOOGIE_COMMIT} - cd ${BOOGIE_DIR}/Source - ${WGET} https://dist.nuget.org/win-x86-commandline/latest/nuget.exe - mono ./nuget.exe restore Boogie.sln - rm -rf /tmp/nuget/ - msbuild Boogie.sln /p:Configuration=Release - ln -sf ${Z3_DIR}/bin/z3 ${BOOGIE_DIR}/Binaries/z3.exe - - puts "Built Boogie" fi -if [ ${BUILD_CORRAL} -eq 1 ] -then - puts "Building Corral" - - if [ ! -d "$CORRAL_DIR" ] ; then - git clone https://github.com/boogie-org/corral.git ${CORRAL_DIR} +if [ ${BUILD_BOOGIE} -eq 1 ] ; then + if ! upToDate $BOOGIE_DIR $BOOGIE_COMMIT ; then + puts "Building Boogie" + if [ ! -d "$BOOGIE_DIR/.git" ] ; then + git clone https://github.com/boogie-org/boogie.git ${BOOGIE_DIR} + fi + cd ${BOOGIE_DIR} + git reset --hard ${BOOGIE_COMMIT} + cd ${BOOGIE_DIR}/Source + ${WGET} https://dist.nuget.org/win-x86-commandline/latest/nuget.exe + mono ./nuget.exe restore Boogie.sln + rm -rf /tmp/nuget/ + msbuild Boogie.sln /p:Configuration=Release + ln -sf ${Z3_DIR}/bin/z3 ${BOOGIE_DIR}/Binaries/z3.exe + puts "Built Boogie" + else + puts "Boogie already built" fi - cd ${CORRAL_DIR} - git reset --hard ${CORRAL_COMMIT} - git submodule init - git submodule update - msbuild cba.sln /p:Configuration=Release - ln -sf ${Z3_DIR}/bin/z3 ${CORRAL_DIR}/bin/Release/z3.exe - - puts "Built Corral" fi -if [ ${BUILD_LOCKPWN} -eq 1 ] -then - puts "Building lockpwn" - cd ${ROOT} - if [ ! -d "$LOCKPWN_DIR" ] ; then - git clone https://github.com/smackers/lockpwn.git +if [ ${BUILD_CORRAL} -eq 1 ] ; then + if ! upToDate $CORRAL_DIR $CORRAL_COMMIT ; then + puts "Building Corral" + if [ ! -d "$CORRAL_DIR/.git" ] ; then + git clone https://github.com/boogie-org/corral.git ${CORRAL_DIR} + fi + cd ${CORRAL_DIR} + git reset --hard ${CORRAL_COMMIT} + git submodule init + git submodule update + msbuild cba.sln /p:Configuration=Release + ln -sf ${Z3_DIR}/bin/z3 ${CORRAL_DIR}/bin/Release/z3.exe + puts "Built Corral" + else + puts "Corral already built" + fi +fi + +if [ ${BUILD_SYMBOOGLIX} -eq 1 ] ; then + if ! upToDate $SYMBOOGLIX_DIR $SYMBOOGLIX_COMMIT ; then + puts "Building Symbooglix" + if [ ! -d "$SYMBOOGLIX_DIR/.git" ] ; then + git clone --recursive https://github.com/boogie-org/symbooglix.git ${SYMBOOGLIX_DIR} + fi + cd ${SYMBOOGLIX_DIR}/src + git reset --hard ${SYMBOOGLIX_COMMIT} + ${WGET} https://dist.nuget.org/win-x86-commandline/latest/nuget.exe + mono ./nuget.exe restore Symbooglix.sln + rm -rf /tmp/nuget/ + xbuild Symbooglix.sln /p:Configuration=Release + ln -s ${Z3_DIR}/bin/z3 ${SYMBOOGLIX_DIR}/src/SymbooglixDriver/bin/Release/z3.exe + ln -s ${Z3_DIR}/bin/z3 ${SYMBOOGLIX_DIR}/src/Symbooglix/bin/Release/z3.exe + puts "Built Symbooglix" + else + puts "Symbooglix already built" fi - cd ${LOCKPWN_DIR} - git reset --hard ${LOCKPWN_COMMIT} - msbuild lockpwn.sln /p:Configuration=Release - ln -sf ${Z3_DIR}/bin/z3 ${LOCKPWN_DIR}/Binaries/z3.exe +fi - puts "Built lockpwn" +if [ ${BUILD_LOCKPWN} -eq 1 ] ; then + if ! upToDate $LOCKPWN_DIR $LOCKPWN_COMMIT ; then + puts "Building lockpwn" + if [ ! -d "$LOCKPWN_DIR/.git" ] ; then + git clone https://github.com/smackers/lockpwn.git ${LOCKPWN_DIR} + fi + cd ${LOCKPWN_DIR} + git reset --hard ${LOCKPWN_COMMIT} + msbuild lockpwn.sln /p:Configuration=Release + ln -sf ${Z3_DIR}/bin/z3 ${LOCKPWN_DIR}/Binaries/z3.exe + puts "Built lockpwn" + else + puts "Lockpwn already built" + fi fi -if [ ${BUILD_SMACK} -eq 1 ] -then +if [ ${BUILD_SMACK} -eq 1 ] ; then puts "Building SMACK" mkdir -p ${SMACK_DIR}/build @@ -412,6 +480,7 @@ then puts "Configuring shell environment" echo export BOOGIE=\"mono ${BOOGIE_DIR}/Binaries/Boogie.exe\" >> ${SMACKENV} echo export CORRAL=\"mono ${CORRAL_DIR}/bin/Release/corral.exe\" >> ${SMACKENV} + echo export SYMBOOGLIX=\"mono ${SYMBOOGLIX_DIR}/src/SymbooglixDriver/bin/Release/sbx.exe\" >> ${SMACKENV} echo export LOCKPWN=\"mono ${LOCKPWN_DIR}/Binaries/lockpwn.exe\" >> ${SMACKENV} source ${SMACKENV} puts "The required environment variables have been set in ${SMACKENV}" @@ -421,8 +490,7 @@ then fi -if [ ${TEST_SMACK} -eq 1 ] -then +if [ ${TEST_SMACK} -eq 1 ] ; then puts "Running SMACK regression tests" cd ${SMACK_DIR}/test diff --git a/bin/corral b/bin/corral index 4707c5d96..b26192e81 100755 --- a/bin/corral +++ b/bin/corral @@ -1,2 +1,6 @@ #!/bin/bash +if [ -z "$CORRAL" ] ; then + echo "The required CORRAL environment variable is not set. See SMACK documentation for details." + exit 1 +fi $CORRAL "$@" diff --git a/bin/lockpwn b/bin/lockpwn index cd8cd9b34..c8cdfec33 100755 --- a/bin/lockpwn +++ b/bin/lockpwn @@ -1,2 +1,6 @@ #!/bin/bash +if [ -z "$LOCKPWN" ] ; then + echo "The required LOCKPWN environment variable is not set. See SMACK documentation for details." + exit 1 +fi $LOCKPWN "$@" diff --git a/bin/smack b/bin/smack index fb3b08eb7..bbc4e0601 100755 --- a/bin/smack +++ b/bin/smack @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 # # This file is distributed under the MIT License. See LICENSE for details. # diff --git a/bin/smack-doctor b/bin/smack-doctor old mode 100644 new mode 100755 index cf21e5509..c206adfd9 --- a/bin/smack-doctor +++ b/bin/smack-doctor @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 # # This file is distributed under the MIT License. See LICENSE for details. # diff --git a/bin/symbooglix b/bin/symbooglix new file mode 100755 index 000000000..79c20a3cb --- /dev/null +++ b/bin/symbooglix @@ -0,0 +1,6 @@ +#!/bin/bash +if [ -z "$SYMBOOGLIX" ] ; then + echo "The required SYMBOOGLIX environment variable is not set. See SMACK documentation for details." + exit 1 +fi +$SYMBOOGLIX "$@" diff --git a/bin/versions b/bin/versions index 7a2e11fcb..eb99b176f 100644 --- a/bin/versions +++ b/bin/versions @@ -1,7 +1,9 @@ MONO_VERSION=5.0.0.100 -Z3_VERSION=4.5.0 -BOOGIE_COMMIT=c609ee2864 -CORRAL_COMMIT=b2738b4839 -LOCKPWN_COMMIT=a4d802a1cb +Z3_VERSION=4.6.0 +BOOGIE_COMMIT=c92bebd817 +CORRAL_COMMIT=179251cc9c +SYMBOOGLIX_COMMIT=7210e5d09b +LOCKPWN_COMMIT=73eddf97bd LLVM_SHORT_VERSION=3.9 LLVM_FULL_VERSION=3.9.1 +RUST_VERSION=2016-12-16 diff --git a/bin/vsmack b/bin/vsmack index 9285696d6..8cbbdf037 100755 --- a/bin/vsmack +++ b/bin/vsmack @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 import argparse import os.path diff --git a/docs/installation.md b/docs/installation.md index 98f9920f7..282819486 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -37,7 +37,7 @@ installation support. The following versions are required: * [Vagrant][] version 1.7.2 or greater Once both are properly installed, launch [Vagrant][] by running the following -command in SMACK.s root directory (that which contains `Vagrantfile`): +command in SMACK's root directory (that which contains `Vagrantfile`): ````Shell vagrant up ```` @@ -76,9 +76,9 @@ Some distributions of Linux may have various SMACK dependencies like [Python][] installed out of the box. Nevertheless it is important to ensure that the required version numbers, as indicated above, are installed and selected for use. Generally speaking, apart from [Z3][], [Boogie][], and [Corral][], these -dependencies can be installed via the system.s default package manager, such as +dependencies can be installed via the system's default package manager, such as `apt-get`, `rpm`, or `yast`. In some cases, it may be necessary to specify -alternate package repositories for the system.s default package manager, or to +alternate package repositories for the system's default package manager, or to subvert the package manager altogether, and download, compile, and install the required project manually. The [Z3][], [Boogie][], and [Corral][] projects are generally not indexed by Linux package managers, and must be installed manually. @@ -86,9 +86,14 @@ generally not indexed by Linux package managers, and must be installed manually. To facilitate the installation of SMACK and its requirements, we provide an automated [build.sh][] script in `bin/build.sh`. Running this script on a fresh installation of Ubuntu or openSUSE Linux should actually result in the full -installation of SMACK and its requirements. However, we do not expect this -script to work out of the box on all configurations. Instead, it can be used as -reference guidelines for manual installation. +installation of SMACK and its requirements, apart from setting the required +environment variables in your shell's `.profile`. However, we do not expect +this script to work out of the box on all configurations. Instead, it can be +used as reference guidelines for manual installation. + +**NOTE** A common omission is to forget to set the required environment +variables after the installation process, as indicated in the end of the build +script. Alternatively, you can read how to accomplish this below. ### Installation on OS X @@ -119,7 +124,7 @@ and [Clang][] is problematic on some [Cygwin][] configurations. Please consult ### Installing SMACK Itself SMACK is built using [CMake][] via the following sequence of shell commands -from SMACK.s root directory: +from SMACK's root directory: ````Shell mkdir build cd build @@ -141,7 +146,7 @@ residing in paths prefixed by `XXX` and `YYY`: export BOOGIE="mono /XXX/Boogie/Binaries/Boogie.exe" export CORRAL="mono /YYY/Corral/bin/Release/corral.exe" ```` -Source the preceding lines in your shell.s `.profile`, and ensure they invoke +Source the preceding lines in your shell's `.profile`, and ensure they invoke Boogie/Corral correctly. For example, running ````Shell BOOGIE @@ -172,7 +177,7 @@ shell in the `test` directory by executing [Clang]: http://clang.llvm.org [Clang-3.9.1]: http://llvm.org/releases/download.html#3.9.1 [Boogie]: https://github.com/boogie-org/boogie -[Corral]: https://corral.codeplex.com/ +[Corral]: https://github.com/boogie-org/corral [Z3]: https://github.com/Z3Prover/z3/ [Mono]: http://www.mono-project.com/ [Cygwin]: https://www.cygwin.com diff --git a/docs/projects.md b/docs/projects.md index a34f153a2..3eaaa2236 100644 --- a/docs/projects.md +++ b/docs/projects.md @@ -16,7 +16,7 @@ be targeted by SMACK, at least in theory. So pick your favorite language (e.g., C++, Objective-C, Swift, Fortran) supported by LLVM and try to extend SMACK to support it. For example, if you are an iPhone developer, you might have some expertise in Objective-C and/or Swift. And you could -even base the project around verifying your own iPhone app.s code. +even base the project around verifying your own iPhone app's code. 3. Try to use and extend SMACK to verify some of the example from the annual [Verified Software Competition (VSCOMP)](http://vscomp.org/). diff --git a/docs/publications.md b/docs/publications.md index 3012a042f..81b2d3e69 100644 --- a/docs/publications.md +++ b/docs/publications.md @@ -14,11 +14,40 @@ Zvonimir Rakamaric, Michael Emmi, This is an incomplete list of publications that use, leverage, or extend SMACK. If you have a publication for this list, please email [Zvonimir](mailto:zvonimir@cs.utah.edu). +1. [Reducer-Based Construction of Conditional Verifiers](https://dl.acm.org/citation.cfm?id=3180259), +Dirk Beyer, Marie-Christine Jakobs, Thomas Lemberger, Heike Wehrheim, +40th International Conference on Software Engineering (ICSE 2018) + +1. [ZEUS: Analyzing Safety of Smart Contracts](http://wp.internetsociety.org/ndss/wp-content/uploads/sites/25/2018/02/ndss2018_09-1_Kalra_paper.pdf), +Sukrit Kalra, Seep Goel, Mohan Dhawan, Subodh Sharma, +25th Annual Network and Distributed System Security Symposium (NDSS 2018) + +1. [Formal Verification of Optimizing Compilers](https://link.springer.com/chapter/10.1007/978-3-319-72344-0_3), +Yiji Zhang, Lenore D. Zuck, +Keynote at the 14th International Conference on Distributed Computing and Internet Technology (ICDCIT 2018) + +1. [Counterexample-Guided Bit-Precision Selection](http://soarlab.org/2017/09/aplas2017-hr/), +Shaobo He, Zvonimir Rakamaric, +15th Asian Symposium on Programming Languages and Systems (APLAS 2017) + +1. [FaCT: A Flexible, Constant-Time Programming Language](https://cseweb.ucsd.edu/~dstefan/pubs/cauligi:2017:fact.pdf), +Sunjay Cauligi, Gary Soeller, Fraser Brown, Brian Johannesmeyer, Yunlu Huang, Ranjit Jhala, Deian Stefan, +IEEE Secure Development Conference (SecDev 2017) + +1. [Static Assertion Checking of Production Software with Angelic Verification](http://soarlab.org/2017/09/tapas2017-hllr/), +Shaobo He, Shuvendu Lahiri, Akash Lal, Zvonimir Rakamaric, +8th Workshop on Tools for Automatic Program Analysis (TAPAS 2017) + 1. [Refining Interprocedural Change-Impact Analysis using Equivalence Relations](https://www.microsoft.com/en-us/research/publication/refining-interprocedural-change-impact-analysis-using-equivalence-relations), Alex Gyori, Shuvendu Lahiri, Nimrod Partush, 26th ACM SIGSOFT International Symposium on Software Testing and Analysis (ISSTA 2017) +1. [System Programming in Rust: Beyond Safety](http://soarlab.org/2017/06/hotos2017-bbbprr/), +Abhiram Balasubramanian, Marek S. Baranowski, Anton Burtsev, Aurojit Panda, +Zvonimir Rakamaric, Leonid Ryzhyk, +16th Workshop on Hot Topics in Operating Systems (HotOS 2017) + 1. [Verifying Constant-Time Implementations](https://www.usenix.org/conference/usenixsecurity16/technical-sessions/presentation/almeida), Jose Bacelar Almeida, Manuel Barbosa, Gilles Barthe, Francois Dupressoir, Michael Emmi, 25th USENIX Security Symposium diff --git a/include/smack/BoogieAst.h b/include/smack/BoogieAst.h index cb8205756..9c96c79ba 100644 --- a/include/smack/BoogieAst.h +++ b/include/smack/BoogieAst.h @@ -10,12 +10,16 @@ namespace smack { +typedef std::pair Binding; + +enum class RModeKind { RNE, RNA, RTP, RTN, RTZ }; + class Expr { public: virtual ~Expr() {} virtual void print(std::ostream& os) const = 0; - static const Expr* exists(std::string v, std::string t, const Expr* e); - static const Expr* forall(std::string v, std::string t, const Expr* e); + static const Expr* exists(std::list, const Expr* e); + static const Expr* forall(std::list, const Expr* e); static const Expr* and_(const Expr* l, const Expr* r); static const Expr* cond(const Expr* c, const Expr* t, const Expr* e); static const Expr* eq(const Expr* l, const Expr* r); @@ -34,10 +38,13 @@ class Expr { static const Expr* lit(std::string v, unsigned w); static const Expr* lit(unsigned long v, unsigned w); static const Expr* lit(bool n, std::string s, std::string e, unsigned ss, unsigned es); + static const Expr* lit(RModeKind v); static const Expr* neq(const Expr* l, const Expr* r); static const Expr* not_(const Expr* e); static const Expr* sel(const Expr* b, const Expr* i); static const Expr* sel(std::string b, std::string i); + static const Expr* upd(const Expr* b, const Expr* i, const Expr* v); + static const Expr* if_then_else(const Expr* c, const Expr* t, const Expr* e); }; class BinExpr : public Expr { @@ -79,6 +86,13 @@ class BoolLit : public Expr { void print(std::ostream& os) const; }; +class RModeLit : public Expr { + RModeKind val; +public: + RModeLit(RModeKind v) : val(v) {} + void print(std::ostream& os) const; +}; + class IntLit : public Expr { std::string val; public: @@ -146,10 +160,10 @@ class QuantExpr : public Expr { enum Quantifier { Exists, Forall }; private: Quantifier quant; - std::list< std::pair > vars; + std::list vars; const Expr* expr; public: - QuantExpr(Quantifier q, std::list< std::pair > vs, const Expr* e) : quant(q), vars(vs), expr(e) {} + QuantExpr(Quantifier q, std::list vs, const Expr* e) : quant(q), vars(vs), expr(e) {} void print(std::ostream& os) const; }; @@ -182,6 +196,16 @@ class VarExpr : public Expr { void print(std::ostream& os) const; }; +class IfThenElseExpr : public Expr { + const Expr* cond; + const Expr* true_value; + const Expr* false_value; +public: + IfThenElseExpr(const Expr* c, const Expr* t, const Expr* e) + : cond(c), true_value(t), false_value(e) {} + void print(std::ostream& os) const; +}; + class Attr { protected: std::string name; @@ -361,11 +385,12 @@ class Decl { std::string getName() const { return name; } void addAttr(const Attr* a) { attrs.push_back(a); } - static Decl* typee(std::string name, std::string type); - static Decl* axiom(const Expr* e); + static Decl* typee(std::string name, std::string type, + std::list attrs = std::list()); + static Decl* axiom(const Expr* e, std::string name = ""); static FuncDecl* function( std::string name, - std::list< std::pair > args, + std::list args, std::string type, const Expr* e = NULL, std::list attrs = std::list()); @@ -374,8 +399,8 @@ class Decl { static Decl* constant(std::string name, std::string type, std::list ax, bool unique); static Decl* variable(std::string name, std::string type); static ProcDecl* procedure(std::string name, - std::list< std::pair > params = std::list< std::pair >(), - std::list< std::pair > rets = std::list< std::pair >(), + std::list params = std::list(), + std::list rets = std::list(), std::list decls = std::list(), std::list blocks = std::list()); static Decl* code(std::string name, std::string s); @@ -385,7 +410,8 @@ class Decl { class TypeDecl : public Decl { std::string alias; public: - TypeDecl(std::string n, std::string t) : Decl(TYPE, n, {}), alias(t) {} + TypeDecl(std::string n, std::string t, std::list ax) + : Decl(TYPE, n, ax), alias(t) {} void print(std::ostream& os) const; static bool classof(const Decl* D) { return D->getKind() == TYPE; } }; @@ -394,7 +420,7 @@ class AxiomDecl : public Decl { const Expr* expr; static int uniqueId; public: - AxiomDecl(const Expr* e) : Decl(AXIOM, "", {}), expr(e) {} + AxiomDecl(std::string n, const Expr* e) : Decl(AXIOM, n, {}), expr(e) {} void print(std::ostream& os) const; static bool classof(const Decl* D) { return D->getKind() == AXIOM; } }; @@ -410,11 +436,11 @@ class ConstDecl : public Decl { }; class FuncDecl : public Decl { - std::list< std::pair > params; + std::list params; std::string type; const Expr* body; public: - FuncDecl(std::string n, std::list ax, std::list< std::pair > ps, + FuncDecl(std::string n, std::list ax, std::list ps, std::string t, const Expr* b) : Decl(FUNCTION, n, ax), params(ps), type(t), body(b) {} void print(std::ostream& os) const; @@ -491,7 +517,7 @@ class CodeExpr : public Expr, public CodeContainer { }; class ProcDecl : public Decl, public CodeContainer { - typedef std::pair Parameter; + typedef Binding Parameter; typedef std::list ParameterList; typedef std::list SpecificationList; diff --git a/include/smack/ExtractContracts.h b/include/smack/ExtractContracts.h index 5c7d7e9dd..dbf35cc9b 100644 --- a/include/smack/ExtractContracts.h +++ b/include/smack/ExtractContracts.h @@ -2,8 +2,6 @@ // This file is distributed under the MIT License. See LICENSE for details. // -#include "llvm/IR/Instructions.h" -#include "llvm/IR/InstVisitor.h" #include "llvm/IR/Module.h" #include "llvm/Pass.h" @@ -11,19 +9,11 @@ namespace smack { using namespace llvm; -class ExtractContracts : public ModulePass, public InstVisitor { -private: - bool modified; - void validateAnnotation(CallInst &I); - bool hasDominatedIncomingValue(Value* V); - std::tuple< Function*, std::vector > extractExpression( - Value* V, BasicBlock* E); - +class ExtractContracts : public ModulePass { public: static char ID; ExtractContracts() : ModulePass(ID) {} virtual bool runOnModule(Module& M); virtual void getAnalysisUsage(AnalysisUsage &AU) const; - void visitCallInst(CallInst&); }; } diff --git a/include/smack/IntegerOverflowChecker.h b/include/smack/IntegerOverflowChecker.h new file mode 100644 index 000000000..2fd095e25 --- /dev/null +++ b/include/smack/IntegerOverflowChecker.h @@ -0,0 +1,32 @@ +// +// This file is distributed under the MIT License. See LICENSE for details. +// +#ifndef INTEGEROVERFLOWCHECKER_H +#define INTEGEROVERFLOWCHECKER_H + +#include "llvm/Pass.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Instructions.h" +#include + +namespace smack { + +class IntegerOverflowChecker: public llvm::ModulePass { +public: + static char ID; // Pass identification, replacement for typeid + IntegerOverflowChecker() : llvm::ModulePass(ID) {} + const char* getPassName() const; + virtual bool runOnModule(llvm::Module& m); +private: + static const std::map INSTRUCTION_TABLE; + std::string getMax(unsigned bits, bool isSigned); + std::string getMin(unsigned bits, bool isSigned); + llvm::Value* extendBitWidth(llvm::Value* v, int bits, bool isSigned, llvm::Instruction* i); + llvm::BinaryOperator* createFlag(llvm::Value* v, int bits, bool isSigned, llvm::Instruction* i); + llvm::Value* createResult(llvm::Value* v, int bits, llvm::Instruction* i); + void addCheck(llvm::Function* co, llvm::BinaryOperator* flag, llvm::Instruction* i); + void addBlockingAssume(llvm::Function* va, llvm::BinaryOperator* flag, llvm::Instruction* i); +}; +} + +#endif //INTEGEROVERFLOWCHECKER_H diff --git a/include/smack/MemorySafetyChecker.h b/include/smack/MemorySafetyChecker.h index d02b21c0c..a5007606d 100644 --- a/include/smack/MemorySafetyChecker.h +++ b/include/smack/MemorySafetyChecker.h @@ -5,17 +5,35 @@ #define MEMORYSAFETYCHECKER_H #include "llvm/Pass.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/InstVisitor.h" +#include namespace smack { - -class MemorySafetyChecker: public llvm::ModulePass { + +class MemorySafetyChecker: public llvm::FunctionPass, public llvm::InstVisitor { +private: + std::map leakCheckFunction; + std::map safetyCheckFunction; + + llvm::Function* getLeakCheckFunction(llvm::Module& M); + llvm::Function* getSafetyCheckFunction(llvm::Module& M); + + void insertMemoryLeakCheck(llvm::Instruction* I); + void insertMemoryAccessCheck(llvm::Value* addr, llvm::Value* size, llvm::Instruction* I); + public: static char ID; // Pass identification, replacement for typeid - MemorySafetyChecker() : llvm::ModulePass(ID) {} - virtual bool runOnModule(llvm::Module& m); + MemorySafetyChecker() : llvm::FunctionPass(ID) {} + virtual bool runOnFunction(llvm::Function& F); + + void visitReturnInst(llvm::ReturnInst& I); + void visitLoadInst(llvm::LoadInst& I); + void visitStoreInst(llvm::StoreInst& I); + void visitMemSetInst(llvm::MemSetInst& I); + void visitMemTransferInst(llvm::MemTransferInst& I); }; } #endif //MEMORYSAFETYCHECKER_H - diff --git a/include/smack/Naming.h b/include/smack/Naming.h index b217f0a8e..17c1d4fbc 100644 --- a/include/smack/Naming.h +++ b/include/smack/Naming.h @@ -22,14 +22,17 @@ class Naming { unsigned blockNum; unsigned varNum; unsigned undefNum; + unsigned globalNum; public: static const std::string BOOL_TYPE; static const std::string UNINTERPRETED_FLOAT_TYPE; + static const std::string HALF_TYPE; static const std::string FLOAT_TYPE; static const std::string DOUBLE_TYPE; static const std::string LONG_DOUBLE_TYPE; static const std::string PTR_TYPE; + static const std::string VECTOR_TYPE; static const std::string NULL_VAL; static const std::string INIT_FUNC_PREFIX; @@ -76,10 +79,13 @@ class Naming { static const std::string RET_VAR; static const std::string EXN_VAR; static const std::string EXN_VAL_VAR; + static const std::string RMODE_VAR; static const std::string BOOL_VAR; static const std::string FLOAT_VAR; static const std::string INT_VAR; + static const std::string VECTOR_VAR; static const std::string PTR_VAR; + static const std::string GLOBAL_VAR; static const std::string UNDEF_SYM; static const std::string CONTRACT_EXPR; static const std::string MEMORY_SAFETY_FUNCTION; @@ -89,12 +95,13 @@ class Naming { static const std::map CMPINST_TABLE; static const std::map ATOMICRMWINST_TABLE; - Naming() : blockNum(0), varNum(0), undefNum(0) { } + Naming() : blockNum(0), varNum(0), undefNum(0), globalNum(0) { } Naming(Naming& n) : blockNum(n.blockNum), varNum(n.varNum) { } void reset(); std::string get(const Value& V); + std::string freshGlobalName(); std::string freshBlockName(); std::string freshUndefName(); std::string freshVarName(const Value& V); diff --git a/include/smack/NormalizeLoops.h b/include/smack/NormalizeLoops.h new file mode 100644 index 000000000..9ba13c7f5 --- /dev/null +++ b/include/smack/NormalizeLoops.h @@ -0,0 +1,24 @@ +// +// This file is distributed under the MIT License. See LICENSE for details. +// +#ifndef NORMALIZELOOPS_H +#define NORMALIZELOOPS_H + +#include "llvm/Pass.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Instructions.h" +#include + +namespace smack { + +class NormalizeLoops: public llvm::ModulePass { +public: + static char ID; // Pass identification, replacement for typeid + NormalizeLoops() : llvm::ModulePass(ID) {} + const char* getPassName() const override; + virtual bool runOnModule(llvm::Module& m) override; + virtual void getAnalysisUsage(llvm::AnalysisUsage&) const override; +}; +} + +#endif //NORMALIZELOOPS_H diff --git a/include/smack/SignedIntegerOverflowChecker.h b/include/smack/SignedIntegerOverflowChecker.h deleted file mode 100644 index 5a502fcc2..000000000 --- a/include/smack/SignedIntegerOverflowChecker.h +++ /dev/null @@ -1,27 +0,0 @@ -// -// This file is distributed under the MIT License. See LICENSE for details. -// -#ifndef SIGNEDINTEGEROVERFLOWCHECKER_H -#define SIGNEDINTEGEROVERFLOWCHECKER_H - -#include "llvm/Pass.h" -#include "llvm/IR/Module.h" -#include - -namespace smack { - -class SignedIntegerOverflowChecker: public llvm::ModulePass { -public: - static char ID; // Pass identification, replacement for typeid - SignedIntegerOverflowChecker() : llvm::ModulePass(ID) {} - virtual bool runOnModule(llvm::Module& m); -private: - static std::map INSTRUCTION_TABLE; - static std::map INT_MAX_TABLE; - static std::map INT_MIN_TABLE; - void replaceValue(llvm::Value* ee, llvm::Value* er); -}; - -} - -#endif //SIGNEDINTEGEROVERFLOWCHECKER_H diff --git a/include/smack/SmackInstGenerator.h b/include/smack/SmackInstGenerator.h index 75d30c4cc..627d88572 100644 --- a/include/smack/SmackInstGenerator.h +++ b/include/smack/SmackInstGenerator.h @@ -43,7 +43,7 @@ class SmackInstGenerator : public llvm::InstVisitor { void nameInstruction(llvm::Instruction& i); void annotate(llvm::Instruction& i, Block* b); - const Stmt* recordProcedureCall(llvm::Value* V, std::list attrs); + const Stmt* recordProcedureCall(const llvm::Value* V, std::list attrs); public: void emit(const Stmt* s); @@ -66,9 +66,9 @@ class SmackInstGenerator : public llvm::InstVisitor { void visitBinaryOperator(llvm::BinaryOperator& I); - // TODO implement extractelement - // TODO implement insertelement - // TODO implement shufflestd::vector + void visitExtractElementInst(llvm::ExtractElementInst &I); + void visitInsertElementInst(llvm::InsertElementInst &I); + void visitShuffleVectorInst(llvm::ShuffleVectorInst &I); void visitExtractValueInst(llvm::ExtractValueInst& i); void visitInsertValueInst(llvm::InsertValueInst& i); diff --git a/include/smack/SmackOptions.h b/include/smack/SmackOptions.h index 811679c32..c19cc9b9a 100644 --- a/include/smack/SmackOptions.h +++ b/include/smack/SmackOptions.h @@ -24,6 +24,7 @@ class SmackOptions { static const llvm::cl::opt NoByteAccessInference; static const llvm::cl::opt FloatEnabled; static const llvm::cl::opt MemorySafety; + static const llvm::cl::opt IntegerOverflow; static const llvm::cl::opt AddTiming; static bool isEntryPoint(std::string); diff --git a/include/smack/SmackRep.h b/include/smack/SmackRep.h index d0e305ccd..d1d31f264 100644 --- a/include/smack/SmackRep.h +++ b/include/smack/SmackRep.h @@ -28,6 +28,8 @@ using llvm::SmallVector; using llvm::StringRef; class SmackRep { + friend class VectorOperations; + protected: const llvm::DataLayout* targetData; Naming* naming; @@ -64,7 +66,7 @@ class SmackRep { const Expr* pointerToInteger(const Expr* e, unsigned width); const Expr* integerToPointer(const Expr* e, unsigned width); - std::string opName(const std::string& operation, std::initializer_list types); + std::string opName(const std::string& operation, std::list types); std::string opName(const std::string& operation, std::initializer_list types); const Stmt* store(unsigned R, const llvm::Type* T, const Expr* P, const Expr* V); @@ -83,6 +85,7 @@ class SmackRep { std::string pointerType(); std::string intType(unsigned width); + std::string vectorType(int n, llvm::Type *T); unsigned numElements(const llvm::Constant* v); @@ -91,6 +94,8 @@ class SmackRep { Decl* memsetProc(std::string type, unsigned length = std::numeric_limits::max()); + bool isUnsafeFloatAccess(const llvm::Type* elemTy, const llvm::Type* resultTy); + public: const Expr* pointerLit(unsigned v) { return pointerLit((unsigned long) v); } const Expr* pointerLit(unsigned long v); @@ -143,6 +148,7 @@ class SmackRep { std::string memReg(unsigned i); std::string memType(unsigned region); std::string memPath(unsigned region); + std::string memPath(const llvm::Value* v); std::list< std::pair< std::string, std::string > > memoryMaps(); @@ -158,12 +164,11 @@ class SmackRep { std::string getPrelude(); const Expr* declareIsExternal(const Expr* e); - std::list auxiliaryDeclarations() { - std::list ds; - for (auto D : auxDecls) - ds.push_back(D.second); - return ds; - } + bool isContractExpr(const llvm::Value* V) const; + bool isContractExpr(const std::string S) const; + + void addAuxiliaryDeclaration(Decl* D); + std::list auxiliaryDeclarations(); }; } diff --git a/include/smack/SplitAggregateLoadStore.h b/include/smack/SplitAggregateLoadStore.h deleted file mode 100644 index 897222b5e..000000000 --- a/include/smack/SplitAggregateLoadStore.h +++ /dev/null @@ -1,31 +0,0 @@ -// -// This file is distributed under the MIT License. See LICENSE for details. -// - -#include "llvm/IR/DataLayout.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/Module.h" -#include "llvm/Pass.h" -#include "llvm/IR/IRBuilder.h" - -#include -#include - -namespace smack { - -class SplitAggregateLoadStore : public llvm::BasicBlockPass { -public: - static char ID; - - SplitAggregateLoadStore() : llvm::BasicBlockPass(ID) {} - virtual bool runOnBasicBlock(llvm::BasicBlock& BB); - -private: - void splitAggregateLoad(llvm::LoadInst* li); - llvm::Value* buildAggregateValues(llvm::IRBuilder<> *irb, llvm::Value* ptr, llvm::Type* ct, - llvm::Value* val, std::vector> idxs); - void splitAggregateStore(llvm::StoreInst* si, llvm::Value* ptr, llvm::Value* val); - void copyAggregateValues(llvm::IRBuilder<> *irb, llvm::Value* ptr, llvm::Type* ct, - llvm::Value* val, std::vector> idxs); -}; -} diff --git a/include/smack/SplitAggregateValue.h b/include/smack/SplitAggregateValue.h new file mode 100644 index 000000000..ea39f51a0 --- /dev/null +++ b/include/smack/SplitAggregateValue.h @@ -0,0 +1,34 @@ +// +// This file is distributed under the MIT License. See LICENSE for details. +// + +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Module.h" +#include "llvm/Pass.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Constants.h" + +#include +#include + +namespace smack { + +class SplitAggregateValue : public llvm::BasicBlockPass { +public: + typedef std::vector> IndexT; + typedef std::pair InfoT; + static char ID; + SplitAggregateValue() : llvm::BasicBlockPass(ID) {} + virtual bool runOnBasicBlock(llvm::BasicBlock& BB); + +private: + llvm::Value* splitAggregateLoad(llvm::LoadInst* li, std::vector& info, llvm::IRBuilder<>& irb); + void splitAggregateStore(llvm::StoreInst* si, std::vector& info, llvm::IRBuilder<>& irb); + void splitConstantReturn(llvm::ReturnInst* ri, std::vector& info); + void splitConstantArg(llvm::CallInst* ci, unsigned i, std::vector& info); + void visitAggregateValue(llvm::Constant* baseVal, llvm::Type* T, IndexT idxs, std::vector& info, llvm::LLVMContext& C); + llvm::Value* createInsertedValue(llvm::IRBuilder<>& irb, llvm::Type* T, std::vector& info, llvm::Value* V); + bool isConstantAggregate(llvm::Value* V); +}; +} diff --git a/include/smack/VectorOperations.h b/include/smack/VectorOperations.h new file mode 100644 index 000000000..1cb3a04f7 --- /dev/null +++ b/include/smack/VectorOperations.h @@ -0,0 +1,45 @@ +// +// This file is distributed under the MIT License. See LICENSE for details. +// +#ifndef VECTOROPERATIONS_H +#define VECTOROPERATIONS_H + +#include "llvm/IR/Type.h" +#include + +class SmackRep; +class Decl; +class FuncDecl; + +using namespace llvm; + +namespace smack { + class VectorOperations { + SmackRep *rep; + std::string constructor(Type *T); + std::string field(Type *T, unsigned idx); + std::string selector(Type *T, unsigned idx); + + FuncDecl *cast(unsigned OpCode, Type *SrcTy, Type *DstTy); + Decl *inverseAxiom(unsigned OpCode, Type *SrcTy, Type *DstTy); + FuncDecl *binary(unsigned OpCode, VectorType *T); + FuncDecl *cmp(CmpInst::Predicate P, VectorType *T); + + public: + VectorOperations(SmackRep *rep) : rep(rep) {} + std::list type(Type *T); + const Expr *constant(const ConstantDataVector *C); + const Expr *constant(const ConstantAggregateZero *C); + + FuncDecl *cast(CastInst *I); + FuncDecl *binary(BinaryOperator *I); + FuncDecl *cmp(CmpInst *I); + FuncDecl *shuffle(Type *T, Type *U, std::vector mask); + FuncDecl *insert(Type *T, Type *IT); + FuncDecl *extract(Type *T, Type *IT); + FuncDecl *load(const Value *V); + FuncDecl *store(const Value *V); + }; +} + +#endif // VECTOROPERATIONS_H diff --git a/lib/smack/BoogieAst.cpp b/lib/smack/BoogieAst.cpp index c4b5d4688..92ca8a692 100644 --- a/lib/smack/BoogieAst.cpp +++ b/lib/smack/BoogieAst.cpp @@ -12,15 +12,11 @@ namespace smack { unsigned Decl::uniqueId = 0; -const Expr* Expr::exists(std::string v, std::string t, const Expr* e) { - std::list< std::pair > vars; - vars.push_back({v,t}); +const Expr* Expr::exists(std::list vars, const Expr* e) { return new QuantExpr(QuantExpr::Exists, vars, e); } -const Expr* Expr::forall(std::string v, std::string t, const Expr* e) { - std::list< std::pair > vars; - vars.push_back({v,t}); +const Expr* Expr::forall(std::list vars, const Expr* e) { return new QuantExpr(QuantExpr::Forall, vars, e); } @@ -99,6 +95,10 @@ const Expr* Expr::lit(bool n, std::string s, std::string e, unsigned ss, unsigne return new FPLit(n, s, e, ss, es); } +const Expr* Expr::lit(RModeKind v) { + return new RModeLit(v); +} + const Expr* Expr::neq(const Expr* l, const Expr* r) { return new BinExpr(BinExpr::Neq, l, r); } @@ -115,6 +115,14 @@ const Expr* Expr::sel(std::string b, std::string i) { return new SelExpr(id(b), id(i)); } +const Expr* Expr::upd(const Expr* b, const Expr* i, const Expr* v) { + return new UpdExpr(b, i, v); +} + +const Expr* Expr::if_then_else(const Expr* c, const Expr* t, const Expr* e) { + return new IfThenElseExpr(c, t, e); +} + const Attr* Attr::attr(std::string s, std::initializer_list vs) { return new Attr(s,vs); } @@ -209,13 +217,13 @@ const Stmt* Stmt::code(std::string s) { return new CodeStmt(s); } -Decl* Decl::typee(std::string name, std::string type) { - return new TypeDecl(name,type); +Decl* Decl::typee(std::string name, std::string type, std::list attrs) { + return new TypeDecl(name,type,attrs); } -Decl* Decl::axiom(const Expr* e) { - return new AxiomDecl(e); +Decl* Decl::axiom(const Expr* e, std::string name) { + return new AxiomDecl(name, e); } -FuncDecl* Decl::function(std::string name, std::list< std::pair > args, +FuncDecl* Decl::function(std::string name, std::list args, std::string type, const Expr* e, std::list attrs) { return new FuncDecl(name,attrs,args,type,e); } @@ -232,7 +240,7 @@ Decl* Decl::variable(std::string name, std::string type) { return new VarDecl(name, type); } ProcDecl* Decl::procedure(std::string name, - std::list< std::pair > args, std::list< std::pair > rets, + std::list args, std::list rets, std::list decls, std::list blocks) { return new ProcDecl(name, args, rets, decls, blocks); } @@ -403,7 +411,7 @@ void BinExpr::print(std::ostream& os) const { } void CondExpr::print(std::ostream& os) const { - os << "if " << cond << " then " << then << " else " << else_; + os << "(if " << cond << " then " << then << " else " << else_ << ")"; } void FunExpr::print(std::ostream& os) const { @@ -415,6 +423,26 @@ void BoolLit::print(std::ostream& os) const { os << (val ? "true" : "false"); } +void RModeLit::print(std::ostream& os) const { + switch (val) { + case RModeKind::RNE: + os << "RNE"; + break; + case RModeKind::RNA: + os << "RNA"; + break; + case RModeKind::RTP: + os << "RTP"; + break; + case RModeKind::RTN: + os << "RTN"; + break; + case RModeKind::RTZ: + os << "RTZ"; + break; + } +} + void IntLit::print(std::ostream& os) const { os << val; } @@ -445,7 +473,7 @@ void QuantExpr::print(std::ostream& os) const { os << "exists "; break; } - print_seq< std::pair >(os, vars, ","); + print_seq(os, vars, ", "); os << " :: " << expr << ")"; } @@ -472,6 +500,10 @@ void CodeExpr::print(std::ostream& os) const { os << "\n" << "}|"; } +void IfThenElseExpr::print(std::ostream& os) const { + os << "if " << cond << " then " << true_value << " else " << false_value; +} + void StringLit::print(std::ostream& os) const { os << "\"" << val << "\""; } diff --git a/lib/smack/CodifyStaticInits.cpp b/lib/smack/CodifyStaticInits.cpp index 71de62ccd..ead8c9113 100644 --- a/lib/smack/CodifyStaticInits.cpp +++ b/lib/smack/CodifyStaticInits.cpp @@ -59,7 +59,8 @@ bool CodifyStaticInits::runOnModule(Module& M) { if (V->getType()->isIntegerTy() || V->getType()->isPointerTy() || - V->getType()->isFloatingPointTy()) + V->getType()->isFloatingPointTy() || + V->getType()->isVectorTy()) IRB.CreateStore(V, IRB.CreateGEP(P, ArrayRef(I))); diff --git a/lib/smack/ExtractContracts.cpp b/lib/smack/ExtractContracts.cpp index c60563913..ebf3b009f 100644 --- a/lib/smack/ExtractContracts.cpp +++ b/lib/smack/ExtractContracts.cpp @@ -10,6 +10,9 @@ #include "llvm/IR/DataLayout.h" #include "llvm/IR/Dominators.h" #include "llvm/Analysis/LoopInfo.h" +#include "llvm/Transforms/Utils/CodeExtractor.h" +#include "llvm/Transforms/Utils/Cloning.h" +#include "llvm/IR/IRBuilder.h" #include "smack/Debug.h" #include @@ -22,311 +25,274 @@ namespace smack { using namespace llvm; namespace { - std::string getString(const llvm::Value* v) { - if (const llvm::ConstantExpr* constantExpr = llvm::dyn_cast(v)) - if (constantExpr->getOpcode() == llvm::Instruction::GetElementPtr) - if (const llvm::GlobalValue* cc = llvm::dyn_cast(constantExpr->getOperand(0))) - if (const llvm::ConstantDataSequential* cds = llvm::dyn_cast(cc->getOperand(0))) - return cds ->getAsCString(); - return ""; + + bool isContractFunction(Function *F) { + auto name = F->getName(); + return name == Naming::CONTRACT_REQUIRES + || name == Naming::CONTRACT_ENSURES + || name == Naming::CONTRACT_INVARIANT; } - Value* getVariable(Value* V) { - if (auto I = dyn_cast(V)) { - if (auto F = I->getCalledFunction()) { - if (F->getName().find("__CONTRACT_int_variable") != std::string::npos) { - assert(I->getNumArgOperands() == 1 && "Unexpected operands."); - return I->getArgOperand(0); - } + typedef std::vector BlockList; + typedef std::map LoopMap; + + // Return the list of blocks which dominate the given blocks in the given + // function. + // NOTE this procedure assumes blocks are ordered in dominated order, both + // in the given selection of blocks, as well as in the given function. + BlockList blockPrefix(BlockList BBs, Function &F) { + BlockList prefix; + if (!BBs.empty()) { + for (auto &BB : F) { + prefix.push_back(&BB); + if (&BB == BBs.back()) + break; } } - return nullptr; + return prefix; } - std::string getBinding(Value* V) { - if (auto I = dyn_cast(V)) { - if (auto F = I->getCalledFunction()) { - auto name = F->getName(); - if (name == Naming::CONTRACT_FORALL || - name == Naming::CONTRACT_EXISTS) { - return getString(I->getArgOperand(0)); - } + // Return the list of blocks which dominate the given blocks in the given + // loop, not including the loop head. + // NOTE this procedure assumes blocks are ordered in dominated order, both + // in the given selection of blocks, as well as in the given loop. + BlockList blockPrefix(BlockList BBs, const Loop &L) { + BlockList prefix; + if (!BBs.empty()) { + for (auto BB : L.getBlocks()) { + if (BB == L.getHeader()) + continue; + prefix.push_back(BB); + if (BB == BBs.back()) + break; } } - return ""; + return prefix; } - Function* projection(Function* F, Type* T, - std::vector& arguments, std::map& clones) { - - std::vector parameters; - for (auto A : arguments) - parameters.push_back(A->getType()); - - auto FF = Function::Create( - FunctionType::get(T, parameters, false), - GlobalValue::InternalLinkage, Naming::CONTRACT_EXPR, F->getParent()); - - FF->setDoesNotAccessMemory(); - - FF->getArgumentList().clear(); - for (auto A : arguments) { - auto P = dyn_cast(clones[A]); - FF->getArgumentList().push_back(P); - if (auto S = getVariable(A)) { - AttributeSet Ax; - P->addAttr(Ax.addAttribute(A->getContext(), 1, "contract-var", getString(S))); + // Split the basic blocks of the given function such that each invocation to + // contract functions is the last non-terminator instruction in its block. + std::tuple splitContractBlocks(Function &F, LoopInfo &LI) { + + BlockList contractBlocks; + LoopMap invariantBlocks; + + std::deque blocks; + for (auto &BB : F) + blocks.push_back(&BB); + + while (!blocks.empty()) { + auto BB = blocks.front(); + blocks.pop_front(); + + for (auto &I : *BB) { + if (auto CI = dyn_cast(&I)) { + if (auto *CF = CI->getCalledFunction()) { + if (isContractFunction(CF)) { + DEBUG(errs() << "splitting block at contract invocation: " << *CI << "\n"); + BasicBlock *B = CI->getParent(); + auto NewBB = B->splitBasicBlock(++CI->getIterator()); + LI.getLoopFor(B)->addBasicBlockToLoop(NewBB, LI); + blocks.push_front(NewBB); + + if (auto L = LI[B]) + invariantBlocks[L].push_back(B); + else + contractBlocks.push_back(B); + + break; + } + } + } } } - for (auto& B : *F) { - if (clones.count(&B)) { - auto BB = dyn_cast(clones[&B]); - for (auto& I : B) { - if (clones.count(&I) && clones[&I]) { - if (auto II = dyn_cast(clones[&I])) { - if (!II->getParent()) { + contractBlocks = blockPrefix(contractBlocks, F); - // Add the block if it’s not already - if (!BB->size()) - FF->getBasicBlockList().push_back(BB); + for (auto const& entry : invariantBlocks) { + auto L = entry.first; + auto BBs = entry.second; + invariantBlocks[L] = blockPrefix(BBs, *L); + } - BB->getInstList().push_back(II); - } - } - } else if (auto T = dyn_cast(&I)) { - if (!clones.count(T)) { + return std::make_tuple( + contractBlocks, + invariantBlocks + ); + } - // TODO filter out targets not in the projection, i.e., to avoid - // failing the assertion below. + // Return the list of contract invocations in the given function. + std::vector getContractInvocations(Function &F) { + std::vector CIs; + for (auto &BB : F) + for (auto &I : BB) + if (auto CI = dyn_cast(&I)) + if (auto F = CI->getCalledFunction()) + if (isContractFunction(F)) + CIs.push_back(CI); + return CIs; + } - auto TT = T->clone(); - for (auto& O : TT->operands()) { - assert(clones.count(O.get()) && "Unvisited block."); - O.set(clones[O.get()]); - } + // Replace the given invocation with a return of its argument; also remove + // all other contract invocations. + void setReturnToArgumentValue(Function *F, CallInst *II) { + + for (auto &BB : *F) { - // Add the block if it’s not already - if (!BB->size()) - FF->getBasicBlockList().push_back(BB); + // Replace existing returns with return true. + if (auto RI = dyn_cast(BB.getTerminator())) { + IRBuilder<> Builder(RI); + Builder.CreateRet(ConstantInt::getTrue(F->getFunctionType()->getReturnType())); + RI->eraseFromParent(); + continue; + } - BB->getInstList().push_back(TT); + // Erase contract invocations, and replace the given invocation + // with a return of its argument. + for (auto &I : BB) { + if (auto CI = dyn_cast(&I)) { + if (auto F = CI->getCalledFunction()) { + if (isContractFunction(F)) { + if (CI == II) { + IRBuilder<> Builder(CI); + BB.getTerminator()->eraseFromParent(); + Builder.CreateRet(CI->getArgOperand(0)); + } + CI->eraseFromParent(); + break; } } } } } - return FF; } - Function* extractedFunction(Value* V, BasicBlock* B, - std::vector& arguments, std::map& clones) { - - auto &C = V->getContext(); - auto R = ReturnInst::Create(C, clones[V], dyn_cast(clones[B])); - R->removeFromParent(); - clones[B->getTerminator()] = R; - return projection(B->getParent(), V->getType(), arguments, clones); + // Return a copy of the given function in which the given invocation is + // replaced by a return of its argument value, and all contract + // invocations are removed. + Function *getContractExpr(Function *F, CallInst *I) { + ValueToValueMapTy VMap; + SmallVector Returns; + + FunctionType *FT = FunctionType::get( + I->getFunctionType()->getParamType(0), + F->getFunctionType()->params(), + F->getFunctionType()->isVarArg()); + + Function *NewF = Function::Create(FT, F->getLinkage(), Naming::CONTRACT_EXPR, F->getParent()); + + // Loop over the arguments, copying the names of the mapped arguments over... + // See implementation of llvm::CloneFunction + Function::arg_iterator DestA = NewF->arg_begin(); + for (auto &A : F->args()) { + DestA->setName(A.getName()); + VMap[&A] = &*DestA++; + } + CloneFunctionInto(NewF, F, VMap, false, Returns); + setReturnToArgumentValue(NewF, dyn_cast(VMap[I])); + return NewF; } -} - -void ExtractContracts::getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequired(); - AU.addRequired(); -} -bool ExtractContracts::runOnModule(Module& M) { - modified = false; - visit(M); - return modified; + // Return copies of the given function in for each contract invocation, in + // which each returns the argument value of the corresponding contract + // invocation. The first function of each returned pair is the invoked + // contract function; the second function is the new function created for the + // given invocation. + std::vector> getContractExprs(Function &F) { + std::vector> Fs; + for (auto CI : getContractInvocations(F)) { + Function *newF = getContractExpr(&F, CI); + Fs.push_back(std::make_tuple(CI->getCalledFunction(), newF)); + } + return Fs; + } } -void ExtractContracts::visitCallInst(CallInst &I) { - if (auto F = I.getCalledFunction()) { - auto name = F->getName(); - if (name == Naming::CONTRACT_REQUIRES || - name == Naming::CONTRACT_ENSURES || - name == Naming::CONTRACT_INVARIANT) { +bool ExtractContracts::runOnModule(Module &M) { + bool modified = false; - validateAnnotation(I); + std::vector Fs; + std::vector newFs; - if (auto J = dyn_cast(I.getArgOperand(0))) - if (auto G = J->getCalledFunction()) - if (G->getName().find(Naming::CONTRACT_EXPR) != std::string::npos) - return; - - Function* EF; - std::vector Args; - tie(EF, Args) = extractExpression(I.getArgOperand(0), I.getParent()); - I.setArgOperand(0, CallInst::Create(EF, Args, "", &I)); - modified = true; + for (Function &F : M) + if (!F.isDeclaration()) + Fs.push_back(&F); - // TODO can we somehow force LLVM to consider calls to the obsoleted - // forall, exists, etc., to be dead code? + for (auto F : Fs) { + BlockList contractBlocks; + LoopMap invariantBlocks; + auto& LI = getAnalysis(*F).getLoopInfo(); + std::tie(contractBlocks, invariantBlocks) = splitContractBlocks(*F, LI); - } else if (name == Naming::CONTRACT_FORALL || - name == Naming::CONTRACT_EXISTS) { - - if (auto J = dyn_cast(I.getArgOperand(1))) - if (auto G = J->getCalledFunction()) - if (G->getName().find(Naming::CONTRACT_EXPR) != std::string::npos) - return; - - Function* EF; - std::vector Args; - tie(EF, Args) = extractExpression(I.getArgOperand(1), I.getParent()); - I.setArgOperand(1, CallInst::Create(EF, Args, "", &I)); + if (!contractBlocks.empty() || !invariantBlocks.empty()) { + DEBUG(errs() << "function " << F->getName() << " after splitting: " << *F << "\n"); modified = true; } - } -} -void ExtractContracts::validateAnnotation(CallInst &I) { - assert(I.getCalledFunction() && "Unexpected virtual function."); - assert(I.getNumArgOperands() == 1 && "Unexpected operands."); - auto B = I.getParent(); - auto F = B->getParent(); - auto& DT = getAnalysis(*F).getDomTree(); - auto& LI = getAnalysis(*F).getLoopInfo(); - if (I.getCalledFunction()->getName() == Naming::CONTRACT_INVARIANT) { - auto L = LI[B]; - if (!L) { - llvm_unreachable("Loop invariants must occur inside loops."); - } - } else { - for (auto L : LI) { - auto& J = L->getHeader()->getInstList().front(); - if (DT.dominates(&J, &I)) { - llvm_unreachable("Procedure specifications must occur before loops."); + if (!contractBlocks.empty()) { + auto *newF = CodeExtractor(contractBlocks).extractCodeRegion(); + + std::vector Is; + for (auto V : newF->users()) + if (auto I = dyn_cast(V)) + Is.push_back(I); + + for (auto I : Is) { + IRBuilder<> Builder(I); + + // insert one contract invocation per invocation in the original function + for (auto Fs : getContractExprs(*newF)) { + std::vector Args; + for (auto &A : I->arg_operands()) + Args.push_back(A); + auto *E = Builder.CreateCall(std::get<1>(Fs), Args); + Builder.CreateCall(std::get<0>(Fs), {E}); + newFs.push_back(std::get<1>(Fs)); + } + I->eraseFromParent(); } + newF->eraseFromParent(); + DEBUG(errs() << "function " << F->getName() << " after contract extraction: " << *F << "\n"); } - } -} - -bool ExtractContracts::hasDominatedIncomingValue(Value* V) { - if (auto PHI = dyn_cast(V)) { - auto F = PHI->getParent()->getParent(); - const DominatorTree& DT = - getAnalysis(*F).getDomTree(); - for (unsigned i = 0; i < PHI->getNumIncomingValues(); i++) - if (auto I = dyn_cast(PHI->getIncomingValue(i))) - if (DT.dominates(PHI, I)) - return true; - } - - return false; -} - -std::tuple< Function*, std::vector > -ExtractContracts::extractExpression(Value* V, BasicBlock* E) { - - std::vector captures; - auto var = getBinding(V); - if (var != "") - captures.push_back(var); - - DEBUG(errs() << "[contracts]" - << " extracting " << *V - << " from " << E->getParent()->getName() - << ":" << E->getName() << "\n"); - - auto &C = V->getContext(); - - std::stack value_stack; - std::map clones; - std::map variables; - std::vector arguments; - - value_stack.push(V); - value_stack.push(E); - clones[E->getTerminator()] = nullptr; - - while (!value_stack.empty()) { - Value* V = value_stack.top(); - - if (!clones.count(V)) { - - DEBUG(errs() << "[contracts]" - << " (" << value_stack.size() << ")" - << " entering " << *V << "\n"); - - clones[V] = V; - - if (hasDominatedIncomingValue(V)) - continue; - if (auto I = dyn_cast(V)) - value_stack.push(I->getParent()); - - if (auto PHI = dyn_cast(V)) - for (unsigned i = 0; i < PHI->getNumIncomingValues(); i++) - value_stack.push(PHI->getIncomingBlock(i)->getTerminator()); - - if (auto U = dyn_cast(V)) - for (auto& O : U->operands()) - value_stack.push(O.get()); - - continue; - - } else if (clones[V] == V) { - - DEBUG(errs() << "[contracts]" - << " (" << value_stack.size() << ")" - << " leaving " << *V << "\n"); - - if (auto B = dyn_cast(V)) { - clones[B] = BasicBlock::Create(C, B->getName()); - - } else if (auto X = getVariable(V)) { - if (!variables.count(X)) { - if (std::find(captures.begin(), captures.end(), getString(X)) != captures.end()) { - auto I = dyn_cast(V); - assert(I && "Expected instruction."); - variables[X] = I->clone(); - } else { - variables[X] = new Argument(V->getType(), getString(X)); - arguments.push_back(V); - } - } - clones[V] = variables[X]; - - } else if (hasDominatedIncomingValue(V) || - isa(V) || - (isa(V) && !isa(V))) { - clones[V] = new Argument(V->getType(), V->getName()); - arguments.push_back(V); - - } else if (isa(V)) { - llvm_unreachable("Unexpected store instruction!"); - - } else if (auto I = dyn_cast(V)) { - assert(clones.count(I->getParent()) && "Forgot to visit parent block."); - assert(clones[I->getParent()] != I->getParent() && "Forgot to clone parent block."); - - auto II = I->clone(); - clones[I] = II; - for (auto& O : II->operands()) { - assert(clones.count(O.get()) && "Forgot to visit operand."); - O.set(clones[O.get()]); - } - if (auto PHI = dyn_cast(II)) { - for (unsigned i = 0; i < PHI->getNumIncomingValues(); i++) { - auto B = PHI->getIncomingBlock(i); - assert(clones.count(B) && "Forgot to visit incoming block."); - assert(clones[B] != B && "Forgot to clone incoming block."); - PHI->setIncomingBlock(i, dyn_cast(clones[B])); - } + for (auto const & entry : invariantBlocks) { + auto BBs = entry.second; + auto *newF = CodeExtractor(BBs).extractCodeRegion(); + + std::vector Is; + for (auto V : newF->users()) + if (auto I = dyn_cast(V)) + Is.push_back(I); + + for (auto I : Is) { + IRBuilder<> Builder(I); + + // insert one invariant invocation per invocation in the original loop + for (auto Fs : getContractExprs(*newF)) { + std::vector Args; + for (auto &A : I->arg_operands()) + Args.push_back(A); + auto *E = Builder.CreateCall(std::get<1>(Fs), Args); + Builder.CreateCall(std::get<0>(Fs), {E}); + newFs.push_back(std::get<1>(Fs)); } + I->eraseFromParent(); } - + newF->eraseFromParent(); + DEBUG(errs() << "function " << F->getName() << " after invariant extraction: " << *F << "\n"); } + } - value_stack.pop(); + for (auto F : newFs) { + DEBUG(errs() << "added function:" << *F); } - return std::make_tuple( - extractedFunction(V, E, arguments, clones), - arguments); + return modified; +} + +void ExtractContracts::getAnalysisUsage(AnalysisUsage &AU) const { + AU.addRequired(); + AU.addRequired(); } // Pass ID variable diff --git a/lib/smack/IntegerOverflowChecker.cpp b/lib/smack/IntegerOverflowChecker.cpp new file mode 100644 index 000000000..284a58514 --- /dev/null +++ b/lib/smack/IntegerOverflowChecker.cpp @@ -0,0 +1,191 @@ +// +// This file is distributed under the MIT License. See LICENSE for details. +// + +// +// This pass converts LLVM's checked integer-arithmetic operations into basic +// operations, and optionally allows for the checking of overflow. +// + +#include "smack/IntegerOverflowChecker.h" +#include "smack/Naming.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/Constants.h" +#include "smack/Debug.h" +#include "llvm/IR/ValueSymbolTable.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/Support/Regex.h" +#include +#include "llvm/ADT/APInt.h" +#include "smack/SmackOptions.h" + +namespace smack { + +using namespace llvm; + +Regex OVERFLOW_INTRINSICS("^llvm.(u|s)(add|sub|mul).with.overflow.i([0-9]+)$"); + +const std::map IntegerOverflowChecker::INSTRUCTION_TABLE { + {"add", Instruction::Add}, + {"sub", Instruction::Sub}, + {"mul", Instruction::Mul} +}; + +std::string IntegerOverflowChecker::getMax(unsigned bits, bool isSigned) { + if (isSigned) + return APInt::getSignedMaxValue(bits).toString(10, true); + else + return APInt::getMaxValue(bits).toString(10, false); +} + +std::string IntegerOverflowChecker::getMin(unsigned bits, bool isSigned) { + if (isSigned) + return APInt::getSignedMinValue(bits).toString(10, true); + else + return APInt::getMinValue(bits).toString(10, false); +} + +/* + * Optionally generates a double wide version of v for the purpose of detecting + * overflow. + */ +Value* IntegerOverflowChecker::extendBitWidth(Value* v, int bits, bool isSigned, Instruction* i) { + if (SmackOptions::IntegerOverflow) { + if (isSigned) + return CastInst::CreateSExtOrBitCast(v, IntegerType::get(i->getFunction()->getContext(), bits*2), "", i); + else + return CastInst::CreateZExtOrBitCast(v, IntegerType::get(i->getFunction()->getContext(), bits*2), "", i); + } else + return v; +} + +/* + * Generates instructions to determine whether a Value v is is out of range for + * its bit width and sign. + */ +BinaryOperator* IntegerOverflowChecker::createFlag(Value* v, int bits, bool isSigned, Instruction* i) { + if (SmackOptions::IntegerOverflow) { + ConstantInt* max = ConstantInt::get(IntegerType::get(i->getFunction()->getContext(), bits*2), getMax(bits, isSigned), 10); + ConstantInt* min = ConstantInt::get(IntegerType::get(i->getFunction()->getContext(), bits*2), getMin(bits, isSigned), 10); + CmpInst::Predicate maxCmpPred = (isSigned ? CmpInst::ICMP_SGT : CmpInst::ICMP_UGT); + CmpInst::Predicate minCmpPred = (isSigned ? CmpInst::ICMP_SLT : CmpInst::ICMP_ULT); + ICmpInst* gt = new ICmpInst(i, maxCmpPred, v, max, ""); + ICmpInst* lt = new ICmpInst(i, minCmpPred, v, min, ""); + return BinaryOperator::Create(Instruction::Or, gt, lt, "", i); + } else { + ConstantInt* a = ConstantInt::getFalse(i->getFunction()->getContext()); + return BinaryOperator::Create(Instruction::And, a, a, "", i); + } +} + +/* + * Create an instruction to cast v to bits size. + */ +Value* IntegerOverflowChecker::createResult(Value* v, int bits, Instruction* i) { + if (SmackOptions::IntegerOverflow) + return CastInst::CreateTruncOrBitCast(v, IntegerType::get(i->getFunction()->getContext(), bits), "", i); + else + return v; +} + +/* + * This adds a call instruction to __SMACK_check_overflow to determine if an + * overflow occured as indicated by flag. + */ +void IntegerOverflowChecker::addCheck(Function* co, BinaryOperator* flag, Instruction* i) { + ArrayRef args(CastInst::CreateIntegerCast(flag, co->arg_begin()->getType(), false, "", i)); + CallInst::Create(co, args, "", i); +} + +/* + * This inserts a call to assume with flag negated to prevent the verifier + * from exploring paths past a __SMACK_check_overflow + */ +void IntegerOverflowChecker::addBlockingAssume(Function* va, BinaryOperator* flag, Instruction* i) { + ArrayRef args(CastInst::CreateIntegerCast(BinaryOperator::CreateNot(flag, "", i), + va->arg_begin()->getType(), false, "", i)); + CallInst::Create(va, args, "", i); +} + +bool IntegerOverflowChecker::runOnModule(Module& m) { + Function* co = m.getFunction("__SMACK_check_overflow"); + assert(co != NULL && "Function __SMACK_check_overflow should be present."); + Function* va = m.getFunction("__VERIFIER_assume"); + assert(va != NULL && "Function __VERIFIER_assume should be present."); + std::vector instToRemove; + for (auto& F : m) { + if (Naming::isSmackName(F.getName())) + continue; + for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) { + if (auto ei = dyn_cast(&*I)) { + if (auto ci = dyn_cast(ei->getAggregateOperand())) { + Function* f = ci->getCalledFunction(); + SmallVectorImpl *info = new SmallVector; + if (f && f->hasName() && OVERFLOW_INTRINSICS.match(f->getName().str(), info) + && ei->getIndices()[0] == 1) { + /* + * If ei is an ExtractValueInst whose value flows from an LLVM + * checked value intrinsic f, then we do the following: + * - The intrinsic is replaced with the non-intrinsic version of the + * operation. + * - If checking is enabled, the operation is computed in double bit + * width. + * - A flag is computed to determine whether an overflow occured. + * - The overflow flag is optionally checked to raise an + * integer-overflow assertion violation. + * - Finally, an assumption about the value of the flag is created + * to block erroneous checking of paths after the overflow check. + */ + Instruction* prev = &*std::prev(I); + bool isSigned = info->begin()[1].str() == "s"; + std::string op = info->begin()[2].str(); + std::string len = info->begin()[3].str(); + int bits = std::stoi(len); + Value* eo1 = extendBitWidth(ci->getArgOperand(0), bits, isSigned, &*I); + Value* eo2 = extendBitWidth(ci->getArgOperand(1), bits, isSigned, &*I); + BinaryOperator* ai = BinaryOperator::Create(INSTRUCTION_TABLE.at(op), eo1, eo2, "", &*I); + if (auto pei = dyn_cast_or_null(prev)) { + if (ci == dyn_cast(pei->getAggregateOperand())) { + Value* r = createResult(ai, bits, &*I); + prev->replaceAllUsesWith(r); + instToRemove.push_back(prev); + } + } + BinaryOperator* flag = createFlag(ai, bits, isSigned, &*I); + if (SmackOptions::IntegerOverflow) + addCheck(co, flag, &*I); + addBlockingAssume(va, flag, &*I); + I->replaceAllUsesWith(flag); + instToRemove.push_back(&*I); + } + } + } + if (auto sdi = dyn_cast(&*I)) { + if (sdi->getOpcode() == Instruction::SDiv && SmackOptions::IntegerOverflow) { + int bits = sdi->getType()->getIntegerBitWidth(); + Value* eo1 = extendBitWidth(sdi->getOperand(0), bits, true, &*I); + Value* eo2 = extendBitWidth(sdi->getOperand(1), bits, true, &*I); + BinaryOperator* lsdi = BinaryOperator::Create(Instruction::SDiv, eo1, eo2, "", &*I); + BinaryOperator* flag = createFlag(lsdi, bits, true, &*I); + addCheck(co, flag, &*I); + Value* r = createResult(lsdi, bits, &*I); + I->replaceAllUsesWith(r); + instToRemove.push_back(&*I); + } + } + } + } + for (auto I : instToRemove) { + I->removeFromParent(); + } + return true; +} + +// Pass ID variable +char IntegerOverflowChecker::ID = 0; + +const char* IntegerOverflowChecker::getPassName() const { + return "Checked integer arithmetic intrinsics"; +} +} diff --git a/lib/smack/MemorySafetyChecker.cpp b/lib/smack/MemorySafetyChecker.cpp index 7e716b3e1..b0f86299c 100644 --- a/lib/smack/MemorySafetyChecker.cpp +++ b/lib/smack/MemorySafetyChecker.cpp @@ -16,66 +16,100 @@ namespace smack { using namespace llvm; -void insertMemoryLeakCheck(Function& F, Module& m) { - Function* memoryLeakCheckFunction = m.getFunction(Naming::MEMORY_LEAK_FUNCTION); - assert (memoryLeakCheckFunction != NULL && "Memory leak check function must be present."); - for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) { - if (isa(&*I)) { - CallInst::Create(memoryLeakCheckFunction, "", &*I); - } +Function* MemorySafetyChecker::getLeakCheckFunction(Module& M) { + if (!leakCheckFunction.count(&M)) { + auto F = M.getFunction(Naming::MEMORY_LEAK_FUNCTION); + assert (F && "Memory leak check function must be present."); + leakCheckFunction[&M] = F; } + return leakCheckFunction[&M]; } -void inserMemoryAccessCheck(Value* memoryPointer, Instruction* I, DataLayout* dataLayout, Function* memorySafetyFunction, Function* F) { - // Finding the exact type of the second argument to our memory safety function - Type* sizeType = memorySafetyFunction->getFunctionType()->getParamType(1); - PointerType* pointerType = cast(memoryPointer->getType()); - uint64_t storeSize = dataLayout->getTypeStoreSize(pointerType->getPointerElementType()); - Value* size = ConstantInt::get(sizeType, storeSize); - Type *voidPtrTy = PointerType::getUnqual(IntegerType::getInt8Ty(F->getContext())); - CastInst* castPointer = CastInst::Create(Instruction::BitCast, memoryPointer, voidPtrTy, "", &*I); - Value* args[] = {castPointer, size}; - CallInst::Create(memorySafetyFunction, ArrayRef(args, 2), "", &*I); +Function* MemorySafetyChecker::getSafetyCheckFunction(Module& M) { + if (!safetyCheckFunction.count(&M)) { + auto& C = M.getContext(); + auto T = PointerType::getUnqual(Type::getInt8Ty(C)); + auto F = dyn_cast(M.getOrInsertFunction( + Naming::MEMORY_SAFETY_FUNCTION, + FunctionType::get(Type::getVoidTy(C), {T, T}, false))); + assert(F && "Memory safety function must be present."); + F->addFnAttr(Attribute::AttrKind::ReadNone); + F->addFnAttr(Attribute::AttrKind::NoUnwind); + safetyCheckFunction[&M] = F; + } + return safetyCheckFunction[&M]; } -bool MemorySafetyChecker::runOnModule(Module& m) { - DataLayout* dataLayout = new DataLayout(&m); - Function* memorySafetyFunction = m.getFunction(Naming::MEMORY_SAFETY_FUNCTION); - assert(memorySafetyFunction != NULL && "Memory safety function must be present."); - for (auto& F : m) { - if (!Naming::isSmackName(F.getName())) { - if (SmackOptions::isEntryPoint(F.getName())) { - insertMemoryLeakCheck(F, m); - } - for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) { - if (LoadInst* li = dyn_cast(&*I)) { - inserMemoryAccessCheck(li->getPointerOperand(), &*I, dataLayout, memorySafetyFunction, &F); - } else if (StoreInst* si = dyn_cast(&*I)) { - inserMemoryAccessCheck(si->getPointerOperand(), &*I, dataLayout, memorySafetyFunction, &F); - } else if (MemSetInst* memseti = dyn_cast(&*I)) { - Value* dest = memseti->getDest(); - Value* size = memseti->getLength(); - Type* voidPtrTy = PointerType::getUnqual(IntegerType::getInt8Ty(F.getContext())); - CastInst* castPtr = CastInst::Create(Instruction::BitCast, dest, voidPtrTy, "", &*I); - CallInst::Create(memorySafetyFunction, {castPtr, size}, "", &*I); - } else if (MemTransferInst* memtrni = dyn_cast(&*I)) { - // MemTransferInst is abstract class for both MemCpyInst and MemMoveInst - Value* dest = memtrni->getDest(); - Value* src = memtrni->getSource(); - Value* size = memtrni->getLength(); - Type* voidPtrTy = PointerType::getUnqual(IntegerType::getInt8Ty(F.getContext())); - CastInst* castPtrDest = CastInst::Create(Instruction::BitCast, dest, voidPtrTy, "", &*I); - CastInst* castPtrSrc = CastInst::Create(Instruction::BitCast, src, voidPtrTy, "", &*I); - CallInst::Create(memorySafetyFunction, {castPtrDest, size}, "", &*I); - CallInst::Create(memorySafetyFunction, {castPtrSrc, size}, "", &*I); - } - } - } - } +void MemorySafetyChecker::insertMemoryLeakCheck(Instruction* I) { + auto& M = *I->getParent()->getParent()->getParent(); + CallInst::Create(getLeakCheckFunction(M), "", I); +} + +void MemorySafetyChecker::insertMemoryAccessCheck(Value* addr, Value* size, Instruction* I) { + auto& M = *I->getParent()->getParent()->getParent(); + auto& C = M.getContext(); + auto T = PointerType::getUnqual(Type::getInt8Ty(C)); + CallInst::Create(getSafetyCheckFunction(M), { + CastInst::Create(Instruction::BitCast, addr, T, "", I), + CastInst::CreateBitOrPointerCast(size, T, "", I) + }, "", I); +} + +bool MemorySafetyChecker::runOnFunction(Function& F) { + if (Naming::isSmackName(F.getName())) + return false; + + this->visit(F); return true; } +void MemorySafetyChecker::visitReturnInst(llvm::ReturnInst& I) { + auto& F = *I.getParent()->getParent(); + + if (SmackOptions::isEntryPoint(F.getName())) + insertMemoryLeakCheck(&I); +} + +namespace { + Value* accessSizeAsPointer(Module& M, Value* V) { + auto T = dyn_cast(V->getType()); + assert(T && "expected pointer type"); + + return ConstantExpr::getIntToPtr( + ConstantInt::get( + Type::getInt64Ty(M.getContext()), + M.getDataLayout().getTypeStoreSize(T->getPointerElementType())), + PointerType::getUnqual(Type::getInt8Ty(M.getContext()))); + } + + Value* accessSizeAsPointer(LoadInst& I) { + auto& M = *I.getParent()->getParent()->getParent(); + return accessSizeAsPointer(M, I.getPointerOperand()); + } + + Value* accessSizeAsPointer(StoreInst& I) { + auto& M = *I.getParent()->getParent()->getParent(); + return accessSizeAsPointer(M, I.getPointerOperand()); + } +} + +void MemorySafetyChecker::visitLoadInst(LoadInst& I) { + insertMemoryAccessCheck(I.getPointerOperand(), accessSizeAsPointer(I), &I); +} + +void MemorySafetyChecker::visitStoreInst(StoreInst& I) { + insertMemoryAccessCheck(I.getPointerOperand(), accessSizeAsPointer(I), &I); +} + +void MemorySafetyChecker::visitMemSetInst(MemSetInst& I) { + insertMemoryAccessCheck(I.getDest(), I.getLength(), &I); +} + +void MemorySafetyChecker::visitMemTransferInst(MemTransferInst& I) { + insertMemoryAccessCheck(I.getDest(), I.getLength(), &I); + insertMemoryAccessCheck(I.getSource(), I.getLength(), &I); +} + // Pass ID variable char MemorySafetyChecker::ID = 0; } - diff --git a/lib/smack/Naming.cpp b/lib/smack/Naming.cpp index 5a47eb4a7..645510fc0 100644 --- a/lib/smack/Naming.cpp +++ b/lib/smack/Naming.cpp @@ -13,10 +13,12 @@ namespace smack { const std::string Naming::BOOL_TYPE = "bool"; const std::string Naming::UNINTERPRETED_FLOAT_TYPE = "float"; +const std::string Naming::HALF_TYPE = "bvhalf"; const std::string Naming::FLOAT_TYPE = "bvfloat"; const std::string Naming::DOUBLE_TYPE = "bvdouble"; const std::string Naming::LONG_DOUBLE_TYPE = "bvlongdouble"; const std::string Naming::PTR_TYPE = "ref"; +const std::string Naming::VECTOR_TYPE = "vec"; const std::string Naming::NULL_VAL = "$0.ref"; const std::string Naming::INIT_FUNC_PREFIX = "__SMACK_init_func"; @@ -63,10 +65,13 @@ const std::string Naming::BLOCK_LBL = "$bb"; const std::string Naming::RET_VAR = "$r"; const std::string Naming::EXN_VAR = "$exn"; const std::string Naming::EXN_VAL_VAR = "$exnv"; +const std::string Naming::RMODE_VAR = "$rmode"; const std::string Naming::BOOL_VAR = "$b"; const std::string Naming::FLOAT_VAR = "$f"; const std::string Naming::INT_VAR = "$i"; +const std::string Naming::VECTOR_VAR = "$v"; const std::string Naming::PTR_VAR = "$p"; +const std::string Naming::GLOBAL_VAR = "$g"; const std::string Naming::UNDEF_SYM = "$u"; const std::string Naming::CONTRACT_EXPR = "$expr"; const std::string Naming::MEMORY_SAFETY_FUNCTION = "__SMACK_check_memory_safety"; @@ -104,7 +109,10 @@ const std::map Naming::INSTRUCTION_TABLE { {Instruction::FSub, "$fsub"}, {Instruction::FMul, "$fmul"}, {Instruction::FDiv, "$fdiv"}, - {Instruction::FRem, "$frem"} + {Instruction::FRem, "$frem"}, + {Instruction::ShuffleVector, "$shufflevector"}, + {Instruction::InsertElement, "$insertelement"}, + {Instruction::ExtractElement, "$extractelement"} }; const std::map Naming::CMPINST_TABLE { @@ -170,15 +178,24 @@ bool Naming::isSmackGeneratedName(std::string n) { } std::string Naming::escape(std::string s) { - std::string Str(llvm::DOT::EscapeString(s)); + std::string Str(s); for (unsigned i = 0; i != Str.length(); ++i) switch (Str[i]) { - case '\01': - Str[i] = '_'; - break; case '@': Str[i] = '.'; break; + case '\01': case '\\': + case ':': case ' ': + case '(': case ')': + case '[': case ']': + case '{': case '}': + case '<': case '>': + case '|': case '"': + case '-': case ';': + Str[i] = '_'; + break; + // Another character to escape would be '$', but SMACK internally + // generates LLVM IR that uses this character. } return Str; } @@ -201,8 +218,7 @@ std::string Naming::get(const Value& V) { name = name + "_"; } else if (isa(&V)) { - // XXX is this a problem? - assert( false && "Unexpected unnamed global vlaue." ); + name = freshGlobalName(); } else if (isa(&V)) { name = freshBlockName(); @@ -224,6 +240,12 @@ std::string Naming::get(const Value& V) { return name; } +std::string Naming::freshGlobalName() { + std::stringstream s; + s << GLOBAL_VAR << globalNum++; + return s.str(); +} + std::string Naming::freshBlockName() { std::stringstream s; s << BLOCK_LBL << blockNum++; @@ -245,6 +267,9 @@ std::string Naming::freshVarName(const Value& V) { else if (V.getType()->isIntegerTy()) s << INT_VAR; + else if (auto VT = dyn_cast(V.getType())) + s << VECTOR_VAR; + else s << PTR_VAR; diff --git a/lib/smack/NormalizeLoops.cpp b/lib/smack/NormalizeLoops.cpp new file mode 100644 index 000000000..fbca98d92 --- /dev/null +++ b/lib/smack/NormalizeLoops.cpp @@ -0,0 +1,153 @@ +// +// This file is distributed under the MIT License. See LICENSE for details. +// + +// +// This pass normalizes loop structures to allow easier generation of Boogie +// code when a loop edge comes from a branch. Specifically, a forwarding block +// is added between a branching block and the loop header. +// + +#include "smack/NormalizeLoops.h" +#include "smack/Naming.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/ValueSymbolTable.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/IR/Dominators.h" +#include +#include +#include + +namespace smack { + +using namespace llvm; + +// Register LoopInfo +void NormalizeLoops::getAnalysisUsage(AnalysisUsage& AU) const { + AU.addRequired(); +} + +/** + * Creates a basic block which unconditionally branches to \param target. + */ +BasicBlock* makeForwardingBlock(BasicBlock* target) { + auto& context = target->getContext(); + BasicBlock* result = BasicBlock::Create(context, "forwarder", target->getParent()); + BranchInst* branch = BranchInst::Create(target); + result->getInstList().push_back(branch); + return result; +} + +/** + * Returns a vector of each successor index in \param ti which equals \param + * headerBlock. + */ +std::vector getSuccessorIndices(TerminatorInst* ti, BasicBlock* headerBlock) { + std::vector result; + unsigned numSuccs = ti->getNumSuccessors(); + + if (numSuccs <= 1) { return result; } + + for (unsigned i = 0; i < numSuccs; ++i) { + if (ti->getSuccessor(i) == headerBlock) { + result.push_back(i); + } + } + return result; +} + +/** + * Splits any edge between \param BB and \param headerBlock in a loop body, + * by adding a forwarding block between \param BB and \param headerBlock. The + * \param blockMap is updated to map between \param BB and the newly created + * forwarding block. + */ +void splitBlock(BasicBlock* BB, BasicBlock* headerBlock, + std::map& blockMap) { + TerminatorInst* ti = BB->getTerminator(); + + // Get a list of all successor indices which point to headerBlock. + std::vector succIndices = getSuccessorIndices(ti, headerBlock); + + // TerminatorInsts may have the header block listed multiple times as a + // successor block, e.g., in a SwitchInst. We need to make sure each such + // index uses the same forwarding block. + if (succIndices.size()) { + BasicBlock* forwarder = makeForwardingBlock(headerBlock); + blockMap[BB] = forwarder; + for (auto succIndex : succIndices) { + ti->setSuccessor(succIndex, forwarder); + } + } +} + +/** + * \param blockMap a map from old BasicBlocks and new BasicBlocks. + * Fixes any PHI nodes in \param phis to get their incoming block from the new + * blocks in \param blockMap. + */ +void processPhis(std::vector& phis, std::map& blockMap) { + for (PHINode* phi : phis) { + unsigned numIncoming = phi->getNumIncomingValues(); + for (unsigned i = 0; i < numIncoming; ++i) { + BasicBlock* incomingBlock = phi->getIncomingBlock(i); + if (blockMap.count(incomingBlock)) { + phi->setIncomingBlock(i, blockMap[incomingBlock]); + } + } + } +} + +void processLoop(Loop *loop) { + std::vector phis; + std::set phiIncBlocks; + std::set loopBlocks(loop->block_begin(), loop->block_end()); + BasicBlock* headerBlock = loop->getHeader(); + + // Gather Phis in the header + for (Instruction& I : *headerBlock) { + if (auto* phi = dyn_cast(&I)) { + phis.push_back(phi); + phiIncBlocks.insert(phi->block_begin(), phi->block_end()); + } + } + + std::map blockMap; + + // Add forwarding blocks + for (BasicBlock* BB : phiIncBlocks) { + if (loopBlocks.count(BB) == 0) { continue; } + splitBlock(BB, headerBlock, blockMap); + } + + // Fix up Phi nodes + processPhis(phis, blockMap); + + // Handle subloops + for (Loop *subloop : loop->getSubLoops()) { + processLoop(subloop); + } +} + +bool NormalizeLoops::runOnModule(Module& m) { + for (auto F = m.begin(), FEnd = m.end(); F != FEnd; ++F) { + if (F->isIntrinsic() || F->empty()) { continue; } + LoopInfo& loopInfo = getAnalysis(*F).getLoopInfo(); + for (LoopInfo::iterator LI = loopInfo.begin(), LIEnd = loopInfo.end(); LI != LIEnd; ++LI) { + processLoop(*LI); + } + } + + return true; +} + +// Pass ID variable +char NormalizeLoops::ID = 0; + +const char* NormalizeLoops::getPassName() const { + return "NormalizeLoops"; +} +} diff --git a/lib/smack/RemoveDeadDefs.cpp b/lib/smack/RemoveDeadDefs.cpp index 129c73665..2b9ff09c9 100644 --- a/lib/smack/RemoveDeadDefs.cpp +++ b/lib/smack/RemoveDeadDefs.cpp @@ -31,6 +31,9 @@ bool RemoveDeadDefs::runOnModule(Module& M) { if (name.find("__SMACK_") != std::string::npos) continue; + if (name.find("__VERIFIER_assume") != std::string::npos) + continue; + if (SmackOptions::isEntryPoint(name)) continue; diff --git a/lib/smack/SignedIntegerOverflowChecker.cpp b/lib/smack/SignedIntegerOverflowChecker.cpp deleted file mode 100644 index 07d505698..000000000 --- a/lib/smack/SignedIntegerOverflowChecker.cpp +++ /dev/null @@ -1,112 +0,0 @@ -// -// This file is distributed under the MIT License. See LICENSE for details. -// -#include "smack/SignedIntegerOverflowChecker.h" -#include "smack/Naming.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/InstIterator.h" -#include "llvm/IR/Constants.h" -#include "smack/Debug.h" -#include "llvm/IR/ValueSymbolTable.h" -#include "llvm/IR/IRBuilder.h" -#include "llvm/Support/Regex.h" -#include - -namespace smack { - -using namespace llvm; - -Regex OVERFLOW_INTRINSICS("^llvm.s(add|sub|mul).with.overflow.i(32|64)$"); - -std::map SignedIntegerOverflowChecker::INSTRUCTION_TABLE { - {"add", Instruction::Add}, - {"sub", Instruction::Sub}, - {"mul", Instruction::Mul} -}; - -std::map SignedIntegerOverflowChecker::INT_MAX_TABLE { - {32, "2147483647"}, - {64, "9223372036854775807"} -}; - -std::map SignedIntegerOverflowChecker::INT_MIN_TABLE { - {32, "-2147483648"}, - {64, "-9223372036854775808"} -}; - -bool SignedIntegerOverflowChecker::runOnModule(Module& m) { - Function* va = m.getFunction("__SMACK_overflow_false"); - Function* co = m.getFunction("__SMACK_check_overflow"); - - for (auto& F : m) { - if (!Naming::isSmackName(F.getName())) { - for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) { - if (auto ci = dyn_cast(&*I)) { - Function* f = ci->getCalledFunction(); - if (f && f->hasName() && f->getName() == "llvm.trap") { - ci->setCalledFunction(va); - } - } - if (auto ei = dyn_cast(&*I)) { - if (auto ci = dyn_cast(ei->getAggregateOperand())) { - Function* f = ci->getCalledFunction(); - SmallVectorImpl *ar = new SmallVector; - if (f && f->hasName() && OVERFLOW_INTRINSICS.match(f->getName().str(), ar)) { - std::string op = ar->begin()[1].str(); - std::string len = ar->begin()[2].str(); - int bits = std::stoi(len); - if (ei->getIndices()[0] == 1) { - Instruction* prev = &*std::prev(I); - Value* o1 = ci->getArgOperand(0); - Value* o2 = ci->getArgOperand(1); - CastInst* so1 = CastInst::CreateSExtOrBitCast(o1, IntegerType::get(F.getContext(), bits*2), "", &*I); - CastInst* so2 = CastInst::CreateSExtOrBitCast(o2, IntegerType::get(F.getContext(), bits*2), "", &*I); - BinaryOperator* ai = BinaryOperator::Create(INSTRUCTION_TABLE.at(op), so1, so2, "", &*I); - if (prev && isa(prev)) { - ExtractValueInst* pei = cast(prev); - if (auto pci = dyn_cast(pei->getAggregateOperand())) { - if (pci == ci) { - CastInst* tr = CastInst::CreateTruncOrBitCast(ai, IntegerType::get(F.getContext(), bits), "", &*I); - prev->replaceAllUsesWith(tr); - } - } - } - ConstantInt* max = ConstantInt::get(IntegerType::get(F.getContext(), bits*2), INT_MAX_TABLE.at(bits), 10); - ConstantInt* min = ConstantInt::get(IntegerType::get(F.getContext(), bits*2), INT_MIN_TABLE.at(bits), 10); - ICmpInst* gt = new ICmpInst(&*I, CmpInst::ICMP_SGT, ai, max, ""); - ICmpInst* lt = new ICmpInst(&*I, CmpInst::ICMP_SLT, ai, min, ""); - BinaryOperator* flag = BinaryOperator::Create(Instruction::Or, gt, lt, "", &*I); - (*I).replaceAllUsesWith(flag); - } - } - } - } - if (auto sdi = dyn_cast(&*I)) { - if (sdi->getOpcode() == Instruction::SDiv) { - int bits = sdi->getType()->getIntegerBitWidth(); - Value* o1 = sdi->getOperand(0); - Value* o2 = sdi->getOperand(1); - CastInst* so1 = CastInst::CreateSExtOrBitCast(o1, IntegerType::get(F.getContext(), bits*2), "", &*I); - CastInst* so2 = CastInst::CreateSExtOrBitCast(o2, IntegerType::get(F.getContext(), bits*2), "", &*I); - BinaryOperator* lsdi = BinaryOperator::Create(Instruction::SDiv, so1, so2, "", &*I); - ConstantInt* max = ConstantInt::get(IntegerType::get(F.getContext(), bits*2), INT_MAX_TABLE.at(bits), 10); - ConstantInt* min = ConstantInt::get(IntegerType::get(F.getContext(), bits*2), INT_MIN_TABLE.at(bits), 10); - ICmpInst* gt = new ICmpInst(&*I, CmpInst::ICMP_SGT, lsdi, max, ""); - ICmpInst* lt = new ICmpInst(&*I, CmpInst::ICMP_SLT, lsdi, min, ""); - BinaryOperator* flag = BinaryOperator::Create(Instruction::Or, gt, lt, "", &*I); - CastInst* tf = CastInst::CreateSExtOrBitCast(flag, co->getArgumentList().begin()->getType(), "", &*I); - CallInst::Create(co, {tf}, "", &*I); - CastInst* tv = CastInst::CreateTruncOrBitCast(lsdi, sdi->getType(), "", &*I); - (*I).replaceAllUsesWith(tv); - } - } - } - } - } - return true; -} - -// Pass ID variable -char SignedIntegerOverflowChecker::ID = 0; -} diff --git a/lib/smack/SmackInstGenerator.cpp b/lib/smack/SmackInstGenerator.cpp index b08714ac2..3e0484f82 100644 --- a/lib/smack/SmackInstGenerator.cpp +++ b/lib/smack/SmackInstGenerator.cpp @@ -5,6 +5,7 @@ #include "smack/SmackInstGenerator.h" #include "smack/BoogieAst.h" #include "smack/SmackRep.h" +#include "smack/VectorOperations.h" #include "smack/SmackOptions.h" #include "smack/Naming.h" #include "llvm/IR/InstVisitor.h" @@ -53,8 +54,10 @@ void SmackInstGenerator::emit(const Stmt* s) { } const Stmt* SmackInstGenerator::recordProcedureCall( - llvm::Value* V, std::list attrs) { - return Stmt::call("boogie_si_record_" + rep->type(V), {rep->expr(V)}, {}, attrs); + const llvm::Value* V, std::list attrs) { + auto D = Decl::procedure("boogie_si_record_" + rep->type(V), {{"x", rep->type(V)}}); + rep->addAuxiliaryDeclaration(D); + return Stmt::call(D->getName(), {rep->expr(V)}, {}, attrs); } Block* SmackInstGenerator::createBlock() { @@ -137,7 +140,7 @@ void SmackInstGenerator::visitBasicBlock(llvm::BasicBlock& bb) { currBlock = getBlock(&bb); auto* F = bb.getParent(); - if (SmackOptions::isEntryPoint(naming->get(*F)) && &bb == &F->getEntryBlock()) { + if (&bb == &F->getEntryBlock()) { for (auto& I : bb.getInstList()) { if (llvm::isa(I)) continue; @@ -146,9 +149,11 @@ void SmackInstGenerator::visitBasicBlock(llvm::BasicBlock& bb) { break; } } - emit(recordProcedureCall(F, {Attr::attr("cexpr", "smack:entry:" + naming->get(*F))})); - for (auto& A : F->getArgumentList()) { - emit(recordProcedureCall(&A, {Attr::attr("cexpr", "smack:arg:" + naming->get(*F) + ":" + naming->get(A))})); + if (SmackOptions::isEntryPoint(naming->get(*F))) { + emit(recordProcedureCall(F, {Attr::attr("cexpr", "smack:entry:" + naming->get(*F))})); + for (auto& A : F->getArgumentList()) { + emit(recordProcedureCall(&A, {Attr::attr("cexpr", "smack:arg:" + naming->get(*F) + ":" + naming->get(A))})); + } } } } @@ -323,14 +328,50 @@ void SmackInstGenerator::visitUnreachableInst(llvm::UnreachableInst& ii) { void SmackInstGenerator::visitBinaryOperator(llvm::BinaryOperator& I) { processInstruction(I); - emit(Stmt::assign(rep->expr(&I),rep->bop(&I))); + const Expr *E; + if (isa(I.getType())) { + auto X = I.getOperand(0); + auto Y = I.getOperand(1); + auto D = VectorOperations(rep).binary(&I); + E = Expr::fn(D->getName(), {rep->expr(X), rep->expr(Y)}); + } else { + E = rep->bop(&I); + } + emit(Stmt::assign(rep->expr(&I), E)); } /******************************************************************************/ /* VECTOR OPERATIONS */ /******************************************************************************/ -// TODO implement std::vector operations +void SmackInstGenerator::visitExtractElementInst(ExtractElementInst &I) { + processInstruction(I); + auto X = I.getOperand(0); + auto Y = I.getOperand(1); + auto D = VectorOperations(rep).extract(X->getType(), Y->getType()); + emit(Stmt::assign(rep->expr(&I), Expr::fn(D->getName(), {rep->expr(X), rep->expr(Y)}))); +} + +void SmackInstGenerator::visitInsertElementInst(InsertElementInst &I) { + processInstruction(I); + auto X = I.getOperand(0); + auto Y = I.getOperand(1); + auto Z = I.getOperand(2); + auto D = VectorOperations(rep).insert(X->getType(), Z->getType()); + emit(Stmt::assign(rep->expr(&I), Expr::fn(D->getName(), {rep->expr(X), rep->expr(Y), rep->expr(Z)}))); +} + +void SmackInstGenerator::visitShuffleVectorInst(ShuffleVectorInst &I) { + processInstruction(I); + auto X = I.getOperand(0); + auto Y = I.getOperand(1); + auto M = I.getShuffleMask(); + std::vector mask; + for (auto idx : M) + mask.push_back(idx); + auto D = VectorOperations(rep).shuffle(X->getType(), I.getType(), mask); + emit(Stmt::assign(rep->expr(&I), Expr::fn(D->getName(), {rep->expr(X), rep->expr(Y)}))); +} /******************************************************************************/ /* AGGREGATE OPERATIONS */ @@ -393,17 +434,28 @@ void SmackInstGenerator::visitAllocaInst(llvm::AllocaInst& ai) { void SmackInstGenerator::visitLoadInst(llvm::LoadInst& li) { processInstruction(li); + auto P = li.getPointerOperand(); + auto T = dyn_cast(P->getType()); + assert(T && "expected pointer type"); // TODO what happens with aggregate types? // assert (!li.getType()->isAggregateType() && "Unexpected load value."); - emit(Stmt::assign(rep->expr(&li), rep->load(li.getPointerOperand()))); + const Expr *E; + if (isa(T->getElementType())) { + auto D = VectorOperations(rep).load(P); + E = Expr::fn(D->getName(), {Expr::id(rep->memPath(P)), rep->expr(P)}); + } else { + E = rep->load(P); + } + + emit(Stmt::assign(rep->expr(&li), E)); if (SmackOptions::MemoryModelDebug) { emit(Stmt::call(Naming::REC_MEM_OP, {Expr::id(Naming::MEM_OP_VAL)})); - emit(Stmt::call("boogie_si_record_int", {Expr::lit(0L)})); - emit(Stmt::call("boogie_si_record_int", {rep->expr(li.getPointerOperand())})); - emit(Stmt::call("boogie_si_record_int", {rep->expr(&li)})); + emit(recordProcedureCall(ConstantInt::get(Type::getInt32Ty(li.getContext()), 0), {})); + emit(recordProcedureCall(P, {})); + emit(recordProcedureCall(&li, {})); } } @@ -413,14 +465,21 @@ void SmackInstGenerator::visitStoreInst(llvm::StoreInst& si) { const llvm::Value* V = si.getOperand(0)->stripPointerCasts(); assert (!V->getType()->isAggregateType() && "Unexpected store value."); - emit(rep->store(P,V)); + if (isa(V->getType())) { + auto D = VectorOperations(rep).store(P); + auto M = Expr::id(rep->memPath(P)); + auto E = Expr::fn(D->getName(), {M, rep->expr(P), rep->expr(V)}); + emit(Stmt::assign(M, E)); + } else { + emit(rep->store(P,V)); + } if (SmackOptions::SourceLocSymbols) { if (const llvm::GlobalVariable* G = llvm::dyn_cast(P)) { if (const llvm::PointerType* t = llvm::dyn_cast(G->getType())) { if (!t->getElementType()->isPointerTy()) { assert(G->hasName() && "Expected named global variable."); - emit(Stmt::call("boogie_si_record_" + rep->type(V), {rep->expr(V)}, {}, {Attr::attr("cexpr", G->getName().str())})); + emit(recordProcedureCall(V, {Attr::attr("cexpr", G->getName().str())})); } } } @@ -428,9 +487,9 @@ void SmackInstGenerator::visitStoreInst(llvm::StoreInst& si) { if (SmackOptions::MemoryModelDebug) { emit(Stmt::call(Naming::REC_MEM_OP, {Expr::id(Naming::MEM_OP_VAL)})); - emit(Stmt::call("boogie_si_record_int", {Expr::lit(1L)})); - emit(Stmt::call("boogie_si_record_int", {rep->expr(P)})); - emit(Stmt::call("boogie_si_record_int", {rep->expr(V)})); + emit(recordProcedureCall(ConstantInt::get(Type::getInt32Ty(si.getContext()), 1), {})); + emit(recordProcedureCall(P, {})); + emit(recordProcedureCall(V, {})); } } @@ -468,7 +527,15 @@ void SmackInstGenerator::visitGetElementPtrInst(llvm::GetElementPtrInst& I) { void SmackInstGenerator::visitCastInst(llvm::CastInst& I) { processInstruction(I); - emit(Stmt::assign(rep->expr(&I),rep->cast(&I))); + const Expr *E; + if (isa(I.getType())) { + auto X = I.getOperand(0); + auto D = VectorOperations(rep).cast(&I); + E = Expr::fn(D->getName(), rep->expr(X)); + } else { + E = rep->cast(&I); + } + emit(Stmt::assign(rep->expr(&I), E)); } /******************************************************************************/ @@ -477,7 +544,16 @@ void SmackInstGenerator::visitCastInst(llvm::CastInst& I) { void SmackInstGenerator::visitCmpInst(llvm::CmpInst& I) { processInstruction(I); - emit(Stmt::assign(rep->expr(&I),rep->cmp(&I))); + const Expr *E; + if (isa(I.getType())) { + auto X = I.getOperand(0); + auto Y = I.getOperand(1); + auto D = VectorOperations(rep).cmp(&I); + E = Expr::fn(D->getName(), rep->expr(X), rep->expr(Y)); + } else { + E = rep->cmp(&I); + } + emit(Stmt::assign(rep->expr(&I), E)); } void SmackInstGenerator::visitPHINode(llvm::PHINode& phi) { @@ -490,15 +566,13 @@ void SmackInstGenerator::visitSelectInst(llvm::SelectInst& i) { processInstruction(i); std::string x = naming->get(i); const Expr - *c = rep->expr(i.getOperand(0)), - *v1 = rep->expr(i.getOperand(1)), - *v2 = rep->expr(i.getOperand(2)); + *c = rep->expr(i.getCondition()), + *v1 = rep->expr(i.getTrueValue()), + *v2 = rep->expr(i.getFalseValue()); - emit(Stmt::havoc(x)); - emit(Stmt::assume(Expr::and_( - Expr::impl(Expr::eq(c,rep->integerLit(1L,1)), Expr::eq(Expr::id(x), v1)), - Expr::impl(Expr::neq(c,rep->integerLit(1L,1)), Expr::eq(Expr::id(x), v2)) - ))); + assert(!i.getCondition()->getType()->isVectorTy() && "Vector condition is not supported."); + emit(Stmt::assign(Expr::id(x), + Expr::if_then_else(Expr::eq(c, rep->integerLit(1L,1)), v1, v2))); } void SmackInstGenerator::visitCallInst(llvm::CallInst& ci) { @@ -520,6 +594,13 @@ void SmackInstGenerator::visitCallInst(llvm::CallInst& ci) { WARN("ignoring llvm.debug call."); emit(Stmt::skip()); + } else if (name.find("llvm.expect.") != std::string::npos) { + // The llvm.expect.* function has two arguments: a value v and an expected + // value that is supposed to be used by optimizers. + // Semantically, this function simply returns the value v. + Value* val = ci.getArgOperand(0); + emit(Stmt::assign(rep->expr(&ci), rep->expr(val))); + } else if (name.find(Naming::VALUE_PROC) != std::string::npos) { emit(rep->valueAnnotation(ci)); @@ -544,7 +625,7 @@ void SmackInstGenerator::visitCallInst(llvm::CallInst& ci) { rep->addBplGlobal(var); } - } else if (name.find(Naming::CONTRACT_EXPR) != std::string::npos) { + } else if (rep->isContractExpr(f)) { // NOTE do not generate code for contract expressions } else if (name == "__CONTRACT_int_variable") { @@ -553,31 +634,34 @@ void SmackInstGenerator::visitCallInst(llvm::CallInst& ci) { // emit(Stmt::assign(rep->expr(&ci), Expr::id(rep->getString(ci.getArgOperand(0))))); } else if (name == Naming::CONTRACT_FORALL) { - assert(ci.getNumArgOperands() == 2 - && "Expected contract expression argument to contract function."); - CallInst* cj = dyn_cast(ci.getArgOperand(1)); - assert(cj && "Expected contract expression argument to contract function."); - Function* F = cj->getCalledFunction(); - assert(F && F->getName().find(Naming::CONTRACT_EXPR) != std::string::npos - && "Expected contract expression argument to contract function."); - auto binding = rep->getString(ci.getArgOperand(0)); - std::list args; - - auto AX = F->getAttributes(); - for (unsigned i = 0; i < cj->getNumArgOperands(); i++) { - std::string var = ""; - if (AX.hasAttribute(i+1, "contract-var")) - var = AX.getAttribute(i+1, "contract-var").getValueAsString(); - args.push_back( - var == binding ? Expr::id(binding) : rep->expr(cj->getArgOperand(i))); - } - for (auto m : rep->memoryMaps()) - args.push_back(Expr::id(m.first)); - auto E = Expr::fn(F->getName(), args); - emit(Stmt::assign(rep->expr(&ci), - Expr::cond(Expr::forall(binding, "int", E), - rep->integerLit(1U,1), rep->integerLit(0U,1)))); + llvm_unreachable("universal quantifiers not implemented."); + + // assert(ci.getNumArgOperands() == 2 + // && "Expected contract expression argument to contract function."); + // CallInst* cj = dyn_cast(ci.getArgOperand(1)); + // assert(cj && "Expected contract expression argument to contract function."); + // Function* F = cj->getCalledFunction(); + // assert(F && rep->isContractExpr(F) + // && "Expected contract expression argument to contract function."); + // + // auto binding = rep->getString(ci.getArgOperand(0)); + // std::list args; + // + // auto AX = F->getAttributes(); + // for (unsigned i = 0; i < cj->getNumArgOperands(); i++) { + // std::string var = ""; + // if (AX.hasAttribute(i+1, "contract-var")) + // var = AX.getAttribute(i+1, "contract-var").getValueAsString(); + // args.push_back( + // var == binding ? Expr::id(binding) : rep->expr(cj->getArgOperand(i))); + // } + // for (auto m : rep->memoryMaps()) + // args.push_back(Expr::id(m.first)); + // auto E = Expr::fn(F->getName(), args); + // emit(Stmt::assign(rep->expr(&ci), + // Expr::cond(Expr::forall(binding, "int", E), + // rep->integerLit(1U,1), rep->integerLit(0U,1)))); } else if (name == Naming::CONTRACT_REQUIRES || name == Naming::CONTRACT_ENSURES || @@ -588,7 +672,7 @@ void SmackInstGenerator::visitCallInst(llvm::CallInst& ci) { CallInst* cj = dyn_cast(ci.getArgOperand(0)); assert(cj && "Expected contract expression argument to contract function."); Function* F = cj->getCalledFunction(); - assert(F && F->getName().find(Naming::CONTRACT_EXPR) != std::string::npos + assert(F && rep->isContractExpr(F) && "Expected contract expression argument to contract function."); std::list args; @@ -672,7 +756,7 @@ void SmackInstGenerator::visitDbgValueInst(llvm::DbgValueInst& dvi) { processInstruction(dvi); if (SmackOptions::SourceLocSymbols) { - const Value* V = dvi.getValue(); + Value* V = dvi.getValue(); const llvm::DILocalVariable *var = dvi.getVariable(); //if (V && !V->getType()->isPointerTy() && !llvm::isa(V)) { if (V && !V->getType()->isPointerTy()) { @@ -685,10 +769,14 @@ void SmackInstGenerator::visitDbgValueInst(llvm::DbgValueInst& dvi) { const Instruction& pi = *std::prev(currInst); V = V->stripPointerCasts(); WARN(i2s(pi)); - if (!llvm::isa(&pi) && V == llvm::dyn_cast(&pi)) { - std::stringstream recordProc; - recordProc << "boogie_si_record_" << rep->type(V); - emit(Stmt::call(recordProc.str(), {rep->expr(V)}, {}, {Attr::attr("cexpr", var->getName().str())})); + if (!llvm::isa(&pi) && V == llvm::dyn_cast(&pi)) + emit(recordProcedureCall(V, {Attr::attr("cexpr", var->getName().str())})); + } + Function* F = dvi.getFunction(); + for(auto &arg : F->args()) { + if (&arg == V && var->getScope() == F->getMetadata("dbg")) { + emit(recordProcedureCall(V, {Attr::attr("cexpr", naming->get(*F) + ":arg:"+ var->getName().str())})); + break; } } } diff --git a/lib/smack/SmackModuleGenerator.cpp b/lib/smack/SmackModuleGenerator.cpp index 8b6cad53d..00fc49d79 100644 --- a/lib/smack/SmackModuleGenerator.cpp +++ b/lib/smack/SmackModuleGenerator.cpp @@ -99,7 +99,7 @@ void SmackModuleGenerator::generateProgram(llvm::Module& M) { std::list kill_list; for (auto D : *program) { if (auto P = dyn_cast(D)) { - if (D->getName().find(Naming::CONTRACT_EXPR) != std::string::npos) { + if (rep.isContractExpr(D->getName())) { decls.insert(decls.end(), Decl::code(P)); kill_list.push_back(P); } diff --git a/lib/smack/SmackOptions.cpp b/lib/smack/SmackOptions.cpp index 82f5b02e1..8c46708fb 100644 --- a/lib/smack/SmackOptions.cpp +++ b/lib/smack/SmackOptions.cpp @@ -55,6 +55,9 @@ const llvm::cl::opt SmackOptions::FloatEnabled( const llvm::cl::opt SmackOptions::MemorySafety( "memory-safety", llvm::cl::desc("Enable memory safety checks")); +const llvm::cl::opt SmackOptions::IntegerOverflow( + "integer-overflow", llvm::cl::desc("Enable integer overflow checks")); + bool SmackOptions::isEntryPoint(std::string name) { for (auto EP : EntryPoints) if (name == EP) diff --git a/lib/smack/SmackRep.cpp b/lib/smack/SmackRep.cpp index 6281070f4..d0913e2af 100644 --- a/lib/smack/SmackRep.cpp +++ b/lib/smack/SmackRep.cpp @@ -5,6 +5,7 @@ #include "smack/SmackRep.h" #include "smack/SmackOptions.h" #include "smack/CodifyStaticInits.h" +#include "smack/VectorOperations.h" #include "smack/BoogieAst.h" #include "smack/Naming.h" @@ -53,7 +54,7 @@ namespace smack { const unsigned MEMORY_INTRINSIC_THRESHOLD = 0; -const std::vector INTEGER_SIZES = {1, 8, 16, 24, 32, 40, 48, 56, 64, 88, 96, 128}; +const std::vector INTEGER_SIZES = {1, 8, 16, 24, 32, 40, 48, 56, 64, 80, 88, 96, 128}; const std::vector REF_CONSTANTS = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 1024 @@ -114,6 +115,19 @@ SmackRep::SmackRep(const DataLayout* L, Naming* N, Program* P, Regions* R) initFuncs.push_back(Naming::STATIC_INIT_PROC); } +void SmackRep::addAuxiliaryDeclaration(Decl* D) { + if (auxDecls.count(D->getName())) + return; + auxDecls[D->getName()] = D; +} + +std::list SmackRep::auxiliaryDeclarations() { + std::list ds; + for (auto D : auxDecls) + ds.push_back(D.second); + return ds; +} + std::string SmackRep::getString(const llvm::Value* v) { if (const llvm::ConstantExpr* constantExpr = llvm::dyn_cast(v)) if (constantExpr->getOpcode() == llvm::Instruction::GetElementPtr) @@ -155,7 +169,13 @@ std::string SmackRep::intType(unsigned width) { return (SmackOptions::BitPrecise ? "bv" : "i") + std::to_string(width); } -std::string SmackRep::opName(const std::string& operation, std::initializer_list types) { +std::string SmackRep::vectorType(int n, Type *T) { + std::stringstream s; + s << Naming::VECTOR_TYPE << "." << n << "x" << type(T); + return s.str(); +} + +std::string SmackRep::opName(const std::string& operation, std::list types) { std::stringstream s; s << operation; for (auto t : types) @@ -197,9 +217,11 @@ std::string SmackRep::procName(llvm::Function* F, std::list t std::string SmackRep::type(const llvm::Type* t) { if (t->isFloatingPointTy()) { - if (!SmackOptions::BitPrecise) + if (!SmackOptions::FloatEnabled) return Naming::UNINTERPRETED_FLOAT_TYPE; - if (t->isFloatTy()) + if (t->isHalfTy()) + return Naming::HALF_TYPE; + else if (t->isFloatTy()) return Naming::FLOAT_TYPE; else if (t->isDoubleTy()) return Naming::DOUBLE_TYPE; @@ -215,6 +237,9 @@ std::string SmackRep::type(const llvm::Type* t) { else if (t->isPointerTy()) return Naming::PTR_TYPE; + else if (auto VT = dyn_cast(t)) + return vectorType(VT->getNumElements(), VT->getElementType()); + else return Naming::PTR_TYPE; } @@ -253,6 +278,10 @@ std::string SmackRep::memPath(unsigned region) { return memReg(region); } +std::string SmackRep::memPath(const llvm::Value* v) { + return memPath(regions->idx(v)); +} + std::list< std::pair< std::string, std::string > > SmackRep::memoryMaps() { std::list< std::pair< std::string, std::string > > mms; for (unsigned i=0; isize(); i++) @@ -345,14 +374,11 @@ const Stmt* SmackRep::valueAnnotation(const CallInst& CI) { assert(CI.getNumArgOperands() > 0 && "Expected at least one argument."); assert(CI.getNumArgOperands() <= 2 && "Expected at most two arguments."); - const Value* V = CI.getArgOperand(0); - while (isa(V)) - V = dyn_cast(V)->getOperand(0); + const Value* V = CI.getArgOperand(0)->stripPointerCasts(); if (CI.getNumArgOperands() == 1) { name = indexedName(Naming::VALUE_PROC, {type(V->getType())}); if (dyn_cast(V)) { - assert(V->hasName() && "Expected named argument."); attrs.push_back(Attr::attr("name", {Expr::id(naming->get(*V))})); } else if (auto LI = dyn_cast(V)) { @@ -360,9 +386,8 @@ const Stmt* SmackRep::valueAnnotation(const CallInst& CI) { assert(GEP && "Expected GEP argument to load instruction."); auto A = dyn_cast(GEP->getPointerOperand()); assert(A && "Expected function argument to GEP instruction."); - assert(A->hasName() && "Expected named argument."); auto T = GEP->getType()->getElementType(); - const unsigned bits = T->getIntegerBitWidth(); + const unsigned bits = this->getSize(T); const unsigned bytes = bits / 8; const unsigned R = regions->idx(GEP); bool bytewise = regions->get(R).bytewiseAccess(); @@ -381,7 +406,7 @@ const Stmt* SmackRep::valueAnnotation(const CallInst& CI) { } else { name = Naming::VALUE_PROC + "s"; const Argument* A; - const Type* T; + Type* T; const Expr* addr; if ((A = dyn_cast(V))) { @@ -411,12 +436,11 @@ const Stmt* SmackRep::valueAnnotation(const CallInst& CI) { llvm_unreachable("Unexpected argument type."); } - assert(A->hasName() && "Expected named argument."); assert(T && "Unkown access type."); auto I = dyn_cast(CI.getArgOperand(1)); assert(I && "expected constant size expression."); const unsigned count = I->getZExtValue(); - const unsigned bits = T->getIntegerBitWidth(); + const unsigned bits = this->getSize(T); const unsigned bytes = bits / 8; const unsigned length = count * bytes; const unsigned R = regions->idx(V, length); @@ -489,15 +513,27 @@ const Stmt* SmackRep::returnValueAnnotation(const CallInst& CI) { // // } +bool SmackRep::isUnsafeFloatAccess(const Type* elemTy, const Type* resultTy) { + if (elemTy->isFloatingPointTy()) { + bool isByteMap = !resultTy || (resultTy->isIntegerTy() && resultTy->getIntegerBitWidth() == 8UL); + if (isByteMap && !SmackOptions::BitPrecise) + return true; + assert(resultTy->isFloatingPointTy() && "Unsupported map result type."); + } + return false; +} + const Expr* SmackRep::load(const llvm::Value* P) { const PointerType* T = dyn_cast(P->getType()); assert(T && "Expected pointer type."); const unsigned R = regions->idx(P); bool bytewise = regions->get(R).bytewiseAccess(); bool singleton = regions->get(R).isSingleton(); + const Type* resultTy = regions->get(R).getType(); const Expr* M = Expr::id(memPath(R)); - std::string N = Naming::LOAD + "." + (bytewise ? "bytes." : "") + - type(T->getElementType()); + std::string N = Naming::LOAD + "." + + (bytewise ? "bytes." : (isUnsafeFloatAccess(T->getElementType(), resultTy)? "unsafe." : "")) + + type(T->getElementType()); return singleton ? M : Expr::fn(N, M, SmackRep::expr(P)); } @@ -515,8 +551,9 @@ const Stmt* SmackRep::store(unsigned R, const Type* T, const Expr* P, const Expr* V) { bool bytewise = regions->get(R).bytewiseAccess(); bool singleton = regions->get(R).isSingleton(); - - std::string N = Naming::STORE + "." + (bytewise ? "bytes." : "") + type(T); + const Type* resultTy = regions->get(R).getType(); + std::string N = Naming::STORE + "." + + (bytewise ? "bytes." : (isUnsafeFloatAccess(T, resultTy)? "unsafe." : "")) + type(T); const Expr* M = Expr::id(memPath(R)); return Stmt::assign(M, singleton ? V : Expr::fn(N,M,P,V)); } @@ -611,7 +648,7 @@ const Expr* SmackRep::lit(const llvm::Value* v, bool isUnsigned) { return neg ? Expr::fn(op.str(), integerLit(0UL,width), e) : e; } else if (const ConstantFP* CFP = dyn_cast(v)) { - if (SmackOptions::BitPrecise) { + if (SmackOptions::FloatEnabled) { const APFloat APF = CFP->getValueAPF(); const Type* type = CFP->getType(); unsigned expSize, sigSize; @@ -713,7 +750,6 @@ const Expr* SmackRep::expr(const llvm::Value* v, bool isConstIntUnsigned) { } if (isa(v)) { - assert(v->hasName()); return Expr::id(naming->get(*v)); } else if (isa(v)) { @@ -751,6 +787,12 @@ const Expr* SmackRep::expr(const llvm::Value* v, bool isConstIntUnsigned) { } else if (const ConstantFP* cf = dyn_cast(constant)) { return lit(cf); + } else if (auto cv = dyn_cast(constant)) { + return VectorOperations(this).constant(cv); + + } else if (auto cd = dyn_cast(constant)) { + return VectorOperations(this).constant(cd); + } else if (constant->isNullValue()) return Expr::id(Naming::NULL_VAL); @@ -778,7 +820,22 @@ const Expr* SmackRep::cast(const llvm::ConstantExpr* CE) { } const Expr* SmackRep::cast(unsigned opcode, const llvm::Value* v, const llvm::Type* t) { - return Expr::fn(opName(Naming::INSTRUCTION_TABLE.at(opcode), {v->getType(), t}), expr(v)); + std::string fn = Naming::INSTRUCTION_TABLE.at(opcode); + if (opcode == Instruction::FPTrunc || opcode == Instruction::FPExt + || opcode == Instruction::SIToFP || opcode == Instruction::UIToFP) { + if (SmackOptions::FloatEnabled) { + return Expr::fn(opName(fn, {v->getType(), t}), Expr::id(Naming::RMODE_VAR), expr(v)); + } else { + return Expr::fn(opName(fn, {v->getType(), t}), expr(v)); + } + } else if (opcode == Instruction::FPToSI || opcode == Instruction::FPToUI) { + if (SmackOptions::FloatEnabled) { + return Expr::fn(opName(fn, {v->getType(), t}), Expr::lit(RModeKind::RTZ), expr(v)); + } else { + return Expr::fn(opName(fn, {v->getType(), t}), expr(v)); + } + } + return Expr::fn(opName(fn, {v->getType(), t}), expr(v)); } const Expr* SmackRep::bop(const llvm::ConstantExpr* CE) { @@ -791,6 +848,14 @@ const Expr* SmackRep::bop(const llvm::BinaryOperator* BO) { const Expr* SmackRep::bop(unsigned opcode, const llvm::Value* lhs, const llvm::Value* rhs, const llvm::Type* t) { std::string fn = Naming::INSTRUCTION_TABLE.at(opcode); + if (opcode == Instruction::FAdd || opcode == Instruction::FSub + || opcode == Instruction::FMul || opcode == Instruction::FDiv) { + if (SmackOptions::FloatEnabled) { + return Expr::fn(opName(fn, {t}), Expr::id(Naming::RMODE_VAR), expr(lhs), expr(rhs)); + } else { + return Expr::fn(opName(fn, {t}), expr(lhs), expr(rhs)); + } + } return Expr::fn(opName(fn, {t}), expr(lhs), expr(rhs)); } @@ -804,8 +869,23 @@ const Expr* SmackRep::cmp(const llvm::ConstantExpr* CE) { } const Expr* SmackRep::cmp(unsigned predicate, const llvm::Value* lhs, const llvm::Value* rhs, bool isUnsigned) { - std::string fn = Naming::CMPINST_TABLE.at(predicate); - return Expr::fn(opName(fn, {lhs->getType()}), expr(lhs, isUnsigned), expr(rhs, isUnsigned)); + std::string fn = opName(Naming::CMPINST_TABLE.at(predicate), {lhs->getType()}); + const Expr* e1 = expr(lhs, isUnsigned); + const Expr* e2 = expr(rhs, isUnsigned); + if (lhs->getType()->isFloatingPointTy()) + return Expr::if_then_else(Expr::fn(fn+".bool", e1, e2), integerLit(1UL,1), integerLit(0UL,1)); + else + return Expr::fn(fn, e1, e2); +} + + +bool SmackRep::isContractExpr(const llvm::Value* V) const { + auto name = naming->get(*V); + return isContractExpr(name); +} + +bool SmackRep::isContractExpr(const std::string S) const { + return S.find(Naming::CONTRACT_EXPR) == 0; } ProcDecl* SmackRep::procedure(Function* F, CallInst* CI) { @@ -841,7 +921,7 @@ ProcDecl* SmackRep::procedure(Function* F, CallInst* CI) { }) ); - } else if (name.find(Naming::CONTRACT_EXPR) != std::string::npos) { + } else if (isContractExpr(F)) { for (auto m : memoryMaps()) params.push_back(m); @@ -899,9 +979,6 @@ std::list SmackRep::procedure(llvm::Function* F) { const Expr* SmackRep::arg(llvm::Function* f, unsigned pos, llvm::Value* v) { return expr(v); - // (f && f->isVarArg() && isFloat(v)) - // ? Expr::fn(opName("$fp2si", {v->getType(), f->getType()}), expr(v)) - // : expr(v); } const Stmt* SmackRep::call(llvm::Function* f, const llvm::User& ci) { @@ -957,16 +1034,20 @@ std::string SmackRep::getPrelude() { s << Decl::typee("i" + std::to_string(size),"int") << "\n"; s << Decl::typee(Naming::PTR_TYPE, pointerType()) << "\n"; if (SmackOptions::FloatEnabled) { + s << Decl::typee(Naming::HALF_TYPE, "float11e5") << "\n"; s << Decl::typee(Naming::FLOAT_TYPE, "float24e8") << "\n"; s << Decl::typee(Naming::DOUBLE_TYPE, "float53e11") << "\n"; s << Decl::typee(Naming::LONG_DOUBLE_TYPE, "float65e15") << "\n"; + } else { + s << Decl::typee(Naming::UNINTERPRETED_FLOAT_TYPE, "") << "\n"; } - s << Decl::typee(Naming::UNINTERPRETED_FLOAT_TYPE, intType(32)) << "\n"; s << "\n"; s << "// Basic constants" << "\n"; s << Decl::constant("$0",intType(32)) << "\n"; s << Decl::axiom(Expr::eq(Expr::id("$0"),integerLit(0UL,32))) << "\n"; + s << Decl::constant("$1",intType(32)) << "\n"; + s << Decl::axiom(Expr::eq(Expr::id("$1"),integerLit(1UL,32))) << "\n"; for (unsigned i : REF_CONSTANTS) { std::stringstream t; @@ -1028,7 +1109,7 @@ std::string SmackRep::getPrelude() { s << "\n"; if (SmackOptions::BitPrecise) { - // XXX TODO don’t assume 64-bit pointers TODO XXX + // XXX TODO don't assume 64-bit pointers TODO XXX s << "// Bytewise pointer storage" << "\n"; s << "function {:inline} $load.bytes.ref(M: [ref] bv8, p: ref) " << "returns (ref) { $i2p.bv64.ref($load.bytes.bv64(M, p)) }" @@ -1106,6 +1187,9 @@ Decl* SmackRep::getInitFuncs() { Block* b = Block::block(); for (auto name : initFuncs) b->addStmt(Stmt::call(name)); + if (SmackOptions::FloatEnabled) { + b->addStmt(Stmt::assign(Expr::id(Naming::RMODE_VAR), Expr::lit(RModeKind::RNE))); + } b->addStmt(Stmt::return_()); proc->getBlocks().push_back(b); return proc; diff --git a/lib/smack/SplitAggregateLoadStore.cpp b/lib/smack/SplitAggregateLoadStore.cpp deleted file mode 100644 index 94dacd547..000000000 --- a/lib/smack/SplitAggregateLoadStore.cpp +++ /dev/null @@ -1,143 +0,0 @@ -// -// This file is distributed under the MIT License. See LICENSE for details. -// -#include "smack/SplitAggregateLoadStore.h" -#include "llvm/IR/InstIterator.h" - -namespace smack { - -using namespace llvm; - -std::vector getFirsts(std::vector> lst) { - std::vector ret; - for (auto& p : lst) - ret.push_back(std::get<0>(p)); - return ret; -} - -std::vector getSeconds(std::vector> lst) { - std::vector ret; - for (auto p = lst.begin()+1; p != lst.end(); ++p) - ret.push_back(std::get<1>(*p)); - return ret; -} - -static bool isUsedByReturnInst(Value* v) { - for (auto u = v->user_begin(); u != v->user_end(); ++u) { - if (isa(*u)) { - return true; - } - } - return false; -} - -bool SplitAggregateLoadStore::runOnBasicBlock(BasicBlock& BB) { - std::vector toRemove; - for(Instruction& I : BB) { - if (LoadInst* li = dyn_cast(&I)) { - if (!isUsedByReturnInst(li) && li->getType()->isAggregateType()) { - splitAggregateLoad(li); - toRemove.push_back(li); - } - } else if (StoreInst* si = dyn_cast(&I)) { - Value* P = si->getPointerOperand(); - Value* V = si->getOperand(0)->stripPointerCasts(); - if (V->getType()->isAggregateType()) { - splitAggregateStore(si, P, V); - toRemove.push_back(si); - } - } - } - - for (auto& i : toRemove) - i->eraseFromParent(); - return true; -} - -void SplitAggregateLoadStore::splitAggregateLoad(LoadInst* li) { - std::vector> idx; - IRBuilder<> irb(li); - li->replaceAllUsesWith(buildAggregateValues(&irb, li->getPointerOperand(), li->getType(), nullptr, idx)); -} - -Value* SplitAggregateLoadStore::buildAggregateValues(IRBuilder<> *irb, Value* ptr, Type* ct, Value* val, - std::vector > idxs) { - LLVMContext& C = ptr->getContext(); - Value* cv = val? val : UndefValue::get(ct); - - if (ct->isIntegerTy() || ct->isPointerTy() || ct->isFloatingPointTy()) - return irb->CreateInsertValue(val, - irb->CreateLoad(irb->CreateGEP(ptr, ArrayRef(getFirsts(idxs)))), - ArrayRef(getSeconds(idxs))); - else if (ArrayType* AT = dyn_cast(ct)) { - for (unsigned i = 0; i < AT->getNumElements(); ++i) { - std::vector > lidxs(idxs); - if (lidxs.empty()) - lidxs.push_back(std::make_pair(ConstantInt::get(Type::getInt32Ty(C),0), 0)); - lidxs.push_back(std::make_pair(ConstantInt::get(Type::getInt64Ty(C),i), i)); - cv = buildAggregateValues(irb, ptr, AT->getElementType(), cv, lidxs); - } - } else if (StructType* ST = dyn_cast(ct)) { - for (unsigned i = 0; i < ST->getNumElements(); ++i) { - std::vector > lidxs(idxs); - if (lidxs.empty()) - lidxs.push_back(std::make_pair(ConstantInt::get(Type::getInt32Ty(C),0), 0)); - lidxs.push_back(std::make_pair(ConstantInt::get(Type::getInt32Ty(C),i), i)); - cv = buildAggregateValues(irb, ptr, ST->getElementType(i), cv, lidxs); - } - } else - llvm_unreachable("Unsupported type"); - - return cv; -} - -void SplitAggregateLoadStore::splitAggregateStore(StoreInst* si, Value* ptr, Value* val) { - std::vector> idx; - IRBuilder<> irb(si); - copyAggregateValues(&irb, ptr, val->getType(), val, idx); -} - -void SplitAggregateLoadStore::copyAggregateValues(IRBuilder<> *irb, Value* ptr, Type* ct, Value* val, - std::vector > idxs) { - LLVMContext& C = ptr->getContext(); - Constant* cv = dyn_cast(val); - - if (ct->isIntegerTy() || ct->isPointerTy() || ct->isFloatingPointTy()) { - std::vector vidxs = getFirsts(idxs); - if (cv) - irb->CreateStore(val, irb->CreateGEP(ptr, ArrayRef(vidxs))); - else - irb->CreateStore(irb->CreateExtractValue( - val, ArrayRef(getSeconds(idxs))), - irb->CreateGEP(ptr, ArrayRef(vidxs))); - } else if (ArrayType* AT = dyn_cast(ct)) { - for (unsigned i = 0; i < AT->getNumElements(); ++i) { - auto A = cv? cv->getAggregateElement(i) : val; - std::vector > lidxs(idxs); - if (lidxs.empty()) - lidxs.push_back(std::make_pair(ConstantInt::get(Type::getInt32Ty(C),0), 0)); - lidxs.push_back(std::make_pair(ConstantInt::get(Type::getInt64Ty(C),i), i)); - copyAggregateValues(irb, ptr, AT->getElementType(), A, lidxs); - } - } else if (StructType* ST = dyn_cast(ct)) { - for (unsigned i = 0; i < ST->getNumElements(); ++i) { - auto A = cv? cv->getAggregateElement(i) : val; - std::vector > lidxs(idxs); - if (lidxs.empty()) - lidxs.push_back(std::make_pair(ConstantInt::get(Type::getInt32Ty(C),0), 0)); - lidxs.push_back(std::make_pair(ConstantInt::get(Type::getInt32Ty(C),i), i)); - copyAggregateValues(irb, ptr, ST->getElementType(i), A, lidxs); - } - } else - llvm_unreachable("Unsupported type"); -} - -// Pass ID variable -char SplitAggregateLoadStore::ID = 0; - -// Register the pass -static RegisterPass -X("split-aggregate-load-store", "Split Load/Store to Aggregate Types"); - -} - diff --git a/lib/smack/SplitAggregateValue.cpp b/lib/smack/SplitAggregateValue.cpp new file mode 100644 index 000000000..8df67e764 --- /dev/null +++ b/lib/smack/SplitAggregateValue.cpp @@ -0,0 +1,162 @@ +// +// This file is distributed under the MIT License. See LICENSE for details. +// +#include "smack/SplitAggregateValue.h" +#include "llvm/IR/InstIterator.h" + +namespace smack { + +using namespace llvm; + +std::vector getFirsts(SplitAggregateValue::IndexT lst) { + std::vector ret; + for (auto& p : lst) + ret.push_back(std::get<0>(p)); + return ret; +} + +std::vector getSeconds(SplitAggregateValue::IndexT lst) { + std::vector ret; + for (auto p = lst.begin()+1; p != lst.end(); ++p) + ret.push_back(std::get<1>(*p)); + return ret; +} + +bool SplitAggregateValue::runOnBasicBlock(BasicBlock& BB) { + std::vector toRemove; + LLVMContext& C = BB.getContext(); + for(Instruction& I : BB) { + IndexT idx; + std::vector info; + if (LoadInst* li = dyn_cast(&I)) { + if (li->getType()->isAggregateType()) { + visitAggregateValue(nullptr, li->getType(), idx, info, C); + IRBuilder<> irb(li); + li->replaceAllUsesWith(splitAggregateLoad(li, info, irb)); + toRemove.push_back(li); + } + } else if (StoreInst* si = dyn_cast(&I)) { + Value* V = si->getValueOperand(); + if (V->getType()->isAggregateType()) { + visitAggregateValue(dyn_cast_or_null(V), V->getType(), idx, info, C); + IRBuilder<> irb(si); + splitAggregateStore(si, info, irb); + toRemove.push_back(si); + } + } else if (ReturnInst* ri = dyn_cast(&I)) { + Value* V = ri->getReturnValue(); + if (isConstantAggregate(V)) { + visitAggregateValue(cast(V), V->getType(), idx, info, C); + splitConstantReturn(ri, info); + } + } else if (CallInst* ci = dyn_cast(&I)) { + for (unsigned i = 0; i < ci->getNumArgOperands(); ++i) { + Value* arg = ci->getArgOperand(i); + if (isConstantAggregate(arg)) { + info.clear(); + idx.clear(); + visitAggregateValue(cast(arg), arg->getType(), idx, info, C); + splitConstantArg(ci, i, info); + } + } + } + } + + for (auto& i : toRemove) + i->eraseFromParent(); + return true; +} + +bool SplitAggregateValue::isConstantAggregate(Value* V) { + // we do not want to touch vector type here since there is + // special support for it + if (V && (V->getType()->isStructTy() || V->getType()->isArrayTy())) + return isa(V) || isa(V); + else + return false; +} + +Value* SplitAggregateValue::splitAggregateLoad(LoadInst* li, std::vector& info, IRBuilder<>& irb) { + Value* V = UndefValue::get(li->getType()); + Value* P = li->getPointerOperand(); + for (auto& e : info) { + IndexT idxs = std::get<0>(e); + V = irb.CreateInsertValue(V, + irb.CreateLoad(irb.CreateGEP(P, ArrayRef(getFirsts(idxs)))), + ArrayRef(getSeconds(idxs))); + } + return V; +} + +void SplitAggregateValue::splitAggregateStore(StoreInst* si, std::vector& info, IRBuilder<>& irb) { + Value* P = si->getPointerOperand(); + Value* V = si->getValueOperand(); + for (auto& e : info) { + IndexT idxs = std::get<0>(e); + Constant* c = std::get<1>(e); + std::vector vidxs = getFirsts(idxs); + if (c) + irb.CreateStore(c, irb.CreateGEP(P, ArrayRef(vidxs))); + else + irb.CreateStore(irb.CreateExtractValue( + V, ArrayRef(getSeconds(idxs))), + irb.CreateGEP(P, ArrayRef(vidxs))); + } +} + +Value* SplitAggregateValue::createInsertedValue(IRBuilder<>& irb, Type* T, std::vector& info, Value* V) { + Value* box = irb.CreateAlloca(T); + StoreInst* si = new StoreInst(V, box); + LoadInst* li = new LoadInst(box); + splitAggregateStore(si, info, irb); + return splitAggregateLoad(li, info, irb); +} + +void SplitAggregateValue::splitConstantReturn(ReturnInst* ri, std::vector& info) { + IRBuilder<> irb(ri); + Type* T = ri->getReturnValue()->getType(); + ri->setOperand(0, createInsertedValue(irb, T, info, ri->getReturnValue())); +} + +void SplitAggregateValue::splitConstantArg(CallInst* ci, unsigned i, std::vector& info) { + IRBuilder<> irb(ci); + Type* T = ci->getArgOperand(i)->getType(); + ci->setArgOperand(i, createInsertedValue(irb, T, info, ci->getArgOperand(i))); +} + +void SplitAggregateValue::visitAggregateValue(Constant* baseVal, Type* T, IndexT idxs, + std::vector& info, LLVMContext& C){ + Constant* newBaseVal = baseVal; + if (T->isIntegerTy() || T->isFloatingPointTy() || T->isPointerTy()) + info.push_back({idxs, newBaseVal}); + else if (ArrayType* AT = dyn_cast(T)) { + for (unsigned i = 0; i < AT->getNumElements(); ++i) { + newBaseVal = baseVal? baseVal->getAggregateElement(i) : baseVal; + IndexT lidxs(idxs); + if (lidxs.empty()) + lidxs.push_back({ConstantInt::get(Type::getInt32Ty(C),0), 0}); + lidxs.push_back({ConstantInt::get(Type::getInt64Ty(C),i), i}); + visitAggregateValue(newBaseVal, AT->getElementType(), lidxs, info, C); + } + } else if (StructType* ST = dyn_cast(T)) { + for (unsigned i = 0; i < ST->getNumElements(); ++i) { + newBaseVal = baseVal? baseVal->getAggregateElement(i) : baseVal; + IndexT lidxs(idxs); + if (lidxs.empty()) + lidxs.push_back({ConstantInt::get(Type::getInt32Ty(C),0), 0}); + lidxs.push_back({ConstantInt::get(Type::getInt32Ty(C),i), i}); + visitAggregateValue(newBaseVal, ST->getElementType(i), lidxs, info, C); + } + } else + llvm_unreachable("Unsupported type"); +} + +// Pass ID variable +char SplitAggregateValue::ID = 0; + +// Register the pass +static RegisterPass +X("split-aggregate-values", "Split Load/Store/ConstantReturn of Aggregate Types"); + +} + diff --git a/lib/smack/VectorOperations.cpp b/lib/smack/VectorOperations.cpp new file mode 100644 index 000000000..f4c93a36a --- /dev/null +++ b/lib/smack/VectorOperations.cpp @@ -0,0 +1,304 @@ +// +// This file is distributed under the MIT License. See LICENSE for details. +// +#define DEBUG_TYPE "vector-ops" +#include "llvm/IR/Instruction.h" +#include "smack/BoogieAst.h" +#include "smack/SmackRep.h" +#include "smack/Regions.h" +#include "smack/VectorOperations.h" +#include "smack/Naming.h" +#include "smack/Debug.h" +#include +#include + +using namespace llvm; + +namespace smack { + std::string VectorOperations::constructor(Type *T) { + return "mk." + rep->type(T); + } + + std::string VectorOperations::field(Type *T, unsigned idx) { + std::stringstream ss; + ss << "i" << idx; + return ss.str(); + } + + std::string VectorOperations::selector(Type *T, unsigned idx) { + return field(T, idx) + "#" + constructor(T); + } + + std::list VectorOperations::type(Type *T) { + auto VT = dyn_cast(T); + assert(VT && "expected vector type"); + std::list decls; + + std::list< std::pair< std::string, std::string > > args; + for (unsigned i=0; igetNumElements(); i++) + args.push_back({field(T, i), rep->type(VT->getElementType())}); + + decls.push_back(Decl::typee(rep->type(T), "", {Attr::attr("datatype")})); + decls.push_back(Decl::function(constructor(T), args, rep->type(T), NULL, {Attr::attr("constructor")})); + + for (auto D : decls) + rep->addAuxiliaryDeclaration(D); + return decls; + } + + const Expr *VectorOperations::constant(const ConstantDataVector *C) { + auto T = C->getType(); + std::list args; + for (unsigned i = 0; i < C->getNumElements(); i++) + args.push_back(rep->expr(C->getElementAsConstant(i))); + return Expr::fn(constructor(T), args); + } + + const Expr *VectorOperations::constant(const ConstantAggregateZero *C) { + auto T = C->getType(); + std::list args; + for (unsigned i = 0; i < C->getNumElements(); i++) + args.push_back(rep->expr(C->getElementValue(i))); + return Expr::fn(constructor(T), args); + } + + FuncDecl *VectorOperations::cast(unsigned OpCode, Type *SrcTy, Type *DstTy) { + auto SrcVecTy = dyn_cast(SrcTy); + auto DstVecTy = dyn_cast(DstTy); + assert((SrcVecTy || DstVecTy) && "Expected a vector type"); + + auto FnName = rep->opName(Naming::INSTRUCTION_TABLE.at(OpCode), {SrcTy, DstTy}); + const Expr *Body; + + if (!SrcVecTy && DstVecTy && DstVecTy->getNumElements() == 1) + Body = Expr::fn(constructor(DstVecTy), Expr::id("v")); + else if (SrcVecTy && SrcVecTy->getNumElements() == 1 && !DstVecTy) + Body = Expr::fn(selector(SrcVecTy,0), Expr::id("v")); + else + Body = nullptr; + + return Decl::function(FnName, {{"v", rep->type(SrcTy)}}, rep->type(DstTy), Body); + } + + Decl *VectorOperations::inverseAxiom(unsigned OpCode, Type *SrcTy, Type *DstTy) { + auto Fn = rep->opName(Naming::INSTRUCTION_TABLE.at(OpCode), {SrcTy, DstTy}); + auto Inv = rep->opName(Naming::INSTRUCTION_TABLE.at(OpCode), {DstTy, SrcTy}); + return Decl::axiom(Expr::forall({{"v", rep->type(SrcTy)}}, Expr::eq( + Expr::fn(Inv, Expr::fn(Fn, Expr::id("v"))), + Expr::id("v")) + ), + Fn + "inverse" + ); + } + + FuncDecl *VectorOperations::binary(unsigned OpCode, VectorType *T) { + auto FnName = rep->opName(Naming::INSTRUCTION_TABLE.at(OpCode), {T}); + auto FnBase = rep->opName(Naming::INSTRUCTION_TABLE.at(OpCode), {T->getElementType()}); + std::list Args; + for (unsigned i = 0; i < T->getNumElements(); i++) { + Args.push_back(Expr::fn(FnBase, { + Expr::fn(selector(T, i), Expr::id("v1")), + Expr::fn(selector(T, i), Expr::id("v2")) + })); + } + return Decl::function(FnName, + {{"v1", rep->type(T)}, {"v2", rep->type(T)}}, + rep->type(T), + Expr::fn(constructor(T), Args)); + } + + FuncDecl *VectorOperations::cmp(CmpInst::Predicate P, VectorType *T) { + auto FnName = rep->opName(Naming::CMPINST_TABLE.at(P), {T}); + auto FnBase = rep->opName(Naming::CMPINST_TABLE.at(P), {T->getElementType()}); + std::list Args; + for (unsigned i = 0; i < T->getNumElements(); i++) { + Args.push_back(Expr::fn(FnBase, { + Expr::fn(selector(T, i), Expr::id("v1")), + Expr::fn(selector(T, i), Expr::id("v2")) + })); + } + return Decl::function(FnName, + {{"v1", rep->type(T)}, {"v2", rep->type(T)}}, + rep->type(VectorType::get(IntegerType::get(T->getContext(), 1), T->getNumElements())), + Expr::fn(constructor(T), Args)); + } + + FuncDecl *VectorOperations::cast(CastInst *I) { + DEBUG(errs() << "simd-cast: " << *I << "\n"); + auto F = cast(I->getOpcode(), I->getSrcTy(), I->getDestTy()); + auto G = cast(I->getOpcode(), I->getDestTy(), I->getSrcTy()); + auto A = inverseAxiom(I->getOpcode(), I->getSrcTy(), I->getDestTy()); + auto B = inverseAxiom(I->getOpcode(), I->getDestTy(), I->getSrcTy()); + if (isa(I->getSrcTy())) + type(I->getSrcTy()); + if (isa(I->getDestTy())) + type(I->getDestTy()); + rep->addAuxiliaryDeclaration(F); + rep->addAuxiliaryDeclaration(G); + rep->addAuxiliaryDeclaration(A); + rep->addAuxiliaryDeclaration(B); + return F; + } + + FuncDecl *VectorOperations::binary(BinaryOperator *I) { + DEBUG(errs() << "simd-binary: " << *I << "\n"); + auto T = dyn_cast(I->getType()); + assert(T && T == I->getOperand(0)->getType() && "expected equal vector types"); + auto F = binary(I->getOpcode(), T); + type(T); + rep->addAuxiliaryDeclaration(F); + return F; + } + + FuncDecl *VectorOperations::cmp(CmpInst *I) { + DEBUG(errs() << "simd-binary: " << *I << "\n"); + auto T = dyn_cast(I->getOperand(0)->getType()); + assert(T && "expected vector type"); + auto F = cmp(I->getPredicate(), T); + type(T); + type(VectorType::get(IntegerType::get(T->getContext(), 1), T->getNumElements())); + rep->addAuxiliaryDeclaration(F); + return F; + } + + FuncDecl *VectorOperations::shuffle(Type *T, Type *U, std::vector mask) { + auto VT = dyn_cast(T); + assert(VT && "expected vector type"); + assert(isa(U) && "expected vector type"); + type(T); + type(U); + + std::stringstream FN; + FN << rep->opName(Naming::INSTRUCTION_TABLE.at(Instruction::ShuffleVector), {T}); + for (auto m : mask) + FN << "." << m; + + auto N = VT->getNumElements(); + std::list args; + for (int m : mask) { + if (m < 0) + llvm_unreachable("TODO: handle undefined mask values"); + + auto idx = (unsigned) m; + if (idx < N) + args.push_back(Expr::fn(selector(T, idx), Expr::id("v1"))); + else + args.push_back(Expr::fn(selector(T, idx - N), Expr::id("v2"))); + } + + auto V = rep->type(T); + auto F = Decl::function(FN.str(), {{"v1", V}, {"v2", V}}, rep->type(U), + Expr::fn(constructor(U), args)); + rep->addAuxiliaryDeclaration(F); + return F; + } + + FuncDecl *VectorOperations::insert(Type *T, Type *IT) { + auto VT = dyn_cast(T); + assert(VT && "expected vector type"); + type(T); + + auto FN = rep->opName(Naming::INSTRUCTION_TABLE.at(Instruction::InsertElement), {T, IT}); + + auto V = rep->type(T); + auto E = rep->type(VT->getElementType()); + auto I = rep->type(IT); + auto F = Decl::function(FN, {{"v", V}, {"x", E}, {"i", I}}, V); + rep->addAuxiliaryDeclaration(F); + + // A per-index axiomatization + for (unsigned i=0; i < VT->getNumElements(); i++) { + std::stringstream ss; + ss << FN << "(" << i << ")"; + + std::list args; + for (unsigned j=0; j < VT->getNumElements(); j++) { + args.push_back(i == j ? Expr::id("x") : Expr::fn(selector(T,j), Expr::id("v"))); + } + + rep->addAuxiliaryDeclaration(Decl::axiom( + Expr::forall({{"v", V}, {"x", E}}, Expr::eq( + Expr::fn(FN, Expr::id("v"), Expr::id("x"), Expr::lit(i)), + Expr::fn(constructor(T), args) + )), + ss.str() + )); + } + + return F; + + std::stringstream procName; + procName << Naming::INSTRUCTION_TABLE.at(Instruction::InsertElement); + procName << "." << rep->type(T); + return nullptr; + } + + FuncDecl *VectorOperations::extract(Type *T, Type *IT) { + auto VT = dyn_cast(T); + assert(VT && "expected vector type"); + type(T); + + auto FN = rep->opName(Naming::INSTRUCTION_TABLE.at(Instruction::ExtractElement), {T, IT}); + + auto V = rep->type(T); + auto I = rep->type(IT); + auto E = rep->type(VT->getElementType()); + auto F = Decl::function(FN, {{"v", V}, {"i", I}}, E); + rep->addAuxiliaryDeclaration(F); + + // A per-index axiomatization + for (unsigned i=0; i < VT->getNumElements(); i++) { + std::stringstream ss; + ss << FN << "(" << i << ")"; + rep->addAuxiliaryDeclaration(Decl::axiom( + Expr::forall({{"v", V}}, Expr::eq( + Expr::fn(FN, Expr::id("v"), Expr::lit(i)), + Expr::fn(selector(T, i), Expr::id("v")) + )), + ss.str() + )); + } + + return F; + } + + FuncDecl *VectorOperations::load(const Value *V) { + auto PT = dyn_cast(V->getType()); + assert(PT && "expected pointer type"); + auto ET = PT->getElementType(); + type(ET); + + auto R = rep->regions->idx(V); + auto MT = rep->regions->get(R).getType(); + MT || (MT = IntegerType::get(V->getContext(), 8)); + auto FN = rep->opName(Naming::LOAD, {ET, MT}); + auto M = rep->memType(R); + auto P = rep->type(PT); + auto E = rep->type(ET); + auto F = (MT == ET) + ? Decl::function(FN, {{"M", M}, {"p", P}}, E, Expr::sel(Expr::id("M"), Expr::id("p"))) + : Decl::function(FN, {{"M", M}, {"p", P}}, E); + rep->addAuxiliaryDeclaration(F); + return F; + } + + FuncDecl *VectorOperations::store(const Value *V) { + auto PT = dyn_cast(V->getType()); + assert(PT && "expected pointer type"); + auto ET = PT->getElementType(); + type(ET); + + auto R = rep->regions->idx(V); + auto MT = rep->regions->get(R).getType(); + MT || (MT = IntegerType::get(V->getContext(), 8)); + auto FN = rep->opName(Naming::STORE, {ET, MT}); + auto M = rep->memType(R); + auto P = rep->type(PT); + auto E = rep->type(ET); + auto F = (MT == ET) + ? Decl::function(FN, {{"M", M}, {"p", P}, {"v", E}}, M, Expr::upd(Expr::id("M"), Expr::id("p"), Expr::id("v"))) + : Decl::function(FN, {{"M", M}, {"p", P}, {"v", E}}, M); + rep->addAuxiliaryDeclaration(F); + return F; + } +} diff --git a/rise4fun/smack_server.py b/rise4fun/smack_server.py index c71ac4cf9..e543f4a8a 100644 --- a/rise4fun/smack_server.py +++ b/rise4fun/smack_server.py @@ -11,12 +11,12 @@ PORT = 8080 version = "1.4.4" rise_simple = """#include "smack.h" -//__VERIFIER_nondet() : Is used to permit assigned memory to have unconstrained values +//__VERIFIER_nondet_int() : Is used to permit assigned memory to have unconstrained values //assume(): Is used to enforce constraints on specified regions of memory //assert(): Is used to prove some assertions on values in the program. Assertions may contain unconstrained values. int main() { - int x = __VERIFIER_nondet(); - int n = __VERIFIER_nondet(); + int x = __VERIFIER_nondet_int(); + int n = __VERIFIER_nondet_int(); assume(n>0); assert(x+n > x); return 0; @@ -27,8 +27,8 @@ //assume(): Is used to enforce constraints on specified regions of memory //assert(): Is used to prove some assertions on values in the program. Assertions may contain unconstrained values int main() { - int x = __VERIFIER_nondet(); - int n = __VERIFIER_nondet(); + int x = __VERIFIER_nondet_int(); + int n = __VERIFIER_nondet_int(); assume(n>=0); assert(x+n > x); return 0; @@ -46,7 +46,7 @@ int main(void) { int (*fp)(int); - int x = __VERIFIER_nondet(), y = __VERIFIER_nondet(), old_x = x; + int x = __VERIFIER_nondet_int(), y = __VERIFIER_nondet_int(), old_x = x; if (y > 0) { fp = incr; @@ -73,7 +73,7 @@ int main() { int num[6], size = 6; - int i = __VERIFIER_nondet(); + int i = __VERIFIER_nondet_int(); initDescArray(num,size); if(i >= 1 && i < 6) assert(num[i] > num[i-1]); @@ -116,7 +116,7 @@ int main(void) { int b; - b = foo(__VERIFIER_nondet(), __VERIFIER_nondet()); + b = foo(__VERIFIER_nondet_int(), __VERIFIER_nondet_int()); assert(b != 0); return 0; }""" @@ -129,8 +129,8 @@ x = 4; y = 3; z = 19; - a = __VERIFIER_nondet(); - b = __VERIFIER_nondet(); + a = __VERIFIER_nondet_int(); + b = __VERIFIER_nondet_int(); if(a>=0 && b>=0) assert(z != (a*x+b*y)); return 0; @@ -243,11 +243,11 @@ def do_GET(self): return return except IOError: - print 'IOError' + print ('IOError') self.send_error(404,'File Not Found: %s' % self.path) def do_POST(self): - length = int(self.headers.getheader('content-length')) + length = int(self.headers.getheader('content-length')) data_string = self.rfile.read(length) data = json.loads(data_string) @@ -267,15 +267,21 @@ def do_POST(self): lucount = regulex.groupdict()["lu"] else: lucount = '2' - + f = open('logs','a') - p = subprocess.Popen(["timeout","10s",'smackverify.py', '--unroll', lucount, filename + '.c', '-o', filename +'.bpl'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + p = subprocess.Popen(["timeout", "10s", '/uusoc/exports/scratch/rise4fun/smack/install/bin/smack', '--time-limit', '10', '--unroll', lucount, filename + '.c', '-bpl', + filename + '.bpl'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) smack_string = p.communicate() + smack_response = "" return_code = p.returncode + #check that smack ran successfully. if not return_code == 0: - if return_code == 124: + output = smack_string[0].replace(filename + '.c', 'input.c') + print("Output contained timeout code: " + str('timed out' in output)) + output = output.split('\n') + if "SMACK timed out." in smack_string[1]: resp = "Program is taking unusually long to verify. Request timed out." smack_response = { "Version": version, @@ -289,113 +295,61 @@ def do_POST(self): f.write(self.client_address[0]+"--"+filename+".c--"+"Timed Out\n") f.close() else: - output = smack_string[0].replace(filename+'.c', 'input.c') - output = output.split(' ') error = [] smack = '' for i in range(len(output)): - if(output[i] == "error:" or output[i] == "warning:"): - error.append(i) - for i in range(len(error)): - t = output[error[i]-1].split(':') - flag =1 - if(output[error[i]-1] == 'fatal'): - flag = 0 - if(i < len(error)-1 and flag): - m = output[error[i]].split(':') - j = error[i]+1 - while 1: - if('\n' in output[j]): - break - j = j+1 - haha = output[j].find('\n') - output[j] = output[j][0:haha] - p = output[error[i]+1:j+1] - we = " " - p = we.join(p) - if(len(t) < 3 or len(m) < 1): - smack = smack+" SMACK Error\r\n" - else: - smack = smack+"input.c("+t[1]+","+t[2]+") : "+m[0]+" "+str(i)+": "+p+"\r\n" - elif(i == len(error)-1 and flag): - m = output[error[i]].split(':') - j = error[i]+1 - while 1: - if('\n' in output[j]): - break - j = j+ 1 - haha = output[j].find('\n') - output[j] = output[j][0:haha] - p = output[error[i]+1:j+1] - we = " " - p = we.join(p) - if(len(t) >= 3 or len(m) >= 1): - smack = smack+"input.c("+t[1]+","+t[2]+") : "+m[0]+" "+str(i)+": "+p+"\r\n" - else: - smack = smack+" SMACK Error\r\n" - if(smack == ''): - smack = "SMACK Error" - smack_response = { - "Version": version, - "Outputs": [ + #Check if an error's trace is avaliable in the smack output. + if "Trace" in output[i] and "input.c" in output[i]: + line_number = output[i][output[i].index("input.c("):output[i].index(",")] + trace = output[i][output[i].index(":") + 1:] + smack += line_number + "): error 1: " + trace + "\r\n" + #Check if an assert failed while running smack. + if "(ASSERTION FAILS" in output[i]: #we have an assertion that is failing, so report it. + line_number = output[i+1][output[i+1].index("("):output[i+1].index(",")] + smack = "input.c" + line_number + "): error 1: Assertion Failed!\r\n" + smack + #Grab each individual trace from the failed assertion and add to smack string + if "error: " in output[i]: #check if any syntax errors exist. + line_number = "(" + output[i][output[i].index(":") + 1:output[i].index(" ") - 1] + ")" #grab the line and column number from the error. + line_number = line_number[:line_number.index(":")] + ")" + error = output[i][output[i].index("error: "):] #grab the error + error = error.replace("error:", "error 2:") + smack += "input.c " + line_number + ": " + error + "\r\n" + if smack == '': #Something happened while trying to read the input. Let Rise4Fun know we couldn't process the file. + smack = "input.c(0): error 3: SMACK encountered an error and was unable to process the input file.\r\n" + smack_response = { + "Version": version, + "Outputs": [ { "MimeType": "text/plain", "Value": smack } ] - } - f.write(self.client_address[0]+"--"+filename+".c--"+"SMACK Error\n") - f.close() - else: + } + f.write(self.client_address[0]+"--"+filename+".c--"+"SMACK Error\n") + f.close() + else: outp = smack_string[0].replace(filename+'.c', 'input.c') output = outp.split(' ') output = [i for i in output if '$' not in i] for i in range(len(output)): if '):' in output[i]: - output[i]=output[i][0:len(output[i])-1]+"\n" + output[i]=output[i][0:len(output[i])-1]+"\n" t=" " - smack = t.join(output) + smack = t.join(output) g = open(filename+".output",'w') g.write(smack) g.close() f.write(self.client_address[0]+"--"+filename+".c--"+"Output\n") f.close() - if('not hold' in outp): - temp = smack.split('\n') - temp = [w for w in temp if w != ''] - response = temp[0]+"\r\n" - flag = 1 - cnt = 0 - for i in range(len(temp)): - if('input' in temp[i] and flag): - response = response+temp[i]+" : error main: This assertion might not hold\r\n" - flag = 0 - elif('input' in temp[i] and flag == 0): - response = response+temp[i]+" : Trace Element: Error trace["+str(cnt)+"]\r\n" - cnt = cnt +1 - response = response + temp[len(temp)-1] - - smack_response = { - "Version": version, - "Outputs": [ - { - "MimeType": "text/plain", - "Value": response - } - ] + smack_response = { + "Version": version, + "Outputs": [ + { + "MimeType": "text/plain", + "Value": smack } - else: - smack_response = { - "Version": version, - "Outputs": [ - { - "MimeType": "text/plain", - "Value": smack - } - ] - } - - f.close() + ] + } body = json.dumps(smack_response) self.send_response(200) self.send_header('Content-Type', 'text/javascript') @@ -409,7 +363,7 @@ def do_POST(self): self.end_headers() self.wfile.write(body) self.wfile.flush() - os.system("rm "+filename+".b*") + os.system("rm "+filename+".c*") self.connection.shutdown(1) return diff --git a/share/smack/doctor.py b/share/smack/doctor.py index 7d9028a3f..329d26c96 100755 --- a/share/smack/doctor.py +++ b/share/smack/doctor.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 # # This file is distributed under the MIT License. See LICENSE for details. # @@ -58,7 +58,6 @@ def check_verifier(cmd): check("%s invokes mono" % var, re.match(r'\Amono', os.environ[var])) verifier_exe = os.environ[var].split()[1] check("%s verifier executable exists" % var, os.path.isfile(verifier_exe)) - check("%s verifier is executable" % var, os.access(verifier_exe, os.X_OK)) solver_exe = os.path.join(os.path.dirname(verifier_exe), "z3.exe") check("%s solver executable exists" % var, os.path.isfile(solver_exe)) check("%s solver is executable" % var, os.access(solver_exe, os.X_OK)) @@ -79,6 +78,7 @@ def check_headers(prefix): def main(): global args + global count parser = argparse.ArgumentParser(description='Diagnose SMACK configuration issues.') parser.add_argument('-q', '--quiet', dest='quiet', action="store_true", default=False, help='only show failed diagnostics') diff --git a/share/smack/frontend.py b/share/smack/frontend.py new file mode 100644 index 000000000..fac614d6e --- /dev/null +++ b/share/smack/frontend.py @@ -0,0 +1,304 @@ +import os +import sys +from utils import temporary_file, try_command + +def languages(): + """A dictionary of languages per file extension.""" + return { + 'c' : 'c', + 'i' : 'c', + 'cc' : 'cxx', + 'cpp' : 'cxx', + 'm' : 'objc', + 'd' : 'd', + 'json' : 'json', + 'svcomp' : 'svcomp', + 'bc' : 'llvm', + 'll' : 'llvm', + 'bpl' : 'boogie', + 'f' : 'fortran', + 'for' : 'fortran', + 'f90' : 'fortran', + 'f95' : 'fortran', + 'f03' : 'fortran', + 'rs' : 'rust', + } + +def frontends(): + """A dictionary of front-ends per language.""" + + # Avoid circular import + from svcomp.utils import svcomp_frontend + + return { + 'c' : clang_frontend, + 'cxx' : clang_plusplus_frontend, + 'objc' : clang_objc_frontend, + 'd' : d_frontend, + 'json' : json_compilation_database_frontend, + 'svcomp' : svcomp_frontend, + 'llvm' : llvm_frontend, + 'boogie' : boogie_frontend, + 'fortran' : fortran_frontend, + 'rust' : rust_frontend, + } + +def extra_libs(): + """A dictionary of extra SMACK libraries required by languages.""" + return { + 'fortran' : fortran_build_libs, + 'cxx' : cplusplus_build_libs, + # coming soon - libraries for OBJC, Rust, Swift, etc. + } + + +def smack_root(): + return os.path.dirname(os.path.dirname(os.path.abspath(sys.argv[0]))) + +def smack_header_path(): + return os.path.join(smack_root(), 'share', 'smack', 'include') + +def smack_headers(args): + paths = [] + paths.append(smack_header_path()) + if args.memory_safety or args.integer_overflow: + paths.append(os.path.join(smack_header_path(), 'string')) + if args.float: + paths.append(os.path.join(smack_header_path(), 'math')) + return paths + +def smack_lib(): + return os.path.join(smack_root(), 'share', 'smack', 'lib') + +def default_clang_compile_command(args, lib = False): + cmd = ['clang', '-c', '-emit-llvm', '-O0', '-g', '-gcolumn-info'] + cmd += map(lambda path: '-I' + path, smack_headers(args)) + cmd += args.clang_options.split() + cmd += ['-DMEMORY_MODEL_' + args.mem_mod.upper().replace('-','_')] + if args.memory_safety: cmd += ['-DMEMORY_SAFETY'] + if args.integer_overflow: cmd += (['-ftrapv'] if not lib else ['-DSIGNED_INTEGER_OVERFLOW_CHECK']) + if args.float: cmd += ['-DFLOAT_ENABLED'] + if sys.stdout.isatty(): cmd += ['-fcolor-diagnostics'] + return cmd + +def compile_to_bc(input_file, compile_command, args): + """Compile a source file to LLVM IR.""" + bc = temporary_file(os.path.splitext(os.path.basename(input_file))[0], '.bc', args) + try_command(compile_command + ['-o', bc, input_file], console=True) + return bc + +def fortran_compile_to_bc(input_file, compile_command, args): + """Compile a FORTRAN source file to LLVM IR.""" + + # This method only exists as a hack to get flang to work + # with SMACK. When we update to the latest flang on LLVM 5, + # this method will no longer be necessary. The hack is + # self-contained in this method. + + # The Debug Info Version in flang is incompatible with + # the version that clang uses. The workaround is to use + # sed to change the file so llvm-link gives a warning + # and not an error. + + # compile to human-readable format in order to tweak the IR + compile_command[1] = '-S' + ll = temporary_file(os.path.splitext(os.path.basename(input_file))[0], '.ll', args) + try_command(compile_command + ['-o', ll, input_file], console=True) + # change the throw level of 'Debug Info Version' from error to warning in the IR + try_command(['sed', '-i', 's/i32 1, !\"Debug Info Version\"/i32 2, !\"Debug Info Version\"/g', ll]) + try_command(['llvm-as', ll]) + try_command(['rm', ll]) + bc = '.'.join(ll.split('.')[:-1] + ['bc']) + return bc + + +# Frontend functions here + +def llvm_frontend(input_file, args): + """Return LLVM IR file. Exists for symmetry with other frontends.""" + + return input_file + +def clang_frontend(input_file, args): + """Generate LLVM IR from C-language source(s).""" + + compile_command = default_clang_compile_command(args) + return compile_to_bc(input_file,compile_command,args) + +def clang_plusplus_frontend(input_file, args): + """Generate LLVM IR from C++ language source(s).""" + compile_command = default_clang_compile_command(args) + compile_command[0] = 'clang++' + return compile_to_bc(input_file,compile_command,args) + +def clang_objc_frontend(input_file, args): + """Generate LLVM IR from Objective-C language source(s).""" + + compile_command = default_clang_compile_command(args) + if sys.platform in ['linux', 'linux2']: + objc_flags = try_command(['gnustep-config', '--objc-flags']) + compile_command += objc_flags.split() + elif sys.platform == 'darwin': + sys.exit("Objective-C not yet supported on macOS") + else: + sys.exit("Objective-C not supported for this operating system.") + return compile_to_bc(input_file,compile_command,args) + +def d_frontend(input_file, args): + """Generate Boogie code from D programming language source(s).""" + + # note: -g and -O0 are not used here. + # Right now, it works, and with these options, smack crashes. + compile_command = ['ldc2', '-output-ll'] + compile_command += map(lambda path: '-I=' + path, smack_headers(args)) + args.entry_points += ['_Dmain'] + return compile_to_bc(input_file,compile_command,args) + +def fortran_frontend(input_file, args): + """Generate Boogie code from Fortran language source(s).""" + + # For a fortran file that includes smack.f90 as a module, + # it will not compile unless the file 'smack.mod' exists + # in the working directory. 'smack.mod' is a build artifact + # of compiling smack.f90. Therefore, the solution is to + # compile smack.f90 before the source files. + fortran_build_libs(args) + # The result of this computation will be discarded when SMACK + # builds it's libraries later. + + # replace the default entry point with the fortran default 'MAIN_' + args.entry_points += ['MAIN_'] + + compile_command = default_clang_compile_command(args) + compile_command[0] = 'flang' + + return fortran_compile_to_bc(input_file,compile_command,args) + +def boogie_frontend(input_file, args): + """Pass Boogie code to the verifier.""" + if len(args.input_files) > 1: + raise RuntimeError("Expected a single Boogie file.") + + with open(args.bpl_file, 'a+') as out: + with open(input_file) as f: + out.write(f.read()) + +def json_compilation_database_frontend(input_file, args): + """Generate Boogie code from a JSON compilation database.""" + + if len(args.input_files) > 1: + raise RuntimeError("Expected a single JSON compilation database.") + + output_flags = re.compile(r"-o ([^ ]*)[.]o\b") + optimization_flags = re.compile(r"-O[1-9]\b") + + with open(input_file) as f: + for cc in json.load(f): + if 'objects' in cc: + # TODO what to do when there are multiple linkings? + bit_codes = map(lambda f: re.sub('[.]o$','.bc',f), cc['objects']) + try_command(['llvm-link', '-o', args.bc_file] + bit_codes) + try_command(['llvm-link', '-o', args.linked_bc_file, args.bc_file] + build_libs(args)) + + else: + out_file = output_flags.findall(cc['command'])[0] + '.bc' + command = cc['command'] + command = output_flags.sub(r"-o \1.bc", command) + command = optimization_flags.sub("-O0", command) + command = command + " -emit-llvm" + try_command(command.split(),cc['directory'], console=True) + + llvm_to_bpl(args) + +def rust_frontend(input_file, args): + """Generate Boogie code from Rust programming language source(s).""" + compile_command = ['rustc', '-A', 'unused-imports', '-C', 'opt-level=0', + '-C', 'no-prepopulate-passes', '-g', '--emit=llvm-bc', + '--cfg', 'verifier="smack"'] + + # This links in the Rust SMACK library. This is needed due to the way rustc + # finds a programs libraries. + try: + abs_path = os.path.dirname(os.path.abspath(input_file)) + mod_path = os.path.join(abs_path, "smack") + if not os.path.exists(mod_path): + os.mkdir(mod_path) + link_target = os.path.join(mod_path, "mod.rs") + if not os.path.exists(link_target): + rust_macros = os.path.join(smack_lib(), 'smack.rs') + os.symlink(rust_macros, link_target) + except: + raise RuntimeError("Could not find or create smack module.") + + return compile_to_bc(input_file,compile_command,args) + +# Build libs functions here + +def default_build_libs(args): + """Generate LLVM bitcodes for SMACK libraries.""" + bitcodes = [] + libs = ['smack.c'] + + if args.pthread: + libs += ['pthread.c'] + + if args.strings or args.memory_safety or args.integer_overflow: + libs += ['string.c'] + + if args.float: + libs += ['math.c'] + libs += ['fenv.c'] + + compile_command = default_clang_compile_command(args, True) + for c in map(lambda c: os.path.join(smack_lib(), c), libs): + bc = compile_to_bc(c,compile_command,args) + bitcodes.append(bc) + + return bitcodes + +def fortran_build_libs(args): + """Generate FORTRAN-specific LLVM bitcodes for SMACK libraries.""" + + bitcodes = [] + libs = ['smack.f90'] + + compile_command = default_clang_compile_command(args) + compile_command[0] = 'flang' + + for c in map(lambda c: os.path.join(smack_lib(), c), libs): + bc = fortran_compile_to_bc(c,compile_command,args) + bitcodes.append(bc) + + return bitcodes + +def cplusplus_build_libs(args): + """Generate C++ specific LLVM bitcodes for SMACK libraries.""" + + bitcodes = [] + libs = ['smack.cpp'] + + compile_command = default_clang_compile_command(args,True) + compile_command[0] = 'clang++' + + for c in map(lambda c: os.path.join(smack_lib(), c), libs): + bc = compile_to_bc(c,compile_command,args) + bitcodes.append(bc) + + return bitcodes + +# llvm link files + +def link_bc_files(bitcodes, libs, args): + """Link generated LLVM bitcode and relevant smack libraries.""" + + smack_libs = default_build_libs(args) + for build_lib in libs: + smack_libs += build_lib(args) + + try_command(['llvm-link', '-o', args.bc_file] + bitcodes) + try_command(['llvm-link', '-o', args.linked_bc_file, args.bc_file] + smack_libs) + + # import here to avoid a circular import + from top import llvm_to_bpl + llvm_to_bpl(args) + diff --git a/share/smack/include/bits/gthr-default.h b/share/smack/include/bits/gthr-default.h new file mode 100644 index 000000000..efb6c3072 --- /dev/null +++ b/share/smack/include/bits/gthr-default.h @@ -0,0 +1,7 @@ +// +// This file is distributed under the MIT License. See LICENSE for details. +// + +// Empty header file to prevent various pthread types from being redefined +// when the standard header is included. + diff --git a/share/smack/include/fenv.h b/share/smack/include/fenv.h new file mode 100644 index 000000000..bfff6644d --- /dev/null +++ b/share/smack/include/fenv.h @@ -0,0 +1,15 @@ +// This file is distributed under the MIT License. See LICENSE for details. +// + +#ifndef FENV_H +#define FENV_H + +#define FE_TONEAREST 0 +#define FE_DOWNWARD 0x400 +#define FE_UPWARD 0x800 +#define FE_TOWARDZERO 0xc00 + +int fegetround(void); +int fesetround(int); + +#endif diff --git a/share/smack/include/math/math.h b/share/smack/include/math/math.h index 88b543c4a..88d35e565 100644 --- a/share/smack/include/math/math.h +++ b/share/smack/include/math/math.h @@ -4,15 +4,53 @@ #ifndef MATH_H #define MATH_H -//floats +#define FP_NAN 0 +#define FP_INFINITE 1 +#define FP_ZERO 2 +#define FP_SUBNORMAL 3 +#define FP_NORMAL 4 + +#define isnormal(x) (sizeof(x) == sizeof(long double) ? __isnormall(x) : sizeof(x) == sizeof(double) ? __isnormal(x) : __isnormalf(x)) +#define isinf(x) (sizeof(x) == sizeof(long double) ? __isinfl(x) : sizeof(x) == sizeof(double) ? __isinf(x) : __isinff(x)) +#define isnan(x) (sizeof(x) == sizeof(long double) ? __isnanl(x) : sizeof(x) == sizeof(double) ? __isnan(x) : __isnanf(x)) +#define signbit(x) (sizeof(x) == sizeof(long double) ? __signbitl(x) : sizeof(x) == sizeof(double) ? __signbit(x) : __signbitf(x)) +#define fpclassify(x) (sizeof(x) == sizeof(long double) ? __fpclassifyl(x) : sizeof(x) == sizeof(double) ? __fpclassify(x) : __fpclassifyf(x)) +#define isfinite(x) (sizeof(x) == sizeof(long double) ? __isfinitel(x) : sizeof(x) == sizeof(double) ? __finite(x) : __finitef(x)) + +typedef union { + float f; + struct { + unsigned sigAndExp: 31; + unsigned sign: 1; + } i; +} fi; + +typedef union { + double d; + struct { + unsigned sigAndExpLower: 32; + unsigned sigAndExpUpper: 31; + unsigned sign: 1; + } i; +} di; + +typedef union { + long double l; + struct { + unsigned sigAndExpLower: 32; + unsigned sigAndExpMiddle: 32; + unsigned sigAndExpUpper: 15; + unsigned sign: 1; + } i; +} li; + float fabsf(float x); float fdimf(float x, float y); float roundf(float x); -//The following 3 functions are incomplete pending rounding mode implementation +long lroundf(float x); float rintf(float x); float nearbyintf(float x); long lrintf(float x); -long lroundf(float x); float floorf(float x); float ceilf(float x); float truncf(float x); @@ -23,26 +61,21 @@ float fmaxf(float x, float y); float fmodf(float x, float y); float modff(float x, float* y); float copysignf(float x, float y); +float nanf(const char* x); int __isnormalf(float x); -int __isSubnormalf(float x); +int __issubnormalf(float x); int __iszerof(float x); int __isinff(float x); int __isnanf(float x); int __isnegativef(float x); -int __ispositivef(float x); int __signbitf(float x); -int signbitf(float x); int __fpclassifyf(float x); -int fpclassifyf(float x); int __finitef(float x); -//float nan(float x); -//doubles double fabs(double x); double fdim(double x, double y); double round(double x); long lround(double x); -//The following 3 functions are incomplete pending rounding mode implementation double rint(double x); double nearbyint(double x); long lrint(double x); @@ -58,30 +91,41 @@ double modf(double x, double* y); double copysign(double x, double y); double nan(const char* x); int __isnormal(double x); -int __isSubnormal(double x); +int __issubnormal(double x); int __iszero(double x); int __isinf(double x); int __isnan(double x); int __isnegative(double x); -int __ispositive(double x); int __signbit(double x); -int signbit(double x); int __fpclassify(double x); -int fpclassify(double x); int __finite(double x); -//long doubles -/*int __isnormall(long double x); -int __isSubnormall(long double x); +long double fabsl(long double x); +long double fdiml(long double x, long double y); +long double roundl(long double x); +long lroundl(long double x); +long double rintl(long double x); +long double nearbyintl(long double x); +long lrintl(long double x); +long double floorl(long double x); +long double ceill(long double x); +long double truncl(long double x); +long double sqrtl(long double x); +long double remainderl(long double x, long double y); +long double fminl(long double x, long double y); +long double fmaxl(long double x, long double y); +long double fmodl(long double x, long double y); +long double modfl(long double x, long double* y); +long double copysignl(long double x, long double y); +long double nanl(const char* x); +int __isnormall(long double x); +int __issubnormall(long double x); int __iszerol(long double x); int __isinfl(long double x); int __isnanl(long double x); int __isnegativel(long double x); -int __ispositivel(long double x); int __signbitl(long double x); -int signbitl(long double x); int __fpclassifyl(long double x); -int fpclassifyl(long double x); -int __finitel(long double x);*/ +int __finitel(long double x); #endif diff --git a/share/smack/include/pthread.h b/share/smack/include/pthread.h index 4a568e155..7c057921e 100644 --- a/share/smack/include/pthread.h +++ b/share/smack/include/pthread.h @@ -1,12 +1,9 @@ // -// Copyright (c) 2013 Zvonimir Rakamaric (zvonimir@cs.utah.edu), -// Michael Emmi (michael.emmi@gmail.com) // This file is distributed under the MIT License. See LICENSE for details. // #ifndef PTHREAD_H #define PTHREAD_H -// Include pthreadtypes.h #include "pthreadtypes.h" //model mutex: diff --git a/share/smack/include/smack-contracts.h b/share/smack/include/smack-contracts.h index 0128382fd..29cfe2f1b 100644 --- a/share/smack/include/smack-contracts.h +++ b/share/smack/include/smack-contracts.h @@ -9,18 +9,27 @@ void __CONTRACT_requires(bool expr); void __CONTRACT_ensures(bool expr); void __CONTRACT_invariant(bool expr); -int __CONTRACT_int_variable(const char *name) __attribute__((const)); -bool __CONTRACT_forall(const char *var, bool expr) __attribute__((const)); -bool __CONTRACT_exists(const char *var, bool expr) __attribute__((const)); #define requires(X) __CONTRACT_requires(X) #define ensures(X) __CONTRACT_ensures(X) #define invariant(X) __CONTRACT_invariant(X) -#define qvar(X,T) __CONTRACT_ ## T ## _variable(X) -#define forall(X,Y) __CONTRACT_forall(X,Y) -#define exists(X,Y) __CONTRACT_exists(X,Y) -int old(int term); -int result(void); +// TODO provide quantifier bound variables +// int __CONTRACT_int_variable(const char *name) __attribute__((const)); +// #define qvar(X,T) __CONTRACT_ ## T ## _variable(X) + +// TODO provide universal quantifier +// bool __CONTRACT_forall(const char *var, bool expr) __attribute__((const)); +// #define forall(X,Y) __CONTRACT_forall(X,Y) + +// TODO provide existential quantifier +// bool __CONTRACT_exists(const char *var, bool expr) __attribute__((const)); +// #define exists(X,Y) __CONTRACT_exists(X,Y) + +// TODO provide precondition state “old” expressions +// int old(int term); + +// TODO provide procedure “result” expression +// int result(void); #endif diff --git a/share/smack/include/smack-macros.h b/share/smack/include/smack-macros.h new file mode 100644 index 000000000..c830d223c --- /dev/null +++ b/share/smack/include/smack-macros.h @@ -0,0 +1,109 @@ +// +// This file is distributed under the MIT License. See LICENSE for details. +// + +// shamelessly stole these macro definitions from +// https://github.com/pfultz2/Cloak/wiki/C-Preprocessor-tricks,-tips,-and-idioms +#define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__ + +#define DEC_BYTE(x) PRIMITIVE_CAT(DEC_BYTE_, x) +#define DEC_BYTE_0 0 +#define DEC_BYTE_8 0 +#define DEC_BYTE_16 8 +#define DEC_BYTE_24 16 +#define DEC_BYTE_32 24 +#define DEC_BYTE_40 32 +#define DEC_BYTE_48 40 +#define DEC_BYTE_56 48 +#define DEC_BYTE_64 56 +#define DEC_BYTE_72 64 +#define DEC_BYTE_80 72 +#define DEC_BYTE_88 80 +#define DEC_BYTE_96 88 +#define DEC_BYTE_104 96 +#define DEC_BYTE_112 104 +#define DEC_BYTE_120 112 +#define DEC_BYTE_128 120 + +#define EVAL(...) EVAL1(EVAL1(EVAL1(__VA_ARGS__))) +#define EVAL1(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__))) +#define EVAL2(...) EVAL3(EVAL3(EVAL3(__VA_ARGS__))) +#define EVAL3(...) EVAL4(EVAL4(EVAL4(__VA_ARGS__))) +#define EVAL4(...) __VA_ARGS__ + +#define IIF(c) PRIMITIVE_CAT(IIF_, c) +#define IIF_0(t, ...) __VA_ARGS__ +#define IIF_1(t, ...) t + +#define CHECK_N(x, n, ...) n +#define CHECK(...) CHECK_N(__VA_ARGS__, 0,) +#define PROBE(x) x, 1, + +#define NOT(x) CHECK(PRIMITIVE_CAT(NOT_, x)) +#define NOT_0 PROBE(~) + +#define COMPL(b) PRIMITIVE_CAT(COMPL_, b) +#define COMPL_0 1 +#define COMPL_1 0 + +#define BOOL(x) COMPL(NOT(x)) +#define IF(c) IIF(BOOL(c)) + +#define EAT(...) +#define EXPAND(...) __VA_ARGS__ +#define WHEN(c) IF(c)(EXPAND, EAT) + +#define EMPTY() +#define DEFER(id) id EMPTY() +#define OBSTRUCT(...) __VA_ARGS__ DEFER(EMPTY)() + +#define BITAND(x) PRIMITIVE_CAT(BITAND_, x) +#define BITAND_0(y) 0 +#define BITAND_1(y) y + +#define BV_TYPE(bw) PRIMITIVE_CAT(bv, bw) + +#define COMBINE(count1, count2, direction, macro) \ + WHEN(BITAND(BOOL(count1))(BOOL(count2))) \ + ( \ + OBSTRUCT(COMBINE_INDIRECT) () \ + ( \ + count1, direction(count2), direction, macro \ + ) \ + OBSTRUCT(macro) \ + ( \ + count1, count2 \ + ) \ + ) \ + WHEN(BITAND(NOT(BOOL(count2)))(BOOL(count1))) \ + ( \ + OBSTRUCT(COMBINE_INDIRECT) () \ + ( \ + direction(count1), direction(direction(count1)), direction, macro \ + ) \ + ) +#define COMBINE_INDIRECT() COMBINE + +#define UNSAFE_LOAD_OP(type,name,body) \ + function {:inline} name.type(M: [ref] bv8, p: ref) returns (type) body + +#define UNSAFE_STORE_OP(type,name,body) \ + function {:inline} name.type(M: [ref] bv8, p: ref, v: type) returns ([ref] bv8) body + +#define DECLARE_UNSAFE_LOAD(bw1,bw2) \ + WHEN(BOOL(DEC_BYTE(bw2))) \ + ( \ + DECLARE(UNSAFE_LOAD_OP, BV_TYPE(bw2), $load.bytes, {$load.bytes.BV_TYPE(DEC_BYTE(bw2))(M, $add.ref(p, $1.ref)) ++ $load.bytes.bv8(M,p)}); \ + ) + +#define DECLARE_UNSAFE_STORE(bw1,bw2) \ + WHEN(BOOL(DEC_BYTE(bw2))) \ + ( \ + DECLARE(UNSAFE_STORE_OP, BV_TYPE(bw2), $store.bytes, {$store.bytes.BV_TYPE(DEC_BYTE(bw2))(M, $add.ref(p, $1.ref), v[bw2:8])[p := v[8:0]]}); \ + ) + +#define DECLARE_UNSAFE_LOADS \ + EVAL(COMBINE(8,128,DEC_BYTE,DECLARE_UNSAFE_LOAD)) + +#define DECLARE_UNSAFE_STORES \ + EVAL(COMBINE(8,128,DEC_BYTE,DECLARE_UNSAFE_STORE)) diff --git a/share/smack/include/smack.di b/share/smack/include/smack.di new file mode 100644 index 000000000..8ceda9a3e --- /dev/null +++ b/share/smack/include/smack.di @@ -0,0 +1,5 @@ +// +// This file is distributed under the MIT License. See LICENSE for details. +// + +extern (C): void __VERIFIER_assert(int); diff --git a/share/smack/include/smack.h b/share/smack/include/smack.h index e6df7f30d..26958f3bc 100644 --- a/share/smack/include/smack.h +++ b/share/smack/include/smack.h @@ -41,7 +41,7 @@ smack_value_t __SMACK_return_value(void); #if MEMORY_SAFETY // Inserts memory access checks in form of assert to check null pointer access // and buffer overflow errors -void __SMACK_check_memory_safety(void*, unsigned long); +void __SMACK_check_memory_safety(void*, void*) __attribute__((const)); void __SMACK_check_memory_leak(void); #endif @@ -146,7 +146,11 @@ NONDET_DECL(__VERIFIER_nondet,long,double); #undef NONDET_DECL // Used in SVCOMP benchmarks +#ifdef __cplusplus +bool __VERIFIER_nondet_bool(void); +#else _Bool __VERIFIER_nondet_bool(void); +#endif unsigned char __VERIFIER_nondet_uchar(void); unsigned short __VERIFIER_nondet_ushort(void); unsigned __VERIFIER_nondet_uint(void); diff --git a/share/smack/lib/fenv.c b/share/smack/lib/fenv.c new file mode 100644 index 000000000..fd663fd04 --- /dev/null +++ b/share/smack/lib/fenv.c @@ -0,0 +1,31 @@ +// +// This file is distributed under the MIT License. See LICENSE for details. +// +#include +#include + +int fegetround(void) { + const int CONST_FE_TONEAREST = FE_TONEAREST; + const int CONST_FE_DOWNWARD = FE_DOWNWARD; + const int CONST_FE_UPWARD = FE_UPWARD; + const int CONST_FE_TOWARDZERO = FE_TOWARDZERO; + int ret = __VERIFIER_nondet_int(); + assume(ret < 0); + __SMACK_code("if ($rmode == RNE) {@ := @;}", ret, CONST_FE_TONEAREST); + __SMACK_code("if ($rmode == RTN) {@ := @;}", ret, CONST_FE_DOWNWARD); + __SMACK_code("if ($rmode == RTP) {@ := @;}", ret, CONST_FE_UPWARD); + __SMACK_code("if ($rmode == RTZ) {@ := @;}", ret, CONST_FE_TOWARDZERO); + return ret; +} + +int fesetround(int rm) { + switch (rm) { + case FE_TONEAREST: __SMACK_code("$rmode := RNE;"); break; + case FE_DOWNWARD: __SMACK_code("$rmode := RTN;"); break; + case FE_UPWARD: __SMACK_code("$rmode := RTP;"); break; + case FE_TOWARDZERO: __SMACK_code("$rmode := RTZ;"); break; + default: return 1; + } + return 0; +} + diff --git a/share/smack/lib/math.c b/share/smack/lib/math.c index d841acf84..4c3f80216 100644 --- a/share/smack/lib/math.c +++ b/share/smack/lib/math.c @@ -1,198 +1,184 @@ +// // This file is distributed under the MIT License. See LICENSE for details. // #include #include -//Check the length of pointers -//#if ( __WORDSIZE == 64 ) -#if defined(__LP64__) || defined(_LP64) -#define BUILD_64 1 -#endif - float fabsf(float x) { double ret = __VERIFIER_nondet_double(); - __SMACK_code("@ := $abs.bvfloat(@);", ret, x); + __SMACK_code("@ := ftd($rmode, $abs.bvfloat(dtf($rmode, @)));", ret, x); return ret; } float fdimf(float x, float y) { - if(x>y) - return x-y; - else - return 0; + if (__isnanf(x) || __isnanf(y)) { + return nanf(0); + } + double val = __VERIFIER_nondet_double(); + __SMACK_code("@ := ftd($rmode, $fsub.bvfloat($rmode, dtf($rmode, @), dtf($rmode, @)));", val, x, y); + return fmaxf(0.0f, val); } float roundf(float x) { - if (__isnan(x) || __isinf(x) || __iszero(x)) - return x; - double rete = __VERIFIER_nondet_double(); - double reta = __VERIFIER_nondet_double(); - __SMACK_code("@ := sbv32td($round.rne.bvfloat(@));", rete, x); - __SMACK_code("@ := sbv32td($round.rna.bvfloat(@));", reta, x); - if (x > 0) - return fmax(rete, reta); - return fmin(rete, reta); + double ret = __VERIFIER_nondet_double(); + __SMACK_code("@ := ftd($rmode, $round.bvfloat(RNA, dtf($rmode, @)));", ret, x); + return ret; } long lroundf(float x) { - long ret = __VERIFIER_nondet_long(); - __SMACK_code("@ := $lround.bvfloat(dtf(@));", ret, x); - return ret; + return roundf(x); } float rintf(float x) { - return roundf(x); + double ret = __VERIFIER_nondet_double(); + __SMACK_code("@ := ftd($rmode, $round.bvfloat($rmode, dtf($rmode, @)));", ret, x); + return ret; } float nearbyintf(float x) { - return roundf(x); + double ret = __VERIFIER_nondet_double(); + __SMACK_code("@ := ftd($rmode, $round.bvfloat($rmode, dtf($rmode, @)));", ret, x); + return ret; } long lrintf(float x) { - long ret = __VERIFIER_nondet_long(); - __SMACK_code("@ := $lround.bvfloat(dtf(@));", ret, x); - return ret; + return rintf(x); } float floorf(float x) { - if (__isnanf(x) || __isinff(x) || __iszerof(x)) - return x; double ret = __VERIFIER_nondet_double(); - __SMACK_code("@ := sbv32td($floor.bvfloat(dtf(@)));", ret, x); + __SMACK_code("@ := ftd($rmode, $round.bvfloat(RTN, dtf($rmode, @)));", ret, x); return ret; } float ceilf(float x) { - if (__isnanf(x) || __isinff(x) || __iszerof(x)) - return x; double ret = __VERIFIER_nondet_double(); - __SMACK_code("@ := sbv32td($ceil.bvfloat(dtf(@)));", ret, x); + __SMACK_code("@ := ftd($rmode, $round.bvfloat(RTP, dtf($rmode, @)));", ret, x); return ret; } float truncf(float x) { - if (__isnanf(x) || __isinff(x) || __iszerof(x)) - return x; double ret = __VERIFIER_nondet_double(); - __SMACK_code("@ := sbv32td($trunc.bvfloat(dtf(@)));", ret, x); + __SMACK_code("@ := ftd($rmode, $round.bvfloat(RTZ, dtf($rmode, @)));", ret, x); return ret; } float sqrtf(float x) { double ret = __VERIFIER_nondet_double(); - __SMACK_code("@ := $sqrt.bvfloat(dtf(@));", ret, x); + __SMACK_code("@ := ftd($rmode, $sqrt.bvfloat($rmode, dtf($rmode, @)));", ret, x); return ret; } float remainderf(float x, float y) { double ret = __VERIFIER_nondet_double(); - __SMACK_code("@ := ftd($rem.bvfloat(dtf(@), dtf(@)));", ret, x, y); + __SMACK_code("@ := ftd($rmode, $frem.bvfloat(dtf($rmode, @), dtf($rmode, @)));", ret, x, y); return ret; } float fminf(float x, float y) { double ret = __VERIFIER_nondet_double(); - __SMACK_code("@ := $min.bvfloat(dtf(@), dtf(@));", ret, x, y); + __SMACK_code("@ := ftd($rmode, $min.bvfloat(dtf($rmode, @), dtf($rmode, @)));", ret, x, y); return ret; } float fmaxf(float x, float y) { double ret = __VERIFIER_nondet_double(); - __SMACK_code("@ := $max.bvfloat(dtf(@), dtf(@));", ret, x, y); + __SMACK_code("@ := ftd($rmode, $max.bvfloat(dtf($rmode, @), dtf($rmode, @)));", ret, x, y); return ret; } float fmodf(float x, float y) { - float result = remainderf(fabsf(x), fabsf(y)); - if (signbitf(result)) - result += fabsf(y); - return copysignf(result, x); + if (__isnanf(x) || __isnanf(y) || __isinff(x) || __iszerof(y)) { + return nanf(0); + } + double ret = __VERIFIER_nondet_double(); + y = fabsf(y); + ret = remainderf(fabsf(x), y); + if (__signbitf(ret)) { + __SMACK_code("@ := ftd($rmode, $fadd.bvfloat($rmode, dtf($rmode, @), dtf($rmode, @)));", ret, ret, y); + } + return copysignf(ret, x); +} + +float modff(float x, float *iPart) { + double fPart = __VERIFIER_nondet_double(); + if (__isinff(x)) { + *iPart = x; + fPart = 0.0f; + } else { + *iPart = truncf(x); + __SMACK_code("@ := ftd($rmode, $fsub.bvfloat($rmode, dtf($rmode, @), dtf($rmode, @)));", fPart, x, *iPart); + } + if (__iszerof(fPart)) { + fPart = __signbitf(x) ? -0.0f : 0.0f; + } + return fPart; } -float modff(float x, float* y) { - *y = floorf(x); - return x -*y; +float copysignf(float x, float y) { + if (__signbitf(x) != __signbitf(y)) { + fi u; + u.f = x; + u.i.sign ^= 1; + x = u.f; + } + return x; } -float copysignf(float x, float y) { - double ret = __VERIFIER_nondet_double(); - if (__isnegativef(x)^__isnegativef(y)) - __SMACK_code("@ := $fmul.bvfloat(dtf(@), -0e127f24e8);", ret, x); - else - ret = x; - return ret; +float nanf(const char *c) { + return 0.0f / 0.0f; } int __isnormalf(float x) { int ret = __VERIFIER_nondet_int(); - __SMACK_code("@ := if $isnormal.bvfloat(dtf(@)) then 1bv32 else 0bv32;", ret, x); + __SMACK_code("@ := if $isnormal.bvfloat.bool(dtf($rmode, @)) then $1 else $0;", ret, x); return ret; } -int __isSubnormalf(float x) { +int __issubnormalf(float x) { int ret = __VERIFIER_nondet_int(); - __SMACK_code("@ := if $issubnormal.bvfloat(dtf(@)) then 1bv32 else 0bv32;", ret, x); + __SMACK_code("@ := if $issubnormal.bvfloat.bool(dtf($rmode, @)) then $1 else $0;", ret, x); return ret; } int __iszerof(float x) { int ret = __VERIFIER_nondet_int(); - __SMACK_code("@ := if $iszero.bvfloat(dtf(@)) then 1bv32 else 0bv32;", ret, x); + __SMACK_code("@ := if $iszero.bvfloat.bool(dtf($rmode, @)) then $1 else $0;", ret, x); return ret; } int __isinff(float x) { int ret = __VERIFIER_nondet_int(); - __SMACK_code("@ := if $isinfinite.bvfloat(dtf(@)) then 1bv32 else 0bv32;", ret, x); + __SMACK_code("@ := if $isinfinite.bvfloat.bool(dtf($rmode, @)) then $1 else $0;", ret, x); return ret; } int __isnanf(float x) { int ret = __VERIFIER_nondet_int(); - __SMACK_code("@ := if $isnan.bvfloat(dtf(@)) then 1bv32 else 0bv32;", ret, x); - return ret; -} - -int __isnegativef(float x) { - int ret = __VERIFIER_nondet_int(); - __SMACK_code("@ := if $isnegative.bvfloat(dtf(@)) then 1bv32 else 0bv32;", ret, x); - return ret; -} - -int __ispositivef(float x) { - int ret = __VERIFIER_nondet_int(); - __SMACK_code("@ := if $ispositive.bvfloat(dtf(@)) then 1bv32 else 0bv32;", ret, x); + __SMACK_code("@ := if $isnan.bvfloat.bool(dtf($rmode, @)) then $1 else $0;", ret, x); return ret; } int __signbitf(float x) { - int ret = __VERIFIER_nondet_int(); - __SMACK_code("@ := if (dtf(@) <= 0e0f24e8) then 1bv32 else 0bv32;", ret, x); - return ret; -} - -int signbitf(float x) { - return __signbitf(x); + fi u; + u.f = x; + return u.i.sign; } int __fpclassifyf(float x) { if (__isnanf(x)) - return 0; + return FP_NAN; if (__isinff(x)) - return 1; + return FP_INFINITE; if (__iszerof(x)) - return 2; - if (__isSubnormalf(x)) - return 3; - return 4; -} - -int fpclassifyf(float x) { - return __fpclassifyf(x); + return FP_ZERO; + if (__issubnormalf(x)) + return FP_SUBNORMAL; + return FP_NORMAL; } int __finitef(float x) { - return !__isinf(x) && !__isnanf(x); + return !__isinff(x) && !__isnanf(x); } double fabs(double x) { @@ -202,75 +188,67 @@ double fabs(double x) { } double fdim(double x, double y) { - if(x>y) - return x-y; - else - return 0; + if (__isnan(x) || __isnan(y)) { + return nan(0); + } + double val = __VERIFIER_nondet_double(); + __SMACK_code("@ := $fsub.bvdouble($rmode, @, @);", val, x, y); + return fmax(0.0, val); } double round(double x) { - if (__isnan(x) || __isinf(x) || __iszero(x)) - return x; - double rete = __VERIFIER_nondet_double(); - double reta = __VERIFIER_nondet_double(); - __SMACK_code("@ := sbv64td($round.rne.bvdouble(@));", rete, x); - __SMACK_code("@ := sbv64td($round.rna.bvdouble(@));", reta, x); - if (x > 0) - return fmax(rete, reta); - return fmin(rete, reta); + double ret = __VERIFIER_nondet_double(); + __SMACK_code("@ := $round.bvdouble(RNA, @);", ret, x); + return ret; } long lround(double x) { - long ret = __VERIFIER_nondet_long(); - __SMACK_code("@ := $lround.bvdouble(@);", ret, x); - return ret; + return round(x); } double rint(double x) { - return round(x); + double ret = __VERIFIER_nondet_double(); + __SMACK_code("@ := $round.bvdouble($rmode, @);", ret, x); + return ret; } double nearbyint(double x) { - return round(x); + double ret = __VERIFIER_nondet_double(); + __SMACK_code("@ := $round.bvdouble($rmode, @);", ret, x); + return ret; } long lrint(double x) { - return lround(x); + return rint(x); } double floor(double x) { - if (__isnan(x) || __isinf(x) || __iszero(x)) - return x; double ret = __VERIFIER_nondet_double(); - __SMACK_code("@ := sbv64td($floor.bvdouble(@));", ret, x); + __SMACK_code("@ := $round.bvdouble(RTN, @);", ret, x); return ret; } double ceil(double x) { - if (__isnan(x) || __isinf(x) || __iszero(x)) - return x; double ret = __VERIFIER_nondet_double(); - __SMACK_code("@ := sbv64td($ceil.bvdouble(@));", ret, x); + __SMACK_code("@ := $round.bvdouble(RTP, @);", ret, x); return ret; } double trunc(double x) { - if (__isnan(x) || __isinf(x) || __iszero(x)) - return x; double ret = __VERIFIER_nondet_double(); - __SMACK_code("@ := sbv64td($trunc.bvdouble(@));", ret, x); + __SMACK_code("@ := $round.bvdouble(RTZ, @);", ret, x); return ret; } double sqrt(double x) { double ret = __VERIFIER_nondet_double(); - __SMACK_code("@ := $sqrt.bvdouble(@);", ret, x); + __SMACK_code("@ := $sqrt.bvdouble($rmode, @);", ret, x); return ret; } double remainder(double x, double y) { double ret = __VERIFIER_nondet_double(); - __SMACK_code("@ := ftd(dtf($rem.bvdouble(ftd(dtf(@)), ftd(dtf(@)))));", ret, x, y); + __SMACK_code("@ := $frem.bvdouble(@, @);", ret, x, y); return ret; } @@ -287,170 +265,273 @@ double fmax(double x, double y) { } double fmod(double x, double y) { - double result = remainder(fabs(x), fabs(y)); - if (signbit(result)) - result += fabs(y); - return copysign(result, x); -} - -double modf(double x, double* y) { - *y = floor(x); - return x - *y; + if (__isnan(x) || __isnan(y) || __isinf(x) || __iszero(y)) { + return nan(0); + } + double ret = __VERIFIER_nondet_double(); + y = fabs(y); + ret = remainder(fabs(x), y); + if (__signbit(ret)) { + __SMACK_code("@ := $fadd.bvdouble($rmode, @, @);", ret, ret, y); + } + return copysign(ret, x); +} + +double modf(double x, double *iPart) { + double fPart = __VERIFIER_nondet_double(); + if (__isinf(x)) { + *iPart = x; + fPart = 0.0; + } else { + *iPart = trunc(x); + __SMACK_code("@ := $fsub.bvdouble($rmode, @, @);", fPart, x, *iPart); + } + if (__iszero(fPart)) { + fPart = (__signbit(x)) ? -0.0 : 0.0; + } + return fPart; } double copysign(double x, double y) { - double ret = __VERIFIER_nondet_double(); - if (__isnegative(x)^__isnegative(y)) - __SMACK_code("@ := $fmul.bvdouble(@, -0e1023f53e11);", ret, x); - else - ret = x; - return ret; + if (__signbit(x) != __signbit(y)) { + di u; + u.d = x; + u.i.sign ^= 1; + x = u.d; + } + return x; } -double nan(const char* x) { - return 0.0/0.0; +double nan(const char *x) { + return 0.0 / 0.0; } int __isnormal(double x) { int ret = __VERIFIER_nondet_int(); - __SMACK_code("@ := if $isnormal.bvdouble(@) then 1bv32 else 0bv32;", ret, x); + __SMACK_code("@ := if $isnormal.bvdouble.bool(@) then $1 else $0;", ret, x); return ret; } -int __isSubnormal(double x) { +int __issubnormal(double x) { int ret = __VERIFIER_nondet_int(); - __SMACK_code("@ := if $issubnormal.bvdouble(@) then 1bv32 else 0bv32;", ret, x); + __SMACK_code("@ := if $issubnormal.bvdouble.bool(@) then $1 else $0;", ret, x); return ret; } int __iszero(double x) { int ret = __VERIFIER_nondet_int(); - __SMACK_code("@ := if $iszero.bvdouble(@) then 1bv32 else 0bv32;", ret, x); + __SMACK_code("@ := if $iszero.bvdouble.bool(@) then $1 else $0;", ret, x); return ret; } int __isinf(double x) { int ret = __VERIFIER_nondet_int(); - __SMACK_code("@ := if $isinfinite.bvdouble(@) then 1bv32 else 0bv32;", ret, x); + __SMACK_code("@ := if $isinfinite.bvdouble.bool(@) then $1 else $0;", ret, x); return ret; } int __isnan(double x) { int ret = __VERIFIER_nondet_int(); - __SMACK_code("@ := if $isnan.bvdouble(@) then 1bv32 else 0bv32;", ret, x); + __SMACK_code("@ := if $isnan.bvdouble.bool(@) then $1 else $0;", ret, x); return ret; } -int __isnegative(double x) { - int ret = __VERIFIER_nondet_int(); - __SMACK_code("@ := if $isnegative.bvdouble(@) then 1bv32 else 0bv32;", ret, x); +int __signbit(double x) { + di u; + u.d = x; + return u.i.sign; +} + +int __fpclassify(double x) { + if (__isnan(x)) + return FP_NAN; + if (__isinf(x)) + return FP_INFINITE; + if (__iszero(x)) + return FP_ZERO; + if (__issubnormal(x)) + return FP_SUBNORMAL; + return FP_NORMAL; +} + +int __finite(double x) { + return !__isinf(x) && !__isnan(x); +} + +long double fabsl(long double x) { + long double ret = __VERIFIER_nondet_long_double(); + __SMACK_code("@ := $abs.bvlongdouble(@);", ret, x); return ret; } -int __ispositive(double x) { - int ret = __VERIFIER_nondet_int(); - __SMACK_code("@ := if $ispositive.bvdouble(@) then 1bv32 else 0bv32;", ret, x); +long double fdiml(long double x, long double y) { + if (__isnanl(x) || __isnanl(y)) { + return nanl(0); + } + double val = __VERIFIER_nondet_long_double(); + __SMACK_code("@ := $fsub.bvlongdouble($rmode, @, @);", val, x, y); + return fmaxl(0.0l, val); +} + +long double roundl(long double x) { + long double ret = __VERIFIER_nondet_long_double(); + __SMACK_code("@ := $round.bvlongdouble(RNA, @);", ret, x); return ret; } -int __signbit(double x) { - int ret = __VERIFIER_nondet_int(); - __SMACK_code("@ := if (@ <= 0e0f53e11) then 1bv32 else 0bv32;", ret, x); +long lroundl(long double x) { + return roundl(x); +} + +long double rintl(long double x) { + long double ret = __VERIFIER_nondet_long_double(); + __SMACK_code("@ := $round.bvlongdouble($rmode, @);", ret, x); return ret; } -int signbit(double x) { - return __signbit(x); +long double nearbyintl(long double x) { + long double ret = __VERIFIER_nondet_long_double(); + __SMACK_code("@ := $round.bvlongdouble($rmode, @);", ret, x); + return ret; } -int __fpclassify(double x) { - if (__isnan(x)) - return 0; - if (__isinf(x)) - return 1; - if (__iszero(x)) - return 2; - if (__isSubnormal(x)) - return 3; - return 4; +long lrintl(long double x) { + return rintl(x); } -int fpclassify(double x) { - return __fpclassify(x); +long double floorl(long double x) { + long double ret = __VERIFIER_nondet_long_double(); + __SMACK_code("@ := $round.bvlongdouble(RTN, @);", ret, x); + return ret; } -int __finite(double x) { - return !__isinf(x) && !__isnan(x); +long double ceill(long double x) { + long double ret = __VERIFIER_nondet_long_double(); + __SMACK_code("@ := $round.bvlongdouble(RTP, @);", ret, x); + return ret; } -/*int __isnormall(long double x) { - int ret = __VERIFIER_nondet_int(); - __SMACK_code("@ := if $isnormal.bvlongdouble(@) then 1bv32 else 0bv32;", ret, x); +long double truncl(long double x) { + long double ret = __VERIFIER_nondet_long_double(); + __SMACK_code("@ := $round.bvlongdouble(RTZ, @);", ret, x); return ret; } -int __isSubnormall(long double x) { - int ret = __VERIFIER_nondet_int(); - __SMACK_code("@ := if $issubnormal.bvlongdouble(@) then 1bv32 else 0bv32;", ret, x); +long double sqrtl(long double x) { + long double ret = __VERIFIER_nondet_long_double(); + __SMACK_code("@ := $sqrt.bvlongdouble($rmode, @);", ret, x); return ret; } -int __iszerol(long double x) { - int ret = __VERIFIER_nondet_int(); - __SMACK_code("@ := if $iszero.bvlongdouble(@) then 1bv32 else 0bv32;", ret, x); +long double remainderl(long double x, long double y) { + long double ret = __VERIFIER_nondet_long_double(); + __SMACK_code("@ := $frem.bvlongdouble(@, @);", ret, x, y); return ret; } -int __isinfl(long double x) { +long double fminl(long double x, long double y) { + long double ret = __VERIFIER_nondet_long_double(); + __SMACK_code("@ := $min.bvlongdouble(@, @);", ret, x, y); + return ret; +} + +long double fmaxl(long double x, long double y) { + long double ret = __VERIFIER_nondet_long_double(); + __SMACK_code("@ := $max.bvlongdouble(@, @);", ret, x, y); + return ret; +} + +long double fmodl(long double x, long double y) { + if (__isnanl(x) || __isnanl(y) || __isinfl(x) || __iszerol(y)) { + return nanl(0); + } + long double ret = __VERIFIER_nondet_long_double(); + y = fabsl(y); + ret = remainderl(fabsl(x), y); + if (__signbitl(ret)) { + __SMACK_code("@ := $fadd.bvlongdouble($rmode, @, @);", ret, ret, y); + } + return copysignl(ret, x); +} + +long double modfl(long double x, long double *iPart) { + long double fPart = __VERIFIER_nondet_long_double(); + if (__isinfl(x)) { + *iPart = x; + fPart = 0.0l; + } else { + *iPart = truncl(x); + __SMACK_code("@ := $fsub.bvlongdouble($rmode, @, @);", fPart, x, *iPart); + } + if (__iszerol(fPart)) { + fPart = __signbitl(x) ? -0.0l : 0.0l; + } + return fPart; +} + +long double copysignl(long double x, long double y) { + if (__signbitl(x) != __signbitl(y)) { + li u; + u.l = x; + u.i.sign ^= 1; + x = u.l; + } + return x; +} + +long double nanl(const char *c) { + return 0.0l / 0.0l; +} + +int __isnormall(long double x) { int ret = __VERIFIER_nondet_int(); - __SMACK_code("@ := if $isinfinite.bvlongdouble(@) then 1bv32 else 0bv32;", ret, x); + __SMACK_code("@ := if $isnormal.bvlongdouble.bool(@) then $1 else $0;", ret, x); return ret; } -int __isnanl(long double x) { +int __issubnormall(long double x) { int ret = __VERIFIER_nondet_int(); - __SMACK_code("@ := if $isnan.bvlongdouble(@) then 1bv32 else 0bv32;", ret, x); + __SMACK_code("@ := if $issubnormal.bvlongdouble.bool(@) then $1 else $0;", ret, x); return ret; } -int __isnegativel(long double x) { +int __iszerol(long double x) { int ret = __VERIFIER_nondet_int(); - __SMACK_code("@ := if $isnegative.bvlongdouble(@) then 1bv32 else 0bv32;", ret, x); + __SMACK_code("@ := if $iszero.bvlongdouble.bool(@) then $1 else $0;", ret, x); return ret; } -int __ispositivel(long double x) { +int __isinfl(long double x) { int ret = __VERIFIER_nondet_int(); - __SMACK_code("@ := if $ispositive.bvlongdouble(@) then 1bv32 else 0bv32;", ret, x); + __SMACK_code("@ := if $isinfinite.bvlongdouble.bool(@) then $1 else $0;", ret, x); return ret; } -int __signbitl(long double x) { +int __isnanl(long double x) { int ret = __VERIFIER_nondet_int(); - __SMACK_code("@ := if (@ <= 0e0f53e11) then 1bv32 else 0bv32;", ret, x); + __SMACK_code("@ := if $isnan.bvlongdouble.bool(@) then $1 else $0;", ret, x); return ret; } -int signbitl(long double x) { - return __signbitl(x); +int __signbitl(long double x) { + li u; + u.l = x; + return u.i.sign; } int __fpclassifyl(long double x) { if (__isnanl(x)) - return 0; + return FP_NAN; if (__isinfl(x)) - return 1; + return FP_INFINITE; if (__iszerol(x)) - return 2; - if (__isSubnormall(x)) - return 3; - return 4; -} - -int fpclassifyl(long double x) { - return __fpclassifyl(x); + return FP_ZERO; + if (__issubnormall(x)) + return FP_SUBNORMAL; + return FP_NORMAL; } int __finitel(long double x) { return !__isinfl(x) && !__isnanl(x); -}*/ +} + diff --git a/share/smack/lib/pthread.c b/share/smack/lib/pthread.c index 55b477cdd..beaffaef4 100644 --- a/share/smack/lib/pthread.c +++ b/share/smack/lib/pthread.c @@ -1,3 +1,6 @@ +// +// This file is distributed under the MIT License. See LICENSE for details. +// #include "pthread.h" #include "smack.h" diff --git a/share/smack/lib/smack.c b/share/smack/lib/smack.c index ec844899c..f2e8b54e0 100644 --- a/share/smack/lib/smack.c +++ b/share/smack/lib/smack.c @@ -1,10 +1,11 @@ // // This file is distributed under the MIT License. See LICENSE for details. - +// #include #include #include #include +#include /** * The SMACK "prelude" definitions @@ -50,15 +51,9 @@ void __VERIFIER_error(void) { #endif } -#if SIGNED_INTEGER_OVERFLOW_CHECK -void __SMACK_overflow_false(void) { - __SMACK_code("assert {:overflow} false;"); -} - void __SMACK_check_overflow(int flag) { __SMACK_dummy(flag); __SMACK_code("assert {:overflow} @ == $0;", flag); } -#endif void exit(int x) { #if MEMORY_SAFETY @@ -130,13 +125,19 @@ signed int __VERIFIER_nondet_signed_int(void) { unsigned __VERIFIER_nondet_unsigned(void) { unsigned x = __SMACK_nondet_unsigned(); - __VERIFIER_assume(x >= 0 && x <= UINT_MAX); + unsigned min = __SMACK_nondet_unsigned(); + unsigned max = __SMACK_nondet_unsigned(); + __VERIFIER_assume(min == 0 && max >= UINT_MAX && max <= UINT_MAX); + __VERIFIER_assume(x >= min && x <= max); return x; } unsigned int __VERIFIER_nondet_unsigned_int(void) { unsigned int x = __SMACK_nondet_unsigned_int(); - __VERIFIER_assume(x >= 0 && x <= UINT_MAX); + unsigned int min = __SMACK_nondet_unsigned_int(); + unsigned int max = __SMACK_nondet_unsigned_int(); + __VERIFIER_assume(min == 0 && max >= UINT_MAX && max <= UINT_MAX); + __VERIFIER_assume(x >= min && x <= max); return x; } @@ -166,13 +167,19 @@ signed long int __VERIFIER_nondet_signed_long_int(void) { unsigned long __VERIFIER_nondet_unsigned_long(void) { unsigned long x = __SMACK_nondet_unsigned_long(); - __VERIFIER_assume(x >= 0 && x <= ULONG_MAX); + unsigned long min = __SMACK_nondet_unsigned_long(); + unsigned long max = __SMACK_nondet_unsigned_long(); + __VERIFIER_assume(min == 0 && max >= ULONG_MAX && max <= ULONG_MAX); + __VERIFIER_assume(x >= min && x <= max); return x; } unsigned long int __VERIFIER_nondet_unsigned_long_int(void) { unsigned long int x = __SMACK_nondet_unsigned_long_int(); - __VERIFIER_assume(x >= 0 && x <= ULONG_MAX); + unsigned long int min = __SMACK_nondet_unsigned_long_int(); + unsigned long int max = __SMACK_nondet_unsigned_long_int(); + __VERIFIER_assume(min == 0 && max >= ULONG_MAX && max <= ULONG_MAX); + __VERIFIER_assume(x >= min && x <= max); return x; } @@ -202,17 +209,24 @@ signed long long int __VERIFIER_nondet_signed_long_long_int(void) { unsigned long long __VERIFIER_nondet_unsigned_long_long(void) { unsigned long long x = __SMACK_nondet_unsigned_long_long(); - __VERIFIER_assume(x >= 0 && x <= ULLONG_MAX); + unsigned long long min = __SMACK_nondet_unsigned_long_long(); + unsigned long long max = __SMACK_nondet_unsigned_long_long(); + __VERIFIER_assume(min == 0 && max >= ULLONG_MAX && max <= ULLONG_MAX); + __VERIFIER_assume(x >= min && x <= max); return x; } unsigned long long int __VERIFIER_nondet_unsigned_long_long_int(void) { unsigned long long int x = __SMACK_nondet_unsigned_long_long_int(); - __VERIFIER_assume(x >= 0 && x <= ULLONG_MAX); + unsigned long long int min = __SMACK_nondet_unsigned_long_long_int(); + unsigned long long int max = __SMACK_nondet_unsigned_long_long_int(); + __VERIFIER_assume(min == 0 && max >= ULLONG_MAX && max <= ULLONG_MAX); + __VERIFIER_assume(x >= min && x <= max); return x; } // Used in SVCCOMP benchmarks + _Bool __VERIFIER_nondet_bool(void) { _Bool x = (_Bool)__VERIFIER_nondet_int(); __VERIFIER_assume(x == 0 || x == 1); @@ -254,8 +268,6 @@ void* calloc(size_t num, size_t size) { return ret; } - - void __SMACK_dummy(int v) { __SMACK_code("assume true;"); } @@ -273,220 +285,98 @@ void __SMACK_dummy(int v) { #define xstr(s) str(s) #define str(s) #s -#define RECORD_PROC(type) \ - procedure boogie_si_record_ ## type (i: type); - #define UNINTERPRETED_UNARY_OP(type,name) \ function name.type(i: type) returns (type); #define UNINTERPRETED_BINARY_OP(type,name) \ function name.type(i1: type, i2: type) returns (type); +#define UNINTERPRETED_UNARY_PRED(type,name) \ + function name.type(i: type) returns (i1); + #define UNINTERPRETED_BINARY_PRED(type,name) \ function name.type(i1: type, i2: type) returns (i1); -#define INLINE_UNARY_OP(type,name,body) \ - function {:inline} name.type(i: type) returns (type) body +#define UNINTERPRETED_BINARY_COMP(type,name) \ + function name.type.bool(i1: type, i2: type) returns (bool); -#define INLINE_BINARY_OP(type,name,body) \ - function {:inline} name.type(i1: type, i2: type) returns (type) body +#define UNINTERPRETED_CONVERSION(t1,t2,name) \ + function name.t1.t2(i: t1) returns (t2); -#define INLINE_BINARY_PRED(type,name,cond) \ - function {:inline} name.type.bool(i1: type, i2: type) returns (bool) {cond} \ - function {:inline} name.type(i1: type, i2: type) returns (i1) {if cond then 1 else 0} +#define UNINTERPRETED_RMODE_CONVERSION(t1,t2,name) \ + function name.t1.t2(rm: rmode, i: t1) returns (t2); -#define INLINE_BINARY_BV_PRED(type,name,cond) \ - function {:inline} name.type.bool(i1: type, i2: type) returns (bool) {cond} \ - function {:inline} name.type(i1: type, i2: type) returns (bv1) {if cond then 1bv1 else 0bv1} +#define UNARY_OP(attrib,type,name,body) \ + function {:attrib} name.type(i: type) returns (type) body -#define INLINE_CONVERSION(t1,t2,name,body) \ - function {:inline} name.t1.t2(i: t1) returns (t2) body +#define RMODE_UNARY_OP(attrib,type,name,body) \ + function {:attrib} name.type(rm: rmode, i: type) returns (type) body -#define BUILTIN_UNARY_OP(type,name,prim) \ - function {:builtin xstr(prim)} name.type(i: type) returns (type); +#define BINARY_OP(attrib,type,name,body) \ + function {:attrib} name.type(i1: type, i2: type) returns (type) body -#define BUILTIN_BINARY_OP(type,name,prim) \ - function {:builtin xstr(prim)} name.type(i1: type, i2: type) returns (type); +#define RMODE_BINARY_OP(attrib,type,name,body) \ + function {:attrib} name.type(rm: rmode, i1: type, i2: type) returns (type) body -#define BUILTIN_BINARY_PRED(type,name,prim) \ - function {:builtin xstr(prim)} name.type(i1: type, i2: type) returns (i1); +#define BINARY_COMP(attrib,type,name,cond) \ + function {:attrib} name.type.bool(i1: type, i2: type) returns (bool) cond -#define BVBUILTIN_UNARY_OP(type,name,prim) \ - function {:bvbuiltin xstr(prim)} name.type(i: type) returns (type); +#define INLINE_BINARY_COMP(type,name,cond) \ + BINARY_COMP(inline,type,name,cond) -#define BVBUILTIN_BINARY_OP(type,name,prim) \ - function {:bvbuiltin xstr(prim)} name.type(i1: type, i2: type) returns (type); +#define BUILTIN_CONVERSION(t1,t2,name,prim) \ + function {:builtin xstr(prim)} name.t1.t2(i: t1) returns (t2); -#define BVBUILTIN_BINARY_PRED(type,name,prim) \ - function {:bvbuiltin xstr(prim)} name.type(i1: type, i2: type) returns (i1); +#define BUILTIN_RMODE_CONVERSION(t1,t2,name,prim) \ + function {:builtin xstr(prim)} name.t1.t2(rm: rmode, i: t1) returns (t2); -#define INLINE_BVBUILTIN_BINARY_PRED(type,name,prim) \ - function {:bvbuiltin xstr(prim)} name.type.bool(i1: type, i2: type) returns (bool); \ - function {:inline} name.type(i1: type, i2: type) returns (bv1) {if name.type.bool(i1,i2) then 1bv1 else 0bv1} +#define INLINE_CONVERSION(t1,t2,name,body) \ + function {:inline} name.t1.t2(i: t1) returns (t2) body -#define INLINE_BVBUILTIN_BINARY_SELECT(type,name,pred) \ - function {:inline} name.type(i1: type, i2: type) returns (type) {if pred.type.bool(i1,i2) then i1 else i2} +#define INLINE_RMODE_CONVERSION(t1,t2,name,body) \ + function {:inline} name.t1.t2(rm: rmode, i: t1) returns (t2) body -#define FPBUILTIN_UNARY_OP(type,name,prim) \ - function {:bvbuiltin xstr(prim)} name.type(f: type) returns (type); +#define BUILTIN_UNARY_OP(type,name,prim) \ + UNARY_OP(builtin xstr(prim),type,name,); -#define FPBUILTIN_BINARY_OP(type,name,prim) \ - function {:bvbuiltin xstr(prim)} name.type(f1: type, f2: type) returns (type); +#define BUILTIN_RMODE_UNARY_OP(type,name,prim) \ + RMODE_UNARY_OP(builtin xstr(prim),type,name,); -#define FPBUILTIN_BINARY_PRED(type,name,prim) \ - function {:bvbuiltin xstr(prim)} name.type(f1: type, f2: type) returns (i1); +#define BUILTIN_UNARY_PRED(type,name,prim) \ + function {:builtin xstr(prim)} name.type.bool(i: type) returns (bool); -#define INLINE_FPBUILTIN_BINARY_PRED(type,name,prim) \ - function {:bvbuiltin xstr(prim)} name.type.bool(f1: type, f2: type) returns (bool); \ - function {:inline} name.type(f1: type, f2: type) returns (bv1) {if name.type.bool(f1,f2) then 1bv1 else 0bv1} +#define BUILTIN_BINARY_COMP(type,name,prim) \ + BINARY_COMP(builtin xstr(prim),type,name,); -#define INLINE_FPBUILTIN_BINARY_SELECT(type,name,pred) \ - function {:inline} name.type(f1: type, f2: type) returns (type) {if pred.type.bool(f1,f2) then i1 else i2} +#define BUILTIN_BINARY_OP(type,name,prim) \ + BINARY_OP(builtin xstr(prim),type,name,); + +#define BUILTIN_RMODE_BINARY_OP(type,name,prim) \ + RMODE_BINARY_OP(builtin xstr(prim),type,name,); #define D(d) __SMACK_top_decl(d) #define DECLARE(M,args...) \ D(xstr(M(args))) -#define DECLARE_EACH_INT_TYPE(M,args...) \ - D(xstr(M(i128,args))); \ - D(xstr(M(i96,args))); \ - D(xstr(M(i88,args))); \ - D(xstr(M(i64,args))); \ - D(xstr(M(i56,args))); \ - D(xstr(M(i48,args))); \ - D(xstr(M(i40,args))); \ - D(xstr(M(i32,args))); \ - D(xstr(M(i24,args))); \ - D(xstr(M(i16,args))); \ - D(xstr(M(i8,args))); \ - D(xstr(M(i1,args))); - -#define DECLARE_EACH_BV_TYPE(M,args...) \ - D(xstr(M(bv128,args))); \ - D(xstr(M(bv96,args))); \ - D(xstr(M(bv88,args))); \ - D(xstr(M(bv64,args))); \ - D(xstr(M(bv56,args))); \ - D(xstr(M(bv48,args))); \ - D(xstr(M(bv40,args))); \ - D(xstr(M(bv32,args))); \ - D(xstr(M(bv24,args))); \ - D(xstr(M(bv16,args))); \ - D(xstr(M(bv8,args))); \ - D(xstr(M(bv1,args))); +#include "smack-macros.h" #define DECLARE_EACH_FLOAT_TYPE(M,args...) \ + D(xstr(M(bvhalf,args))); \ D(xstr(M(bvfloat,args))); \ D(xstr(M(bvdouble,args))); \ D(xstr(M(bvlongdouble,args))); void __SMACK_decls(void) { +#if FLOAT_ENABLED + D("var $rmode: rmode;"); +#endif + DECLARE(INLINE_CONVERSION,ref,ref,$bitcast,{i}); // BITVECTOR MODELING - DECLARE_EACH_BV_TYPE(BVBUILTIN_BINARY_OP, $add, bvadd) - DECLARE_EACH_BV_TYPE(BVBUILTIN_BINARY_OP, $sub, bvsub) - DECLARE_EACH_BV_TYPE(BVBUILTIN_BINARY_OP, $mul, bvmul) - DECLARE_EACH_BV_TYPE(BVBUILTIN_BINARY_OP, $udiv, bvudiv) - DECLARE_EACH_BV_TYPE(BVBUILTIN_BINARY_OP, $sdiv, bvsdiv) - DECLARE_EACH_BV_TYPE(BVBUILTIN_BINARY_OP, $smod, bvsmod) - DECLARE_EACH_BV_TYPE(BVBUILTIN_BINARY_OP, $srem, bvsrem) - DECLARE_EACH_BV_TYPE(BVBUILTIN_BINARY_OP, $urem, bvurem) - - DECLARE_EACH_BV_TYPE(INLINE_BVBUILTIN_BINARY_SELECT, $min, $slt) - DECLARE_EACH_BV_TYPE(INLINE_BVBUILTIN_BINARY_SELECT, $max, $sgt) - DECLARE_EACH_BV_TYPE(INLINE_BVBUILTIN_BINARY_SELECT, $umin, $ult) - DECLARE_EACH_BV_TYPE(INLINE_BVBUILTIN_BINARY_SELECT, $umax, $ugt) - - DECLARE_EACH_BV_TYPE(BVBUILTIN_BINARY_OP, $shl, bvshl) - DECLARE_EACH_BV_TYPE(BVBUILTIN_BINARY_OP, $lshr, bvlshr) - DECLARE_EACH_BV_TYPE(BVBUILTIN_BINARY_OP, $ashr, bvashr) - DECLARE_EACH_BV_TYPE(BVBUILTIN_UNARY_OP, $not, bvnot) - DECLARE_EACH_BV_TYPE(BVBUILTIN_BINARY_OP, $and, bvand) - DECLARE_EACH_BV_TYPE(BVBUILTIN_BINARY_OP, $or, bvor) - DECLARE_EACH_BV_TYPE(BVBUILTIN_BINARY_OP, $xor, bvxor) - DECLARE_EACH_BV_TYPE(BVBUILTIN_BINARY_OP, $nand, bvnand) - - DECLARE_EACH_BV_TYPE(INLINE_BINARY_BV_PRED, $eq, i1 == i2) - DECLARE_EACH_BV_TYPE(INLINE_BINARY_BV_PRED, $ne, i1 != i2) - DECLARE_EACH_BV_TYPE(INLINE_BVBUILTIN_BINARY_PRED, $ule, bvule) - DECLARE_EACH_BV_TYPE(INLINE_BVBUILTIN_BINARY_PRED, $ult, bvult) - DECLARE_EACH_BV_TYPE(INLINE_BVBUILTIN_BINARY_PRED, $uge, bvuge) - DECLARE_EACH_BV_TYPE(INLINE_BVBUILTIN_BINARY_PRED, $ugt, bvugt) - DECLARE_EACH_BV_TYPE(INLINE_BVBUILTIN_BINARY_PRED, $sle, bvsle) - DECLARE_EACH_BV_TYPE(INLINE_BVBUILTIN_BINARY_PRED, $slt, bvslt) - DECLARE_EACH_BV_TYPE(INLINE_BVBUILTIN_BINARY_PRED, $sge, bvsge) - DECLARE_EACH_BV_TYPE(INLINE_BVBUILTIN_BINARY_PRED, $sgt, bvsgt) - - DECLARE(INLINE_CONVERSION,bv128,bv96,$trunc,{i[96:0]}); - DECLARE(INLINE_CONVERSION,bv128,bv88,$trunc,{i[88:0]}); - DECLARE(INLINE_CONVERSION,bv128,bv64,$trunc,{i[64:0]}); - DECLARE(INLINE_CONVERSION,bv128,bv56,$trunc,{i[56:0]}); - DECLARE(INLINE_CONVERSION,bv128,bv48,$trunc,{i[48:0]}); - DECLARE(INLINE_CONVERSION,bv128,bv40,$trunc,{i[40:0]}); - DECLARE(INLINE_CONVERSION,bv128,bv32,$trunc,{i[32:0]}); - DECLARE(INLINE_CONVERSION,bv128,bv24,$trunc,{i[24:0]}); - DECLARE(INLINE_CONVERSION,bv128,bv16,$trunc,{i[16:0]}); - DECLARE(INLINE_CONVERSION,bv128,bv8,$trunc,{i[8:0]}); - DECLARE(INLINE_CONVERSION,bv128,bv1,$trunc,{i[1:0]}); - DECLARE(INLINE_CONVERSION,bv96,bv88,$trunc,{i[88:0]}); - DECLARE(INLINE_CONVERSION,bv96,bv64,$trunc,{i[64:0]}); - DECLARE(INLINE_CONVERSION,bv96,bv56,$trunc,{i[56:0]}); - DECLARE(INLINE_CONVERSION,bv96,bv48,$trunc,{i[48:0]}); - DECLARE(INLINE_CONVERSION,bv96,bv40,$trunc,{i[40:0]}); - DECLARE(INLINE_CONVERSION,bv96,bv32,$trunc,{i[32:0]}); - DECLARE(INLINE_CONVERSION,bv96,bv24,$trunc,{i[24:0]}); - DECLARE(INLINE_CONVERSION,bv96,bv16,$trunc,{i[16:0]}); - DECLARE(INLINE_CONVERSION,bv96,bv8,$trunc,{i[8:0]}); - DECLARE(INLINE_CONVERSION,bv96,bv1,$trunc,{i[1:0]}); - DECLARE(INLINE_CONVERSION,bv88,bv64,$trunc,{i[64:0]}); - DECLARE(INLINE_CONVERSION,bv88,bv56,$trunc,{i[56:0]}); - DECLARE(INLINE_CONVERSION,bv88,bv48,$trunc,{i[48:0]}); - DECLARE(INLINE_CONVERSION,bv88,bv40,$trunc,{i[40:0]}); - DECLARE(INLINE_CONVERSION,bv88,bv32,$trunc,{i[32:0]}); - DECLARE(INLINE_CONVERSION,bv88,bv24,$trunc,{i[24:0]}); - DECLARE(INLINE_CONVERSION,bv88,bv16,$trunc,{i[16:0]}); - DECLARE(INLINE_CONVERSION,bv88,bv8,$trunc,{i[8:0]}); - DECLARE(INLINE_CONVERSION,bv88,bv1,$trunc,{i[1:0]}); - DECLARE(INLINE_CONVERSION,bv64,bv56,$trunc,{i[56:0]}); - DECLARE(INLINE_CONVERSION,bv64,bv48,$trunc,{i[48:0]}); - DECLARE(INLINE_CONVERSION,bv64,bv40,$trunc,{i[40:0]}); - DECLARE(INLINE_CONVERSION,bv64,bv32,$trunc,{i[32:0]}); - DECLARE(INLINE_CONVERSION,bv64,bv24,$trunc,{i[24:0]}); - DECLARE(INLINE_CONVERSION,bv64,bv16,$trunc,{i[16:0]}); - DECLARE(INLINE_CONVERSION,bv64,bv8,$trunc,{i[8:0]}); - DECLARE(INLINE_CONVERSION,bv64,bv1,$trunc,{i[1:0]}); - DECLARE(INLINE_CONVERSION,bv56,bv48,$trunc,{i[48:0]}); - DECLARE(INLINE_CONVERSION,bv56,bv40,$trunc,{i[40:0]}); - DECLARE(INLINE_CONVERSION,bv56,bv32,$trunc,{i[32:0]}); - DECLARE(INLINE_CONVERSION,bv56,bv24,$trunc,{i[24:0]}); - DECLARE(INLINE_CONVERSION,bv56,bv16,$trunc,{i[16:0]}); - DECLARE(INLINE_CONVERSION,bv56,bv8,$trunc,{i[8:0]}); - DECLARE(INLINE_CONVERSION,bv56,bv1,$trunc,{i[1:0]}); - DECLARE(INLINE_CONVERSION,bv48,bv32,$trunc,{i[32:0]}); - DECLARE(INLINE_CONVERSION,bv48,bv24,$trunc,{i[24:0]}); - DECLARE(INLINE_CONVERSION,bv48,bv16,$trunc,{i[16:0]}); - DECLARE(INLINE_CONVERSION,bv48,bv8,$trunc,{i[8:0]}); - DECLARE(INLINE_CONVERSION,bv48,bv1,$trunc,{i[1:0]}); - DECLARE(INLINE_CONVERSION,bv40,bv32,$trunc,{i[32:0]}); - DECLARE(INLINE_CONVERSION,bv40,bv24,$trunc,{i[24:0]}); - DECLARE(INLINE_CONVERSION,bv40,bv16,$trunc,{i[16:0]}); - DECLARE(INLINE_CONVERSION,bv40,bv8,$trunc,{i[8:0]}); - DECLARE(INLINE_CONVERSION,bv40,bv1,$trunc,{i[1:0]}); - DECLARE(INLINE_CONVERSION,bv32,bv24,$trunc,{i[24:0]}); - DECLARE(INLINE_CONVERSION,bv32,bv16,$trunc,{i[16:0]}); - DECLARE(INLINE_CONVERSION,bv32,bv8,$trunc,{i[8:0]}); - DECLARE(INLINE_CONVERSION,bv32,bv1,$trunc,{i[1:0]}); - DECLARE(INLINE_CONVERSION,bv24,bv16,$trunc,{i[16:0]}); - DECLARE(INLINE_CONVERSION,bv24,bv8,$trunc,{i[8:0]}); - DECLARE(INLINE_CONVERSION,bv24,bv1,$trunc,{i[1:0]}); - DECLARE(INLINE_CONVERSION,bv16,bv8,$trunc,{i[8:0]}); - DECLARE(INLINE_CONVERSION,bv16,bv1,$trunc,{i[1:0]}); - DECLARE(INLINE_CONVERSION,bv8,bv1,$trunc,{i[1:0]}); - DECLARE(INLINE_CONVERSION,bv1,bv8,$zext,{if i == 0bv1 then 0bv8 else 1bv8}); DECLARE(INLINE_CONVERSION,bv1,bv16,$zext,{if i == 0bv1 then 0bv16 else 1bv16}); DECLARE(INLINE_CONVERSION,bv1,bv24,$zext,{if i == 0bv1 then 0bv24 else 1bv24}); @@ -495,6 +385,7 @@ void __SMACK_decls(void) { DECLARE(INLINE_CONVERSION,bv1,bv48,$zext,{if i == 0bv1 then 0bv48 else 1bv48}); DECLARE(INLINE_CONVERSION,bv1,bv56,$zext,{if i == 0bv1 then 0bv56 else 1bv56}); DECLARE(INLINE_CONVERSION,bv1,bv64,$zext,{if i == 0bv1 then 0bv64 else 1bv64}); + DECLARE(INLINE_CONVERSION,bv1,bv80,$zext,{if i == 0bv1 then 0bv80 else 1bv80}); DECLARE(INLINE_CONVERSION,bv1,bv88,$zext,{if i == 0bv1 then 0bv88 else 1bv88}); DECLARE(INLINE_CONVERSION,bv1,bv96,$zext,{if i == 0bv1 then 0bv96 else 1bv96}); DECLARE(INLINE_CONVERSION,bv1,bv128,$zext,{if i == 0bv1 then 0bv128 else 1bv128}); @@ -505,6 +396,7 @@ void __SMACK_decls(void) { D("function {:bvbuiltin \"(_ zero_extend 40)\"} $zext.bv8.bv48(i: bv8) returns (bv48);"); D("function {:bvbuiltin \"(_ zero_extend 48)\"} $zext.bv8.bv56(i: bv8) returns (bv56);"); D("function {:bvbuiltin \"(_ zero_extend 56)\"} $zext.bv8.bv64(i: bv8) returns (bv64);"); + D("function {:bvbuiltin \"(_ zero_extend 72)\"} $zext.bv8.bv80(i: bv8) returns (bv80);"); D("function {:bvbuiltin \"(_ zero_extend 80)\"} $zext.bv8.bv88(i: bv8) returns (bv88);"); D("function {:bvbuiltin \"(_ zero_extend 88)\"} $zext.bv8.bv96(i: bv8) returns (bv96);"); D("function {:bvbuiltin \"(_ zero_extend 120)\"} $zext.bv8.bv128(i: bv8) returns (bv128);"); @@ -514,6 +406,7 @@ void __SMACK_decls(void) { D("function {:bvbuiltin \"(_ zero_extend 32)\"} $zext.bv16.bv48(i: bv16) returns (bv48);"); D("function {:bvbuiltin \"(_ zero_extend 40)\"} $zext.bv16.bv56(i: bv16) returns (bv56);"); D("function {:bvbuiltin \"(_ zero_extend 48)\"} $zext.bv16.bv64(i: bv16) returns (bv64);"); + D("function {:bvbuiltin \"(_ zero_extend 64)\"} $zext.bv16.bv80(i: bv16) returns (bv80);"); D("function {:bvbuiltin \"(_ zero_extend 72)\"} $zext.bv16.bv88(i: bv16) returns (bv88);"); D("function {:bvbuiltin \"(_ zero_extend 80)\"} $zext.bv16.bv96(i: bv16) returns (bv96);"); D("function {:bvbuiltin \"(_ zero_extend 112)\"} $zext.bv16.bv128(i: bv16) returns (bv128);"); @@ -522,6 +415,7 @@ void __SMACK_decls(void) { D("function {:bvbuiltin \"(_ zero_extend 24)\"} $zext.bv24.bv48(i: bv24) returns (bv48);"); D("function {:bvbuiltin \"(_ zero_extend 32)\"} $zext.bv24.bv56(i: bv24) returns (bv56);"); D("function {:bvbuiltin \"(_ zero_extend 40)\"} $zext.bv24.bv64(i: bv24) returns (bv64);"); + D("function {:bvbuiltin \"(_ zero_extend 56)\"} $zext.bv24.bv80(i: bv24) returns (bv80);"); D("function {:bvbuiltin \"(_ zero_extend 64)\"} $zext.bv24.bv88(i: bv24) returns (bv88);"); D("function {:bvbuiltin \"(_ zero_extend 72)\"} $zext.bv24.bv96(i: bv24) returns (bv96);"); D("function {:bvbuiltin \"(_ zero_extend 104)\"} $zext.bv24.bv128(i: bv24) returns (bv128);"); @@ -529,26 +423,34 @@ void __SMACK_decls(void) { D("function {:bvbuiltin \"(_ zero_extend 16)\"} $zext.bv32.bv48(i: bv32) returns (bv48);"); D("function {:bvbuiltin \"(_ zero_extend 24)\"} $zext.bv32.bv56(i: bv32) returns (bv56);"); D("function {:bvbuiltin \"(_ zero_extend 32)\"} $zext.bv32.bv64(i: bv32) returns (bv64);"); + D("function {:bvbuiltin \"(_ zero_extend 48)\"} $zext.bv32.bv80(i: bv32) returns (bv80);"); D("function {:bvbuiltin \"(_ zero_extend 56)\"} $zext.bv32.bv88(i: bv32) returns (bv88);"); D("function {:bvbuiltin \"(_ zero_extend 64)\"} $zext.bv32.bv96(i: bv32) returns (bv96);"); D("function {:bvbuiltin \"(_ zero_extend 96)\"} $zext.bv32.bv128(i: bv32) returns (bv128);"); D("function {:bvbuiltin \"(_ zero_extend 8)\"} $zext.bv40.bv48(i: bv40) returns (bv48);"); D("function {:bvbuiltin \"(_ zero_extend 16)\"} $zext.bv40.bv56(i: bv40) returns (bv56);"); D("function {:bvbuiltin \"(_ zero_extend 24)\"} $zext.bv40.bv64(i: bv40) returns (bv64);"); + D("function {:bvbuiltin \"(_ zero_extend 40)\"} $zext.bv40.bv80(i: bv40) returns (bv80);"); D("function {:bvbuiltin \"(_ zero_extend 48)\"} $zext.bv40.bv88(i: bv40) returns (bv88);"); D("function {:bvbuiltin \"(_ zero_extend 56)\"} $zext.bv40.bv96(i: bv40) returns (bv96);"); D("function {:bvbuiltin \"(_ zero_extend 88)\"} $zext.bv40.bv128(i: bv40) returns (bv128);"); D("function {:bvbuiltin \"(_ zero_extend 16)\"} $zext.bv48.bv64(i: bv48) returns (bv64);"); + D("function {:bvbuiltin \"(_ zero_extend 32)\"} $zext.bv48.bv80(i: bv48) returns (bv80);"); D("function {:bvbuiltin \"(_ zero_extend 40)\"} $zext.bv48.bv88(i: bv48) returns (bv88);"); D("function {:bvbuiltin \"(_ zero_extend 48)\"} $zext.bv48.bv96(i: bv48) returns (bv96);"); D("function {:bvbuiltin \"(_ zero_extend 80)\"} $zext.bv48.bv128(i: bv48) returns (bv128);"); D("function {:bvbuiltin \"(_ zero_extend 8)\"} $zext.bv56.bv64(i: bv56) returns (bv64);"); + D("function {:bvbuiltin \"(_ zero_extend 24)\"} $zext.bv56.bv80(i: bv56) returns (bv80);"); D("function {:bvbuiltin \"(_ zero_extend 32)\"} $zext.bv56.bv88(i: bv56) returns (bv88);"); D("function {:bvbuiltin \"(_ zero_extend 40)\"} $zext.bv56.bv96(i: bv56) returns (bv96);"); D("function {:bvbuiltin \"(_ zero_extend 72)\"} $zext.bv56.bv128(i: bv56) returns (bv128);"); + D("function {:bvbuiltin \"(_ zero_extend 16)\"} $zext.bv64.bv80(i: bv64) returns (bv80);"); D("function {:bvbuiltin \"(_ zero_extend 24)\"} $zext.bv64.bv88(i: bv64) returns (bv88);"); D("function {:bvbuiltin \"(_ zero_extend 32)\"} $zext.bv64.bv96(i: bv64) returns (bv96);"); D("function {:bvbuiltin \"(_ zero_extend 64)\"} $zext.bv64.bv128(i: bv64) returns (bv128);"); + D("function {:bvbuiltin \"(_ zero_extend 8)\"} $zext.bv80.bv88(i: bv80) returns (bv88);"); + D("function {:bvbuiltin \"(_ zero_extend 16)\"} $zext.bv80.bv96(i: bv80) returns (bv96);"); + D("function {:bvbuiltin \"(_ zero_extend 48)\"} $zext.bv80.bv128(i: bv80) returns (bv128);"); D("function {:bvbuiltin \"(_ zero_extend 8)\"} $zext.bv88.bv96(i: bv88) returns (bv96);"); D("function {:bvbuiltin \"(_ zero_extend 40)\"} $zext.bv88.bv128(i: bv88) returns (bv128);"); D("function {:bvbuiltin \"(_ zero_extend 32)\"} $zext.bv96.bv128(i: bv96) returns (bv128);"); @@ -561,6 +463,7 @@ void __SMACK_decls(void) { DECLARE(INLINE_CONVERSION,bv1,bv48,$sext,{if i == 0bv1 then 0bv48 else 281474976710655bv48}); DECLARE(INLINE_CONVERSION,bv1,bv56,$sext,{if i == 0bv1 then 0bv56 else 72057594037927935bv56}); DECLARE(INLINE_CONVERSION,bv1,bv64,$sext,{if i == 0bv1 then 0bv64 else 18446744073709551615bv64}); + DECLARE(INLINE_CONVERSION,bv1,bv80,$sext,{if i == 0bv1 then 0bv80 else 1208925819614629174706175bv80}); DECLARE(INLINE_CONVERSION,bv1,bv88,$sext,{if i == 0bv1 then 0bv88 else 309485009821345068724781055bv88}); DECLARE(INLINE_CONVERSION,bv1,bv96,$sext,{if i == 0bv1 then 0bv96 else 79228162514264337593543950335bv96}); DECLARE(INLINE_CONVERSION,bv1,bv128,$sext,{if i == 0bv1 then 0bv128 else 340282366920938463463374607431768211455bv128}); @@ -571,6 +474,7 @@ void __SMACK_decls(void) { D("function {:bvbuiltin \"(_ sign_extend 40)\"} $sext.bv8.bv48(i: bv8) returns (bv48);"); D("function {:bvbuiltin \"(_ sign_extend 48)\"} $sext.bv8.bv56(i: bv8) returns (bv56);"); D("function {:bvbuiltin \"(_ sign_extend 56)\"} $sext.bv8.bv64(i: bv8) returns (bv64);"); + D("function {:bvbuiltin \"(_ sign_extend 72)\"} $sext.bv8.bv80(i: bv8) returns (bv80);"); D("function {:bvbuiltin \"(_ sign_extend 80)\"} $sext.bv8.bv88(i: bv8) returns (bv88);"); D("function {:bvbuiltin \"(_ sign_extend 88)\"} $sext.bv8.bv96(i: bv8) returns (bv96);"); D("function {:bvbuiltin \"(_ sign_extend 120)\"} $sext.bv8.bv128(i: bv8) returns (bv128);"); @@ -580,6 +484,7 @@ void __SMACK_decls(void) { D("function {:bvbuiltin \"(_ sign_extend 32)\"} $sext.bv16.bv48(i: bv16) returns (bv48);"); D("function {:bvbuiltin \"(_ sign_extend 40)\"} $sext.bv16.bv56(i: bv16) returns (bv56);"); D("function {:bvbuiltin \"(_ sign_extend 48)\"} $sext.bv16.bv64(i: bv16) returns (bv64);"); + D("function {:bvbuiltin \"(_ sign_extend 64)\"} $sext.bv16.bv80(i: bv16) returns (bv80);"); D("function {:bvbuiltin \"(_ sign_extend 72)\"} $sext.bv16.bv88(i: bv16) returns (bv88);"); D("function {:bvbuiltin \"(_ sign_extend 80)\"} $sext.bv16.bv96(i: bv16) returns (bv96);"); D("function {:bvbuiltin \"(_ sign_extend 112)\"} $sext.bv16.bv128(i: bv16) returns (bv128);"); @@ -588,6 +493,7 @@ void __SMACK_decls(void) { D("function {:bvbuiltin \"(_ sign_extend 24)\"} $sext.bv24.bv48(i: bv24) returns (bv48);"); D("function {:bvbuiltin \"(_ sign_extend 32)\"} $sext.bv24.bv56(i: bv24) returns (bv56);"); D("function {:bvbuiltin \"(_ sign_extend 40)\"} $sext.bv24.bv64(i: bv24) returns (bv64);"); + D("function {:bvbuiltin \"(_ sign_extend 56)\"} $sext.bv24.bv80(i: bv24) returns (bv80);"); D("function {:bvbuiltin \"(_ sign_extend 64)\"} $sext.bv24.bv88(i: bv24) returns (bv88);"); D("function {:bvbuiltin \"(_ sign_extend 72)\"} $sext.bv24.bv96(i: bv24) returns (bv96);"); D("function {:bvbuiltin \"(_ sign_extend 104)\"} $sext.bv24.bv128(i: bv24) returns (bv128);"); @@ -595,73 +501,47 @@ void __SMACK_decls(void) { D("function {:bvbuiltin \"(_ sign_extend 16)\"} $sext.bv32.bv48(i: bv32) returns (bv48);"); D("function {:bvbuiltin \"(_ sign_extend 24)\"} $sext.bv32.bv56(i: bv32) returns (bv56);"); D("function {:bvbuiltin \"(_ sign_extend 32)\"} $sext.bv32.bv64(i: bv32) returns (bv64);"); + D("function {:bvbuiltin \"(_ sign_extend 48)\"} $sext.bv32.bv80(i: bv32) returns (bv80);"); D("function {:bvbuiltin \"(_ sign_extend 56)\"} $sext.bv32.bv88(i: bv32) returns (bv88);"); D("function {:bvbuiltin \"(_ sign_extend 64)\"} $sext.bv32.bv96(i: bv32) returns (bv96);"); D("function {:bvbuiltin \"(_ sign_extend 96)\"} $sext.bv32.bv128(i: bv32) returns (bv128);"); D("function {:bvbuiltin \"(_ sign_extend 8)\"} $sext.bv40.bv48(i: bv40) returns (bv48);"); D("function {:bvbuiltin \"(_ sign_extend 16)\"} $sext.bv40.bv56(i: bv40) returns (bv56);"); D("function {:bvbuiltin \"(_ sign_extend 24)\"} $sext.bv40.bv64(i: bv40) returns (bv64);"); + D("function {:bvbuiltin \"(_ sign_extend 40)\"} $sext.bv40.bv80(i: bv40) returns (bv80);"); D("function {:bvbuiltin \"(_ sign_extend 48)\"} $sext.bv40.bv88(i: bv40) returns (bv88);"); D("function {:bvbuiltin \"(_ sign_extend 56)\"} $sext.bv40.bv96(i: bv40) returns (bv96);"); D("function {:bvbuiltin \"(_ sign_extend 88)\"} $sext.bv40.bv128(i: bv40) returns (bv128);"); D("function {:bvbuiltin \"(_ sign_extend 8)\"} $sext.bv48.bv56(i: bv48) returns (bv56);"); D("function {:bvbuiltin \"(_ sign_extend 16)\"} $sext.bv48.bv64(i: bv48) returns (bv64);"); + D("function {:bvbuiltin \"(_ sign_extend 32)\"} $sext.bv48.bv80(i: bv48) returns (bv80);"); D("function {:bvbuiltin \"(_ sign_extend 40)\"} $sext.bv48.bv88(i: bv48) returns (bv88);"); D("function {:bvbuiltin \"(_ sign_extend 48)\"} $sext.bv48.bv96(i: bv48) returns (bv96);"); D("function {:bvbuiltin \"(_ sign_extend 80)\"} $sext.bv48.bv128(i: bv48) returns (bv128);"); D("function {:bvbuiltin \"(_ sign_extend 8)\"} $sext.bv56.bv64(i: bv56) returns (bv64);"); + D("function {:bvbuiltin \"(_ sign_extend 24)\"} $sext.bv56.bv80(i: bv56) returns (bv80);"); D("function {:bvbuiltin \"(_ sign_extend 32)\"} $sext.bv56.bv88(i: bv56) returns (bv88);"); D("function {:bvbuiltin \"(_ sign_extend 40)\"} $sext.bv56.bv96(i: bv56) returns (bv96);"); D("function {:bvbuiltin \"(_ sign_extend 72)\"} $sext.bv56.bv128(i: bv56) returns (bv128);"); + D("function {:bvbuiltin \"(_ sign_extend 16)\"} $sext.bv64.bv80(i: bv64) returns (bv80);"); D("function {:bvbuiltin \"(_ sign_extend 24)\"} $sext.bv64.bv88(i: bv64) returns (bv88);"); D("function {:bvbuiltin \"(_ sign_extend 32)\"} $sext.bv64.bv96(i: bv64) returns (bv96);"); D("function {:bvbuiltin \"(_ sign_extend 64)\"} $sext.bv64.bv128(i: bv64) returns (bv128);"); + D("function {:bvbuiltin \"(_ sign_extend 8)\"} $sext.bv80.bv88(i: bv80) returns (bv88);"); + D("function {:bvbuiltin \"(_ sign_extend 16)\"} $sext.bv80.bv96(i: bv80) returns (bv96);"); + D("function {:bvbuiltin \"(_ sign_extend 48)\"} $sext.bv80.bv128(i: bv80) returns (bv128);"); D("function {:bvbuiltin \"(_ sign_extend 8)\"} $sext.bv88.bv96(i: bv88) returns (bv96);"); D("function {:bvbuiltin \"(_ sign_extend 40)\"} $sext.bv88.bv128(i: bv88) returns (bv128);"); D("function {:bvbuiltin \"(_ sign_extend 32)\"} $sext.bv96.bv128(i: bv96) returns (bv128);"); // INTEGER MODELING - DECLARE_EACH_INT_TYPE(INLINE_BINARY_OP, $add, {i1 + i2}) - DECLARE_EACH_INT_TYPE(INLINE_BINARY_OP, $sub, {i1 - i2}) - DECLARE_EACH_INT_TYPE(INLINE_BINARY_OP, $mul, {i1 * i2}) D("function {:builtin \"div\"} $div(i1: int, i2: int) returns (int);"); D("function {:builtin \"mod\"} $mod(i1: int, i2: int) returns (int);"); D("function {:builtin \"rem\"} $rem(i1: int, i2: int) returns (int);"); D("function {:inline} $min(i1: int, i2: int) returns (int) {if i1 < i2 then i1 else i2}"); D("function {:inline} $max(i1: int, i2: int) returns (int) {if i1 > i2 then i1 else i2}"); - DECLARE_EACH_INT_TYPE(BUILTIN_BINARY_OP, $sdiv, div) - DECLARE_EACH_INT_TYPE(BUILTIN_BINARY_OP, $smod, mod) - DECLARE_EACH_INT_TYPE(BUILTIN_BINARY_OP, $srem, rem) - DECLARE_EACH_INT_TYPE(BUILTIN_BINARY_OP, $udiv, div); - DECLARE_EACH_INT_TYPE(BUILTIN_BINARY_OP, $urem, rem); - - DECLARE_EACH_INT_TYPE(INLINE_BINARY_OP, $smin, {$min(i1,i2)}) - DECLARE_EACH_INT_TYPE(INLINE_BINARY_OP, $smax, {$max(i1,i2)}) - DECLARE_EACH_INT_TYPE(INLINE_BINARY_OP, $umin, {$min(i1,i2)}) - DECLARE_EACH_INT_TYPE(INLINE_BINARY_OP, $umax, {$max(i1,i2)}) - - DECLARE_EACH_INT_TYPE(UNINTERPRETED_BINARY_OP, $shl) - DECLARE_EACH_INT_TYPE(UNINTERPRETED_BINARY_OP, $lshr) - DECLARE_EACH_INT_TYPE(UNINTERPRETED_BINARY_OP, $ashr) - DECLARE_EACH_INT_TYPE(UNINTERPRETED_UNARY_OP, $not) - DECLARE_EACH_INT_TYPE(UNINTERPRETED_BINARY_OP, $and) - DECLARE_EACH_INT_TYPE(UNINTERPRETED_BINARY_OP, $or) - DECLARE_EACH_INT_TYPE(UNINTERPRETED_BINARY_OP, $xor) - DECLARE_EACH_INT_TYPE(UNINTERPRETED_BINARY_OP, $nand) - - DECLARE_EACH_INT_TYPE(INLINE_BINARY_PRED, $eq, i1 == i2) - DECLARE_EACH_INT_TYPE(INLINE_BINARY_PRED, $ne, i1 != i2) - DECLARE_EACH_INT_TYPE(INLINE_BINARY_PRED, $ule, i1 <= i2) - DECLARE_EACH_INT_TYPE(INLINE_BINARY_PRED, $ult, i1 < i2) - DECLARE_EACH_INT_TYPE(INLINE_BINARY_PRED, $uge, i1 >= i2) - DECLARE_EACH_INT_TYPE(INLINE_BINARY_PRED, $ugt, i1 > i2) - DECLARE_EACH_INT_TYPE(INLINE_BINARY_PRED, $sle, i1 <= i2) - DECLARE_EACH_INT_TYPE(INLINE_BINARY_PRED, $slt, i1 < i2) - DECLARE_EACH_INT_TYPE(INLINE_BINARY_PRED, $sge, i1 >= i2) - DECLARE_EACH_INT_TYPE(INLINE_BINARY_PRED, $sgt, i1 > i2) - D("axiom $and.i1(0,0) == 0;"); D("axiom $and.i1(0,1) == 0;"); D("axiom $and.i1(1,0) == 0;"); @@ -676,704 +556,588 @@ void __SMACK_decls(void) { D("axiom $xor.i1(1,1) == 0;"); D("axiom($and.i32(32, 16) == 0);"); - DECLARE(INLINE_CONVERSION,i128,i96,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i128,i88,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i128,i64,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i128,i56,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i128,i48,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i128,i40,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i128,i32,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i128,i24,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i128,i16,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i128,i8,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i128,i1,$trunc,{i}); - - DECLARE(INLINE_CONVERSION,i96,i64,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i96,i88,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i96,i56,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i96,i48,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i96,i40,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i96,i32,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i96,i24,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i96,i16,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i96,i8,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i96,i1,$trunc,{i}); - - DECLARE(INLINE_CONVERSION,i88,i64,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i88,i88,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i88,i56,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i88,i48,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i88,i40,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i88,i32,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i88,i24,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i88,i16,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i88,i8,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i88,i1,$trunc,{i}); - - DECLARE(INLINE_CONVERSION,i64,i56,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i64,i48,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i64,i40,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i64,i32,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i64,i24,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i64,i16,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i64,i8,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i64,i1,$trunc,{i}); - - DECLARE(INLINE_CONVERSION,i56,i48,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i56,i40,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i56,i32,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i56,i24,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i56,i16,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i56,i8,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i56,i1,$trunc,{i}); - - DECLARE(INLINE_CONVERSION,i48,i40,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i48,i32,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i48,i24,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i48,i16,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i48,i8,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i48,i1,$trunc,{i}); - - DECLARE(INLINE_CONVERSION,i40,i32,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i40,i24,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i40,i16,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i40,i8,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i40,i1,$trunc,{i}); - - DECLARE(INLINE_CONVERSION,i32,i24,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i32,i16,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i32,i8,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i32,i1,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i24,i16,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i24,i8,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i24,i1,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i16,i8,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i16,i1,$trunc,{i}); - DECLARE(INLINE_CONVERSION,i8,i1,$trunc,{i}); - - DECLARE(INLINE_CONVERSION,i1,i8,$zext,{i}); - DECLARE(INLINE_CONVERSION,i1,i16,$zext,{i}); - DECLARE(INLINE_CONVERSION,i1,i24,$zext,{i}); - DECLARE(INLINE_CONVERSION,i1,i32,$zext,{i}); - DECLARE(INLINE_CONVERSION,i1,i40,$zext,{i}); - DECLARE(INLINE_CONVERSION,i1,i48,$zext,{i}); - DECLARE(INLINE_CONVERSION,i1,i56,$zext,{i}); - DECLARE(INLINE_CONVERSION,i1,i64,$zext,{i}); - DECLARE(INLINE_CONVERSION,i1,i88,$zext,{i}); - DECLARE(INLINE_CONVERSION,i1,i96,$zext,{i}); - DECLARE(INLINE_CONVERSION,i1,i128,$zext,{i}); - DECLARE(INLINE_CONVERSION,i8,i16,$zext,{i}); - DECLARE(INLINE_CONVERSION,i8,i24,$zext,{i}); - DECLARE(INLINE_CONVERSION,i8,i32,$zext,{i}); - DECLARE(INLINE_CONVERSION,i8,i40,$zext,{i}); - DECLARE(INLINE_CONVERSION,i8,i48,$zext,{i}); - DECLARE(INLINE_CONVERSION,i8,i56,$zext,{i}); - DECLARE(INLINE_CONVERSION,i8,i64,$zext,{i}); - DECLARE(INLINE_CONVERSION,i8,i88,$zext,{i}); - DECLARE(INLINE_CONVERSION,i8,i96,$zext,{i}); - DECLARE(INLINE_CONVERSION,i8,i128,$zext,{i}); - DECLARE(INLINE_CONVERSION,i16,i24,$zext,{i}); - DECLARE(INLINE_CONVERSION,i16,i32,$zext,{i}); - DECLARE(INLINE_CONVERSION,i16,i40,$zext,{i}); - DECLARE(INLINE_CONVERSION,i16,i48,$zext,{i}); - DECLARE(INLINE_CONVERSION,i16,i56,$zext,{i}); - DECLARE(INLINE_CONVERSION,i16,i64,$zext,{i}); - DECLARE(INLINE_CONVERSION,i16,i88,$zext,{i}); - DECLARE(INLINE_CONVERSION,i16,i96,$zext,{i}); - DECLARE(INLINE_CONVERSION,i16,i128,$zext,{i}); - DECLARE(INLINE_CONVERSION,i24,i32,$zext,{i}); - DECLARE(INLINE_CONVERSION,i24,i40,$zext,{i}); - DECLARE(INLINE_CONVERSION,i24,i48,$zext,{i}); - DECLARE(INLINE_CONVERSION,i24,i56,$zext,{i}); - DECLARE(INLINE_CONVERSION,i24,i64,$zext,{i}); - DECLARE(INLINE_CONVERSION,i24,i88,$zext,{i}); - DECLARE(INLINE_CONVERSION,i24,i96,$zext,{i}); - DECLARE(INLINE_CONVERSION,i24,i128,$zext,{i}); - DECLARE(INLINE_CONVERSION,i32,i40,$zext,{i}); - DECLARE(INLINE_CONVERSION,i32,i48,$zext,{i}); - DECLARE(INLINE_CONVERSION,i32,i56,$zext,{i}); - DECLARE(INLINE_CONVERSION,i32,i64,$zext,{i}); - DECLARE(INLINE_CONVERSION,i32,i88,$zext,{i}); - DECLARE(INLINE_CONVERSION,i32,i96,$zext,{i}); - DECLARE(INLINE_CONVERSION,i32,i128,$zext,{i}); - DECLARE(INLINE_CONVERSION,i40,i48,$zext,{i}); - DECLARE(INLINE_CONVERSION,i40,i56,$zext,{i}); - DECLARE(INLINE_CONVERSION,i40,i64,$zext,{i}); - DECLARE(INLINE_CONVERSION,i40,i88,$zext,{i}); - DECLARE(INLINE_CONVERSION,i40,i96,$zext,{i}); - DECLARE(INLINE_CONVERSION,i40,i128,$zext,{i}); - DECLARE(INLINE_CONVERSION,i48,i56,$zext,{i}); - DECLARE(INLINE_CONVERSION,i48,i64,$zext,{i}); - DECLARE(INLINE_CONVERSION,i48,i88,$zext,{i}); - DECLARE(INLINE_CONVERSION,i48,i96,$zext,{i}); - DECLARE(INLINE_CONVERSION,i48,i128,$zext,{i}); - DECLARE(INLINE_CONVERSION,i56,i64,$zext,{i}); - DECLARE(INLINE_CONVERSION,i56,i88,$zext,{i}); - DECLARE(INLINE_CONVERSION,i56,i96,$zext,{i}); - DECLARE(INLINE_CONVERSION,i56,i128,$zext,{i}); - DECLARE(INLINE_CONVERSION,i64,i88,$zext,{i}); - DECLARE(INLINE_CONVERSION,i64,i96,$zext,{i}); - DECLARE(INLINE_CONVERSION,i64,i128,$zext,{i}); - DECLARE(INLINE_CONVERSION,i88,i96,$zext,{i}); - DECLARE(INLINE_CONVERSION,i88,i128,$zext,{i}); - DECLARE(INLINE_CONVERSION,i96,i128,$zext,{i}); - - DECLARE(INLINE_CONVERSION,i1,i8,$sext,{i}); - DECLARE(INLINE_CONVERSION,i1,i16,$sext,{i}); - DECLARE(INLINE_CONVERSION,i1,i24,$sext,{i}); - DECLARE(INLINE_CONVERSION,i1,i32,$sext,{i}); - DECLARE(INLINE_CONVERSION,i1,i40,$sext,{i}); - DECLARE(INLINE_CONVERSION,i1,i48,$sext,{i}); - DECLARE(INLINE_CONVERSION,i1,i56,$sext,{i}); - DECLARE(INLINE_CONVERSION,i1,i64,$sext,{i}); - DECLARE(INLINE_CONVERSION,i1,i88,$sext,{i}); - DECLARE(INLINE_CONVERSION,i1,i96,$sext,{i}); - DECLARE(INLINE_CONVERSION,i1,i128,$sext,{i}); - DECLARE(INLINE_CONVERSION,i8,i16,$sext,{i}); - DECLARE(INLINE_CONVERSION,i8,i24,$sext,{i}); - DECLARE(INLINE_CONVERSION,i8,i32,$sext,{i}); - DECLARE(INLINE_CONVERSION,i8,i40,$sext,{i}); - DECLARE(INLINE_CONVERSION,i8,i48,$sext,{i}); - DECLARE(INLINE_CONVERSION,i8,i56,$sext,{i}); - DECLARE(INLINE_CONVERSION,i8,i64,$sext,{i}); - DECLARE(INLINE_CONVERSION,i8,i88,$sext,{i}); - DECLARE(INLINE_CONVERSION,i8,i96,$sext,{i}); - DECLARE(INLINE_CONVERSION,i8,i128,$sext,{i}); - DECLARE(INLINE_CONVERSION,i16,i24,$sext,{i}); - DECLARE(INLINE_CONVERSION,i16,i32,$sext,{i}); - DECLARE(INLINE_CONVERSION,i16,i40,$sext,{i}); - DECLARE(INLINE_CONVERSION,i16,i48,$sext,{i}); - DECLARE(INLINE_CONVERSION,i16,i56,$sext,{i}); - DECLARE(INLINE_CONVERSION,i16,i64,$sext,{i}); - DECLARE(INLINE_CONVERSION,i16,i88,$sext,{i}); - DECLARE(INLINE_CONVERSION,i16,i96,$sext,{i}); - DECLARE(INLINE_CONVERSION,i16,i128,$sext,{i}); - DECLARE(INLINE_CONVERSION,i24,i32,$sext,{i}); - DECLARE(INLINE_CONVERSION,i24,i40,$sext,{i}); - DECLARE(INLINE_CONVERSION,i24,i48,$sext,{i}); - DECLARE(INLINE_CONVERSION,i24,i56,$sext,{i}); - DECLARE(INLINE_CONVERSION,i24,i64,$sext,{i}); - DECLARE(INLINE_CONVERSION,i24,i88,$sext,{i}); - DECLARE(INLINE_CONVERSION,i24,i96,$sext,{i}); - DECLARE(INLINE_CONVERSION,i24,i128,$sext,{i}); - DECLARE(INLINE_CONVERSION,i32,i40,$sext,{i}); - DECLARE(INLINE_CONVERSION,i32,i48,$sext,{i}); - DECLARE(INLINE_CONVERSION,i32,i56,$sext,{i}); - DECLARE(INLINE_CONVERSION,i32,i64,$sext,{i}); - DECLARE(INLINE_CONVERSION,i32,i88,$sext,{i}); - DECLARE(INLINE_CONVERSION,i32,i96,$sext,{i}); - DECLARE(INLINE_CONVERSION,i32,i128,$sext,{i}); - DECLARE(INLINE_CONVERSION,i40,i48,$sext,{i}); - DECLARE(INLINE_CONVERSION,i40,i56,$sext,{i}); - DECLARE(INLINE_CONVERSION,i40,i64,$sext,{i}); - DECLARE(INLINE_CONVERSION,i40,i88,$sext,{i}); - DECLARE(INLINE_CONVERSION,i40,i96,$sext,{i}); - DECLARE(INLINE_CONVERSION,i40,i128,$sext,{i}); - DECLARE(INLINE_CONVERSION,i48,i56,$sext,{i}); - DECLARE(INLINE_CONVERSION,i48,i64,$sext,{i}); - DECLARE(INLINE_CONVERSION,i48,i88,$sext,{i}); - DECLARE(INLINE_CONVERSION,i48,i96,$sext,{i}); - DECLARE(INLINE_CONVERSION,i48,i128,$sext,{i}); - DECLARE(INLINE_CONVERSION,i56,i64,$sext,{i}); - DECLARE(INLINE_CONVERSION,i56,i88,$sext,{i}); - DECLARE(INLINE_CONVERSION,i56,i96,$sext,{i}); - DECLARE(INLINE_CONVERSION,i56,i128,$sext,{i}); - DECLARE(INLINE_CONVERSION,i64,i88,$sext,{i}); - DECLARE(INLINE_CONVERSION,i64,i96,$sext,{i}); - DECLARE(INLINE_CONVERSION,i64,i128,$sext,{i}); - DECLARE(INLINE_CONVERSION,i88,i96,$sext,{i}); - DECLARE(INLINE_CONVERSION,i88,i128,$sext,{i}); - DECLARE(INLINE_CONVERSION,i96,i128,$sext,{i}); - - //Non bit-precise modeling of floating-points - - D("function $fp(ipart:int, fpart:int, epart:int) returns (float);"); - D("function $fadd.float(f1:float, f2:float) returns (float);"); - D("function $fsub.float(f1:float, f2:float) returns (float);"); - D("function $fmul.float(f1:float, f2:float) returns (float);"); - D("function $fdiv.float(f1:float, f2:float) returns (float);"); - D("function $frem.float(f1:float, f2:float) returns (float);"); - D("function $ffalse.float(f1:float, f2:float) returns (i1);"); - D("function $ftrue.float(f1:float, f2:float) returns (i1);"); - D("function {:inline} $foeq.float(f1:float, f2:float) returns (i1) { if $foeq.bool(f1,f2) then 1 else 0 }"); - D("function $foeq.bool(f1:float, f2:float) returns (bool);"); - D("function $foge.float(f1:float, f2:float) returns (i1);"); - D("function $fogt.float(f1:float, f2:float) returns (i1);"); - D("function $fole.float(f1:float, f2:float) returns (i1);"); - D("function $folt.float(f1:float, f2:float) returns (i1);"); - D("function $fone.float(f1:float, f2:float) returns (i1);"); - D("function $ford.float(f1:float, f2:float) returns (i1);"); - D("function $fueq.float(f1:float, f2:float) returns (i1);"); - D("function $fuge.float(f1:float, f2:float) returns (i1);"); - D("function $fugt.float(f1:float, f2:float) returns (i1);"); - D("function $fule.float(f1:float, f2:float) returns (i1);"); - D("function $fult.float(f1:float, f2:float) returns (i1);"); - D("function $fune.float(f1:float, f2:float) returns (i1);"); - D("function $funo.float(f1:float, f2:float) returns (i1);"); - - D("function $fp2si.float.i128(f:float) returns (i128);"); - D("function $fp2ui.float.i128(f:float) returns (i128);"); - D("function $si2fp.i128.float(i:i128) returns (float);"); - D("function $ui2fp.i128.float(i:i128) returns (float);"); - D("function $fp2si.float.i96(f:float) returns (i96);"); - D("function $fp2ui.float.i96(f:float) returns (i96);"); - D("function $si2fp.i96.float(i:i96) returns (float);"); - D("function $ui2fp.i96.float(i:i96) returns (float);"); - D("function $fp2si.float.i88(f:float) returns (i88);"); - D("function $fp2ui.float.i88(f:float) returns (i88);"); - D("function $si2fp.i88.float(i:i88) returns (float);"); - D("function $ui2fp.i88.float(i:i88) returns (float);"); - D("function $fp2si.float.i64(f:float) returns (i64);"); - D("function $fp2ui.float.i64(f:float) returns (i64);"); - D("function $si2fp.i64.float(i:i64) returns (float);"); - D("function $ui2fp.i64.float(i:i64) returns (float);"); - D("function $fp2si.float.i56(f:float) returns (i56);"); - D("function $fp2ui.float.i56(f:float) returns (i56);"); - D("function $si2fp.i56.float(i:i56) returns (float);"); - D("function $ui2fp.i56.float(i:i56) returns (float);"); - D("function $fp2si.float.i48(f:float) returns (i48);"); - D("function $fp2ui.float.i48(f:float) returns (i48);"); - D("function $si2fp.i48.float(i:i48) returns (float);"); - D("function $ui2fp.i48.float(i:i48) returns (float);"); - D("function $fp2si.float.i40(f:float) returns (i40);"); - D("function $fp2ui.float.i40(f:float) returns (i40);"); - D("function $si2fp.i40.float(i:i40) returns (float);"); - D("function $ui2fp.i40.float(i:i40) returns (float);"); - - D("function $fp2si.float.i32(f:float) returns (i32);"); - D("function $fp2ui.float.i32(f:float) returns (i32);"); - D("function $si2fp.i32.float(i:i32) returns (float);"); - D("function $ui2fp.i32.float(i:i32) returns (float);"); - D("function $fp2si.float.i24(f:float) returns (i24);"); - D("function $fp2ui.float.i24(f:float) returns (i24);"); - D("function $si2fp.i24.float(i:i24) returns (float);"); - D("function $ui2fp.i24.float(i:i24) returns (float);"); - D("function $fp2si.float.i16(f:float) returns (i16);"); - D("function $fp2ui.float.i16(f:float) returns (i16);"); - D("function $si2fp.i16.float(i:i16) returns (float);"); - D("function $ui2fp.i16.float(i:i16) returns (float);"); - D("function $fp2si.float.i8(f:float) returns (i8);"); - D("function $fp2ui.float.i8(f:float) returns (i8);"); - D("function $si2fp.i8.float(i:i8) returns (float);"); - D("function $ui2fp.i8.float(i:i8) returns (float);"); - - D("function $fptrunc.float.float(f:float) returns (float);"); - D("function $fpext.float.float(f:float) returns (float);"); - D("function $fp2si.float.bv128(f:float) returns (bv128);"); - D("function $fp2ui.float.bv128(f:float) returns (bv128);"); - D("function $si2fp.bv128.float(i:bv128) returns (float);"); - D("function $ui2fp.bv128.float(i:bv128) returns (float);"); - D("function $fp2si.float.bv96(f:float) returns (bv96);"); - D("function $fp2ui.float.bv96(f:float) returns (bv96);"); - D("function $si2fp.bv96.float(i:bv96) returns (float);"); - D("function $ui2fp.bv96.float(i:bv96) returns (float);"); - D("function $fp2si.float.bv88(f:float) returns (bv88);"); - D("function $fp2ui.float.bv88(f:float) returns (bv88);"); - D("function $si2fp.bv88.float(i:bv88) returns (float);"); - D("function $ui2fp.bv88.float(i:bv88) returns (float);"); - D("function $fp2si.float.bv64(f:float) returns (bv64);"); - D("function $fp2ui.float.bv64(f:float) returns (bv64);"); - D("function $si2fp.bv64.float(i:bv64) returns (float);"); - D("function $ui2fp.bv64.float(i:bv64) returns (float);"); - D("function $fp2si.float.bv56(f:float) returns (bv56);"); - D("function $fp2ui.float.bv56(f:float) returns (bv56);"); - D("function $si2fp.bv56.float(i:bv56) returns (float);"); - D("function $ui2fp.bv56.float(i:bv56) returns (float);"); - D("function $fp2si.float.bv48(f:float) returns (bv48);"); - D("function $fp2ui.float.bv48(f:float) returns (bv48);"); - D("function $si2fp.bv48.float(i:bv48) returns (float);"); - D("function $ui2fp.bv48.float(i:bv48) returns (float);"); - D("function $fp2si.float.bv40(f:float) returns (bv40);"); - D("function $fp2ui.float.bv40(f:float) returns (bv40);"); - D("function $si2fp.bv40.float(i:bv40) returns (float);"); - D("function $ui2fp.bv40.float(i:bv40) returns (float);"); - D("function $fp2si.float.bv32(f:float) returns (bv32);"); - D("function $fp2ui.float.bv32(f:float) returns (bv32);"); - D("function $si2fp.bv32.float(i:bv32) returns (float);"); - D("function $ui2fp.bv32.float(i:bv32) returns (float);"); - D("function $fp2si.float.bv24(f:float) returns (bv24);"); - D("function $fp2ui.float.bv24(f:float) returns (bv24);"); - D("function $si2fp.bv24.float(i:bv24) returns (float);"); - D("function $ui2fp.bv24.float(i:bv24) returns (float);"); - D("function $fp2si.float.bv16(f:float) returns (bv16);"); - D("function $fp2ui.float.bv16(f:float) returns (bv16);"); - D("function $si2fp.bv16.float(i:bv16) returns (float);"); - D("function $ui2fp.bv16.float(i:bv16) returns (float);"); - D("function $fp2si.float.bv8(f:float) returns (bv8);"); - D("function $fp2ui.float.bv8(f:float) returns (bv8);"); - D("function $si2fp.bv8.float(i:bv8) returns (float);"); - D("function $ui2fp.bv8.float(i:bv8) returns (float);"); - -#ifndef NO_FORALL - D("axiom (forall f1, f2: float :: f1 != f2 || $foeq.bool(f1,f2));"); - D("axiom (forall i: i128 :: $fp2ui.float.i128($ui2fp.i128.float(i)) == i);"); - D("axiom (forall f: float :: $ui2fp.i128.float($fp2ui.float.i128(f)) == f);"); - D("axiom (forall i: i128 :: $fp2si.float.i128($si2fp.i128.float(i)) == i);"); - D("axiom (forall f: float :: $si2fp.i128.float($fp2si.float.i128(f)) == f);"); - D("axiom (forall i: i96 :: $fp2ui.float.i96($ui2fp.i96.float(i)) == i);"); - D("axiom (forall f: float :: $ui2fp.i96.float($fp2ui.float.i96(f)) == f);"); - D("axiom (forall i: i96 :: $fp2si.float.i96($si2fp.i96.float(i)) == i);"); - D("axiom (forall f: float :: $si2fp.i96.float($fp2si.float.i96(f)) == f);"); - D("axiom (forall i: i88 :: $fp2ui.float.i88($ui2fp.i88.float(i)) == i);"); - D("axiom (forall f: float :: $ui2fp.i88.float($fp2ui.float.i88(f)) == f);"); - D("axiom (forall i: i88 :: $fp2si.float.i88($si2fp.i88.float(i)) == i);"); - D("axiom (forall f: float :: $si2fp.i88.float($fp2si.float.i88(f)) == f);"); - D("axiom (forall i: i64 :: $fp2ui.float.i64($ui2fp.i64.float(i)) == i);"); - D("axiom (forall f: float :: $ui2fp.i64.float($fp2ui.float.i64(f)) == f);"); - D("axiom (forall i: i64 :: $fp2si.float.i64($si2fp.i64.float(i)) == i);"); - D("axiom (forall f: float :: $si2fp.i64.float($fp2si.float.i64(f)) == f);"); - D("axiom (forall i: i56 :: $fp2ui.float.i56($ui2fp.i56.float(i)) == i);"); - D("axiom (forall f: float :: $ui2fp.i56.float($fp2ui.float.i56(f)) == f);"); - D("axiom (forall i: i56 :: $fp2si.float.i56($si2fp.i56.float(i)) == i);"); - D("axiom (forall f: float :: $si2fp.i56.float($fp2si.float.i56(f)) == f);"); - D("axiom (forall i: i48 :: $fp2ui.float.i48($ui2fp.i48.float(i)) == i);"); - D("axiom (forall f: float :: $ui2fp.i48.float($fp2ui.float.i48(f)) == f);"); - D("axiom (forall i: i48 :: $fp2si.float.i48($si2fp.i48.float(i)) == i);"); - D("axiom (forall f: float :: $si2fp.i48.float($fp2si.float.i48(f)) == f);"); - D("axiom (forall i: i40 :: $fp2ui.float.i40($ui2fp.i40.float(i)) == i);"); - D("axiom (forall f: float :: $ui2fp.i40.float($fp2ui.float.i40(f)) == f);"); - D("axiom (forall i: i40 :: $fp2si.float.i40($si2fp.i40.float(i)) == i);"); - D("axiom (forall f: float :: $si2fp.i40.float($fp2si.float.i40(f)) == f);"); - D("axiom (forall i: i32 :: $fp2ui.float.i32($ui2fp.i32.float(i)) == i);"); - D("axiom (forall f: float :: $ui2fp.i32.float($fp2ui.float.i32(f)) == f);"); - D("axiom (forall i: i32 :: $fp2si.float.i32($si2fp.i32.float(i)) == i);"); - D("axiom (forall f: float :: $si2fp.i32.float($fp2si.float.i32(f)) == f);"); - D("axiom (forall i: i24 :: $fp2ui.float.i24($ui2fp.i24.float(i)) == i);"); - D("axiom (forall f: float :: $ui2fp.i24.float($fp2ui.float.i24(f)) == f);"); - D("axiom (forall i: i24 :: $fp2si.float.i24($si2fp.i24.float(i)) == i);"); - D("axiom (forall f: float :: $si2fp.i24.float($fp2si.float.i24(f)) == f);"); - D("axiom (forall i: i16 :: $fp2ui.float.i16($ui2fp.i16.float(i)) == i);"); - D("axiom (forall f: float :: $ui2fp.i16.float($fp2ui.float.i16(f)) == f);"); - D("axiom (forall i: i16 :: $fp2si.float.i16($si2fp.i16.float(i)) == i);"); - D("axiom (forall f: float :: $si2fp.i16.float($fp2si.float.i16(f)) == f);"); - D("axiom (forall i: i8 :: $fp2ui.float.i8($ui2fp.i8.float(i)) == i);"); - D("axiom (forall f: float :: $ui2fp.i8.float($fp2ui.float.i8(f)) == f);"); - D("axiom (forall i: i8 :: $fp2si.float.i8($si2fp.i8.float(i)) == i);"); - D("axiom (forall f: float :: $si2fp.i8.float($fp2si.float.i8(f)) == f);"); -#endif - #if FLOAT_ENABLED // Bit-precise modeling of floating-points - DECLARE_EACH_FLOAT_TYPE(INLINE_BINARY_OP, $fadd, {i1 + i2}) - DECLARE_EACH_FLOAT_TYPE(INLINE_BINARY_OP, $fsub, {i1 - i2}) - DECLARE_EACH_FLOAT_TYPE(INLINE_BINARY_OP, $fmul, {i1 * i2}) - DECLARE_EACH_FLOAT_TYPE(INLINE_BINARY_OP, $fdiv, {i1 / i2}) - DECLARE_EACH_FLOAT_TYPE(FPBUILTIN_BINARY_OP, $frem, fp.rem) - D("function $ffalse.bvfloat(f1:bvfloat, f2:bvfloat) returns (i1);"); - D("function $ftrue.bvfloat(f1:bvfloat, f2:bvfloat) returns (i1);"); - - D("function {:builtin \"fp.abs\"} $abs.bvfloat(bvfloat) returns (bvfloat);"); - D("function {:builtin \"fp.fma\"} $fma.bvfloat(bvfloat, bvfloat, bvfloat) returns (bvfloat);"); - D("function {:builtin \"fp.sqrt\"} $sqrt.bvfloat(bvfloat) returns (bvfloat);"); - D("function {:builtin \"fp.rem\"} $rem.bvfloat(bvfloat, bvfloat) returns (bvfloat);"); - D("function {:builtin \"fp.min\"} $min.bvfloat(bvfloat, bvfloat) returns (bvfloat);"); - D("function {:builtin \"fp.max\"} $max.bvfloat(bvfloat, bvfloat) returns (bvfloat);"); - - D("function {:builtin \"fp.abs\"} $abs.bvdouble(bvdouble) returns (bvdouble);"); - D("function {:builtin \"fp.fma\"} $fma.bvdouble(bvdouble, bvdouble, bvdouble) returns (bvdouble);"); - D("function {:builtin \"fp.sqrt\"} $sqrt.bvdouble(bvdouble) returns (bvdouble);"); - D("function {:builtin \"fp.rem\"} $rem.bvdouble(bvdouble, bvdouble) returns (bvdouble);"); - D("function {:builtin \"fp.min\"} $min.bvdouble(bvdouble, bvdouble) returns (bvdouble);"); - D("function {:builtin \"fp.max\"} $max.bvdouble(bvdouble, bvdouble) returns (bvdouble);"); - - D("function {:builtin \"fp.isNormal\"} $isnormal.bvfloat(bvfloat) returns (bool);"); - D("function {:builtin \"fp.isSubnormal\"} $issubnormal.bvfloat(bvfloat) returns (bool);"); - D("function {:builtin \"fp.isZero\"} $iszero.bvfloat(bvfloat) returns (bool);"); - D("function {:builtin \"fp.isInfinite\"} $isinfinite.bvfloat(bvfloat) returns (bool);"); - D("function {:builtin \"fp.isNaN\"} $isnan.bvfloat(bvfloat) returns (bool);"); - D("function {:builtin \"fp.isNegative\"} $isnegative.bvfloat(bvfloat) returns (bool);"); - D("function {:builtin \"fp.isPositive\"} $ispositive.bvfloat(bvfloat) returns (bool);"); - - D("function {:builtin \"fp.isNormal\"} $isnormal.bvdouble(bvdouble) returns (bool);"); - D("function {:builtin \"fp.isSubnormal\"} $issubnormal.bvdouble(bvdouble) returns (bool);"); - D("function {:builtin \"fp.isZero\"} $iszero.bvdouble(bvdouble) returns (bool);"); - D("function {:builtin \"fp.isInfinite\"} $isinfinite.bvdouble(bvdouble) returns (bool);"); - D("function {:builtin \"fp.isNaN\"} $isnan.bvdouble(bvdouble) returns (bool);"); - D("function {:builtin \"fp.isNegative\"} $isnegative.bvdouble(bvdouble) returns (bool);"); - D("function {:builtin \"fp.isPositive\"} $ispositive.bvdouble(bvdouble) returns (bool);"); - - D("function {:builtin \"fp.isNormal\"} $isnormal.bvlongdouble(bvlongdouble) returns (bool);"); - D("function {:builtin \"fp.isSubnormal\"} $issubnormal.bvlongdouble(bvlongdouble) returns (bool);"); - D("function {:builtin \"fp.isZero\"} $iszero.bvlongdouble(bvlongdouble) returns (bool);"); - D("function {:builtin \"fp.isInfinite\"} $isinfinite.bvlongdouble(bvlongdouble) returns (bool);"); - D("function {:builtin \"fp.isNaN\"} $isnan.bvlongdouble(bvlongdouble) returns (bool);"); - D("function {:builtin \"fp.isNegative\"} $isnegative.bvlongdouble(bvlongdouble) returns (bool);"); - D("function {:builtin \"fp.isPositive\"} $ispositive.bvlongdouble(bvlongdouble) returns (bool);"); - - DECLARE_EACH_FLOAT_TYPE(INLINE_BINARY_BV_PRED, $foeq, i1 == i2) - DECLARE_EACH_FLOAT_TYPE(INLINE_BINARY_BV_PRED, $fone, !(i1 == i2)) - DECLARE_EACH_FLOAT_TYPE(INLINE_BINARY_BV_PRED, $fole, i1 <= i2) - DECLARE_EACH_FLOAT_TYPE(INLINE_BINARY_BV_PRED, $folt, i1 < i2) - DECLARE_EACH_FLOAT_TYPE(INLINE_BINARY_BV_PRED, $foge, i1 >= i2) - DECLARE_EACH_FLOAT_TYPE(INLINE_BINARY_BV_PRED, $fogt, i1 > i2) - DECLARE_EACH_FLOAT_TYPE(INLINE_BINARY_BV_PRED, $fueq, i1 == i2) - DECLARE_EACH_FLOAT_TYPE(INLINE_BINARY_BV_PRED, $fune, !(i1 == i2)) - DECLARE_EACH_FLOAT_TYPE(INLINE_BINARY_BV_PRED, $fule, i1 <= i2) - DECLARE_EACH_FLOAT_TYPE(INLINE_BINARY_BV_PRED, $fult, i1 < i2) - DECLARE_EACH_FLOAT_TYPE(INLINE_BINARY_BV_PRED, $fuge, i1 >= i2) - DECLARE_EACH_FLOAT_TYPE(INLINE_BINARY_BV_PRED, $fugt, i1 > i2) - - D("function {:builtin \"(_ to_fp 8 24) RNE\"} dtf(bvdouble) returns (bvfloat);"); - D("function {:builtin \"(_ to_fp 11 53) RNE\"} ftd(bvfloat) returns (bvdouble);"); - D("function {:builtin \"(_ to_fp 8 24) RNE\"} ltf(bvlongdouble) returns (bvfloat);"); - D("function {:builtin \"(_ to_fp 11 53) RNE\"} ltd(bvlongdouble) returns (bvdouble);"); - D("function {:builtin \"(_ to_fp 15 65) RNE\"} ftl(bvfloat) returns (bvlongdouble);"); - D("function {:builtin \"(_ to_fp 15 65) RNE\"} dtl(bvdouble) returns (bvlongdouble);"); - DECLARE(INLINE_CONVERSION,bvdouble,bvfloat,$fptrunc,{dtf(i)}); - DECLARE(INLINE_CONVERSION,bvfloat,bvdouble,$fpext,{ftd(i)}); - DECLARE(INLINE_CONVERSION,bvlongdouble,bvfloat,$fptrunc,{ltf(i)}); - DECLARE(INLINE_CONVERSION,bvlongdouble,bvdouble,$fptrunc,{ltd(i)}); - DECLARE(INLINE_CONVERSION,bvfloat,bvlongdouble,$fpext,{ftl(i)}); - DECLARE(INLINE_CONVERSION,bvdouble,bvlongdouble,$fpext,{dtl(i)}); - - //This isn't the correct implementation, so change as needed - D("function {:inline} $ford.bvfloat(f1:bvfloat, f2:bvfloat) returns (bv1);"); - D("function {:inline} $funo.bvfloat(f1:bvfloat, f2:bvfloat) returns (bv1);"); - - D("function $fptrunc.bvfloat.bvfloat(f:bvfloat) returns (bvfloat) {f}"); - D("function $fpext.bvfloat.bvfloat(f:bvfloat) returns (bvfloat) {f}"); - - D("function {:builtin \"(_ to_fp 8 24) RNE\"} sbv128tf(bv128) returns (bvfloat);"); - D("function {:builtin \"(_ to_fp 8 24) RNE\"} sbv96tf(bv96) returns (bvfloat);"); - D("function {:builtin \"(_ to_fp 8 24) RNE\"} sbv88tf(bv88) returns (bvfloat);"); - D("function {:builtin \"(_ to_fp 8 24) RNE\"} sbv64tf(bv64) returns (bvfloat);"); - D("function {:builtin \"(_ to_fp 8 24) RNE\"} sbv56tf(bv56) returns (bvfloat);"); - D("function {:builtin \"(_ to_fp 8 24) RNE\"} sbv48tf(bv48) returns (bvfloat);"); - D("function {:builtin \"(_ to_fp 8 24) RNE\"} sbv40tf(bv40) returns (bvfloat);"); - D("function {:builtin \"(_ to_fp 8 24) RNE\"} sbv32tf(bv32) returns (bvfloat);"); - D("function {:builtin \"(_ to_fp 8 24) RNE\"} sbv24tf(bv24) returns (bvfloat);"); - D("function {:builtin \"(_ to_fp 8 24) RNE\"} sbv16tf(bv16) returns (bvfloat);"); - D("function {:builtin \"(_ to_fp 8 24) RNE\"} sbv8tf(bv8) returns (bvfloat);"); - D("function {:builtin \"(_ to_fp 8 24) RNE\"} ubv128tf(bv128) returns (bvfloat);"); - D("function {:builtin \"(_ to_fp 8 24) RNE\"} ubv96tf(bv96) returns (bvfloat);"); - D("function {:builtin \"(_ to_fp 8 24) RNE\"} ubv88tf(bv88) returns (bvfloat);"); - D("function {:builtin \"(_ to_fp 8 24) RNE\"} ubv64tf(bv64) returns (bvfloat);"); - D("function {:builtin \"(_ to_fp 8 24) RNE\"} ubv56tf(bv56) returns (bvfloat);"); - D("function {:builtin \"(_ to_fp 8 24) RNE\"} ubv48tf(bv48) returns (bvfloat);"); - D("function {:builtin \"(_ to_fp 8 24) RNE\"} ubv40tf(bv40) returns (bvfloat);"); - D("function {:builtin \"(_ to_fp 8 24) RNE\"} ubv32tf(bv32) returns (bvfloat);"); - D("function {:builtin \"(_ to_fp 8 24) RNE\"} ubv24tf(bv24) returns (bvfloat);"); - D("function {:builtin \"(_ to_fp 8 24) RNE\"} ubv16tf(bv16) returns (bvfloat);"); - D("function {:builtin \"(_ to_fp 8 24) RNE\"} ubv8tf(bv8) returns (bvfloat);"); - D("function {:builtin \"(_ fp.to_sbv 128) RNE\"} ftsbv128(bvfloat) returns (bv128);"); - D("function {:builtin \"(_ fp.to_sbv 96) RNE\"} ftsbv96(bvfloat) returns (bv96);"); - D("function {:builtin \"(_ fp.to_sbv 88) RNE\"} ftsbv88(bvfloat) returns (bv88);"); - D("function {:builtin \"(_ fp.to_sbv 64) RNE\"} ftsbv64(bvfloat) returns (bv64);"); - D("function {:builtin \"(_ fp.to_sbv 56) RNE\"} ftsbv56(bvfloat) returns (bv56);"); - D("function {:builtin \"(_ fp.to_sbv 48) RNE\"} ftsbv48(bvfloat) returns (bv48);"); - D("function {:builtin \"(_ fp.to_sbv 40) RNE\"} ftsbv40(bvfloat) returns (bv40);"); - D("function {:builtin \"(_ fp.to_sbv 32) RNE\"} ftsbv32(bvfloat) returns (bv32);"); - D("function {:builtin \"(_ fp.to_sbv 24) RNE\"} ftsbv24(bvfloat) returns (bv24);"); - D("function {:builtin \"(_ fp.to_sbv 16) RNE\"} ftsbv16(bvfloat) returns (bv16);"); - D("function {:builtin \"(_ fp.to_sbv 8) RNE\"} ftsbv8(bvfloat) returns (bv8);"); - D("function {:builtin \"(_ fp.to_ubv 128) RNE\"} ftubv128(bvfloat) returns (bv128);"); - D("function {:builtin \"(_ fp.to_ubv 96) RNE\"} ftubv96(bvfloat) returns (bv96);"); - D("function {:builtin \"(_ fp.to_ubv 88) RNE\"} ftubv88(bvfloat) returns (bv88);"); - D("function {:builtin \"(_ fp.to_ubv 64) RNE\"} ftubv64(bvfloat) returns (bv64);"); - D("function {:builtin \"(_ fp.to_ubv 56) RNE\"} ftubv56(bvfloat) returns (bv56);"); - D("function {:builtin \"(_ fp.to_ubv 48) RNE\"} ftubv48(bvfloat) returns (bv48);"); - D("function {:builtin \"(_ fp.to_ubv 40) RNE\"} ftubv40(bvfloat) returns (bv40);"); - D("function {:builtin \"(_ fp.to_ubv 32) RNE\"} ftubv32(bvfloat) returns (bv32);"); - D("function {:builtin \"(_ fp.to_ubv 24) RNE\"} ftubv24(bvfloat) returns (bv24);"); - D("function {:builtin \"(_ fp.to_ubv 16) RNE\"} ftubv16(bvfloat) returns (bv16);"); - D("function {:builtin \"(_ fp.to_ubv 8) RNE\"} ftubv8(bvfloat) returns (bv8);"); + // Floating-point arithmetic + DECLARE_EACH_FLOAT_TYPE(BUILTIN_RMODE_UNARY_OP, $sqrt, fp.sqrt) + DECLARE_EACH_FLOAT_TYPE(BUILTIN_RMODE_UNARY_OP, $round, fp.roundToIntegral) + DECLARE_EACH_FLOAT_TYPE(BUILTIN_RMODE_BINARY_OP, $fadd, fp.add) + DECLARE_EACH_FLOAT_TYPE(BUILTIN_RMODE_BINARY_OP, $fsub, fp.sub) + DECLARE_EACH_FLOAT_TYPE(BUILTIN_RMODE_BINARY_OP, $fmul, fp.mul) + DECLARE_EACH_FLOAT_TYPE(BUILTIN_RMODE_BINARY_OP, $fdiv, fp.div) + + DECLARE_EACH_FLOAT_TYPE(BUILTIN_UNARY_OP, $abs, fp.abs) + DECLARE_EACH_FLOAT_TYPE(BUILTIN_BINARY_OP, $fma, fp.fma) + DECLARE_EACH_FLOAT_TYPE(BUILTIN_BINARY_OP, $frem, fp.rem) + DECLARE_EACH_FLOAT_TYPE(BUILTIN_BINARY_OP, $min, fp.min) + DECLARE_EACH_FLOAT_TYPE(BUILTIN_BINARY_OP, $max, fp.max) + + // Floating-point value predicates + DECLARE_EACH_FLOAT_TYPE(BUILTIN_UNARY_PRED, $isnormal, fp.isNormal) + DECLARE_EACH_FLOAT_TYPE(BUILTIN_UNARY_PRED, $issubnormal, fp.isSubnormal) + DECLARE_EACH_FLOAT_TYPE(BUILTIN_UNARY_PRED, $iszero, fp.isZero) + DECLARE_EACH_FLOAT_TYPE(BUILTIN_UNARY_PRED, $isinfinite, fp.isInfinite) + DECLARE_EACH_FLOAT_TYPE(BUILTIN_UNARY_PRED, $isnan, fp.isNaN) + DECLARE_EACH_FLOAT_TYPE(BUILTIN_UNARY_PRED, $isnegative, fp.isNegative) + DECLARE_EACH_FLOAT_TYPE(BUILTIN_UNARY_PRED, $ispositive, fp.isPositive) + + // Floating-point comparison predicates + // We assume fp.eq is exactly IEEE compareQuietEqual + DECLARE_EACH_FLOAT_TYPE(BUILTIN_BINARY_COMP, $foeq, fp.eq) + DECLARE_EACH_FLOAT_TYPE(BUILTIN_BINARY_COMP, $fole, fp.leq) + DECLARE_EACH_FLOAT_TYPE(BUILTIN_BINARY_COMP, $folt, fp.lt) + DECLARE_EACH_FLOAT_TYPE(BUILTIN_BINARY_COMP, $foge, fp.geq) + DECLARE_EACH_FLOAT_TYPE(BUILTIN_BINARY_COMP, $fogt, fp.gt) + D("function {:inline} $fone.bvhalf.bool(f1:bvhalf, f2:bvhalf) returns (bool) {!$fueq.bvhalf.bool(f1,f2)}"); + D("function {:inline} $fone.bvfloat.bool(f1:bvfloat, f2:bvfloat) returns (bool) {!$fueq.bvfloat.bool(f1,f2)}"); + D("function {:inline} $fone.bvdouble.bool(f1:bvdouble, f2:bvdouble) returns (bool) {!$fueq.bvdouble.bool(f1,f2)}"); + D("function {:inline} $fone.bvlongdouble.bool(f1:bvlongdouble, f2:bvlongdouble) returns (bool) {!$fueq.bvlongdouble.bool(f1,f2)}"); + D("function {:inline} $ford.bvhalf.bool(f1:bvhalf, f2:bvhalf) returns (bool) {!$funo.bvhalf.bool(f1,f2)}"); + D("function {:inline} $ford.bvfloat.bool(f1:bvfloat, f2:bvfloat) returns (bool) {!$funo.bvfloat.bool(f1,f2)}"); + D("function {:inline} $ford.bvdouble.bool(f1:bvdouble, f2:bvdouble) returns (bool) {!$funo.bvdouble.bool(f1,f2)}"); + D("function {:inline} $ford.bvlongdouble.bool(f1:bvlongdouble, f2:bvlongdouble) returns (bool) {!$funo.bvlongdouble.bool(f1,f2)}"); + D("function {:inline} $fueq.bvhalf.bool(f1:bvhalf, f2:bvhalf) returns (bool) {$isnan.bvhalf.bool(f1)||$isnan.bvhalf.bool(f2)||$foeq.bvhalf.bool(f1,f2)}"); + D("function {:inline} $fugt.bvhalf.bool(f1:bvhalf, f2:bvhalf) returns (bool) {$isnan.bvhalf.bool(f1)||$isnan.bvhalf.bool(f2)||$fogt.bvhalf.bool(f1,f2)}"); + D("function {:inline} $fuge.bvhalf.bool(f1:bvhalf, f2:bvhalf) returns (bool) {$isnan.bvhalf.bool(f1)||$isnan.bvhalf.bool(f2)||$foge.bvhalf.bool(f1,f2)}"); + D("function {:inline} $fult.bvhalf.bool(f1:bvhalf, f2:bvhalf) returns (bool) {$isnan.bvhalf.bool(f1)||$isnan.bvhalf.bool(f2)||$folt.bvhalf.bool(f1,f2)}"); + D("function {:inline} $fule.bvhalf.bool(f1:bvhalf, f2:bvhalf) returns (bool) {$isnan.bvhalf.bool(f1)||$isnan.bvhalf.bool(f2)||$fole.bvhalf.bool(f1,f2)}"); + D("function {:inline} $fune.bvhalf.bool(f1:bvhalf, f2:bvhalf) returns (bool) {$isnan.bvhalf.bool(f1)||$isnan.bvhalf.bool(f2)||$fone.bvhalf.bool(f1,f2)}"); + D("function {:inline} $funo.bvhalf.bool(f1:bvhalf, f2:bvhalf) returns (bool) {$isnan.bvhalf.bool(f1)||$isnan.bvhalf.bool(f2)}"); + D("function {:inline} $fueq.bvfloat.bool(f1:bvfloat, f2:bvfloat) returns (bool) {$isnan.bvfloat.bool(f1)||$isnan.bvfloat.bool(f2)||$foeq.bvfloat.bool(f1,f2)}"); + D("function {:inline} $fugt.bvfloat.bool(f1:bvfloat, f2:bvfloat) returns (bool) {$isnan.bvfloat.bool(f1)||$isnan.bvfloat.bool(f2)||$fogt.bvfloat.bool(f1,f2)}"); + D("function {:inline} $fuge.bvfloat.bool(f1:bvfloat, f2:bvfloat) returns (bool) {$isnan.bvfloat.bool(f1)||$isnan.bvfloat.bool(f2)||$foge.bvfloat.bool(f1,f2)}"); + D("function {:inline} $fult.bvfloat.bool(f1:bvfloat, f2:bvfloat) returns (bool) {$isnan.bvfloat.bool(f1)||$isnan.bvfloat.bool(f2)||$folt.bvfloat.bool(f1,f2)}"); + D("function {:inline} $fule.bvfloat.bool(f1:bvfloat, f2:bvfloat) returns (bool) {$isnan.bvfloat.bool(f1)||$isnan.bvfloat.bool(f2)||$fole.bvfloat.bool(f1,f2)}"); + D("function {:inline} $fune.bvfloat.bool(f1:bvfloat, f2:bvfloat) returns (bool) {$isnan.bvfloat.bool(f1)||$isnan.bvfloat.bool(f2)||$fone.bvfloat.bool(f1,f2)}"); + D("function {:inline} $funo.bvfloat.bool(f1:bvfloat, f2:bvfloat) returns (bool) {$isnan.bvfloat.bool(f1)||$isnan.bvfloat.bool(f2)}"); + D("function {:inline} $fueq.bvdouble.bool(f1:bvdouble, f2:bvdouble) returns (bool) {$isnan.bvdouble.bool(f1)||$isnan.bvdouble.bool(f2)||$foeq.bvdouble.bool(f1,f2)}"); + D("function {:inline} $fugt.bvdouble.bool(f1:bvdouble, f2:bvdouble) returns (bool) {$isnan.bvdouble.bool(f1)||$isnan.bvdouble.bool(f2)||$fogt.bvdouble.bool(f1,f2)}"); + D("function {:inline} $fuge.bvdouble.bool(f1:bvdouble, f2:bvdouble) returns (bool) {$isnan.bvdouble.bool(f1)||$isnan.bvdouble.bool(f2)||$foge.bvdouble.bool(f1,f2)}"); + D("function {:inline} $fult.bvdouble.bool(f1:bvdouble, f2:bvdouble) returns (bool) {$isnan.bvdouble.bool(f1)||$isnan.bvdouble.bool(f2)||$folt.bvdouble.bool(f1,f2)}"); + D("function {:inline} $fule.bvdouble.bool(f1:bvdouble, f2:bvdouble) returns (bool) {$isnan.bvdouble.bool(f1)||$isnan.bvdouble.bool(f2)||$fole.bvdouble.bool(f1,f2)}"); + D("function {:inline} $fune.bvdouble.bool(f1:bvdouble, f2:bvdouble) returns (bool) {$isnan.bvdouble.bool(f1)||$isnan.bvdouble.bool(f2)||$fone.bvdouble.bool(f1,f2)}"); + D("function {:inline} $funo.bvdouble.bool(f1:bvdouble, f2:bvdouble) returns (bool) {$isnan.bvdouble.bool(f1)||$isnan.bvdouble.bool(f2)}"); + D("function {:inline} $fueq.bvlongdouble.bool(f1:bvlongdouble, f2:bvlongdouble) returns (bool) {$isnan.bvlongdouble.bool(f1)||$isnan.bvlongdouble.bool(f2)||$foeq.bvlongdouble.bool(f1,f2)}"); + D("function {:inline} $fugt.bvlongdouble.bool(f1:bvlongdouble, f2:bvlongdouble) returns (bool) {$isnan.bvlongdouble.bool(f1)||$isnan.bvlongdouble.bool(f2)||$fogt.bvlongdouble.bool(f1,f2)}"); + D("function {:inline} $fuge.bvlongdouble.bool(f1:bvlongdouble, f2:bvlongdouble) returns (bool) {$isnan.bvlongdouble.bool(f1)||$isnan.bvlongdouble.bool(f2)||$foge.bvlongdouble.bool(f1,f2)}"); + D("function {:inline} $fult.bvlongdouble.bool(f1:bvlongdouble, f2:bvlongdouble) returns (bool) {$isnan.bvlongdouble.bool(f1)||$isnan.bvlongdouble.bool(f2)||$folt.bvlongdouble.bool(f1,f2)}"); + D("function {:inline} $fule.bvlongdouble.bool(f1:bvlongdouble, f2:bvlongdouble) returns (bool) {$isnan.bvlongdouble.bool(f1)||$isnan.bvlongdouble.bool(f2)||$fole.bvlongdouble.bool(f1,f2)}"); + D("function {:inline} $fune.bvlongdouble.bool(f1:bvlongdouble, f2:bvlongdouble) returns (bool) {$isnan.bvlongdouble.bool(f1)||$isnan.bvlongdouble.bool(f2)||$fone.bvlongdouble.bool(f1,f2)}"); + D("function {:inline} $funo.bvlongdouble.bool(f1:bvlongdouble, f2:bvlongdouble) returns (bool) {$isnan.bvlongdouble.bool(f1)||$isnan.bvlongdouble.bool(f2)}"); + DECLARE_EACH_FLOAT_TYPE(INLINE_BINARY_COMP, $ffalse, {false}) + DECLARE_EACH_FLOAT_TYPE(INLINE_BINARY_COMP, $ftrue, {true}) + + D("function {:builtin \"(_ to_fp 8 24)\"} dtf(rmode, bvdouble) returns (bvfloat);"); + D("function {:builtin \"(_ to_fp 11 53)\"} ftd(rmode, bvfloat) returns (bvdouble);"); + D("function {:builtin \"(_ to_fp 8 24)\"} ltf(rmode, bvlongdouble) returns (bvfloat);"); + D("function {:builtin \"(_ to_fp 11 53)\"} ltd(rmode, bvlongdouble) returns (bvdouble);"); + D("function {:builtin \"(_ to_fp 15 65)\"} ftl(rmode, bvfloat) returns (bvlongdouble);"); + D("function {:builtin \"(_ to_fp 15 65)\"} dtl(rmode, bvdouble) returns (bvlongdouble);"); + DECLARE(INLINE_RMODE_CONVERSION,bvdouble,bvfloat,$fptrunc,{dtf(rm, i)}); + DECLARE(INLINE_RMODE_CONVERSION,bvfloat,bvdouble,$fpext,{ftd(rm, i)}); + DECLARE(INLINE_RMODE_CONVERSION,bvlongdouble,bvfloat,$fptrunc,{ltf(rm, i)}); + DECLARE(INLINE_RMODE_CONVERSION,bvlongdouble,bvdouble,$fptrunc,{ltd(rm, i)}); + DECLARE(INLINE_RMODE_CONVERSION,bvfloat,bvlongdouble,$fpext,{ftl(rm, i)}); + DECLARE(INLINE_RMODE_CONVERSION,bvdouble,bvlongdouble,$fpext,{dtl(rm, i)}); // Add truncation for default casts to int - D("function {:builtin \"(_ fp.to_sbv 128) RTZ\"} ftsi128(bvfloat) returns (bv128);"); - D("function {:builtin \"(_ fp.to_sbv 96) RTZ\"} ftsi96(bvfloat) returns (bv96);"); - D("function {:builtin \"(_ fp.to_sbv 88) RTZ\"} ftsi88(bvfloat) returns (bv88);"); - D("function {:builtin \"(_ fp.to_sbv 64) RTZ\"} ftsi64(bvfloat) returns (bv64);"); - D("function {:builtin \"(_ fp.to_sbv 56) RTZ\"} ftsi56(bvfloat) returns (bv56);"); - D("function {:builtin \"(_ fp.to_sbv 48) RTZ\"} ftsi48(bvfloat) returns (bv48);"); - D("function {:builtin \"(_ fp.to_sbv 40) RTZ\"} ftsi40(bvfloat) returns (bv40);"); - D("function {:builtin \"(_ fp.to_sbv 32) RTZ\"} ftsi32(bvfloat) returns (bv32);"); - D("function {:builtin \"(_ fp.to_sbv 24) RTZ\"} ftsi24(bvfloat) returns (bv24);"); - D("function {:builtin \"(_ fp.to_sbv 16) RTZ\"} ftsi16(bvfloat) returns (bv16);"); - D("function {:builtin \"(_ fp.to_sbv 8) RTZ\"} ftsi8(bvfloat) returns (bv8);"); - - DECLARE(INLINE_CONVERSION, bvfloat, bv128, $fp2si, {ftsi128(i)}); - DECLARE(INLINE_CONVERSION, bvfloat, bv128, $fp2ui, {ftubv128(i)}); - DECLARE(INLINE_CONVERSION, bv128, bvfloat, $si2fp, {sbv128tf(i)}); - DECLARE(INLINE_CONVERSION, bv128, bvfloat, $ui2fp, {ubv128tf(i)}); - DECLARE(INLINE_CONVERSION, bvfloat, bv96, $fp2si, {ftsi96(i)}); - DECLARE(INLINE_CONVERSION, bvfloat, bv96, $fp2ui, {ftubv96(i)}); - DECLARE(INLINE_CONVERSION, bv96, bvfloat, $si2fp, {sbv96tf(i)}); - DECLARE(INLINE_CONVERSION, bv96, bvfloat, $ui2fp, {ubv96tf(i)}); - DECLARE(INLINE_CONVERSION, bvfloat, bv88, $fp2si, {ftsi88(i)}); - DECLARE(INLINE_CONVERSION, bvfloat, bv88, $fp2ui, {ftubv88(i)}); - DECLARE(INLINE_CONVERSION, bv88, bvfloat, $si2fp, {sbv88tf(i)}); - DECLARE(INLINE_CONVERSION, bv88, bvfloat, $ui2fp, {ubv88tf(i)}); - DECLARE(INLINE_CONVERSION, bvfloat, bv64, $fp2si, {ftsi64(i)}); - DECLARE(INLINE_CONVERSION, bvfloat, bv64, $fp2ui, {ftubv64(i)}); - DECLARE(INLINE_CONVERSION, bv64, bvfloat, $si2fp, {sbv64tf(i)}); - DECLARE(INLINE_CONVERSION, bv64, bvfloat, $ui2fp, {ubv64tf(i)}); - DECLARE(INLINE_CONVERSION, bvfloat, bv56, $fp2si, {ftsi56(i)}); - DECLARE(INLINE_CONVERSION, bvfloat, bv56, $fp2ui, {ftubv56(i)}); - DECLARE(INLINE_CONVERSION, bv56, bvfloat, $si2fp, {sbv56tf(i)}); - DECLARE(INLINE_CONVERSION, bv56, bvfloat, $ui2fp, {ubv56tf(i)}); - DECLARE(INLINE_CONVERSION, bvfloat, bv48, $fp2si, {ftsi48(i)}); - DECLARE(INLINE_CONVERSION, bvfloat, bv48, $fp2ui, {ftubv48(i)}); - DECLARE(INLINE_CONVERSION, bv48, bvfloat, $si2fp, {sbv48tf(i)}); - DECLARE(INLINE_CONVERSION, bv48, bvfloat, $ui2fp, {ubv48tf(i)}); - DECLARE(INLINE_CONVERSION, bvfloat, bv40, $fp2si, {ftsi40(i)}); - DECLARE(INLINE_CONVERSION, bvfloat, bv40, $fp2ui, {ftubv40(i)}); - DECLARE(INLINE_CONVERSION, bv40, bvfloat, $si2fp, {sbv40tf(i)}); - DECLARE(INLINE_CONVERSION, bv40, bvfloat, $ui2fp, {ubv40tf(i)}); - DECLARE(INLINE_CONVERSION, bvfloat, bv32, $fp2si, {ftsi32(i)}); - DECLARE(INLINE_CONVERSION, bvfloat, bv32, $fp2ui, {ftubv32(i)}); - DECLARE(INLINE_CONVERSION, bv32, bvfloat, $si2fp, {sbv32tf(i)}); - DECLARE(INLINE_CONVERSION, bv32, bvfloat, $ui2fp, {ubv32tf(i)}); - DECLARE(INLINE_CONVERSION, bvfloat, bv24, $fp2si, {ftsi24(i)}); - DECLARE(INLINE_CONVERSION, bvfloat, bv24, $fp2ui, {ftubv24(i)}); - DECLARE(INLINE_CONVERSION, bv24, bvfloat, $si2fp, {sbv24tf(i)}); - DECLARE(INLINE_CONVERSION, bv24, bvfloat, $ui2fp, {ubv24tf(i)}); - DECLARE(INLINE_CONVERSION, bvfloat, bv16, $fp2si, {ftsi16(i)}); - DECLARE(INLINE_CONVERSION, bvfloat, bv16, $fp2ui, {ftubv16(i)}); - DECLARE(INLINE_CONVERSION, bv16, bvfloat, $si2fp, {sbv16tf(i)}); - DECLARE(INLINE_CONVERSION, bv16, bvfloat, $ui2fp, {ubv16tf(i)}); - DECLARE(INLINE_CONVERSION, bvfloat, bv8, $fp2si, {ftsi8(i)}); - DECLARE(INLINE_CONVERSION, bvfloat, bv8, $fp2ui, {ftubv8(i)}); - DECLARE(INLINE_CONVERSION, bv8, bvfloat, $si2fp, {sbv8tf(i)}); - DECLARE(INLINE_CONVERSION, bv8, bvfloat, $ui2fp, {ubv8tf(i)}); - - D("function {:builtin \"(_ fp.to_sbv 32) RNE\"} $round.rne.bvfloat(bvfloat) returns (bv32);"); - D("function {:builtin \"(_ fp.to_sbv 32) RNA\"} $round.rna.bvfloat(bvfloat) returns (bv32);"); - D("function {:builtin \"(_ fp.to_sbv 32) RTN\"} $floor.bvfloat(bvfloat) returns (bv32);"); - D("function {:builtin \"(_ fp.to_sbv 32) RTP\"} $ceil.bvfloat(bvfloat) returns (bv32);"); - D("function {:builtin \"(_ fp.to_sbv 32) RTZ\"} $trunc.bvfloat(bvfloat) returns (bv32);"); - - #if BUILD_64 - D("function {:builtin \"(_ fp.to_sbv 64) RNA\"} $lround.bvfloat(bvfloat) returns (bv64);"); - + DECLARE(BUILTIN_RMODE_CONVERSION,bvfloat,bv128,$fp2si,(_ fp.to_sbv 128)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvfloat,bv96,$fp2si,(_ fp.to_sbv 96)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvfloat,bv88,$fp2si,(_ fp.to_sbv 88)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvfloat,bv80,$fp2si,(_ fp.to_sbv 80)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvfloat,bv64,$fp2si,(_ fp.to_sbv 64)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvfloat,bv56,$fp2si,(_ fp.to_sbv 56)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvfloat,bv48,$fp2si,(_ fp.to_sbv 48)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvfloat,bv40,$fp2si,(_ fp.to_sbv 40)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvfloat,bv32,$fp2si,(_ fp.to_sbv 32)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvfloat,bv24,$fp2si,(_ fp.to_sbv 24)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvfloat,bv16,$fp2si,(_ fp.to_sbv 16)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvfloat,bv8,$fp2si,(_ fp.to_sbv 8)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvfloat,bv1,$fp2si,(_ fp.to_sbv 1)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvfloat,bv128,$fp2ui,(_ fp.to_ubv 128)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvfloat,bv96,$fp2ui,(_ fp.to_ubv 96)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvfloat,bv88,$fp2ui,(_ fp.to_ubv 88)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvfloat,bv80,$fp2ui,(_ fp.to_ubv 80)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvfloat,bv64,$fp2ui,(_ fp.to_ubv 64)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvfloat,bv56,$fp2ui,(_ fp.to_ubv 56)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvfloat,bv48,$fp2ui,(_ fp.to_ubv 48)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvfloat,bv40,$fp2ui,(_ fp.to_ubv 40)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvfloat,bv32,$fp2ui,(_ fp.to_ubv 32)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvfloat,bv24,$fp2ui,(_ fp.to_ubv 24)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvfloat,bv16,$fp2ui,(_ fp.to_ubv 16)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvfloat,bv8,$fp2ui,(_ fp.to_ubv 8)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvfloat,bv1,$fp2ui,(_ fp.to_ubv 1)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvdouble,bv128,$fp2si,(_ fp.to_sbv 128)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvdouble,bv96,$fp2si,(_ fp.to_sbv 96)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvdouble,bv88,$fp2si,(_ fp.to_sbv 88)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvdouble,bv80,$fp2si,(_ fp.to_sbv 80)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvdouble,bv64,$fp2si,(_ fp.to_sbv 64)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvdouble,bv56,$fp2si,(_ fp.to_sbv 56)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvdouble,bv48,$fp2si,(_ fp.to_sbv 48)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvdouble,bv40,$fp2si,(_ fp.to_sbv 40)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvdouble,bv32,$fp2si,(_ fp.to_sbv 32)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvdouble,bv24,$fp2si,(_ fp.to_sbv 24)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvdouble,bv16,$fp2si,(_ fp.to_sbv 16)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvdouble,bv8,$fp2si,(_ fp.to_sbv 8)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvdouble,bv1,$fp2si,(_ fp.to_sbv 1)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvdouble,bv128,$fp2ui,(_ fp.to_ubv 128)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvdouble,bv96,$fp2ui,(_ fp.to_ubv 96)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvdouble,bv88,$fp2ui,(_ fp.to_ubv 88)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvdouble,bv80,$fp2ui,(_ fp.to_ubv 80)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvdouble,bv64,$fp2ui,(_ fp.to_ubv 64)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvdouble,bv56,$fp2ui,(_ fp.to_ubv 56)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvdouble,bv48,$fp2ui,(_ fp.to_ubv 48)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvdouble,bv40,$fp2ui,(_ fp.to_ubv 40)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvdouble,bv32,$fp2ui,(_ fp.to_ubv 32)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvdouble,bv24,$fp2ui,(_ fp.to_ubv 24)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvdouble,bv16,$fp2ui,(_ fp.to_ubv 16)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvdouble,bv8,$fp2ui,(_ fp.to_ubv 8)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvdouble,bv1,$fp2ui,(_ fp.to_ubv 1)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvlongdouble,bv128,$fp2si,(_ fp.to_sbv 128)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvlongdouble,bv96,$fp2si,(_ fp.to_sbv 96)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvlongdouble,bv88,$fp2si,(_ fp.to_sbv 88)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvlongdouble,bv80,$fp2si,(_ fp.to_sbv 80)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvlongdouble,bv64,$fp2si,(_ fp.to_sbv 64)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvlongdouble,bv56,$fp2si,(_ fp.to_sbv 56)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvlongdouble,bv48,$fp2si,(_ fp.to_sbv 48)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvlongdouble,bv40,$fp2si,(_ fp.to_sbv 40)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvlongdouble,bv32,$fp2si,(_ fp.to_sbv 32)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvlongdouble,bv24,$fp2si,(_ fp.to_sbv 24)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvlongdouble,bv16,$fp2si,(_ fp.to_sbv 16)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvlongdouble,bv8,$fp2si,(_ fp.to_sbv 8)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvlongdouble,bv1,$fp2si,(_ fp.to_sbv 1)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvlongdouble,bv128,$fp2ui,(_ fp.to_ubv 128)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvlongdouble,bv96,$fp2ui,(_ fp.to_ubv 96)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvlongdouble,bv88,$fp2ui,(_ fp.to_ubv 88)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvlongdouble,bv80,$fp2ui,(_ fp.to_ubv 80)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvlongdouble,bv64,$fp2ui,(_ fp.to_ubv 64)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvlongdouble,bv56,$fp2ui,(_ fp.to_ubv 56)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvlongdouble,bv48,$fp2ui,(_ fp.to_ubv 48)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvlongdouble,bv40,$fp2ui,(_ fp.to_ubv 40)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvlongdouble,bv32,$fp2ui,(_ fp.to_ubv 32)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvlongdouble,bv24,$fp2ui,(_ fp.to_ubv 24)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvlongdouble,bv16,$fp2ui,(_ fp.to_ubv 16)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvlongdouble,bv8,$fp2ui,(_ fp.to_ubv 8)); + DECLARE(BUILTIN_RMODE_CONVERSION,bvlongdouble,bv1,$fp2ui,(_ fp.to_ubv 1)); + // Warning: do we need bv2int cast here? + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvfloat,i128,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvfloat,i96,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvfloat,i88,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvfloat,i80,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvfloat,i64,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvfloat,i56,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvfloat,i48,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvfloat,i40,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvfloat,i32,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvfloat,i24,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvfloat,i16,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvfloat,i8,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvfloat,i1,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvfloat,i128,$fp2ui); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvfloat,i96,$fp2ui); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvfloat,i88,$fp2ui); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvfloat,i80,$fp2ui); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvfloat,i64,$fp2ui); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvfloat,i56,$fp2ui); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvfloat,i48,$fp2ui); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvfloat,i40,$fp2ui); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvfloat,i32,$fp2ui); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvfloat,i24,$fp2ui); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvfloat,i16,$fp2ui); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvfloat,i8,$fp2ui); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvfloat,i1,$fp2ui); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvdouble,i128,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvdouble,i96,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvdouble,i88,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvdouble,i80,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvdouble,i64,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvdouble,i56,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvdouble,i48,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvdouble,i40,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvdouble,i32,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvdouble,i24,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvdouble,i16,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvdouble,i8,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvdouble,i1,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvdouble,i128,$fp2ui); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvdouble,i96,$fp2ui); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvdouble,i88,$fp2ui); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvdouble,i80,$fp2ui); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvdouble,i64,$fp2ui); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvdouble,i56,$fp2ui); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvdouble,i48,$fp2ui); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvdouble,i40,$fp2ui); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvdouble,i32,$fp2ui); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvdouble,i24,$fp2ui); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvdouble,i16,$fp2ui); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvdouble,i8,$fp2ui); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvdouble,i1,$fp2ui); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvlongdouble,i128,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvlongdouble,i96,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvlongdouble,i88,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvlongdouble,i80,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvlongdouble,i64,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvlongdouble,i56,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvlongdouble,i48,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvlongdouble,i40,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvlongdouble,i32,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvlongdouble,i24,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvlongdouble,i16,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvlongdouble,i8,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvlongdouble,i1,$fp2si); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvlongdouble,i128,$fp2ui); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvlongdouble,i96,$fp2ui); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvlongdouble,i88,$fp2ui); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvlongdouble,i80,$fp2ui); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvlongdouble,i64,$fp2ui); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvlongdouble,i56,$fp2ui); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvlongdouble,i48,$fp2ui); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvlongdouble,i40,$fp2ui); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvlongdouble,i32,$fp2ui); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvlongdouble,i24,$fp2ui); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvlongdouble,i16,$fp2ui); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvlongdouble,i8,$fp2ui); + DECLARE(UNINTERPRETED_RMODE_CONVERSION,bvlongdouble,i1,$fp2ui); + // Warning: undefined behaviors can occur + // https://llvm.org/docs/LangRef.html#uitofp-to-instruction + DECLARE(BUILTIN_RMODE_CONVERSION, bv128, bvfloat, $ui2fp,(_ to_fp_unsigned 8 24)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv96, bvfloat, $ui2fp,(_ to_fp_unsigned 8 24)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv88, bvfloat, $ui2fp,(_ to_fp_unsigned 8 24)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv80, bvfloat, $ui2fp,(_ to_fp_unsigned 8 24)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv64, bvfloat, $ui2fp,(_ to_fp_unsigned 8 24)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv56, bvfloat, $ui2fp,(_ to_fp_unsigned 8 24)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv48, bvfloat, $ui2fp,(_ to_fp_unsigned 8 24)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv40, bvfloat, $ui2fp,(_ to_fp_unsigned 8 24)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv32, bvfloat, $ui2fp,(_ to_fp_unsigned 8 24)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv24, bvfloat, $ui2fp,(_ to_fp_unsigned 8 24)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv16, bvfloat, $ui2fp,(_ to_fp_unsigned 8 24)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv8, bvfloat, $ui2fp,(_ to_fp_unsigned 8 24)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv1, bvfloat, $ui2fp,(_ to_fp_unsigned 8 24)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv128, bvfloat, $si2fp,(_ to_fp 8 24)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv96, bvfloat, $si2fp,(_ to_fp 8 24)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv88, bvfloat, $si2fp,(_ to_fp 8 24)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv80, bvfloat, $si2fp,(_ to_fp 8 24)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv64, bvfloat, $si2fp,(_ to_fp 8 24)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv56, bvfloat, $si2fp,(_ to_fp 8 24)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv48, bvfloat, $si2fp,(_ to_fp 8 24)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv40, bvfloat, $si2fp,(_ to_fp 8 24)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv32, bvfloat, $si2fp,(_ to_fp 8 24)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv24, bvfloat, $si2fp,(_ to_fp 8 24)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv16, bvfloat, $si2fp,(_ to_fp 8 24)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv8, bvfloat, $si2fp,(_ to_fp 8 24)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv1, bvfloat, $si2fp,(_ to_fp 8 24)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv128, bvdouble, $ui2fp,(_ to_fp_unsigned 11 53)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv96, bvdouble, $ui2fp,(_ to_fp_unsigned 11 53)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv88, bvdouble, $ui2fp,(_ to_fp_unsigned 11 53)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv80, bvdouble, $ui2fp,(_ to_fp_unsigned 11 53)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv64, bvdouble, $ui2fp,(_ to_fp_unsigned 11 53)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv56, bvdouble, $ui2fp,(_ to_fp_unsigned 11 53)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv48, bvdouble, $ui2fp,(_ to_fp_unsigned 11 53)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv40, bvdouble, $ui2fp,(_ to_fp_unsigned 11 53)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv32, bvdouble, $ui2fp,(_ to_fp_unsigned 11 53)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv24, bvdouble, $ui2fp,(_ to_fp_unsigned 11 53)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv16, bvdouble, $ui2fp,(_ to_fp_unsigned 11 53)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv8, bvdouble, $ui2fp,(_ to_fp_unsigned 11 53)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv1, bvdouble, $ui2fp,(_ to_fp_unsigned 11 53)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv128, bvdouble, $si2fp,(_ to_fp 11 53)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv96, bvdouble, $si2fp,(_ to_fp 11 53)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv88, bvdouble, $si2fp,(_ to_fp 11 53)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv80, bvdouble, $si2fp,(_ to_fp 11 53)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv64, bvdouble, $si2fp,(_ to_fp 11 53)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv56, bvdouble, $si2fp,(_ to_fp 11 53)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv48, bvdouble, $si2fp,(_ to_fp 11 53)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv40, bvdouble, $si2fp,(_ to_fp 11 53)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv32, bvdouble, $si2fp,(_ to_fp 11 53)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv24, bvdouble, $si2fp,(_ to_fp 11 53)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv16, bvdouble, $si2fp,(_ to_fp 11 53)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv8, bvdouble, $si2fp,(_ to_fp 11 53)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv1, bvdouble, $si2fp,(_ to_fp 11 53)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv128, bvlongdouble, $ui2fp,(_ to_fp_unsigned 15 65)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv96, bvlongdouble, $ui2fp,(_ to_fp_unsigned 15 65)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv88, bvlongdouble, $ui2fp,(_ to_fp_unsigned 15 65)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv80, bvlongdouble, $ui2fp,(_ to_fp_unsigned 15 65)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv64, bvlongdouble, $ui2fp,(_ to_fp_unsigned 15 65)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv56, bvlongdouble, $ui2fp,(_ to_fp_unsigned 15 65)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv48, bvlongdouble, $ui2fp,(_ to_fp_unsigned 15 65)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv40, bvlongdouble, $ui2fp,(_ to_fp_unsigned 15 65)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv32, bvlongdouble, $ui2fp,(_ to_fp_unsigned 15 65)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv24, bvlongdouble, $ui2fp,(_ to_fp_unsigned 15 65)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv16, bvlongdouble, $ui2fp,(_ to_fp_unsigned 15 65)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv8, bvlongdouble, $ui2fp,(_ to_fp_unsigned 15 65)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv1, bvlongdouble, $ui2fp,(_ to_fp_unsigned 15 65)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv128, bvlongdouble, $si2fp,(_ to_fp 15 65)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv96, bvlongdouble, $si2fp,(_ to_fp 15 65)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv88, bvlongdouble, $si2fp,(_ to_fp 15 65)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv80, bvlongdouble, $si2fp,(_ to_fp 15 65)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv64, bvlongdouble, $si2fp,(_ to_fp 15 65)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv56, bvlongdouble, $si2fp,(_ to_fp 15 65)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv48, bvlongdouble, $si2fp,(_ to_fp 15 65)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv40, bvlongdouble, $si2fp,(_ to_fp 15 65)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv32, bvlongdouble, $si2fp,(_ to_fp 15 65)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv24, bvlongdouble, $si2fp,(_ to_fp 15 65)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv16, bvlongdouble, $si2fp,(_ to_fp 15 65)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv8, bvlongdouble, $si2fp,(_ to_fp 15 65)); + DECLARE(BUILTIN_RMODE_CONVERSION, bv1, bvlongdouble, $si2fp,(_ to_fp 15 65)); + // Warning: integer-encoding fixes needed here + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i128, bvfloat, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i96, bvfloat, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i88, bvfloat, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i80, bvfloat, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i64, bvfloat, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i56, bvfloat, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i48, bvfloat, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i40, bvfloat, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i32, bvfloat, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i24, bvfloat, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i16, bvfloat, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i8, bvfloat, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i1, bvfloat, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i128, bvfloat, $si2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i96, bvfloat, $si2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i88, bvfloat, $si2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i80, bvfloat, $si2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i64, bvfloat, $si2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i56, bvfloat, $si2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i48, bvfloat, $si2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i40, bvfloat, $si2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i32, bvfloat, $si2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i24, bvfloat, $si2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i16, bvfloat, $si2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i8, bvfloat, $si2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i1, bvfloat, $si2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i128, bvdouble, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i96, bvdouble, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i88, bvdouble, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i80, bvdouble, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i64, bvdouble, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i56, bvdouble, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i48, bvdouble, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i40, bvdouble, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i32, bvdouble, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i24, bvdouble, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i16, bvdouble, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i8, bvdouble, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i1, bvdouble, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i128, bvdouble, $si2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i96, bvdouble, $si2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i88, bvdouble, $si2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i80, bvdouble, $si2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i64, bvdouble, $si2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i56, bvdouble, $si2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i48, bvdouble, $si2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i40, bvdouble, $si2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i32, bvdouble, $si2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i24, bvdouble, $si2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i16, bvdouble, $si2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i8, bvdouble, $si2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i1, bvdouble, $si2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i128, bvlongdouble, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i96, bvlongdouble, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i88, bvlongdouble, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i80, bvlongdouble, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i64, bvlongdouble, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i56, bvlongdouble, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i48, bvlongdouble, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i40, bvlongdouble, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i32, bvlongdouble, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i24, bvlongdouble, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i16, bvlongdouble, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i8, bvlongdouble, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i1, bvlongdouble, $ui2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i128, bvlongdouble, $si2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i96, bvlongdouble, $si2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i88, bvlongdouble, $si2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i80, bvlongdouble, $si2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i64, bvlongdouble, $si2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i56, bvlongdouble, $si2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i48, bvlongdouble, $si2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i40, bvlongdouble, $si2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i32, bvlongdouble, $si2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i24, bvlongdouble, $si2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i16, bvlongdouble, $si2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i8, bvlongdouble, $si2fp); + DECLARE(UNINTERPRETED_RMODE_CONVERSION, i1, bvlongdouble, $si2fp); + + #if defined(__LP64__) || defined(_LP64) || defined(_WIN64) + D("function {:builtin \"(_ fp.to_sbv 64)\"} $lround.bvfloat(rmode, bvfloat) returns (bv64);"); + D("function {:builtin \"(_ fp.to_sbv 64)\"} $lround.bvdouble(rmode, bvdouble) returns (bv64);"); + D("function {:builtin \"(_ fp.to_sbv 64)\"} $lround.bvlongdouble(rmode, bvlongdouble) returns (bv64);"); #else - D("function {:builtin \"(_ fp.to_sbv 32) RNA\"} $lround.bvfloat(bvfloat) returns (bv32);"); - + D("function {:builtin \"(_ fp.to_sbv 32)\"} $lround.bvfloat(rmode, bvfloat) returns (bv32);"); + D("function {:builtin \"(_ fp.to_sbv 32)\"} $lround.bvdouble(rmode, bvdouble) returns (bv32);"); + D("function {:builtin \"(_ fp.to_sbv 32)\"} $lround.bvlongdouble(rmode, bvlongdouble) returns (bv32);"); #endif - //This isn't the correct implementation, so change as needed - D("function {:inline} $ford.bvdouble(f1:bvdouble, f2:bvdouble) returns (bv1);"); - D("function {:inline} $funo.bvdouble(f1:bvdouble, f2:bvdouble) returns (bv1);"); - - D("function $fptrunc.bvdouble.bvdouble(f:bvdouble) returns (bvdouble) {f}"); - D("function $fpext.bvdouble.bvdouble(f:bvdouble) returns (bvdouble) {f}"); - - D("function {:builtin \"(_ to_fp 11 53) RNE\"} sbv128td(bv128) returns (bvdouble);"); - D("function {:builtin \"(_ to_fp 11 53) RNE\"} sbv96td(bv96) returns (bvdouble);"); - D("function {:builtin \"(_ to_fp 11 53) RNE\"} sbv88td(bv88) returns (bvdouble);"); - D("function {:builtin \"(_ to_fp 11 53) RNE\"} sbv64td(bv64) returns (bvdouble);"); - D("function {:builtin \"(_ to_fp 11 53) RNE\"} sbv56td(bv56) returns (bvdouble);"); - D("function {:builtin \"(_ to_fp 11 53) RNE\"} sbv48td(bv48) returns (bvdouble);"); - D("function {:builtin \"(_ to_fp 11 53) RNE\"} sbv40td(bv40) returns (bvdouble);"); - D("function {:builtin \"(_ to_fp 11 53) RNE\"} sbv32td(bv32) returns (bvdouble);"); - D("function {:builtin \"(_ to_fp 11 53) RNE\"} sbv24td(bv24) returns (bvdouble);"); - D("function {:builtin \"(_ to_fp 11 53) RNE\"} sbv16td(bv16) returns (bvdouble);"); - D("function {:builtin \"(_ to_fp 11 53) RNE\"} sbv8td(bv8) returns (bvdouble);"); - D("function {:builtin \"(_ to_fp 11 53) RNE\"} ubv128td(bv128) returns (bvdouble);"); - D("function {:builtin \"(_ to_fp 11 53) RNE\"} ubv96td(bv96) returns (bvdouble);"); - D("function {:builtin \"(_ to_fp 11 53) RNE\"} ubv88td(bv88) returns (bvdouble);"); - D("function {:builtin \"(_ to_fp 11 53) RNE\"} ubv64td(bv64) returns (bvdouble);"); - D("function {:builtin \"(_ to_fp 11 53) RNE\"} ubv56td(bv56) returns (bvdouble);"); - D("function {:builtin \"(_ to_fp 11 53) RNE\"} ubv48td(bv48) returns (bvdouble);"); - D("function {:builtin \"(_ to_fp 11 53) RNE\"} ubv40td(bv40) returns (bvdouble);"); - D("function {:builtin \"(_ to_fp 11 53) RNE\"} ubv32td(bv32) returns (bvdouble);"); - D("function {:builtin \"(_ to_fp 11 53) RNE\"} ubv24td(bv24) returns (bvdouble);"); - D("function {:builtin \"(_ to_fp 11 53) RNE\"} ubv16td(bv16) returns (bvdouble);"); - D("function {:builtin \"(_ to_fp 11 53) RNE\"} ubv8td(bv8) returns (bvdouble);"); - D("function {:builtin \"(_ fp.to_sbv 128) RNE\"} dtsbv128(bvdouble) returns (bv128);"); - D("function {:builtin \"(_ fp.to_sbv 96) RNE\"} dtsbv96(bvdouble) returns (bv96);"); - D("function {:builtin \"(_ fp.to_sbv 88) RNE\"} dtsbv88(bvdouble) returns (bv88);"); - D("function {:builtin \"(_ fp.to_sbv 64) RNE\"} dtsbv64(bvdouble) returns (bv64);"); - D("function {:builtin \"(_ fp.to_sbv 56) RNE\"} dtsbv56(bvdouble) returns (bv56);"); - D("function {:builtin \"(_ fp.to_sbv 48) RNE\"} dtsbv48(bvdouble) returns (bv48);"); - D("function {:builtin \"(_ fp.to_sbv 40) RNE\"} dtsbv40(bvdouble) returns (bv40);"); - D("function {:builtin \"(_ fp.to_sbv 32) RNE\"} dtsbv32(bvdouble) returns (bv32);"); - D("function {:builtin \"(_ fp.to_sbv 24) RNE\"} dtsbv24(bvdouble) returns (bv24);"); - D("function {:builtin \"(_ fp.to_sbv 16) RNE\"} dtsbv16(bvdouble) returns (bv16);"); - D("function {:builtin \"(_ fp.to_sbv 8) RNE\"} dtsbv8(bvdouble) returns (bv8);"); - D("function {:builtin \"(_ fp.to_ubv 128) RNE\"} dtubv128(bvdouble) returns (bv128);"); - D("function {:builtin \"(_ fp.to_ubv 96) RNE\"} dtubv96(bvdouble) returns (bv96);"); - D("function {:builtin \"(_ fp.to_ubv 88) RNE\"} dtubv88(bvdouble) returns (bv88);"); - D("function {:builtin \"(_ fp.to_ubv 64) RNE\"} dtubv64(bvdouble) returns (bv64);"); - D("function {:builtin \"(_ fp.to_ubv 56) RNE\"} dtubv56(bvdouble) returns (bv56);"); - D("function {:builtin \"(_ fp.to_ubv 48) RNE\"} dtubv48(bvdouble) returns (bv48);"); - D("function {:builtin \"(_ fp.to_ubv 40) RNE\"} dtubv40(bvdouble) returns (bv40);"); - D("function {:builtin \"(_ fp.to_ubv 32) RNE\"} dtubv32(bvdouble) returns (bv32);"); - D("function {:builtin \"(_ fp.to_ubv 24) RNE\"} dtubv24(bvdouble) returns (bv24);"); - D("function {:builtin \"(_ fp.to_ubv 16) RNE\"} dtubv16(bvdouble) returns (bv16);"); - D("function {:builtin \"(_ fp.to_ubv 8) RNE\"} dtubv8(bvdouble) returns (bv8);"); - - // Add truncation for default casts to int - D("function {:builtin \"(_ fp.to_sbv 128) RTZ\"} dtsi128(bvdouble) returns (bv128);"); - D("function {:builtin \"(_ fp.to_sbv 96) RTZ\"} dtsi96(bvdouble) returns (bv96);"); - D("function {:builtin \"(_ fp.to_sbv 88) RTZ\"} dtsi88(bvdouble) returns (bv88);"); - D("function {:builtin \"(_ fp.to_sbv 64) RTZ\"} dtsi64(bvdouble) returns (bv64);"); - D("function {:builtin \"(_ fp.to_sbv 56) RTZ\"} dtsi56(bvdouble) returns (bv56);"); - D("function {:builtin \"(_ fp.to_sbv 48) RTZ\"} dtsi48(bvdouble) returns (bv48);"); - D("function {:builtin \"(_ fp.to_sbv 40) RTZ\"} dtsi40(bvdouble) returns (bv40);"); - D("function {:builtin \"(_ fp.to_sbv 32) RTZ\"} dtsi32(bvdouble) returns (bv32);"); - D("function {:builtin \"(_ fp.to_sbv 24) RTZ\"} dtsi24(bvdouble) returns (bv24);"); - D("function {:builtin \"(_ fp.to_sbv 16) RTZ\"} dtsi16(bvdouble) returns (bv16);"); - D("function {:builtin \"(_ fp.to_sbv 8) RTZ\"} dtsi8(bvdouble) returns (bv8);"); - - DECLARE(INLINE_CONVERSION, bvdouble, bv128, $fp2si, {dtsi128(i)}); - DECLARE(INLINE_CONVERSION, bvdouble, bv128, $fp2ui, {dtubv128(i)}); - DECLARE(INLINE_CONVERSION, bv128, bvdouble, $si2fp, {sbv128td(i)}); - DECLARE(INLINE_CONVERSION, bv128, bvdouble, $ui2fp, {ubv128td(i)}); - DECLARE(INLINE_CONVERSION, bvdouble, bv96, $fp2si, {dtsi96(i)}); - DECLARE(INLINE_CONVERSION, bvdouble, bv96, $fp2ui, {dtubv96(i)}); - DECLARE(INLINE_CONVERSION, bv96, bvdouble, $si2fp, {sbv96td(i)}); - DECLARE(INLINE_CONVERSION, bv96, bvdouble, $ui2fp, {ubv96td(i)}); - DECLARE(INLINE_CONVERSION, bvdouble, bv88, $fp2si, {dtsi88(i)}); - DECLARE(INLINE_CONVERSION, bvdouble, bv88, $fp2ui, {dtubv88(i)}); - DECLARE(INLINE_CONVERSION, bv88, bvdouble, $si2fp, {sbv88td(i)}); - DECLARE(INLINE_CONVERSION, bv88, bvdouble, $ui2fp, {ubv88td(i)}); - DECLARE(INLINE_CONVERSION, bvdouble, bv64, $fp2si, {dtsi64(i)}); - DECLARE(INLINE_CONVERSION, bvdouble, bv64, $fp2ui, {dtubv64(i)}); - DECLARE(INLINE_CONVERSION, bv64, bvdouble, $si2fp, {sbv64td(i)}); - DECLARE(INLINE_CONVERSION, bv64, bvdouble, $ui2fp, {ubv64td(i)}); - DECLARE(INLINE_CONVERSION, bvdouble, bv56, $fp2si, {dtsi56(i)}); - DECLARE(INLINE_CONVERSION, bvdouble, bv56, $fp2ui, {dtubv56(i)}); - DECLARE(INLINE_CONVERSION, bv56, bvdouble, $si2fp, {sbv56td(i)}); - DECLARE(INLINE_CONVERSION, bv56, bvdouble, $ui2fp, {ubv56td(i)}); - DECLARE(INLINE_CONVERSION, bvdouble, bv48, $fp2si, {dtsi48(i)}); - DECLARE(INLINE_CONVERSION, bvdouble, bv48, $fp2ui, {dtubv48(i)}); - DECLARE(INLINE_CONVERSION, bv48, bvdouble, $si2fp, {sbv48td(i)}); - DECLARE(INLINE_CONVERSION, bv48, bvdouble, $ui2fp, {ubv48td(i)}); - DECLARE(INLINE_CONVERSION, bvdouble, bv40, $fp2si, {dtsi40(i)}); - DECLARE(INLINE_CONVERSION, bvdouble, bv40, $fp2ui, {dtubv40(i)}); - DECLARE(INLINE_CONVERSION, bv40, bvdouble, $si2fp, {sbv40td(i)}); - DECLARE(INLINE_CONVERSION, bv40, bvdouble, $ui2fp, {ubv40td(i)}); - DECLARE(INLINE_CONVERSION, bvdouble, bv32, $fp2si, {dtsi32(i)}); - DECLARE(INLINE_CONVERSION, bvdouble, bv32, $fp2ui, {dtubv32(i)}); - DECLARE(INLINE_CONVERSION, bv32, bvdouble, $si2fp, {sbv32td(i)}); - DECLARE(INLINE_CONVERSION, bv32, bvdouble, $ui2fp, {ubv32td(i)}); - DECLARE(INLINE_CONVERSION, bvdouble, bv24, $fp2si, {dtsi24(i)}); - DECLARE(INLINE_CONVERSION, bvdouble, bv24, $fp2ui, {dtubv24(i)}); - DECLARE(INLINE_CONVERSION, bv24, bvdouble, $si2fp, {sbv24td(i)}); - DECLARE(INLINE_CONVERSION, bv24, bvdouble, $ui2fp, {ubv24td(i)}); - DECLARE(INLINE_CONVERSION, bvdouble, bv16, $fp2si, {dtsi16(i)}); - DECLARE(INLINE_CONVERSION, bvdouble, bv16, $fp2ui, {dtubv16(i)}); - DECLARE(INLINE_CONVERSION, bv16, bvdouble, $si2fp, {sbv16td(i)}); - DECLARE(INLINE_CONVERSION, bv16, bvdouble, $ui2fp, {ubv16td(i)}); - DECLARE(INLINE_CONVERSION, bvdouble, bv8, $fp2si, {dtsi8(i)}); - DECLARE(INLINE_CONVERSION, bvdouble, bv8, $fp2ui, {dtubv8(i)}); - DECLARE(INLINE_CONVERSION, bv8, bvdouble, $si2fp, {sbv8td(i)}); - DECLARE(INLINE_CONVERSION, bv8, bvdouble, $ui2fp, {ubv8td(i)}); - - D("function {:builtin \"(_ fp.to_sbv 64) RNE\"} $round.rne.bvdouble(bvdouble) returns (bv64);"); - D("function {:builtin \"(_ fp.to_sbv 64) RNA\"} $round.rna.bvdouble(bvdouble) returns (bv64);"); - D("function {:builtin \"(_ fp.to_sbv 64) RTN\"} $floor.bvdouble(bvdouble) returns (bv64);"); - D("function {:builtin \"(_ fp.to_sbv 64) RTP\"} $ceil.bvdouble(bvdouble) returns (bv64);"); - D("function {:builtin \"(_ fp.to_sbv 64) RTZ\"} $trunc.bvdouble(bvdouble) returns (bv64);"); - - #if BUILD_64 - D("function {:builtin \"(_ fp.to_sbv 64) RNA\"} $lround.bvdouble(bvdouble) returns (bv64);"); +#else + // Non-bit-precise modeling of floating-points - #else - D("function {:builtin \"(_ fp.to_sbv 32) RNA\"} $lround.bvdouble(bvdouble) returns (bv32);"); + D("function $fp(ipart:int, fpart:int, epart:int) returns (float);"); + DECLARE(UNINTERPRETED_BINARY_OP,float,$fadd); + DECLARE(UNINTERPRETED_BINARY_OP,float,$fsub); + DECLARE(UNINTERPRETED_BINARY_OP,float,$fmul); + DECLARE(UNINTERPRETED_BINARY_OP,float,$fdiv); + DECLARE(UNINTERPRETED_BINARY_OP,float,$frem); + DECLARE(INLINE_BINARY_COMP,float,$ffalse,{false}); + DECLARE(INLINE_BINARY_COMP,float,$ftrue,{true}); + DECLARE(UNINTERPRETED_BINARY_COMP,float,$foeq); + DECLARE(UNINTERPRETED_BINARY_COMP,float,$foge); + DECLARE(UNINTERPRETED_BINARY_COMP,float,$fogt); + DECLARE(UNINTERPRETED_BINARY_COMP,float,$fole); + DECLARE(UNINTERPRETED_BINARY_COMP,float,$folt); + DECLARE(UNINTERPRETED_BINARY_COMP,float,$fone); + DECLARE(UNINTERPRETED_BINARY_COMP,float,$ford); + DECLARE(UNINTERPRETED_BINARY_COMP,float,$fueq); + DECLARE(UNINTERPRETED_BINARY_COMP,float,$fuge); + DECLARE(UNINTERPRETED_BINARY_COMP,float,$fugt); + DECLARE(UNINTERPRETED_BINARY_COMP,float,$fule); + DECLARE(UNINTERPRETED_BINARY_COMP,float,$fult); + DECLARE(UNINTERPRETED_BINARY_COMP,float,$fune); + DECLARE(UNINTERPRETED_BINARY_COMP,float,$funo); + + DECLARE(UNINTERPRETED_CONVERSION,float,i128,$fp2si); + DECLARE(UNINTERPRETED_CONVERSION,float,i128,$fp2ui); + DECLARE(UNINTERPRETED_CONVERSION,float,i96,$fp2si); + DECLARE(UNINTERPRETED_CONVERSION,float,i96,$fp2ui); + DECLARE(UNINTERPRETED_CONVERSION,float,i88,$fp2si); + DECLARE(UNINTERPRETED_CONVERSION,float,i88,$fp2ui); + DECLARE(UNINTERPRETED_CONVERSION,float,i80,$fp2si); + DECLARE(UNINTERPRETED_CONVERSION,float,i80,$fp2ui); + DECLARE(UNINTERPRETED_CONVERSION,float,i64,$fp2si); + DECLARE(UNINTERPRETED_CONVERSION,float,i64,$fp2ui); + DECLARE(UNINTERPRETED_CONVERSION,float,i56,$fp2si); + DECLARE(UNINTERPRETED_CONVERSION,float,i56,$fp2ui); + DECLARE(UNINTERPRETED_CONVERSION,float,i48,$fp2si); + DECLARE(UNINTERPRETED_CONVERSION,float,i48,$fp2ui); + DECLARE(UNINTERPRETED_CONVERSION,float,i40,$fp2si); + DECLARE(UNINTERPRETED_CONVERSION,float,i40,$fp2ui); + DECLARE(UNINTERPRETED_CONVERSION,float,i32,$fp2si); + DECLARE(UNINTERPRETED_CONVERSION,float,i32,$fp2ui); + DECLARE(UNINTERPRETED_CONVERSION,float,i24,$fp2si); + DECLARE(UNINTERPRETED_CONVERSION,float,i24,$fp2ui); + DECLARE(UNINTERPRETED_CONVERSION,float,i16,$fp2si); + DECLARE(UNINTERPRETED_CONVERSION,float,i16,$fp2ui); + DECLARE(UNINTERPRETED_CONVERSION,float,i8,$fp2si); + DECLARE(UNINTERPRETED_CONVERSION,float,i8,$fp2ui); + DECLARE(UNINTERPRETED_CONVERSION,float,i1,$fp2si); + DECLARE(UNINTERPRETED_CONVERSION,float,i1,$fp2ui); + DECLARE(UNINTERPRETED_CONVERSION,i128,float,$si2fp); + DECLARE(UNINTERPRETED_CONVERSION,i128,float,$ui2fp); + DECLARE(UNINTERPRETED_CONVERSION,i96,float,$si2fp); + DECLARE(UNINTERPRETED_CONVERSION,i96,float,$ui2fp); + DECLARE(UNINTERPRETED_CONVERSION,i88,float,$si2fp); + DECLARE(UNINTERPRETED_CONVERSION,i88,float,$ui2fp); + DECLARE(UNINTERPRETED_CONVERSION,i80,float,$si2fp); + DECLARE(UNINTERPRETED_CONVERSION,i80,float,$ui2fp); + DECLARE(UNINTERPRETED_CONVERSION,i64,float,$si2fp); + DECLARE(UNINTERPRETED_CONVERSION,i64,float,$ui2fp); + DECLARE(UNINTERPRETED_CONVERSION,i56,float,$si2fp); + DECLARE(UNINTERPRETED_CONVERSION,i56,float,$ui2fp); + DECLARE(UNINTERPRETED_CONVERSION,i48,float,$si2fp); + DECLARE(UNINTERPRETED_CONVERSION,i48,float,$ui2fp); + DECLARE(UNINTERPRETED_CONVERSION,i40,float,$si2fp); + DECLARE(UNINTERPRETED_CONVERSION,i40,float,$ui2fp); + DECLARE(UNINTERPRETED_CONVERSION,i32,float,$si2fp); + DECLARE(UNINTERPRETED_CONVERSION,i32,float,$ui2fp); + DECLARE(UNINTERPRETED_CONVERSION,i24,float,$si2fp); + DECLARE(UNINTERPRETED_CONVERSION,i24,float,$ui2fp); + DECLARE(UNINTERPRETED_CONVERSION,i16,float,$si2fp); + DECLARE(UNINTERPRETED_CONVERSION,i16,float,$ui2fp); + DECLARE(UNINTERPRETED_CONVERSION,i8,float,$si2fp); + DECLARE(UNINTERPRETED_CONVERSION,i8,float,$ui2fp); + DECLARE(UNINTERPRETED_CONVERSION,i1,float,$si2fp); + DECLARE(UNINTERPRETED_CONVERSION,i1,float,$ui2fp); + DECLARE(UNINTERPRETED_CONVERSION,float,bv128,$fp2si); + DECLARE(UNINTERPRETED_CONVERSION,float,bv128,$fp2ui); + DECLARE(UNINTERPRETED_CONVERSION,float,bv96,$fp2si); + DECLARE(UNINTERPRETED_CONVERSION,float,bv96,$fp2ui); + DECLARE(UNINTERPRETED_CONVERSION,float,bv88,$fp2si); + DECLARE(UNINTERPRETED_CONVERSION,float,bv88,$fp2ui); + DECLARE(UNINTERPRETED_CONVERSION,float,bv80,$fp2si); + DECLARE(UNINTERPRETED_CONVERSION,float,bv80,$fp2ui); + DECLARE(UNINTERPRETED_CONVERSION,float,bv64,$fp2si); + DECLARE(UNINTERPRETED_CONVERSION,float,bv64,$fp2ui); + DECLARE(UNINTERPRETED_CONVERSION,float,bv56,$fp2si); + DECLARE(UNINTERPRETED_CONVERSION,float,bv56,$fp2ui); + DECLARE(UNINTERPRETED_CONVERSION,float,bv48,$fp2si); + DECLARE(UNINTERPRETED_CONVERSION,float,bv48,$fp2ui); + DECLARE(UNINTERPRETED_CONVERSION,float,bv40,$fp2si); + DECLARE(UNINTERPRETED_CONVERSION,float,bv40,$fp2ui); + DECLARE(UNINTERPRETED_CONVERSION,float,bv32,$fp2si); + DECLARE(UNINTERPRETED_CONVERSION,float,bv32,$fp2ui); + DECLARE(UNINTERPRETED_CONVERSION,float,bv24,$fp2si); + DECLARE(UNINTERPRETED_CONVERSION,float,bv24,$fp2ui); + DECLARE(UNINTERPRETED_CONVERSION,float,bv16,$fp2si); + DECLARE(UNINTERPRETED_CONVERSION,float,bv16,$fp2ui); + DECLARE(UNINTERPRETED_CONVERSION,float,bv8,$fp2si); + DECLARE(UNINTERPRETED_CONVERSION,float,bv8,$fp2ui); + DECLARE(UNINTERPRETED_CONVERSION,float,bv1,$fp2si); + DECLARE(UNINTERPRETED_CONVERSION,float,bv1,$fp2ui); + DECLARE(UNINTERPRETED_CONVERSION,bv128,float,$si2fp); + DECLARE(UNINTERPRETED_CONVERSION,bv128,float,$ui2fp); + DECLARE(UNINTERPRETED_CONVERSION,bv96,float,$si2fp); + DECLARE(UNINTERPRETED_CONVERSION,bv96,float,$ui2fp); + DECLARE(UNINTERPRETED_CONVERSION,bv88,float,$si2fp); + DECLARE(UNINTERPRETED_CONVERSION,bv88,float,$ui2fp); + DECLARE(UNINTERPRETED_CONVERSION,bv80,float,$si2fp); + DECLARE(UNINTERPRETED_CONVERSION,bv80,float,$ui2fp); + DECLARE(UNINTERPRETED_CONVERSION,bv64,float,$si2fp); + DECLARE(UNINTERPRETED_CONVERSION,bv64,float,$ui2fp); + DECLARE(UNINTERPRETED_CONVERSION,bv56,float,$si2fp); + DECLARE(UNINTERPRETED_CONVERSION,bv56,float,$ui2fp); + DECLARE(UNINTERPRETED_CONVERSION,bv48,float,$si2fp); + DECLARE(UNINTERPRETED_CONVERSION,bv48,float,$ui2fp); + DECLARE(UNINTERPRETED_CONVERSION,bv40,float,$si2fp); + DECLARE(UNINTERPRETED_CONVERSION,bv40,float,$ui2fp); + DECLARE(UNINTERPRETED_CONVERSION,bv32,float,$si2fp); + DECLARE(UNINTERPRETED_CONVERSION,bv32,float,$ui2fp); + DECLARE(UNINTERPRETED_CONVERSION,bv24,float,$si2fp); + DECLARE(UNINTERPRETED_CONVERSION,bv24,float,$ui2fp); + DECLARE(UNINTERPRETED_CONVERSION,bv16,float,$si2fp); + DECLARE(UNINTERPRETED_CONVERSION,bv16,float,$ui2fp); + DECLARE(UNINTERPRETED_CONVERSION,bv8,float,$si2fp); + DECLARE(UNINTERPRETED_CONVERSION,bv8,float,$ui2fp); + DECLARE(UNINTERPRETED_CONVERSION,bv1,float,$si2fp); + DECLARE(UNINTERPRETED_CONVERSION,bv1,float,$ui2fp); + DECLARE(UNINTERPRETED_CONVERSION,float,float,$fptrunc); + DECLARE(UNINTERPRETED_CONVERSION,float,float,$fpext); + + DECLARE(UNINTERPRETED_CONVERSION,float,i1,$bitcast); + DECLARE(UNINTERPRETED_CONVERSION,float,bv1,$bitcast); + DECLARE(UNINTERPRETED_CONVERSION,i1,float,$bitcast); + DECLARE(UNINTERPRETED_CONVERSION,bv1,float,$bitcast); + DECLARE(UNINTERPRETED_CONVERSION,float,i8,$bitcast); + DECLARE(UNINTERPRETED_CONVERSION,float,bv8,$bitcast); + DECLARE(UNINTERPRETED_CONVERSION,i8,float,$bitcast); + DECLARE(UNINTERPRETED_CONVERSION,bv8,float,$bitcast); + DECLARE(UNINTERPRETED_CONVERSION,float,i16,$bitcast); + DECLARE(UNINTERPRETED_CONVERSION,float,bv16,$bitcast); + DECLARE(UNINTERPRETED_CONVERSION,i16,float,$bitcast); + DECLARE(UNINTERPRETED_CONVERSION,bv16,float,$bitcast); + DECLARE(UNINTERPRETED_CONVERSION,float,i32,$bitcast); + DECLARE(UNINTERPRETED_CONVERSION,float,bv32,$bitcast); + DECLARE(UNINTERPRETED_CONVERSION,i32,float,$bitcast); + DECLARE(UNINTERPRETED_CONVERSION,bv32,float,$bitcast); + DECLARE(UNINTERPRETED_CONVERSION,float,i64,$bitcast); + DECLARE(UNINTERPRETED_CONVERSION,float,bv64,$bitcast); + DECLARE(UNINTERPRETED_CONVERSION,i64,float,$bitcast); + DECLARE(UNINTERPRETED_CONVERSION,bv64,float,$bitcast); + DECLARE(UNINTERPRETED_CONVERSION,float,i80,$bitcast); + DECLARE(UNINTERPRETED_CONVERSION,float,bv80,$bitcast); + DECLARE(UNINTERPRETED_CONVERSION,i80,float,$bitcast); + DECLARE(UNINTERPRETED_CONVERSION,bv80,float,$bitcast); - #endif +#ifndef NO_FORALL + D("axiom (forall f1, f2: float :: $foeq.float.bool(f1,f2) <==> !$fune.float.bool(f1,f2));"); + D("axiom (forall f1, f2: float :: $fone.float.bool(f1,f2) <==> !$fueq.float.bool(f1,f2));"); + D("axiom (forall f1, f2: float :: $fogt.float.bool(f1,f2) <==> !$fule.float.bool(f1,f2));"); + D("axiom (forall f1, f2: float :: $foge.float.bool(f1,f2) <==> !$fult.float.bool(f1,f2));"); + D("axiom (forall f1, f2: float :: $folt.float.bool(f1,f2) <==> !$fuge.float.bool(f1,f2));"); + D("axiom (forall f1, f2: float :: $fole.float.bool(f1,f2) <==> !$fugt.float.bool(f1,f2));"); + D("axiom (forall f1, f2: float :: $ford.float.bool(f1,f2) <==> !$funo.float.bool(f1,f2));"); + D("axiom (forall f: float, i: i8 :: $bitcast.float.i8(f) == i <==> $bitcast.i8.float(i) == f);"); + // TODO: add proper axiom for float/bv8 conversions +#endif #endif @@ -1383,188 +1147,109 @@ void __SMACK_decls(void) { D("const $MALLOC_TOP: ref;"); D("function {:inline} $isExternal(p: ref) returns (bool) {$slt.ref.bool(p,$EXTERNS_BOTTOM)}"); - D("function {:inline} $load.i128(M: [ref] i128, p: ref) returns (i128) { M[p] }"); - D("function {:inline} $load.i96(M: [ref] i96, p: ref) returns (i96) { M[p] }"); - D("function {:inline} $load.i88(M: [ref] i88, p: ref) returns (i88) { M[p] }"); - D("function {:inline} $load.i64(M: [ref] i64, p: ref) returns (i64) { M[p] }"); - D("function {:inline} $load.i56(M: [ref] i56, p: ref) returns (i56) { M[p] }"); - D("function {:inline} $load.i48(M: [ref] i48, p: ref) returns (i48) { M[p] }"); - D("function {:inline} $load.i40(M: [ref] i40, p: ref) returns (i40) { M[p] }"); - D("function {:inline} $load.i32(M: [ref] i32, p: ref) returns (i32) { M[p] }"); - D("function {:inline} $load.i24(M: [ref] i24, p: ref) returns (i24) { M[p] }"); - D("function {:inline} $load.i16(M: [ref] i16, p: ref) returns (i16) { M[p] }"); - D("function {:inline} $load.i8(M: [ref] i8, p: ref) returns (i8) { M[p] }"); - - D("function {:inline} $load.bv128(M: [ref] bv128, p: ref) returns (bv128) { M[p] }"); - D("function {:inline} $load.bv96(M: [ref] bv96, p: ref) returns (bv96) { M[p] }"); - D("function {:inline} $load.bv88(M: [ref] bv88, p: ref) returns (bv88) { M[p] }"); - D("function {:inline} $load.bv64(M: [ref] bv64, p: ref) returns (bv64) { M[p] }"); - D("function {:inline} $load.bv56(M: [ref] bv56, p: ref) returns (bv56) { M[p] }"); - D("function {:inline} $load.bv48(M: [ref] bv48, p: ref) returns (bv48) { M[p] }"); - D("function {:inline} $load.bv40(M: [ref] bv40, p: ref) returns (bv40) { M[p] }"); - D("function {:inline} $load.bv32(M: [ref] bv32, p: ref) returns (bv32) { M[p] }"); - D("function {:inline} $load.bv24(M: [ref] bv24, p: ref) returns (bv24) { M[p] }"); - D("function {:inline} $load.bv16(M: [ref] bv16, p: ref) returns (bv16) { M[p] }"); - D("function {:inline} $load.bv8(M: [ref] bv8, p: ref) returns (bv8) { M[p] }"); - - D("function {:inline} $load.bytes.bv128(M: [ref] bv8, p: ref) returns (bv128)" - "{ $load.bytes.bv64(M, $add.ref(p, $8.ref)) ++ $load.bytes.bv64(M, p) }"); - D("function {:inline} $load.bytes.bv96(M: [ref] bv8, p: ref) returns (bv96)" - "{ $load.bytes.bv64(M, $add.ref(p, $4.ref)) ++ $load.bytes.bv32(M, p) }"); - D("function {:inline} $load.bytes.bv88(M: [ref] bv8, p: ref) returns (bv88)" - "{ $load.bytes.bv56(M, $add.ref(p, $4.ref)) ++ $load.bytes.bv32(M, p) }"); - D("function {:inline} $load.bytes.bv64(M: [ref] bv8, p: ref) returns (bv64)" - "{ $load.bytes.bv32(M, $add.ref(p, $4.ref)) ++ $load.bytes.bv32(M, p) }"); - D("function {:inline} $load.bytes.bv56(M: [ref] bv8, p: ref) returns (bv56)" - "{ $load.bytes.bv24(M, $add.ref(p, $4.ref)) ++ $load.bytes.bv32(M, p) }"); - D("function {:inline} $load.bytes.bv48(M: [ref] bv8, p: ref) returns (bv48)" - "{ $load.bytes.bv16(M, $add.ref(p, $4.ref)) ++ $load.bytes.bv32(M, p) }"); - D("function {:inline} $load.bytes.bv40(M: [ref] bv8, p: ref) returns (bv40)" - "{ M[$add.ref(p, $4.ref)] ++ $load.bytes.bv32(M, p) }"); - D("function {:inline} $load.bytes.bv32(M: [ref] bv8, p: ref) returns (bv32)" - "{ M[$add.ref(p, $3.ref)] ++ M[$add.ref(p, $2.ref)] ++ M[$add.ref(p, $1.ref)]++M[p] }"); - D("function {:inline} $load.bytes.bv24(M: [ref] bv8, p: ref) returns (bv24)" - "{ M[$add.ref(p, $2.ref)] ++ M[$add.ref(p, $1.ref)]++M[p] }"); - D("function {:inline} $load.bytes.bv16(M: [ref] bv8, p: ref) returns (bv16)" - "{ M[$add.ref(p, $1.ref)] ++ M[p] }"); - D("function {:inline} $load.bytes.bv8(M: [ref] bv8, p: ref) returns (bv8) { M[p] }"); - - D("function {:inline} $store.i128(M: [ref] i128, p: ref, v: i128) returns ([ref] i128) { M[p := v] }"); - D("function {:inline} $store.i96(M: [ref] i96, p: ref, v: i96) returns ([ref] i96) { M[p := v] }"); - D("function {:inline} $store.i88(M: [ref] i88, p: ref, v: i88) returns ([ref] i88) { M[p := v] }"); - D("function {:inline} $store.i64(M: [ref] i64, p: ref, v: i64) returns ([ref] i64) { M[p := v] }"); - D("function {:inline} $store.i56(M: [ref] i56, p: ref, v: i56) returns ([ref] i56) { M[p := v] }"); - D("function {:inline} $store.i48(M: [ref] i48, p: ref, v: i48) returns ([ref] i48) { M[p := v] }"); - D("function {:inline} $store.i40(M: [ref] i40, p: ref, v: i40) returns ([ref] i40) { M[p := v] }"); - D("function {:inline} $store.i32(M: [ref] i32, p: ref, v: i32) returns ([ref] i32) { M[p := v] }"); - D("function {:inline} $store.i24(M: [ref] i24, p: ref, v: i24) returns ([ref] i24) { M[p := v] }"); - D("function {:inline} $store.i16(M: [ref] i16, p: ref, v: i16) returns ([ref] i16) { M[p := v] }"); - D("function {:inline} $store.i8(M: [ref] i8, p: ref, v: i8) returns ([ref] i8) { M[p := v] }"); - - D("function {:inline} $store.bv128(M: [ref] bv128, p: ref, v: bv128) returns ([ref] bv128) { M[p := v] }"); - D("function {:inline} $store.bv96(M: [ref] bv96, p: ref, v: bv96) returns ([ref] bv96) { M[p := v] }"); - D("function {:inline} $store.bv88(M: [ref] bv88, p: ref, v: bv88) returns ([ref] bv88) { M[p := v] }"); - D("function {:inline} $store.bv64(M: [ref] bv64, p: ref, v: bv64) returns ([ref] bv64) { M[p := v] }"); - D("function {:inline} $store.bv56(M: [ref] bv56, p: ref, v: bv56) returns ([ref] bv56) { M[p := v] }"); - D("function {:inline} $store.bv48(M: [ref] bv48, p: ref, v: bv48) returns ([ref] bv48) { M[p := v] }"); - D("function {:inline} $store.bv40(M: [ref] bv40, p: ref, v: bv40) returns ([ref] bv40) { M[p := v] }"); - D("function {:inline} $store.bv32(M: [ref] bv32, p: ref, v: bv32) returns ([ref] bv32) { M[p := v] }"); - D("function {:inline} $store.bv24(M: [ref] bv24, p: ref, v: bv24) returns ([ref] bv24) { M[p := v] }"); - D("function {:inline} $store.bv16(M: [ref] bv16, p: ref, v: bv16) returns ([ref] bv16) { M[p := v] }"); - D("function {:inline} $store.bv8(M: [ref] bv8, p: ref, v: bv8) returns ([ref] bv8) { M[p := v] }"); - - D("function {:inline} $store.bytes.bv128(M:[ref]bv8, p:ref, v:bv128) returns ([ref]bv8){" - "M[p := v[8:0]][$add.ref(p, $1.ref) := v[16:8]]" - "[$add.ref(p, $2.ref) := v[24:16]][$add.ref(p, $3.ref) := v[32:24]]" - "[$add.ref(p, $4.ref) := v[40:32]][$add.ref(p, $5.ref) := v[48:40]]" - "[$add.ref(p, $6.ref) := v[56:48]][$add.ref(p, $7.ref) := v[64:56]]" - "[$add.ref(p, $7.ref) := v[72:64]][$add.ref(p, $8.ref) := v[80:72]]" - "[$add.ref(p, $9.ref) := v[88:80]][$add.ref(p, $10.ref) := v[96:88]]" - "[$add.ref(p, $11.ref) := v[104:96]][$add.ref(p, $12.ref) := v[112:104]]" - "[$add.ref(p, $13.ref) := v[120:112]][$add.ref(p, $14.ref) := v[128:120]]}"); - D("function {:inline} $store.bytes.bv96(M:[ref]bv8, p:ref, v:bv96) returns ([ref]bv8){" - "M[p := v[8:0]][$add.ref(p, $1.ref) := v[16:8]]" - "[$add.ref(p, $2.ref) := v[24:16]][$add.ref(p, $3.ref) := v[32:24]]" - "[$add.ref(p, $4.ref) := v[40:32]][$add.ref(p, $5.ref) := v[48:40]]" - "[$add.ref(p, $6.ref) := v[56:48]][$add.ref(p, $7.ref) := v[64:56]]" - "[$add.ref(p, $7.ref) := v[72:64]][$add.ref(p, $8.ref) := v[80:72]]" - "[$add.ref(p, $9.ref) := v[88:80]][$add.ref(p, $10.ref) := v[96:88]]}"); - D("function {:inline} $store.bytes.bv88(M:[ref]bv8, p:ref, v:bv88) returns ([ref]bv8){" - "M[p := v[8:0]][$add.ref(p, $1.ref) := v[16:8]]" - "[$add.ref(p, $2.ref) := v[24:16]][$add.ref(p, $3.ref) := v[32:24]]" - "[$add.ref(p, $4.ref) := v[40:32]][$add.ref(p, $5.ref) := v[48:40]]" - "[$add.ref(p, $6.ref) := v[56:48]][$add.ref(p, $7.ref) := v[64:56]]" - "[$add.ref(p, $7.ref) := v[72:64]][$add.ref(p, $8.ref) := v[80:72]]" - "[$add.ref(p, $9.ref) := v[88:80]]}"); - D("function {:inline} $store.bytes.bv64(M:[ref]bv8, p:ref, v:bv64) returns ([ref]bv8){" - "M[p := v[8:0]][$add.ref(p, $1.ref) := v[16:8]]" - "[$add.ref(p, $2.ref) := v[24:16]][$add.ref(p, $3.ref) := v[32:24]]" - "[$add.ref(p, $4.ref) := v[40:32]][$add.ref(p, $5.ref) := v[48:40]]" - "[$add.ref(p, $6.ref) := v[56:48]][$add.ref(p, $7.ref) := v[64:56]]}"); - D("function {:inline} $store.bytes.bv56(M:[ref]bv8, p:ref, v:bv56) returns ([ref]bv8){" - "M[p := v[8:0]][$add.ref(p, $1.ref) := v[16:8]]" - "[$add.ref(p, $2.ref) := v[24:16]][$add.ref(p, $3.ref) := v[32:24]]" - "[$add.ref(p, $4.ref) := v[40:32]][$add.ref(p, $5.ref) := v[48:40]]" - "[$add.ref(p, $6.ref) := v[56:48]]}"); - D("function {:inline} $store.bytes.bv48(M:[ref]bv8, p:ref, v:bv48) returns ([ref]bv8){" - "M[p := v[8:0]][$add.ref(p, $1.ref) := v[16:8]]" - "[$add.ref(p, $2.ref) := v[24:16]][$add.ref(p, $3.ref) := v[32:24]]" - "[$add.ref(p, $4.ref) := v[40:32]][$add.ref(p, $5.ref) := v[48:40]]}"); - D("function {:inline} $store.bytes.bv40(M:[ref]bv8, p:ref, v:bv40) returns ([ref]bv8){" - "M[p := v[8:0]][$add.ref(p, $1.ref) := v[16:8]]" - "[$add.ref(p, $2.ref) := v[24:16]][$add.ref(p, $3.ref) := v[32:24]]" - "[$add.ref(p, $4.ref) := v[40:32]]}"); - D("function {:inline} $store.bytes.bv32(M:[ref]bv8, p:ref, v:bv32) returns ([ref]bv8) {" - "M[p := v[8:0]][$add.ref(p, $1.ref) := v[16:8]]" - "[$add.ref(p, $2.ref) := v[24:16]][$add.ref(p, $3.ref) := v[32:24]]}"); - D("function {:inline} $store.bytes.bv24(M:[ref]bv8, p:ref, v:bv24) returns ([ref]bv8) {" - "M[p := v[8:0]][$add.ref(p, $1.ref) := v[16:8]]" - "[$add.ref(p, $2.ref) := v[24:16]]}"); - D("function {:inline} $store.bytes.bv16(M:[ref]bv8, p:ref, v:bv16) returns ([ref]bv8) {" - "M[p := v[8:0]][$add.ref(p, $1.ref) := v[16:8]]}"); - D("function {:inline} $store.bytes.bv8(M:[ref]bv8, p:ref, v:bv8) returns ([ref]bv8) {M[p := v]}"); + DECLARE_UNSAFE_LOADS + DECLARE(UNSAFE_LOAD_OP, bv8, $load.bytes, { M[p] }); + DECLARE(UNSAFE_LOAD_OP, bv1, $load.bytes, { $trunc.bv8.bv1(M[p]) }); + + DECLARE_UNSAFE_STORES + DECLARE(UNSAFE_STORE_OP, bv8, $store.bytes, {M[p := v]}); + DECLARE(UNSAFE_STORE_OP, bv1, $store.bytes, {M[p := $zext.bv1.bv8(v)]}); D("function {:inline} $load.ref(M: [ref] ref, p: ref) returns (ref) { M[p] }"); D("function {:inline} $store.ref(M: [ref] ref, p: ref, v: ref) returns ([ref] ref) { M[p := v] }"); - D("function {:inline} $load.float(M: [ref] float, p: ref) returns (float) { M[p] }"); - D("function {:inline} $store.float(M: [ref] float, p: ref, v: float) returns ([ref] float) { M[p := v] }"); - - #if FLOAT_ENABLED +#if FLOAT_ENABLED + DECLARE(UNINTERPRETED_CONVERSION,bvhalf,bv16,$bitcast); + DECLARE(UNINTERPRETED_CONVERSION,bvfloat,bv32,$bitcast); + DECLARE(UNINTERPRETED_CONVERSION,bvdouble,bv64,$bitcast); + DECLARE(UNINTERPRETED_CONVERSION,bvlongdouble,bv80,$bitcast); + DECLARE(BUILTIN_CONVERSION,bv16,bvhalf,$bitcast,(_ to_fp 5 11)); + DECLARE(BUILTIN_CONVERSION,bv32,bvfloat,$bitcast,(_ to_fp 8 24)); + DECLARE(BUILTIN_CONVERSION,bv64,bvdouble,$bitcast,(_ to_fp 11 53)); + DECLARE(BUILTIN_CONVERSION,bv80,bvlongdouble,$bitcast,(_ to_fp 15 65)); + DECLARE(UNINTERPRETED_CONVERSION,bvhalf,i16,$bitcast); + DECLARE(UNINTERPRETED_CONVERSION,bvfloat,i32,$bitcast); + DECLARE(UNINTERPRETED_CONVERSION,bvdouble,i64,$bitcast); + DECLARE(UNINTERPRETED_CONVERSION,bvlongdouble,i80,$bitcast); + DECLARE(UNINTERPRETED_CONVERSION,i16,bvhalf,$bitcast); + DECLARE(UNINTERPRETED_CONVERSION,i32,bvfloat,$bitcast); + DECLARE(UNINTERPRETED_CONVERSION,i64,bvdouble,$bitcast); + DECLARE(UNINTERPRETED_CONVERSION,i80,bvlongdouble,$bitcast); + D("axiom (forall f: bvhalf :: $bitcast.bv16.bvhalf($bitcast.bvhalf.bv16(f)) == f);"); + D("axiom (forall f: bvfloat :: $bitcast.bv32.bvfloat($bitcast.bvfloat.bv32(f)) == f);"); + D("axiom (forall f: bvdouble :: $bitcast.bv64.bvdouble($bitcast.bvdouble.bv64(f)) == f);"); + D("axiom (forall f: bvlongdouble :: $bitcast.bv80.bvlongdouble($bitcast.bvlongdouble.bv80(f)) == f);"); + //D("axiom (forall b: bv16 :: b[15:10] == 31bv5 && b[10:0] != 0bv10 ==> $bitcast.bvhalf.bv16($bitcast.bv16.bvhalf(b)) == b);"); + //D("axiom (forall b: bv32 :: b[31:23] == 255bv8 && b[23:0] != 0bv23 ==> $bitcast.bvfloat.bv32($bitcast.bv32.bvfloat(b)) == b);"); + //D("axiom (forall b: bv64 :: b[63:52] == 2047bv11 && b[52:0] != 0bv52 ==> $bitcast.bvdouble.bv64($bitcast.bv64.bvdouble(b)) == b);"); + //D("axiom (forall b: bv80 :: b[79:64] == 32768bv15 && b[64:0] != 0bv64 ==> $bitcast.bvlongdouble.bv80($bitcast.bv80.bvlongdouble(b)) == b);"); + // TODO: add more constraints + + D("axiom (forall f: bvfloat, rm1: rmode, rm2: rmode :: dtf(rm1, ftd(rm2, f)) == f);"); + D("axiom (forall f: bvlongdouble, rm1: rmode, rm2: rmode :: dtl(rm1, ltd(rm2, f)) == f);"); + + D("axiom (forall f: bvhalf, i: i16 :: $bitcast.bvhalf.i16(f) == i <==> $bitcast.i16.bvhalf(i) == f);"); + D("axiom (forall f: bvfloat, i: i32 :: $bitcast.bvfloat.i32(f) == i <==> $bitcast.i32.bvfloat(i) == f);"); + D("axiom (forall f: bvdouble, i: i64 :: $bitcast.bvdouble.i64(f) == i <==> $bitcast.i64.bvdouble(i) == f);"); + D("axiom (forall f: bvlongdouble, i: i80 :: $bitcast.bvlongdouble.i80(f) == i <==> $bitcast.i80.bvlongdouble(i) == f);"); + + D("function {:inline} $load.bvhalf(M: [ref] bvhalf, p: ref) returns (bvhalf) { M[p] }"); + D("function {:inline} $store.bvhalf(M: [ref] bvhalf, p: ref, v: bvhalf) returns ([ref] bvhalf) { M[p := v] }"); D("function {:inline} $load.bvfloat(M: [ref] bvfloat, p: ref) returns (bvfloat) { M[p] }"); D("function {:inline} $store.bvfloat(M: [ref] bvfloat, p: ref, v: bvfloat) returns ([ref] bvfloat) { M[p := v] }"); - D("function {:inline} $load.bvdouble(M: [ref] bvdouble, p: ref) returns (bvdouble) { M[p] }"); D("function {:inline} $store.bvdouble(M: [ref] bvdouble, p: ref, v: bvdouble) returns ([ref] bvdouble) { M[p := v] }"); + D("function {:inline} $load.bvlongdouble(M: [ref] bvlongdouble, p: ref) returns (bvlongdouble) { M[p] }"); + D("function {:inline} $store.bvlongdouble(M: [ref] bvlongdouble, p: ref, v: bvlongdouble) returns ([ref] bvlongdouble) { M[p := v] }"); + D("function {:inline} $store.bytes.bvhalf(M:[ref]bv8, p:ref, v:bvhalf) returns ([ref]bv8) {" + "$store.bytes.bv16(M, p, $bitcast.bvhalf.bv16(v))}"); D("function {:inline} $store.bytes.bvfloat(M:[ref]bv8, p:ref, v:bvfloat) returns ([ref]bv8) {" - "$store.bytes.bv32(M, p, $fp2ui.bvfloat.bv32(v))}"); + "$store.bytes.bv32(M, p, $bitcast.bvfloat.bv32(v))}"); D("function {:inline} $store.bytes.bvdouble(M:[ref]bv8, p:ref, v:bvdouble) returns ([ref]bv8) {" - "$store.bytes.bv64(M, p, $fp2ui.bvdouble.bv64(v))}"); - + "$store.bytes.bv64(M, p, $bitcast.bvdouble.bv64(v))}"); + D("function {:inline} $store.bytes.bvlongdouble(M:[ref]bv8, p:ref, v:bvlongdouble) returns ([ref]bv8) {" + "$store.bytes.bv80(M, p, $bitcast.bvlongdouble.bv80(v))}"); + D("function {:inline} $store.unsafe.bvhalf(M:[ref]i8, p:ref, v:bvhalf) returns ([ref]i8) {" + "$store.i16(M, p, $bitcast.bvhalf.i16(v))}"); + D("function {:inline} $store.unsafe.bvfloat(M:[ref]i8, p:ref, v:bvfloat) returns ([ref]i8) {" + "$store.i32(M, p, $bitcast.bvfloat.i32(v))}"); + D("function {:inline} $store.unsafe.bvdouble(M:[ref]i8, p:ref, v:bvdouble) returns ([ref]i8) {" + "$store.i64(M, p, $bitcast.bvdouble.i64(v))}"); + D("function {:inline} $store.unsafe.bvlongdouble(M:[ref]i8, p:ref, v:bvlongdouble) returns ([ref]i8) {" + "$store.i80(M, p, $bitcast.bvlongdouble.i80(v))}"); + + D("function {:inline} $load.bytes.bvhalf(M: [ref] bv8, p: ref) returns (bvhalf) {" + "$bitcast.bv16.bvhalf($load.bytes.bv16(M, p))}"); D("function {:inline} $load.bytes.bvfloat(M: [ref] bv8, p: ref) returns (bvfloat) {" - "$ui2fp.bv32.bvfloat($load.bytes.bv32(M, p))}"); + "$bitcast.bv32.bvfloat($load.bytes.bv32(M, p))}"); D("function {:inline} $load.bytes.bvdouble(M: [ref] bv8, p: ref) returns (bvdouble) {" - "$ui2fp.bv64.bvdouble($load.bytes.bv64(M, p))}"); - #endif + "$bitcast.bv64.bvdouble($load.bytes.bv64(M, p))}"); + D("function {:inline} $load.bytes.bvlongdouble(M: [ref] bv8, p: ref) returns (bvlongdouble) {" + "$bitcast.bv80.bvlongdouble($load.bytes.bv80(M, p))}"); + D("function {:inline} $load.unsafe.bvhalf(M: [ref] i8, p: ref) returns (bvhalf) {" + "$bitcast.i16.bvhalf($load.i16(M, p))}"); + D("function {:inline} $load.unsafe.bvfloat(M: [ref] i8, p: ref) returns (bvfloat) {" + "$bitcast.i32.bvfloat($load.i32(M, p))}"); + D("function {:inline} $load.unsafe.bvdouble(M: [ref] i8, p: ref) returns (bvdouble) {" + "$bitcast.i64.bvdouble($load.i64(M, p))}"); + D("function {:inline} $load.unsafe.bvlongdouble(M: [ref] i8, p: ref) returns (bvlongdouble) {" + "$bitcast.i80.bvlongdouble($load.i80(M, p))}"); + +#else + D("function {:inline} $load.float(M: [ref] float, p: ref) returns (float) { M[p] }"); + D("function {:inline} $load.unsafe.float(M: [ref] i8, p: ref) returns (float) { $bitcast.i8.float(M[p]) }"); + D("function {:inline} $store.float(M: [ref] float, p: ref, v: float) returns ([ref] float) { M[p := v] }"); + D("function {:inline} $store.unsafe.float(M: [ref] i8, p: ref, v: float) returns ([ref] i8) { M[p := $bitcast.float.i8(v)] }"); + D("function {:inline} $load.bytes.float(M: [ref] bv8, p: ref) returns (float) { $bitcast.bv8.float(M[p]) }"); + D("function {:inline} $store.bytes.float(M:[ref]bv8, p:ref, v:float) returns ([ref]bv8) {M[p := $bitcast.float.bv8(v)]}"); +#endif // Memory debugging symbols D("type $mop;"); D("procedure boogie_si_record_mop(m: $mop);"); D("const $MOP: $mop;"); - DECLARE(RECORD_PROC, bool); - DECLARE(RECORD_PROC, i1); - DECLARE(RECORD_PROC, i8); - DECLARE(RECORD_PROC, i16); - DECLARE(RECORD_PROC, i24); - DECLARE(RECORD_PROC, i32); - DECLARE(RECORD_PROC, i40); - DECLARE(RECORD_PROC, i48); - DECLARE(RECORD_PROC, i56); - DECLARE(RECORD_PROC, i64); - DECLARE(RECORD_PROC, i88); - DECLARE(RECORD_PROC, i96); - DECLARE(RECORD_PROC, i128); - DECLARE(RECORD_PROC, bv1); - DECLARE(RECORD_PROC, bv8); - DECLARE(RECORD_PROC, bv16); - DECLARE(RECORD_PROC, bv24); - DECLARE(RECORD_PROC, bv32); - DECLARE(RECORD_PROC, bv40); - DECLARE(RECORD_PROC, bv48); - DECLARE(RECORD_PROC, bv56); - DECLARE(RECORD_PROC, bv64); - DECLARE(RECORD_PROC, bv88); - DECLARE(RECORD_PROC, bv96); - DECLARE(RECORD_PROC, bv128); - DECLARE(RECORD_PROC, ref); - DECLARE(RECORD_PROC, float); - #if FLOAT_ENABLED - DECLARE(RECORD_PROC, bvfloat); - DECLARE(RECORD_PROC, bvdouble); - #endif - D("var $exn: bool;"); D("var $exnv: int;"); D("function $extractvalue(p: int, i: int) returns (int);\n"); @@ -1575,6 +1260,20 @@ void __SMACK_decls(void) { "}\n"); #if MEMORY_SAFETY + __SMACK_dummy((int) __SMACK_check_memory_safety); + D("implementation __SMACK_check_memory_safety(p: ref, size: ref)\n" + "{\n" + " assert {:valid_deref} $Alloc[$base(p)];\n" + " assert {:valid_deref} $sle.ref.bool($base(p), p);\n" + #if MEMORY_MODEL_NO_REUSE_IMPLS + " assert {:valid_deref} $sle.ref.bool($add.ref(p, size), $add.ref($base(p), $Size($base(p))));\n" + #elif MEMORY_MODEL_REUSE + " assert {:valid_deref} $sle.ref.bool($add.ref(p, size), $add.ref($base(p), $Size[$base(p)]));\n" + #else + " assert {:valid_deref} $sle.ref.bool($add.ref(p, size), $add.ref($base(p), $Size($base(p))));\n" + #endif + "}\n"); + D("function $base(ref) returns (ref);"); D("var $allocatedCounter: int;\n"); @@ -1758,20 +1457,6 @@ void __SMACK_decls(void) { } #if MEMORY_SAFETY -// The size parameter represents number of bytes that are being accessed -void __SMACK_check_memory_safety(void* pointer, unsigned long size) { - void* sizeRef = (void*)size; - __SMACK_code("assert {:valid_deref} $Alloc[$base(@)];", pointer); - __SMACK_code("assert {:valid_deref} $sle.ref.bool($base(@), @);", pointer, pointer); -#if MEMORY_MODEL_NO_REUSE_IMPLS - __SMACK_code("assert {:valid_deref} $sle.ref.bool($add.ref(@, @), $add.ref($base(@), $Size($base(@))));", pointer, sizeRef, pointer, pointer); -#elif MEMORY_MODEL_REUSE - __SMACK_code("assert {:valid_deref} $sle.ref.bool($add.ref(@, @), $add.ref($base(@), $Size[$base(@)]));", pointer, sizeRef, pointer, pointer); -#else - __SMACK_code("assert {:valid_deref} $sle.ref.bool($add.ref(@, @), $add.ref($base(@), $Size($base(@))));", pointer, sizeRef, pointer, pointer); -#endif -} - void __SMACK_check_memory_leak(void) { __SMACK_code("assert {:valid_memtrack} $allocatedCounter == 0;"); } diff --git a/share/smack/lib/smack.cpp b/share/smack/lib/smack.cpp new file mode 100644 index 000000000..b6db06b49 --- /dev/null +++ b/share/smack/lib/smack.cpp @@ -0,0 +1,13 @@ +#include +#include + +extern void *malloc(size_t size); +extern void free(void * p); + +void *operator new(size_t size) throw(std::bad_alloc) { + return malloc(size); +} + +void operator delete(void * p) throw() { + free(p); +} diff --git a/share/smack/lib/smack.f90 b/share/smack/lib/smack.f90 new file mode 100644 index 000000000..7c35d6567 --- /dev/null +++ b/share/smack/lib/smack.f90 @@ -0,0 +1,30 @@ +! +! This file is distributed under the MIT License. See LICENSE for details. +! + +module smack + implicit none + interface + subroutine __verifier_assert(cond) bind(c, name="__VERIFIER_assert") + use, intrinsic :: iso_c_binding, only: c_int + implicit none + integer(c_int), value :: cond + end subroutine __verifier_assert + end interface + contains + subroutine assert(cond) + use, intrinsic :: iso_c_binding, only: c_int + implicit none + logical, intent(in) :: cond + integer(c_int), value :: cond_c + interface + subroutine __verifier_assert(cond) bind(c, name="__VERIFIER_assert") + use, intrinsic :: iso_c_binding, only: c_int + implicit none + integer(c_int), value :: cond + end subroutine __verifier_assert + end interface + cond_c = merge(1,0,cond) + call __verifier_assert(cond_c) + end subroutine assert +end diff --git a/share/smack/lib/smack.rs b/share/smack/lib/smack.rs new file mode 100644 index 000000000..11ee5cc03 --- /dev/null +++ b/share/smack/lib/smack.rs @@ -0,0 +1,480 @@ +#[cfg(verifier = "smack")] +extern { + pub fn __VERIFIER_assert(x: i32); + pub fn __VERIFIER_assume(x: i32); + pub fn __VERIFIER_nondet_signed_char() -> i8; + pub fn __VERIFIER_nondet_unsigned_char() -> u8; + pub fn __VERIFIER_nondet_signed_short() -> i16; + pub fn __VERIFIER_nondet_unsigned_short() -> u16; + pub fn __VERIFIER_nondet_signed_int() -> i32; + pub fn __VERIFIER_nondet_unsigned_int() -> u32; + pub fn __VERIFIER_nondet_signed_long_long() -> i64; + pub fn __VERIFIER_nondet_unsigned_long_long() -> u64; + pub fn malloc(size: usize) -> *mut u8; + pub fn __VERIFIER_memcpy(dest: *mut u8, src: *mut u8, count:usize) -> *mut u8; + pub fn free(ptr: *mut u8); +} + + +#[cfg(verifier = "smack")] +#[macro_export] +macro_rules! assert { + ( $cond:expr ) => + ( + unsafe { __VERIFIER_assert($cond as i32); }; + ) +} + +#[cfg(verifier = "smack")] +#[macro_export] +macro_rules! assert_eq { + ( $lhs:expr, $rhs:expr ) => ( assert!($lhs == $rhs); ) +} + +#[cfg(verifier = "smack")] +#[macro_export] +macro_rules! assert_neq { + ( $lhs:expr, $rhs:expr ) => ( assert!($lhs != $rhs); ) +} + +#[macro_export] +macro_rules! assume { + ( $cond:expr ) => + ( + #[cfg(verifier = "smack")] + unsafe { __VERIFIER_assume($cond as i32); } + + #[cfg(not(verifier = "smack"))] + (); + ) +} + +#[macro_export] +macro_rules! nondet { + ($e:expr) => + ( + #[cfg(verifier = "smack")] + $e.nondet() + + #[cfg(not(verifier = "smack"))] + $e + ) +} + +pub trait NonDet { + fn nondet(self) -> Self; +} + +#[macro_export] +macro_rules! make_nondet { + ($typ:ident, $nondet:ident) => + ( + impl NonDet for $typ { + #[cfg(verifier = "smack")] + fn nondet(self) -> Self { + unsafe { $nondet() as Self } + } + + #[cfg(not(verifier = "smack"))] + fn nondet(self) -> Self { + self + } + } + ); +} + +/* Instantiate nondet for all integer types. */ +make_nondet!(i8, __VERIFIER_nondet_signed_char); +make_nondet!(u8, __VERIFIER_nondet_unsigned_char); +make_nondet!(i16, __VERIFIER_nondet_signed_short); +make_nondet!(u16, __VERIFIER_nondet_unsigned_short); +make_nondet!(i32, __VERIFIER_nondet_signed_int); +make_nondet!(u32, __VERIFIER_nondet_unsigned_int); +make_nondet!(i64, __VERIFIER_nondet_signed_long_long); +make_nondet!(u64, __VERIFIER_nondet_unsigned_long_long); +make_nondet!(isize, __VERIFIER_nondet_signed_long_long); +make_nondet!(usize, __VERIFIER_nondet_unsigned_long_long); + + +#[cfg(not(verifier = "smack"))] +#[allow(dead_code)] +use std::Vec; +/* Vector class. + Based on https://doc.rust-lang.org/nomicon/vec-final.html */ +#[cfg(verifier = "smack")] +#[allow(dead_code)] +fn sized_realloc(orig_ptr: *mut u8, orig_size: usize, new_size: usize) -> *mut u8 { + unsafe { + let result: *mut u8 = malloc(new_size); + __VERIFIER_memcpy(result, orig_ptr, orig_size); + result + } +} + +#[cfg(verifier = "smack")] +use std::ptr::{self,null}; +#[cfg(verifier = "smack")] +use std::mem; +#[cfg(verifier = "smack")] +use std::ops::{Deref, DerefMut}; + +#[cfg(verifier = "smack")] +#[allow(dead_code)] +pub struct PhantomData { + _place_holder: *const T, + _padding: u64 +} + +#[cfg(verifier = "smack")] +impl Default for PhantomData { + fn default() -> Self { + PhantomData:: { _place_holder: ptr::null(), + _padding: 0} + } +} + +#[cfg(verifier = "smack")] +#[allow(dead_code)] +struct Unique { +// _marker: PhantomData, // For the drop checker + ptr: *const T, // *const for variance + _marker: u64, +} + +#[cfg(verifier = "smack")] +impl Unique { + pub fn new(ptr: *mut T) -> Self { + Unique { ptr: ptr, _marker: Default::default() } + } + + pub fn as_ptr(&self) -> *mut T { + self.ptr as *mut T + } +} + +#[cfg(verifier = "smack")] +#[allow(dead_code)] +struct RawVec { + ptr: Unique, + cap: usize, +} + +#[cfg(verifier = "smack")] +#[allow(dead_code)] +impl RawVec { + fn new() -> Self { + let elem_size = mem::size_of::(); + let cap = 32; + let ptr = unsafe { Unique::new(malloc(cap*elem_size) as *mut T) }; + RawVec { ptr: ptr, cap: cap } + } + + + fn new_with_capacity(cap: usize) -> Self { + let elem_size = mem::size_of::(); + let ptr = unsafe { Unique::new(malloc(cap*elem_size) as *mut T) }; + RawVec { ptr: ptr, cap: cap } + } + + fn grow(&mut self) { + let elem_size = mem::size_of::(); + let new_cap = 2 * self.cap; + let ptr = sized_realloc(self.ptr.as_ptr() as *mut _, self.cap*elem_size, new_cap*elem_size); + + self.ptr = Unique::new(ptr as *mut _); + self.cap = new_cap; + } +} + +#[cfg(verifier = "smack")] +impl Drop for RawVec { + fn drop(&mut self) { + unsafe { free(self.ptr.ptr as *mut _) }; + } +} + +#[cfg(verifier = "smack")] +pub struct Vec { + buf: RawVec, + len: usize, +} + +#[cfg(verifier = "smack")] +impl Vec { + fn ptr(&self) -> *mut T { self.buf.ptr.as_ptr() } + + #[allow(dead_code)] + fn cap(&self) -> usize { self.buf.cap } + + pub fn new() -> Self { + Vec { buf: RawVec::new(), len: 0 } + } + + #[allow(dead_code)] + pub fn with_capacity(cap: usize) -> Self { + Vec { buf: RawVec::new_with_capacity(cap), len: 0 } + } + + + #[allow(dead_code)] + pub fn push(&mut self, elem: T) { + if self.len == self.cap() { self.buf.grow(); } + + unsafe { + ptr::write(self.ptr().offset(self.len as isize), elem); + } + + self.len += 1; + } + + #[allow(dead_code)] + pub fn pop(&mut self) -> Option { + if self.len == 0 { + None + } else { + self.len -= 1; + unsafe { + Some(ptr::read(self.ptr().offset(self.len as isize))) + } + } + } + + #[allow(dead_code)] + pub fn append(&mut self, other: &mut Vec) { + let mut i: usize = 0; + let olen = other.len(); + let mut drain = Vec::new(); + while i < olen { + drain.push(other.pop().unwrap()); + i += 1; + } + // Empty other + i = 0; + while i < olen { + self.push(drain.pop().unwrap()); + i += 1; + } + } + + #[allow(dead_code)] + pub fn insert(&mut self, index: usize, elem: T) { + assert!(index <= self.len); + if self.cap() == self.len { self.buf.grow(); } + + unsafe { + if index < self.len { + ptr::copy(self.ptr().offset(index as isize), + self.ptr().offset(index as isize + 1), + self.len - index); + } + ptr::write(self.ptr().offset(index as isize), elem); + self.len += 1; + } + } + + #[allow(dead_code)] + pub fn remove(&mut self, index: usize) -> T { + assert!(index < self.len); + unsafe { + self.len -= 1; + let result = ptr::read(self.ptr().offset(index as isize)); + ptr::copy(self.ptr().offset(index as isize + 1), + self.ptr().offset(index as isize), + self.len - index); + result + } + } + + #[allow(dead_code)] + pub fn into_iter(self) -> IntoIter { + unsafe { + let iter = RawValIter::new(&self); + let buf = ptr::read(&self.buf); + mem::forget(self); + + IntoIter { + iter: iter, + _buf: buf, + } + } + } + #[allow(dead_code)] + pub fn len(&self) -> usize { + self.len + } +} + +#[cfg(verifier = "smack")] +impl Default for Vec { + fn default() -> Self { + Vec::new() + } +} + +#[cfg(verifier = "smack")] +impl Drop for Vec { + fn drop(&mut self) { + while let Some(_) = self.pop() {} + // allocation is handled by RawVec + } +} + +#[cfg(verifier = "smack")] +impl Deref for Vec { + type Target = [T]; + fn deref(&self) -> &[T] { + unsafe { + ::std::slice::from_raw_parts(self.buf.ptr.ptr, self.len) + } + } +} + +#[cfg(verifier = "smack")] +impl DerefMut for Vec { + fn deref_mut(&mut self) -> &mut [T] { + unsafe { + ::std::slice::from_raw_parts_mut(self.buf.ptr.ptr as *mut T, self.len) + } + } +} + +#[cfg(verifier = "smack")] +struct RawValIter { + start: *const T, + end: *const T, +} + +#[cfg(verifier = "smack")] +impl RawValIter { + unsafe fn new(slice: &[T]) -> Self { + RawValIter { + start: slice.as_ptr(), + end: if mem::size_of::() == 0 { + ((slice.as_ptr() as usize) + slice.len()) as *const _ + } else if slice.len() == 0 { + slice.as_ptr() + } else { + slice.as_ptr().offset(slice.len() as isize) + } + } + } +} + +#[cfg(verifier = "smack")] +impl Iterator for RawValIter { + type Item = T; + fn next(&mut self) -> Option { + if self.start == self.end { + None + } else { + unsafe { + let result = ptr::read(self.start); + self.start = if mem::size_of::() == 0 { + (self.start as usize + 1) as *const _ + } else { + self.start.offset(1) + }; + Some(result) + } + } + } + + fn size_hint(&self) -> (usize, Option) { + let elem_size = mem::size_of::(); + let len = (self.end as usize - self.start as usize) + / if elem_size == 0 { 1 } else { elem_size }; + (len, Some(len)) + } +} + +#[cfg(verifier = "smack")] +impl DoubleEndedIterator for RawValIter { + fn next_back(&mut self) -> Option { + if self.start == self.end { + None + } else { + unsafe { + self.end = if mem::size_of::() == 0 { + (self.end as usize - 1) as *const _ + } else { + self.end.offset(-1) + }; + Some(ptr::read(self.end)) + } + } + } +} + +#[cfg(verifier = "smack")] +pub struct IntoIter { + _buf: RawVec, // we don't actually care about this. Just need it to live. + iter: RawValIter, +} + +#[cfg(verifier = "smack")] +impl Iterator for IntoIter { + type Item = T; + fn next(&mut self) -> Option { self.iter.next() } + fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } +} + +#[cfg(verifier = "smack")] +impl DoubleEndedIterator for IntoIter { + fn next_back(&mut self) -> Option { self.iter.next_back() } +} + +#[cfg(verifier = "smack")] +impl Drop for IntoIter { + fn drop(&mut self) { + for _ in &mut *self {} + } +} + +#[cfg(verifier = "smack")] +#[macro_export] +macro_rules! vec { + ( $val:expr ; $count:expr ) => + ({ + let mut result = Vec::new(); + let mut i = 0u64; + while i < $count { + result.push($val); + i += 1; + } + result + }); + ( $( $xs:expr ),* ) => { + { + let mut result = Vec::new(); + $( + result.push($xs); + )* + result + } + }; +} + +#[cfg(verifier = "smack")] +#[allow(dead_code)] +pub struct Box { + ptr: Unique +} + +#[cfg(verifier = "smack")] +#[allow(dead_code)] +impl Box { pub fn new(item: T) -> Box { + let elem_size = mem::size_of::(); + let ptr = unsafe { Unique::new(malloc(elem_size) as *mut T) }; + unsafe{ ptr::write(ptr.as_ptr().offset(0), item) }; + Box {ptr: ptr} + } +} + +#[cfg(verifier = "smack")] +#[allow(dead_code)] +impl Deref for Box { + type Target = T; + fn deref(&self) -> &Self::Target { + unsafe{ mem::transmute::<*mut T, &T>(self.ptr.as_ptr()) } + } +} diff --git a/share/smack/lib/string.c b/share/smack/lib/string.c index 946a5213d..8b2438b28 100644 --- a/share/smack/lib/string.c +++ b/share/smack/lib/string.c @@ -1,6 +1,6 @@ +// // This file is distributed under the MIT License. See LICENSE for details. // - #include #include @@ -10,12 +10,81 @@ char *strcpy(char *dest, const char *src) { return save; } +char *strncpy(char *dest, const char *src, size_t n) { + size_t i; + + for (i = 0; i < n && src[i] != '\0'; i++) + dest[i] = src[i]; + for ( ; i < n; i++) + dest[i] = '\0'; + + return dest; +} + size_t strlen(const char *str) { size_t count = 0; - while (str[count] != 0) count++; + while (str[count]) count++; return count; } +// comparison + +int strcmp(const char *s1, const char *s2) { + size_t n; + for (n = 0; s1[n] == s2[n]; n++) + if (s1[n] == '\0') + return 0; + return s1[n] - s2[n]; +} + +int strncmp(const char *s1, const char *s2, size_t n) { + while (n--) { + if (*s1 != *s2) + return *s1 - *s2; + s1++; + s2++; + } + + return 0; +} + +// concatenation + +char *strcat(char *dest, const char *src) { + char *retDest = dest; + + while (*dest) + dest++; + while (*dest++ = *src++) ; + + return retDest; +} + +char *strncat(char *dest, const char *src, size_t n) { + char *retDest = dest; + + while (*dest) + dest++; + while (n--) + *dest++ = *src++; + *dest = '\0'; + + return retDest; +} + +// searching + +char *strchr(const char *src, int c) { + while (*src != 0) { + if (*src == c) { + return src; + } + src++; + } + + return (char *)0; +} + char *strrchr(const char *src, int c) { char *result = (char *)0; @@ -28,16 +97,74 @@ char *strrchr(const char *src, int c) { return result; } -size_t strspn(const char *cs, const char *ct) { +size_t strspn(const char *s1, const char *s2) { size_t n; const char *p; - for (n = 0; *cs; cs++, n++) { - for (p = ct; *p && *p != *cs; p++); + for (n = 0; *s1; s1++, n++) { + for (p = s2; *p && *p != *s1; p++); if (!*p) break; } return n; } +size_t strcspn(const char *s1, const char *s2) { + size_t n; + const char *p; + for (n = 0; *s1; s1++, n++) { + for (p = s2; *p && *p != *s1; p++); + if (*p) break; + } + return n; +} + +char *strpbrk(const char *s1, const char *s2) { + for (char *c1 = s1; *c1; c1++) + for (char *c2 = s2; *c2; c2++) + if (*c1 == *c2) + return c1; + return 0; +} + +char *strstr(const char *haystack, const char *needle) { + if (!haystack || !needle) + return 0; + + for (; *haystack; haystack++) { + const char *h, *n; + for (h = haystack, n = needle; *h && *n && (*h == *n); h++, n++); + if (*n == '\0') + return haystack; + } + return 0; +} + +static char *olds; + +char *strtok(char *str, const char *delim) { + if (!str) + str = olds; + + // if str and olds are empty, return 0 + if (!str) + return 0; + + // skip first delims + str += strspn(str,delim); + if (*str == '\0') + return 0; + + char *tok = str; + // find end of token + str = strpbrk(str,delim); + if (!str) // this token finishes the string + olds = 0; + else { + *str = '\0'; + olds = str + 1; + } + return tok; +} + unsigned long int strtoul(const char *nptr, char **endptr, int base) { if (__VERIFIER_nondet_int()) { if (endptr != 0) { diff --git a/share/smack/prelude.py b/share/smack/prelude.py new file mode 100644 index 000000000..8d37529dd --- /dev/null +++ b/share/smack/prelude.py @@ -0,0 +1,329 @@ +import itertools + +class Attribute: + def __init__(self, name, arguments = []): + self.name = name + self.arguments = arguments + + def __str__(self): + attribute_str = [] + attribute_str += '{:' + self.name + for i, argument in enumerate(self.arguments): + attribute_str += ' ' + str(argument) + if i < len(self.arguments) - 1: + attribute_str += ',' + attribute_str += '}' + return ''.join(attribute_str) + +class Argument: + def __init__(self, name, type): + self.name = name + self.type = type + + def __str__(self): + return self.name + ': ' + self.type + +class Expr: + def __init__(self, op): + self.op = op + + def __str__(self): + return 'i1 ' + self.op + ' i2' + +class Function: + def __init__(self, name, attributes = [], arguments = [], return_type = None, body = None): + self.name = name + self.attributes = attributes + self.arguments = arguments + self.return_type = return_type + self.body = body + + def __str__(self): + function_str = [] + function_str += 'function' + for attribute in self.attributes: + function_str += ' ' + str(attribute) + function_str += ' ' + self.name + '(' + for i, argument in enumerate(self.arguments): + function_str += str(argument) + if i < len(self.arguments) - 1: + function_str += ', ' + function_str += ')' + if self.return_type is not None: + function_str += ' returns (' + self.return_type + ')' + if self.body is not None: + function_str += ' {'+ self.body + '}' + else: + function_str += ';' + function_str += '\n' + return ''.join(function_str) + +def int(width): + return 'i' + str(width) + +def bv(width): + return 'bv' + str(width) + +def mk_args(type, num): + return [Argument('i' + str(i + 1), type) for i in range(num)] + +def uninterpreted_unary_op(width, name): + type = int(width) + return Function( + name = name + '.' + type, + arguments = mk_args(type, 1), + return_type = type, + ) + +def uninterpreted_binary_op(width, name): + type = int(width) + return Function( + name = name + '.' + type, + arguments = mk_args(type, 2), + return_type = type + ) + +def inline_binary_op(width, name, body): + type = int(width) + return Function( + name = name + '.' + type, + attributes = [Attribute('inline')], + arguments = mk_args(type, 2), + return_type = type, + body = body + ) + +def builtin_binary_op(width, builtin_name, name): + type = int(width) + return Function( + name = name + '.' + type, + attributes = [Attribute('builtin', arguments = [builtin_name])], + arguments = mk_args(type, 2), + return_type = type + ) + +def bvbuiltin_unary_op(width, builtin_name, name): + type = bv(width) + return Function( + name = name + '.' + type, + attributes = [Attribute('bvbuiltin', arguments = [builtin_name])], + arguments = mk_args(type, 1), + return_type = type + ) + +def bvbuiltin_binary_op(width, builtin_name, name): + type = bv(width) + return Function( + name = name + '.' + type, + attributes = [Attribute('bvbuiltin', arguments = [builtin_name])], + arguments = mk_args(type, 2), + return_type = type + ) + +def inline_binary_comp(width, name, body): + type = int(width) + return Function( + name = name + '.' + type + '.bool', + attributes = [Attribute('inline')], + arguments = mk_args(type, 2), + return_type = 'bool', + body = body + ) + +def inline_binary_bv_comp(width, name, body): + type = bv(width) + return Function( + name = name + '.' + type + '.bool', + attributes = [Attribute('inline')], + arguments = mk_args(type, 2), + return_type = 'bool', + body = body + ) + +def bvbuiltin_binary_comp(width, builtin_name, name): + type = bv(width) + return Function( + name = name + '.' + type + '.bool', + attributes = [Attribute('bvbuiltin', arguments = [builtin_name])], + arguments = mk_args(type, 2), + return_type = 'bool' + ) + +def inline_binary_pred(width, name): + type = int(width) + return Function( + name = name + '.' + type, + attributes = [Attribute('inline')], + arguments = mk_args(type, 2), + return_type = 'i1', + body = 'if ' + name + '.' + type + '.bool(i1, i2) then 1 else 0' + ) + +def inline_binary_bv_pred(width, name): + type = bv(width) + return Function( + name = name + '.' + type, + attributes = [Attribute('inline')], + arguments = mk_args(type, 2), + return_type = 'bv1', + body = 'if ' + name + '.' + type + '.bool(i1, i2) then 1bv1 else 0bv1' + ) + +def safe_load_op(width, body): + type = int(width) + return Function( + name = '$load.' + type, + attributes = [Attribute('inline')], + arguments = [Argument('M', '[ref] ' + type), Argument('p', 'ref')], + return_type = type, + body = body + ) + +def safe_store_op(width, body): + type = int(width) + return Function( + name = '$store.' + type, + attributes = [Attribute('inline')], + arguments = [Argument('M', '[ref] ' + type), Argument('p', 'ref'), Argument('v', type)], + return_type = '[ref] ' + type, + body = body + ) + +def safe_load_bv_op(width, body): + type = bv(width) + return Function( + name = '$load.' + type, + attributes = [Attribute('inline')], + arguments = [Argument('M', '[ref] ' + type), Argument('p', 'ref')], + return_type = type, + body = body + ) + +def safe_store_bv_op(width, body): + type = bv(width) + return Function( + name = '$store.' + type, + attributes = [Attribute('inline')], + arguments = [Argument('M', '[ref] ' + type), Argument('p', 'ref'), Argument('v', type)], + return_type = '[ref] ' + type, + body = body + ) + +def inline_bvbuiltin_binary_select(width, name, name_2): + type = bv(width) + return Function( + name = name + '.' + type, + attributes = [Attribute('inline')], + arguments = mk_args(type, 2), + return_type = type, + body = 'if ' + name_2 + '.' + type + '.bool(i1, i2) then i1 else i2' + ) + +def inline_bvbuiltin_binary_pred(width, name): + type = bv(width) + return Function( + name = name + '.' + type, + attributes = [Attribute('inline')], + arguments = mk_args(type, 2), + return_type = 'bv1', + body = 'if ' + name + '.' + type + '.bool(i1, i2) then 1bv1 else 0bv1' + ) + +def inline_conversion(width, width_2, name, body): + type = int(width) + type_2 = int(width_2) + return Function( + name = name + '.' + type + '.' + type_2, + attributes = [Attribute('inline')], + arguments = mk_args(type, 1), + return_type = type_2, + body = body + ) + +def trunc_op(width, width_2): + type = int(width) + type_2 = int(width_2) + return Function( + name = '$trunc.' + type + '.' + type_2, + attributes = [Attribute('inline')], + arguments = mk_args(type, 1), + return_type = type_2, + body = 'i1' + ) + +def trunc_bv_op(width, width_2): + type = bv(width) + type_2 = bv(width_2) + return Function( + name = '$trunc.' + type + '.' + type_2, + attributes = [Attribute('inline')], + arguments = mk_args(type, 1), + return_type = type_2, + body = 'i1[' + str(width_2) + ':0]' + ) + +sizes = [1, 8, 16, 24, 32, 40, 48, 56, 64, 80, 88, 96, 128] + +binary_ops = ['add', 'sub', 'mul', 'sdiv', 'smod', 'srem', 'udiv', 'urem', 'shl', 'lshr', 'ashr', 'and', 'or', 'xor', 'nand'] +comp_ops = ['ule', 'ult', 'uge', 'ugt', 'sle', 'slt', 'sge', 'sgt'] +eq_ops = ['eq', 'ne'] + +binary_ops_body = ['+', '-', '*'] +comp_ops_body = ['<=', '<', '>=', '>', '<=', '<', '>=', '>'] +eq_ops_body = ['==', '!='] + +def get_prelude(): + bpl = [] + + for size in sizes: + for i, op in enumerate(binary_ops): + bpl.append(bvbuiltin_binary_op(width = size, builtin_name = '\"bv' + op + '\"', name = '$' + op)) + if 0 <= i <= 2: + bpl.append(inline_binary_op(width = size, name = '$' + op, body = str(Expr(binary_ops_body[i])))) + elif 3 <= i <= 7: + bpl.append(builtin_binary_op(width = size, builtin_name = '\"' + op[1:] + '\"', name = '$' + op)) + else: + bpl.append(uninterpreted_binary_op(width = size, name = '$' + op)) + + for i, op in enumerate(comp_ops): + bpl.append(bvbuiltin_binary_comp(width = size, builtin_name = '\"bv' + op + '\"', name = '$' + op)) + bpl.append(inline_bvbuiltin_binary_pred(width = size, name = '$' + op)) + bpl.append(inline_binary_comp(width = size, name = '$' + op, body = str(Expr(comp_ops_body[i])))) + bpl.append(inline_binary_pred(width = size, name = '$' + op)) + + for i, op in enumerate(eq_ops): + bpl.append(inline_binary_bv_comp(width = size, name = '$' + op, body = str(Expr(eq_ops_body[i])))) + bpl.append(inline_binary_bv_pred(width = size, name = '$' + op)) + bpl.append(inline_binary_comp(width = size, name = '$' + op, body = str(Expr(eq_ops_body[i])))) + bpl.append(inline_binary_pred(width = size, name = '$' + op)) + + bpl.append(inline_bvbuiltin_binary_select(width = size, name = '$min', name_2 = '$slt')) + bpl.append(inline_bvbuiltin_binary_select(width = size, name = '$max', name_2 = '$sgt')) + bpl.append(inline_bvbuiltin_binary_select(width = size, name = '$umin', name_2 = '$ult')) + bpl.append(inline_bvbuiltin_binary_select(width = size, name = '$umax', name_2 = '$ugt')) + + bpl.append(inline_binary_op(width = size, name = '$smin', body = '$min(i1,i2)')) + bpl.append(inline_binary_op(width = size, name = '$smax', body = '$max(i1,i2)')) + bpl.append(inline_binary_op(width = size, name = '$umin', body = '$min(i1,i2)')) + bpl.append(inline_binary_op(width = size, name = '$umax', body = '$max(i1,i2)')) + + bpl.append(bvbuiltin_unary_op(width = size, builtin_name = '\"bvnot\"', name = '$not')) + bpl.append(uninterpreted_unary_op(width = size, name = '$not')) + + bpl.append(safe_load_op(width = size, body = 'M[p]')) + bpl.append(safe_load_bv_op(width = size, body = 'M[p]')) + bpl.append(safe_store_op(width = size, body = 'M[p := v]')) + bpl.append(safe_store_bv_op(width = size, body = 'M[p := v]')) + + for size_pair in itertools.combinations(sizes, 2): + bpl.append(trunc_bv_op(width = size_pair[1], width_2 = size_pair[0])) + bpl.append(trunc_op(width = size_pair[1], width_2 = size_pair[0])) + + bpl.append(inline_conversion(width = size_pair[0], width_2 = size_pair[1], name = '$zext', body = 'i1')) + bpl.append(inline_conversion(width = size_pair[0], width_2 = size_pair[1], name = '$sext', body = 'i1')) + + return ''.join([str(x) for x in bpl]) + +def append_prelude(args): + f = open(args.bpl_file, 'a+') + f.write(get_prelude()) diff --git a/share/smack/reach.py b/share/smack/reach.py index 5c6063456..53528e443 100755 --- a/share/smack/reach.py +++ b/share/smack/reach.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 # # This file is distributed under the MIT License. See LICENSE for details. # @@ -11,7 +11,7 @@ from smackgen import * from smackverify import * -VERSION = '1.9.0' +VERSION = '1.9.1' def reachParser(): parser = argparse.ArgumentParser(add_help=False, parents=[verifyParser()]) diff --git a/share/smack/svcomp/toSVCOMPformat.py b/share/smack/svcomp/toSVCOMPformat.py index 5e5662efb..4f1bde6e4 100644 --- a/share/smack/svcomp/toSVCOMPformat.py +++ b/share/smack/svcomp/toSVCOMPformat.py @@ -1,4 +1,4 @@ -#! /usr/bin/env python +#! /usr/bin/env python2 import xml.etree as etree import xml.etree.ElementTree as ET diff --git a/share/smack/svcomp/utils.py b/share/smack/svcomp/utils.py index d4d113b3f..26384ad9b 100644 --- a/share/smack/svcomp/utils.py +++ b/share/smack/svcomp/utils.py @@ -5,11 +5,12 @@ import time from shutil import copyfile import smack.top +import smack.frontend import filters from toSVCOMPformat import smackJsonToXmlGraph from random_testing import random_test -def svcomp_frontend(args): +def svcomp_frontend(input_file, args): """Generate Boogie code from SVCOMP-style C-language source(s).""" # enable static LLVM unroll pass @@ -30,7 +31,7 @@ def svcomp_frontend(args): if file_type == 'bitvector': args.bit_precise = True args.bit_precise_pointers = True - if file_type == 'float' and not args.signed_integer_overflow: + if file_type == 'float' and not args.integer_overflow: #sys.exit(smack.top.results(args)['unknown']) args.float = True args.bit_precise = True @@ -40,7 +41,7 @@ def svcomp_frontend(args): args.unroll = 100 args.execute = executable else: - with open(args.input_files[0], "r") as sf: + with open(input_file, "r") as sf: sc = sf.read() if 'unsigned char b:2' in sc or "4294967294u" in sc: args.bit_precise = True @@ -56,11 +57,16 @@ def svcomp_frontend(args): args.clang_options += " -DDISABLE_PTHREAD_ASSERTS" args.clang_options += " -include smack.h" - if os.path.splitext(args.input_files[0])[1] == ".i": + if os.path.splitext(input_file)[1] == ".i": # Ensure clang runs the preprocessor, even with .i extension. args.clang_options += " -x c" - smack.top.clang_frontend(args) + bc = smack.frontend.clang_frontend(args.input_files[0], args) + + # run with no extra smack libraries + libs = set() + + smack.top.link_bc_files([bc],libs,args) def svcomp_check_property(args): # Check if property is vanilla reachability, and return unknown otherwise @@ -70,7 +76,7 @@ def svcomp_check_property(args): if "valid-deref" in prop: args.memory_safety = True elif "overflow" in prop: - args.signed_integer_overflow = True + args.integer_overflow = True elif not "__VERIFIER_error" in prop: sys.exit(smack.top.results(args)['unknown']) @@ -100,13 +106,9 @@ def svcomp_process_file(args, name, ext): while (True): pass - if args.float: - if re.search("fesetround|fegetround|InvSqrt|ccccdp-1",s): - sys.exit(smack.top.results(args)['unknown']) - if 'argv=malloc' in s: # args.bit_precise = True - if args.signed_integer_overflow and ('unsigned int d = (unsigned int)((signed int)(unsigned char)((signed int)*q | (signed int)(char)32) - 48);' in s or 'bb_ascii_isalnum' in s or 'ptm=localtime' in s or '0123456789.' in s): + if args.integer_overflow and ('unsigned int d = (unsigned int)((signed int)(unsigned char)((signed int)*q | (signed int)(char)32) - 48);' in s or 'bb_ascii_isalnum' in s or 'ptm=localtime' in s or '0123456789.' in s): args.bit_precise = True args.bit_precise_pointers = True @@ -191,8 +193,6 @@ def verify_bpl_svcomp(args): if args.bit_precise: x = "bopt:" if args.verifier != 'boogie' else "" boogie_command += ["/%sproverOpt:OPTIMIZE_FOR_BV=true" % x] - boogie_command += ["/%sz3opt:smt.relevancy=0" % x] - boogie_command += ["/%sz3opt:smt.bv.enable_int2bv=true" % x] boogie_command += ["/%sboolControlVC" % x] if args.verifier_options: @@ -286,10 +286,10 @@ def verify_bpl_svcomp(args): elif args.memory_safety and "__main($i0" in bpl: heurTrace += "BusyBox memory safety benchmark detected. Setting loop unroll bar to 4.\n" loopUnrollBar = 4 - elif args.signed_integer_overflow and "__main($i0" in bpl: - heurTrace += "BusyBox overflows benchmark detected. Setting loop unroll bar to 4.\n" - loopUnrollBar = 4 - elif args.signed_integer_overflow and ("jain" in bpl or "TerminatorRec02" in bpl or "NonTerminationSimple" in bpl): + elif args.integer_overflow and "__main($i0" in bpl: + heurTrace += "BusyBox overflows benchmark detected. Setting loop unroll bar to 11.\n" + loopUnrollBar = 11 + elif args.integer_overflow and ("jain" in bpl or "TerminatorRec02" in bpl or "NonTerminationSimple" in bpl): heurTrace += "Infinite loop in overflow benchmark. Setting loop unroll bar to INT_MAX.\n" loopUnrollBar = 2**31 - 1 @@ -301,8 +301,6 @@ def verify_bpl_svcomp(args): heurTrace += "--bit-precise flag passed - enabling bit vectors mode.\n" corral_command += ["/bopt:proverOpt:OPTIMIZE_FOR_BV=true"] corral_command += ["/bopt:boolControlVC"] - if not args.bit_precise_pointers: - corral_command += ["/bopt:z3opt:smt.bv.enable_int2bv=true"] if args.memory_safety: if args.prop_to_check == 'valid-deref': diff --git a/share/smack/top.py b/share/smack/top.py index 753d08543..eafa554ff 100755 --- a/share/smack/top.py +++ b/share/smack/top.py @@ -9,26 +9,13 @@ import sys import shlex import subprocess -from svcomp.utils import svcomp_frontend from svcomp.utils import verify_bpl_svcomp from utils import temporary_file, try_command, remove_temp_files from replay import replay_error_trace +from prelude import append_prelude +from frontend import link_bc_files, frontends, languages, extra_libs -VERSION = '1.9.0' - -def frontends(): - """A dictionary of front-ends per file extension.""" - return { - 'c': clang_frontend, - 'i': clang_frontend, - 'cc': clang_frontend, - 'cpp': clang_frontend, - 'json': json_compilation_database_frontend, - 'svcomp': svcomp_frontend, - 'bc': llvm_frontend, - 'll': llvm_frontend, - 'bpl': boogie_frontend, - } +VERSION = '1.9.1' def results(args): """A dictionary of the result output messages.""" @@ -38,7 +25,7 @@ def results(args): 'invalid-deref': 'SMACK found an error: invalid pointer dereference.', 'invalid-free': 'SMACK found an error: invalid memory deallocation.', 'invalid-memtrack': 'SMACK found an error: memory leak.', - 'overflow': 'SMACK found an error: signed integer overflow.', + 'overflow': 'SMACK found an error: integer overflow.', 'timeout': 'SMACK timed out.', 'unknown': 'SMACK result is unknown.' } @@ -54,7 +41,8 @@ def inlined_procedures(): '__VERIFIER_', '$initialize', '__SMACK_static_init', - '__SMACK_init_func_memory_model' + '__SMACK_init_func_memory_model', + '__SMACK_check_overflow' ] def validate_input_file(file): @@ -64,7 +52,7 @@ def validate_input_file(file): if not os.path.isfile(file): return ("Cannot find file %s." % file) - elif not file_extension in frontends(): + elif not file_extension in languages(): return ("Unexpected source file extension '%s'." % file_extension) else: @@ -172,20 +160,18 @@ def arguments(): translate_group.add_argument('--only-check-memleak', action='store_true', default=False, help='only enable memory leak checks') - translate_group.add_argument('--signed-integer-overflow', action='store_true', default=False, - help='enable signed integer overflow checks') + translate_group.add_argument('--integer-overflow', action='store_true', default=False, + help='enable integer overflow checks') translate_group.add_argument('--float', action="store_true", default=False, help='enable bit-precise floating-point functions') - translate_group.add_argument('--split-aggregate-values', action='store_true', default=False, - help='enable splitting of load/store instructions of LLVM aggregate types') - + translate_group.add_argument('--strings', action='store_true', default=False, help='enable support for string') verifier_group = parser.add_argument_group('verifier options') verifier_group.add_argument('--verifier', - choices=['boogie', 'corral', 'duality', 'svcomp'], default='corral', + choices=['boogie', 'corral', 'symbooglix', 'duality', 'svcomp'], default='corral', help='back-end verification engine') verifier_group.add_argument('--unroll', metavar='N', default='1', @@ -269,119 +255,39 @@ def target_selection(args): def frontend(args): """Generate the LLVM bitcode file.""" - if args.language: - lang = args.language - else: - extensions = map(lambda f: os.path.splitext(f)[1][1:], args.input_files) - if any(map(lambda ext: ext != extensions[0], extensions)): - raise RuntimeError("All input files must have the same file type (extension).") - lang = extensions[0] - return frontends()[lang](args) - -def smack_root(): - return os.path.dirname(os.path.dirname(os.path.abspath(sys.argv[0]))) - -def smack_header_path(): - return os.path.join(smack_root(), 'share', 'smack', 'include') - -def smack_headers(): - paths = [] - paths.append(smack_header_path()) - if args.memory_safety or args.signed_integer_overflow: - paths.append(os.path.join(smack_header_path(), 'string')) - if args.float: - paths.append(os.path.join(smack_header_path(), 'math')) - return paths - -def smack_lib(): - return os.path.join(smack_root(), 'share', 'smack', 'lib') - -def default_clang_compile_command(args, lib = False): - cmd = ['clang', '-c', '-emit-llvm', '-O0', '-g', '-gcolumn-info'] - cmd += map(lambda path: '-I' + path, smack_headers()) - cmd += args.clang_options.split() - cmd += ['-DMEMORY_MODEL_' + args.mem_mod.upper().replace('-','_')] - if args.memory_safety: cmd += ['-DMEMORY_SAFETY'] - if args.signed_integer_overflow: cmd += (['-ftrapv'] if not lib else ['-DSIGNED_INTEGER_OVERFLOW_CHECK']) - if args.float: cmd += ['-DFLOAT_ENABLED'] - return cmd - -def build_libs(args): - """Generate LLVM bitcodes for SMACK libraries.""" - bitcodes = [] - libs = ['smack.c'] - - if args.pthread: - libs += ['pthread.c'] - - if args.memory_safety or args.signed_integer_overflow: - libs += ['string.c'] - - if args.float: - libs += ['math.c'] - - for c in map(lambda c: os.path.join(smack_lib(), c), libs): - bc = temporary_file(os.path.splitext(os.path.basename(c))[0], '.bc', args) - try_command(default_clang_compile_command(args, True) + ['-o', bc, c]) - bitcodes.append(bc) - - return bitcodes - -def boogie_frontend(args): - """Generate Boogie code by concatenating the input file(s).""" - with open(args.bpl_file, 'w') as out: - for src in args.input_files: - with open(src) as f: - out.write(f.read()) - -def llvm_frontend(args): - """Generate Boogie code from LLVM bitcodes.""" - - try_command(['llvm-link', '-o', args.bc_file] + args.input_files) - try_command(['llvm-link', '-o', args.linked_bc_file, args.bc_file] + build_libs(args)) - llvm_to_bpl(args) - -def clang_frontend(args): - """Generate Boogie code from C-language source(s).""" - bitcodes = [] - compile_command = default_clang_compile_command(args) - - for c in args.input_files: - bc = temporary_file(os.path.splitext(os.path.basename(c))[0], '.bc', args) - try_command(compile_command + ['-o', bc, c], console=True) - bitcodes.append(bc) - - try_command(['llvm-link', '-o', args.bc_file] + bitcodes) - try_command(['llvm-link', '-o', args.linked_bc_file, args.bc_file] + build_libs(args)) - llvm_to_bpl(args) - -def json_compilation_database_frontend(args): - """Generate Boogie code from a JSON compilation database.""" - - if len(args.input_files) > 1: - raise RuntimeError("Expected a single JSON compilation database.") + libs = set() + noreturning_frontend = False + + def add_libs(lang): + if lang in extra_libs(): + libs.add(extra_libs()[lang]) - output_flags = re.compile(r"-o ([^ ]*)[.]o\b") - optimization_flags = re.compile(r"-O[1-9]\b") - - with open(args.input_files[0]) as f: - for cc in json.load(f): - if 'objects' in cc: - # TODO what to do when there are multiple linkings? - bit_codes = map(lambda f: re.sub('[.]o$','.bc',f), cc['objects']) - try_command(['llvm-link', '-o', args.bc_file] + bit_codes) - try_command(['llvm-link', '-o', args.linked_bc_file, args.bc_file] + build_libs(args)) - - else: - out_file = output_flags.findall(cc['command'])[0] + '.bc' - command = cc['command'] - command = output_flags.sub(r"-o \1.bc", command) - command = optimization_flags.sub("-O0", command) - command = command + " -emit-llvm" - try_command(command.split(),cc['directory'], console=True) - - llvm_to_bpl(args) + if args.language: + lang = languages()[args.language] + if lang in ['boogie', 'svcomp', 'json']: + noreturning_frontend = True + + add_libs(lang) + frontend = frontends()[lang] + for input_file in args.input_files: + bitcode = frontend(input_file,args) + if bitcode is not None: + bitcodes.append(bitcode) + + else: + for input_file in args.input_files: + lang = languages()[os.path.splitext(input_file)[1][1:]] + if lang in ['boogie', 'svcomp', 'json']: + noreturning_frontend = True + + add_libs(lang) + bitcode = frontends()[lang](input_file,args) + if bitcode is not None: + bitcodes.append(bitcode) + + if not noreturning_frontend: + return link_bc_files(bitcodes,libs,args) def llvm_to_bpl(args): """Translate the LLVM bitcode file to a Boogie source file.""" @@ -402,11 +308,11 @@ def llvm_to_bpl(args): if args.no_byte_access_inference: cmd += ['-no-byte-access-inference'] if args.no_memory_splitting: cmd += ['-no-memory-splitting'] if args.memory_safety: cmd += ['-memory-safety'] - if args.signed_integer_overflow: cmd += ['-signed-integer-overflow'] + if args.integer_overflow: cmd += ['-integer-overflow'] if args.float: cmd += ['-float'] if args.modular: cmd += ['-modular'] - if args.split_aggregate_values: cmd += ['-split-aggregate-values'] try_command(cmd, console=True) + append_prelude(args) annotate_bpl(args) property_selection(args) transform_bpl(args) @@ -480,11 +386,11 @@ def transform_out(args, old): return out def verification_result(verifier_output): - if re.search(r'[1-9]\d* time out|Z3 ran out of resources|timed out', verifier_output): + if re.search(r'[1-9]\d* time out|Z3 ran out of resources|timed out|ERRORS_TIMEOUT', verifier_output): return 'timeout' - elif re.search(r'[1-9]\d* verified, 0 errors?|no bugs', verifier_output): + elif re.search(r'[1-9]\d* verified, 0 errors?|no bugs|NO_ERRORS_NO_TIMEOUT', verifier_output): return 'verified' - elif re.search(r'\d* verified, [1-9]\d* errors?|can fail', verifier_output): + elif re.search(r'\d* verified, [1-9]\d* errors?|can fail|ERRORS_NO_TIMEOUT', verifier_output): if re.search(r'ASSERTION FAILS assert {:valid_deref}', verifier_output): return 'invalid-deref' elif re.search(r'ASSERTION FAILS assert {:valid_free}', verifier_output): @@ -528,6 +434,14 @@ def verify_bpl(args): command += ["/cex:%s" % args.max_violations] command += ["/maxStaticLoopBound:%d" % args.loop_limit] command += ["/recursionBound:%d" % args.unroll] + + elif args.verifier == 'symbooglix': + command = ['symbooglix'] + command += [args.bpl_file] + command += ["--file-logging=0"] + command += ["--entry-points=%s" % ",".join(args.entry_points)] + command += ["--timeout=%d" % args.time_limit] + command += ["--max-loop-depth=%d" % args.unroll] else: # Duality! @@ -535,11 +449,9 @@ def verify_bpl(args): command += ["/tryCTrace", "/noTraceOnDisk", "/useDuality", "/oldStratifiedInlining"] command += ["/recursionBound:1073741824", "/k:1"] - if args.bit_precise: + if (args.bit_precise or args.float) and args.verifier != 'symbooglix': x = "bopt:" if args.verifier != 'boogie' else "" command += ["/%sproverOpt:OPTIMIZE_FOR_BV=true" % x] - command += ["/%sz3opt:smt.relevancy=0" % x] - command += ["/%sz3opt:smt.bv.enable_int2bv=true" % x] command += ["/%sboolControlVC" % x] if args.verifier_options: diff --git a/share/smack/utils.py b/share/smack/utils.py index 1ee05c838..d21c1f314 100644 --- a/share/smack/utils.py +++ b/share/smack/utils.py @@ -65,7 +65,7 @@ def try_command(cmd, cwd=None, console=False, timeout=None): return output + ("\n%s timed out." % cmd[0]) elif rc == -signal.SIGSEGV: raise Exception("segmentation fault") - elif rc: + elif rc and args.verifier != 'symbooglix': raise Exception(output) else: return output diff --git a/svcomp/bench/src/SMACKBench.py b/svcomp/bench/src/SMACKBench.py index 5b7f72db2..da9c72f99 100755 --- a/svcomp/bench/src/SMACKBench.py +++ b/svcomp/bench/src/SMACKBench.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 import sys sys.dont_write_bytecode = True # prevent creation of .pyc files diff --git a/svcomp/bench/src/benchexec/benchexec/tools/smack_benchexec_driver.py b/svcomp/bench/src/benchexec/benchexec/tools/smack_benchexec_driver.py index 24b03b6f3..84e6b9c26 100644 --- a/svcomp/bench/src/benchexec/benchexec/tools/smack_benchexec_driver.py +++ b/svcomp/bench/src/benchexec/benchexec/tools/smack_benchexec_driver.py @@ -35,7 +35,7 @@ def version(self, executable): Sets the version number for SMACK, which gets displayed in the "Tool" row in BenchExec table headers. """ - return '1.9.0' + return '1.9.1' def name(self): """ diff --git a/svcomp/bench/src/checkWitnesses.py b/svcomp/bench/src/checkWitnesses.py index 8e764bad4..e3fea98c6 100755 --- a/svcomp/bench/src/checkWitnesses.py +++ b/svcomp/bench/src/checkWitnesses.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 import xml.etree.ElementTree as ET import os diff --git a/svcomp/bench/src/data/index.py b/svcomp/bench/src/data/index.py index 6bae14c52..1bbf6eebf 100755 --- a/svcomp/bench/src/data/index.py +++ b/svcomp/bench/src/data/index.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 from lib import * import sys import cgitb diff --git a/svcomp/bench/src/data/results.py b/svcomp/bench/src/data/results.py index dbd603470..0149ba930 100755 --- a/svcomp/bench/src/data/results.py +++ b/svcomp/bench/src/data/results.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 from lib import * import datetime import subprocess diff --git a/test/basic/select.c b/test/basic/select.c new file mode 100644 index 000000000..9a090a8a9 --- /dev/null +++ b/test/basic/select.c @@ -0,0 +1,9 @@ +#include "smack.h" + +// @expect verified +// @checkbpl grep -E ":= if.+then.+else.+" + +int main(void) { + int c = 2; + assert(c == 2 ? 1 : 0); +} diff --git a/test/basic/select_fail.c b/test/basic/select_fail.c new file mode 100644 index 000000000..5972bc283 --- /dev/null +++ b/test/basic/select_fail.c @@ -0,0 +1,9 @@ +#include "smack.h" + +// @expect error +// @checkbpl grep -E ":= if.+then.+else.+" + +int main(void) { + int c = 2; + assert(c != 2 ? 1 : 0); +} diff --git a/test/basic/split_aggregate_values.c b/test/basic/split_aggregate_values.c index 6b65460de..ae935312f 100644 --- a/test/basic/split_aggregate_values.c +++ b/test/basic/split_aggregate_values.c @@ -1,8 +1,5 @@ #include "smack.h" -// The assertion will fail without flag `--split-aggregate-values`. - -// @flag --split-aggregate-values // @expect verified typedef struct { diff --git a/test/basic/split_aggregate_values_fail.c b/test/basic/split_aggregate_values_fail.c index 1c44e8bd6..fa96545b4 100644 --- a/test/basic/split_aggregate_values_fail.c +++ b/test/basic/split_aggregate_values_fail.c @@ -1,6 +1,5 @@ #include "smack.h" -// @flag --split-aggregate-values // @expect error typedef struct { diff --git a/test/basic/uninterpreted.c b/test/basic/uninterpreted.c new file mode 100644 index 000000000..a1574153a --- /dev/null +++ b/test/basic/uninterpreted.c @@ -0,0 +1,19 @@ +#include + +// @expect verified + +int foo(int x) { + int y = __VERIFIER_nondet_int(); + __SMACK_top_decl("function FOO(x: int): int;"); + __SMACK_code("@ := FOO(@);", y, x); + return y; +} + + +int main(void) { + int x = foo(42); + int y = foo(42); + assert(x == y); + + return 0; +} diff --git a/test/basic/uninterpreted_fail.c b/test/basic/uninterpreted_fail.c new file mode 100644 index 000000000..88ff6648c --- /dev/null +++ b/test/basic/uninterpreted_fail.c @@ -0,0 +1,19 @@ +#include + +// @expect error + +int foo(int x) { + int y = __VERIFIER_nondet_int(); + __SMACK_top_decl("function FOO(x: int): int;"); + __SMACK_code("@ := FOO(@);", y, x); + return y; +} + + +int main(void) { + int x = foo(42); + int y = foo(43); + assert(x == y); + + return 0; +} diff --git a/test/bits/bit_field.c b/test/bits/bit_field.c new file mode 100644 index 000000000..1f8df2e88 --- /dev/null +++ b/test/bits/bit_field.c @@ -0,0 +1,24 @@ +#include "smack.h" + +// @expect verified + +typedef union { + int v; + struct { + unsigned a: 8; + unsigned b: 8; + unsigned c: 8; + unsigned d: 8; + } i; +} bf; + +int main(void) { + bf b; + b.v = __VERIFIER_nondet_int(); + assert(b.i.a == (b.v & 0xff)); + assert(b.i.b == ((b.v >> 8) & 0xff)); + assert(b.i.c == ((b.v >> 16) & 0xff)); + assert(b.i.d == ((b.v >> 24) & 0xff)); + return 0; +} + diff --git a/test/bits/bit_field_fail.c b/test/bits/bit_field_fail.c new file mode 100644 index 000000000..a98f9a3d8 --- /dev/null +++ b/test/bits/bit_field_fail.c @@ -0,0 +1,24 @@ +#include "smack.h" + +// @expect error + +typedef union { + int v; + struct { + unsigned a: 8; + unsigned b: 8; + unsigned c: 8; + unsigned d: 8; + } i; +} bf; + +int main(void) { + bf b; + b.v = __VERIFIER_nondet_int(); + assert(b.i.d == (b.v & 0xff)); + assert(b.i.c == ((b.v >> 8) & 0xff)); + assert(b.i.b == ((b.v >> 16) & 0xff)); + assert(b.i.a == ((b.v >> 24) & 0xff)); + return 0; +} + diff --git a/test/bits/bit_fields.c b/test/bits/bit_fields.c new file mode 100644 index 000000000..6293f4b05 --- /dev/null +++ b/test/bits/bit_fields.c @@ -0,0 +1,18 @@ +#include "smack.h" + +// @expect verified + +typedef struct { + unsigned int d: 5; + unsigned int m: 4; + unsigned int y; +} date; + +int main(void) { + date dt = {31, 12, 2014}; + assert(dt.d == 31); + assert(dt.m == 12); + assert(dt.y == 2014); + return 0; +} + diff --git a/test/bits/bit_fields_fail.c b/test/bits/bit_fields_fail.c new file mode 100644 index 000000000..b5552dbfa --- /dev/null +++ b/test/bits/bit_fields_fail.c @@ -0,0 +1,18 @@ +#include "smack.h" + +// @expect error + +typedef struct { + unsigned int d: 5; + unsigned int m: 4; + unsigned int y; +} date; + +int main(void) { + date dt = {31, 11, 2014}; + assert(dt.d == 31); + assert(dt.m == 12); + assert(dt.y == 2014); + return 0; +} + diff --git a/test/bits/config.yml b/test/bits/config.yml index c1ce00c1a..7b3fe7f15 100644 --- a/test/bits/config.yml +++ b/test/bits/config.yml @@ -1,2 +1,2 @@ flags: [--bit-precise] -time-limit: 90 +time-limit: 120 diff --git a/test/bits/malloc_non_alias.c b/test/bits/malloc_non_alias.c index 02f28d33e..99ba5fe28 100644 --- a/test/bits/malloc_non_alias.c +++ b/test/bits/malloc_non_alias.c @@ -4,7 +4,7 @@ // @flag --bit-precise-pointers // @expect verified -int main() { +int main(void) { int* x = (int*)malloc(sizeof(int)); int* y = (int*)malloc(sizeof(int)); int* z = (int*)malloc(sizeof(int)); diff --git a/test/contracts/config.yml b/test/contracts/config.yml index 371879ceb..fcb4dd3ce 100644 --- a/test/contracts/config.yml +++ b/test/contracts/config.yml @@ -1,2 +1,3 @@ +skip: ok verifiers: [boogie] flags: [--modular] diff --git a/test/contracts/array_forall.c b/test/contracts/failing/array_forall.c similarity index 100% rename from test/contracts/array_forall.c rename to test/contracts/failing/array_forall.c diff --git a/test/contracts/forall.c b/test/contracts/failing/forall.c similarity index 100% rename from test/contracts/forall.c rename to test/contracts/failing/forall.c diff --git a/test/contracts/forall_fail.c b/test/contracts/failing/forall_fail.c similarity index 100% rename from test/contracts/forall_fail.c rename to test/contracts/failing/forall_fail.c diff --git a/test/basic/array.c b/test/data/array.c similarity index 100% rename from test/basic/array.c rename to test/data/array.c diff --git a/test/basic/array1.c b/test/data/array1.c similarity index 100% rename from test/basic/array1.c rename to test/data/array1.c diff --git a/test/basic/array1_fail.c b/test/data/array1_fail.c similarity index 100% rename from test/basic/array1_fail.c rename to test/data/array1_fail.c diff --git a/test/basic/array2.c b/test/data/array2.c similarity index 100% rename from test/basic/array2.c rename to test/data/array2.c diff --git a/test/basic/array2_fail.c b/test/data/array2_fail.c similarity index 100% rename from test/basic/array2_fail.c rename to test/data/array2_fail.c diff --git a/test/basic/array3.c b/test/data/array3.c similarity index 100% rename from test/basic/array3.c rename to test/data/array3.c diff --git a/test/basic/array3_fail.c b/test/data/array3_fail.c similarity index 100% rename from test/basic/array3_fail.c rename to test/data/array3_fail.c diff --git a/test/basic/array4.c b/test/data/array4.c similarity index 100% rename from test/basic/array4.c rename to test/data/array4.c diff --git a/test/basic/array4_fail.c b/test/data/array4_fail.c similarity index 100% rename from test/basic/array4_fail.c rename to test/data/array4_fail.c diff --git a/test/basic/array_free.c b/test/data/array_free.c similarity index 100% rename from test/basic/array_free.c rename to test/data/array_free.c diff --git a/test/basic/array_free2.c b/test/data/array_free2.c similarity index 100% rename from test/basic/array_free2.c rename to test/data/array_free2.c diff --git a/test/basic/array_free2_fail.c b/test/data/array_free2_fail.c similarity index 100% rename from test/basic/array_free2_fail.c rename to test/data/array_free2_fail.c diff --git a/test/basic/array_free_fail.c b/test/data/array_free_fail.c similarity index 100% rename from test/basic/array_free_fail.c rename to test/data/array_free_fail.c diff --git a/test/basic/extern_func_ptr.c b/test/data/extern_func_ptr.c similarity index 100% rename from test/basic/extern_func_ptr.c rename to test/data/extern_func_ptr.c diff --git a/test/basic/extern_func_ptr_fail.c b/test/data/extern_func_ptr_fail.c similarity index 100% rename from test/basic/extern_func_ptr_fail.c rename to test/data/extern_func_ptr_fail.c diff --git a/test/basic/extern_struct.c b/test/data/extern_struct.c similarity index 100% rename from test/basic/extern_struct.c rename to test/data/extern_struct.c diff --git a/test/basic/free_as_func_ptr.c b/test/data/free_as_func_ptr.c similarity index 100% rename from test/basic/free_as_func_ptr.c rename to test/data/free_as_func_ptr.c diff --git a/test/basic/func_ptr.c b/test/data/func_ptr.c similarity index 100% rename from test/basic/func_ptr.c rename to test/data/func_ptr.c diff --git a/test/basic/func_ptr1.c b/test/data/func_ptr1.c similarity index 100% rename from test/basic/func_ptr1.c rename to test/data/func_ptr1.c diff --git a/test/basic/func_ptr1_fail.c b/test/data/func_ptr1_fail.c similarity index 100% rename from test/basic/func_ptr1_fail.c rename to test/data/func_ptr1_fail.c diff --git a/test/basic/func_ptr2.c b/test/data/func_ptr2.c similarity index 100% rename from test/basic/func_ptr2.c rename to test/data/func_ptr2.c diff --git a/test/basic/func_ptr2_fail.c b/test/data/func_ptr2_fail.c similarity index 100% rename from test/basic/func_ptr2_fail.c rename to test/data/func_ptr2_fail.c diff --git a/test/basic/func_ptr_alias.c b/test/data/func_ptr_alias.c similarity index 100% rename from test/basic/func_ptr_alias.c rename to test/data/func_ptr_alias.c diff --git a/test/basic/func_ptr_alias1.c b/test/data/func_ptr_alias1.c similarity index 100% rename from test/basic/func_ptr_alias1.c rename to test/data/func_ptr_alias1.c diff --git a/test/basic/func_ptr_alias1_fail.c b/test/data/func_ptr_alias1_fail.c similarity index 100% rename from test/basic/func_ptr_alias1_fail.c rename to test/data/func_ptr_alias1_fail.c diff --git a/test/basic/func_ptr_alias_fail.c b/test/data/func_ptr_alias_fail.c similarity index 100% rename from test/basic/func_ptr_alias_fail.c rename to test/data/func_ptr_alias_fail.c diff --git a/test/basic/func_ptr_array.c b/test/data/func_ptr_array.c similarity index 100% rename from test/basic/func_ptr_array.c rename to test/data/func_ptr_array.c diff --git a/test/basic/func_ptr_array_fail.c b/test/data/func_ptr_array_fail.c similarity index 100% rename from test/basic/func_ptr_array_fail.c rename to test/data/func_ptr_array_fail.c diff --git a/test/basic/func_ptr_fail.c b/test/data/func_ptr_fail.c similarity index 100% rename from test/basic/func_ptr_fail.c rename to test/data/func_ptr_fail.c diff --git a/test/basic/func_ptr_vararg.c b/test/data/func_ptr_vararg.c similarity index 100% rename from test/basic/func_ptr_vararg.c rename to test/data/func_ptr_vararg.c diff --git a/test/basic/func_ptr_vararg_fail.c b/test/data/func_ptr_vararg_fail.c similarity index 100% rename from test/basic/func_ptr_vararg_fail.c rename to test/data/func_ptr_vararg_fail.c diff --git a/test/basic/global_structs.c b/test/data/global_structs.c similarity index 100% rename from test/basic/global_structs.c rename to test/data/global_structs.c diff --git a/test/basic/global_structs_fail.c b/test/data/global_structs_fail.c similarity index 100% rename from test/basic/global_structs_fail.c rename to test/data/global_structs_fail.c diff --git a/test/basic/globals_func_ptr.c b/test/data/globals_func_ptr.c similarity index 100% rename from test/basic/globals_func_ptr.c rename to test/data/globals_func_ptr.c diff --git a/test/basic/globals_func_ptr_fail.c b/test/data/globals_func_ptr_fail.c similarity index 100% rename from test/basic/globals_func_ptr_fail.c rename to test/data/globals_func_ptr_fail.c diff --git a/test/basic/nested_struct.c b/test/data/nested_struct.c similarity index 100% rename from test/basic/nested_struct.c rename to test/data/nested_struct.c diff --git a/test/basic/nested_struct1.c b/test/data/nested_struct1.c similarity index 100% rename from test/basic/nested_struct1.c rename to test/data/nested_struct1.c diff --git a/test/basic/nested_struct1_fail.c b/test/data/nested_struct1_fail.c similarity index 100% rename from test/basic/nested_struct1_fail.c rename to test/data/nested_struct1_fail.c diff --git a/test/basic/nested_struct2.c b/test/data/nested_struct2.c similarity index 100% rename from test/basic/nested_struct2.c rename to test/data/nested_struct2.c diff --git a/test/basic/nested_struct2_fail.c b/test/data/nested_struct2_fail.c similarity index 100% rename from test/basic/nested_struct2_fail.c rename to test/data/nested_struct2_fail.c diff --git a/test/basic/nested_struct_fail.c b/test/data/nested_struct_fail.c similarity index 100% rename from test/basic/nested_struct_fail.c rename to test/data/nested_struct_fail.c diff --git a/test/basic/nondet_pointer_fail.c b/test/data/nondet_pointer_fail.c similarity index 100% rename from test/basic/nondet_pointer_fail.c rename to test/data/nondet_pointer_fail.c diff --git a/test/basic/pointers.c b/test/data/pointers.c similarity index 100% rename from test/basic/pointers.c rename to test/data/pointers.c diff --git a/test/basic/pointers1.c b/test/data/pointers1.c similarity index 100% rename from test/basic/pointers1.c rename to test/data/pointers1.c diff --git a/test/basic/pointers1_fail.c b/test/data/pointers1_fail.c similarity index 100% rename from test/basic/pointers1_fail.c rename to test/data/pointers1_fail.c diff --git a/test/basic/pointers2.c b/test/data/pointers2.c similarity index 100% rename from test/basic/pointers2.c rename to test/data/pointers2.c diff --git a/test/basic/pointers2_fail.c b/test/data/pointers2_fail.c similarity index 100% rename from test/basic/pointers2_fail.c rename to test/data/pointers2_fail.c diff --git a/test/basic/pointers3.c b/test/data/pointers3.c similarity index 100% rename from test/basic/pointers3.c rename to test/data/pointers3.c diff --git a/test/basic/pointers3_fail.c b/test/data/pointers3_fail.c similarity index 100% rename from test/basic/pointers3_fail.c rename to test/data/pointers3_fail.c diff --git a/test/basic/pointers4.c b/test/data/pointers4.c similarity index 100% rename from test/basic/pointers4.c rename to test/data/pointers4.c diff --git a/test/basic/pointers4_fail.c b/test/data/pointers4_fail.c similarity index 100% rename from test/basic/pointers4_fail.c rename to test/data/pointers4_fail.c diff --git a/test/basic/pointers8.c b/test/data/pointers8.c similarity index 100% rename from test/basic/pointers8.c rename to test/data/pointers8.c diff --git a/test/basic/pointers_fail.c b/test/data/pointers_fail.c similarity index 100% rename from test/basic/pointers_fail.c rename to test/data/pointers_fail.c diff --git a/test/basic/struct_alias.c b/test/data/struct_alias.c similarity index 100% rename from test/basic/struct_alias.c rename to test/data/struct_alias.c diff --git a/test/basic/struct_alias_fail.c b/test/data/struct_alias_fail.c similarity index 100% rename from test/basic/struct_alias_fail.c rename to test/data/struct_alias_fail.c diff --git a/test/basic/struct_array.c b/test/data/struct_array.c similarity index 100% rename from test/basic/struct_array.c rename to test/data/struct_array.c diff --git a/test/basic/struct_array_fail.c b/test/data/struct_array_fail.c similarity index 100% rename from test/basic/struct_array_fail.c rename to test/data/struct_array_fail.c diff --git a/test/basic/struct_assign.c b/test/data/struct_assign.c similarity index 100% rename from test/basic/struct_assign.c rename to test/data/struct_assign.c diff --git a/test/basic/struct_assign_fail.c b/test/data/struct_assign_fail.c similarity index 100% rename from test/basic/struct_assign_fail.c rename to test/data/struct_assign_fail.c diff --git a/test/basic/struct_cast.c b/test/data/struct_cast.c similarity index 100% rename from test/basic/struct_cast.c rename to test/data/struct_cast.c diff --git a/test/basic/struct_cast1.c b/test/data/struct_cast1.c similarity index 100% rename from test/basic/struct_cast1.c rename to test/data/struct_cast1.c diff --git a/test/basic/struct_cast1_fail.c b/test/data/struct_cast1_fail.c similarity index 100% rename from test/basic/struct_cast1_fail.c rename to test/data/struct_cast1_fail.c diff --git a/test/basic/struct_cast_fail.c b/test/data/struct_cast_fail.c similarity index 100% rename from test/basic/struct_cast_fail.c rename to test/data/struct_cast_fail.c diff --git a/test/basic/struct_const_return.c b/test/data/struct_const_return.c similarity index 100% rename from test/basic/struct_const_return.c rename to test/data/struct_const_return.c diff --git a/test/basic/struct_const_return_fail.c b/test/data/struct_const_return_fail.c similarity index 100% rename from test/basic/struct_const_return_fail.c rename to test/data/struct_const_return_fail.c diff --git a/test/basic/struct_init.c b/test/data/struct_init.c similarity index 100% rename from test/basic/struct_init.c rename to test/data/struct_init.c diff --git a/test/basic/struct_init_fail.c b/test/data/struct_init_fail.c similarity index 100% rename from test/basic/struct_init_fail.c rename to test/data/struct_init_fail.c diff --git a/test/basic/struct_return.c b/test/data/struct_return.c similarity index 100% rename from test/basic/struct_return.c rename to test/data/struct_return.c diff --git a/test/basic/two_arrays.c b/test/data/two_arrays.c similarity index 100% rename from test/basic/two_arrays.c rename to test/data/two_arrays.c diff --git a/test/basic/two_arrays1.c b/test/data/two_arrays1.c similarity index 100% rename from test/basic/two_arrays1.c rename to test/data/two_arrays1.c diff --git a/test/basic/two_arrays1_fail.c b/test/data/two_arrays1_fail.c similarity index 100% rename from test/basic/two_arrays1_fail.c rename to test/data/two_arrays1_fail.c diff --git a/test/basic/two_arrays2.c b/test/data/two_arrays2.c similarity index 100% rename from test/basic/two_arrays2.c rename to test/data/two_arrays2.c diff --git a/test/basic/two_arrays3.c b/test/data/two_arrays3.c similarity index 100% rename from test/basic/two_arrays3.c rename to test/data/two_arrays3.c diff --git a/test/basic/two_arrays4.c b/test/data/two_arrays4.c similarity index 100% rename from test/basic/two_arrays4.c rename to test/data/two_arrays4.c diff --git a/test/basic/two_arrays5.c b/test/data/two_arrays5.c similarity index 100% rename from test/basic/two_arrays5.c rename to test/data/two_arrays5.c diff --git a/test/basic/two_arrays6.c b/test/data/two_arrays6.c similarity index 100% rename from test/basic/two_arrays6.c rename to test/data/two_arrays6.c diff --git a/test/basic/two_arrays6_fail.c b/test/data/two_arrays6_fail.c similarity index 100% rename from test/basic/two_arrays6_fail.c rename to test/data/two_arrays6_fail.c diff --git a/test/basic/two_arrays_fail.c b/test/data/two_arrays_fail.c similarity index 100% rename from test/basic/two_arrays_fail.c rename to test/data/two_arrays_fail.c diff --git a/test/float/bitcast.c b/test/float/bitcast.c new file mode 100644 index 000000000..ceb2e7225 --- /dev/null +++ b/test/float/bitcast.c @@ -0,0 +1,12 @@ +#include "smack.h" + +// @flag --bit-precise --clang-options="-fno-strict-aliasing" +// @expect verified + +int main(void) { + int i = 2; + float f = *((float*) &i); + int i1 = *((int*) &f); + assert (i == i1); + return 0; +} diff --git a/test/float/bitcast_fail.c b/test/float/bitcast_fail.c new file mode 100644 index 000000000..3b28171f4 --- /dev/null +++ b/test/float/bitcast_fail.c @@ -0,0 +1,12 @@ +#include "smack.h" + +// @flag --bit-precise --clang-options="-fno-strict-aliasing" +// @expect error + +int main(void) { + int i = 2; + float f = *((float*) &i); + int i1 = *((int*) &f); + assert (i != i1); + return 0; +} diff --git a/test/float/change_rm.c b/test/float/change_rm.c new file mode 100644 index 000000000..fa4aba764 --- /dev/null +++ b/test/float/change_rm.c @@ -0,0 +1,17 @@ +#include "smack.h" +#include + +// @expect verified + +int main(void) { + assert(fegetround() == FE_TONEAREST); + + int rm = __VERIFIER_nondet_int(); + assume(rm == FE_TONEAREST || rm == FE_DOWNWARD || rm == FE_UPWARD || rm == FE_TOWARDZERO); + + assert(!fesetround(rm)); + + assert(fegetround() == rm); + + return 0; +} diff --git a/test/float/change_rm_fail.c b/test/float/change_rm_fail.c new file mode 100644 index 000000000..1626347f1 --- /dev/null +++ b/test/float/change_rm_fail.c @@ -0,0 +1,11 @@ +#include "smack.h" +#include + +// @expect error + +int main(void) { + int rm = __VERIFIER_nondet_int(); + assert(!fesetround(rm)); + + return 0; +} diff --git a/test/float/config.yml b/test/float/config.yml index 542137897..47439584e 100644 --- a/test/float/config.yml +++ b/test/float/config.yml @@ -1,3 +1,2 @@ -verifiers: [boogie] -flags: [--bit-precise, --float] skip: ok +flags: [--float] diff --git a/test/float/double_to_int.c b/test/float/double_to_int.c new file mode 100644 index 000000000..fe516c6f2 --- /dev/null +++ b/test/float/double_to_int.c @@ -0,0 +1,11 @@ +#include "smack.h" + +// @flag --bit-precise +// @expect verified + +int main(void) { + double x = 1.5; + int y = x; + + assert(y == 1); +} diff --git a/test/float/double_to_int_fail.c b/test/float/double_to_int_fail.c new file mode 100644 index 000000000..5b51c613c --- /dev/null +++ b/test/float/double_to_int_fail.c @@ -0,0 +1,11 @@ +#include "smack.h" + +// @flag --bit-precise +// @expect error + +int main(void) { + double x = 1.5; + int y = x; + + assert(y == 2); +} diff --git a/test/float/float_ops_rm.c b/test/float/float_ops_rm.c new file mode 100644 index 000000000..eb8330ac1 --- /dev/null +++ b/test/float/float_ops_rm.c @@ -0,0 +1,12 @@ +#include "smack.h" +#include + +// @expect verified + +int main(void) { + double d = 1.999999999999; + fesetround(FE_UPWARD); + float f = d; + assert(f == 2); + return 0; +} diff --git a/test/float/float_ops_rm_fail.c b/test/float/float_ops_rm_fail.c new file mode 100644 index 000000000..3c16c39d7 --- /dev/null +++ b/test/float/float_ops_rm_fail.c @@ -0,0 +1,12 @@ +#include "smack.h" +#include + +// @expect error + +int main(void) { + double d = 1.999999999999; + fesetround(FE_DOWNWARD); + float f = d; + assert(f == 2); + return 0; +} diff --git a/test/float/floor.c b/test/float/floor.c index a71e2f8fa..d01280199 100644 --- a/test/float/floor.c +++ b/test/float/floor.c @@ -2,6 +2,7 @@ #include // @expect verified +// @flag --bit-precise int main(void) { assert(floor(2.7) == 2.0); diff --git a/test/float/floor_fail.c b/test/float/floor_fail.c index cbe01e4fc..f484e9db5 100644 --- a/test/float/floor_fail.c +++ b/test/float/floor_fail.c @@ -2,6 +2,7 @@ #include // @expect error +// @flag --bit-precise int main(void) { assert(floor(2.7) == 2.0); diff --git a/test/float/get_rm_invalid.c b/test/float/get_rm_invalid.c new file mode 100644 index 000000000..ae2043b06 --- /dev/null +++ b/test/float/get_rm_invalid.c @@ -0,0 +1,13 @@ +#include "smack.h" +#include + +// @expect verified + +int main(void) { + int rm = fegetround(); + assume(rm != FE_TONEAREST && rm != FE_DOWNWARD && rm != FE_UPWARD && rm != FE_TOWARDZERO); + + assert(rm < 0); + + return 0; +} diff --git a/test/float/get_rm_invalid_fail.c b/test/float/get_rm_invalid_fail.c new file mode 100644 index 000000000..74898b316 --- /dev/null +++ b/test/float/get_rm_invalid_fail.c @@ -0,0 +1,13 @@ +#include "smack.h" +#include + +// @expect error + +int main(void) { + int rm = fegetround(); + assume(rm != FE_DOWNWARD && rm != FE_UPWARD && rm != FE_TOWARDZERO); + + assert(rm < 0); + + return 0; +} diff --git a/test/float/set_rm_invalid.c b/test/float/set_rm_invalid.c new file mode 100644 index 000000000..bd4696c78 --- /dev/null +++ b/test/float/set_rm_invalid.c @@ -0,0 +1,13 @@ +#include "smack.h" +#include + +// @expect verified + +int main(void) { + int rm = __VERIFIER_nondet_int(); + assume(rm != FE_TONEAREST && rm != FE_DOWNWARD && rm != FE_UPWARD && rm != FE_TOWARDZERO); + + assert(fesetround(rm)); + + return 0; +} diff --git a/test/float/set_rm_invalid_fail.c b/test/float/set_rm_invalid_fail.c new file mode 100644 index 000000000..de30ad9f5 --- /dev/null +++ b/test/float/set_rm_invalid_fail.c @@ -0,0 +1,13 @@ +#include "smack.h" +#include + +// @expect error + +int main(void) { + int rm = __VERIFIER_nondet_int(); + assume(rm != FE_TONEAREST && rm != FE_DOWNWARD && rm != FE_UPWARD); + + assert(fesetround(rm)); + + return 0; +} diff --git a/test/mathc/ceil.c b/test/mathc/ceil.c new file mode 100644 index 000000000..219afe7ac --- /dev/null +++ b/test/mathc/ceil.c @@ -0,0 +1,33 @@ +#include "smack.h" +#include + +// @expect verified +// @flag --bit-precise + +int main(void) { + double NaN = 0.0 / 0.0; + double Inf = 1.0 / 0.0; + double negInf = -1.0 / 0.0; + + assert(ceil(2.1) == 3.0); + + double val = __VERIFIER_nondet_double(); + + if (!__isnan(val) && !__isinf(val) && !__iszero(val)) { + assert(ceil(val) >= val); + assert(ceil(val) <= val + 1); + } + + assert(ceil(0.0) == 0.0); + assert(ceil(-0.0) == -0.0); + int isNeg = __signbit(ceil(-0.0)); + assert(isNeg); + + assert(ceil(Inf) == Inf); + assert(ceil(negInf) == negInf); + + assert(__isnan(ceil(NaN))); + + return 0; +} + diff --git a/test/mathc/ceil_fail.c b/test/mathc/ceil_fail.c new file mode 100644 index 000000000..986c8e6d7 --- /dev/null +++ b/test/mathc/ceil_fail.c @@ -0,0 +1,31 @@ +#include "smack.h" +#include + +// @expect error +// @flag --bit-precise + +int main(void) { + double NaN = 0.0 / 0.0; + double Inf = 1.0 / 0.0; + double negInf = -1.0 / 0.0; + + double val = __VERIFIER_nondet_double(); + + if (!__isnan(val) && !__isinf(val) && !__iszero(val)) { + assert(ceil(val) >= val); + assert(ceil(val) <= val + 0.5); + } + + assert(ceil(0.0) == 0.0); + assert(ceil(-0.0) == -0.0); + int isNeg = __signbit(ceil(-0.0)); + assert(isNeg); + + assert(ceil(Inf) == Inf); + assert(ceil(negInf) == negInf); + + assert(__isnan(ceil(NaN))); + + return 0; +} + diff --git a/test/mathc/ceilf.c b/test/mathc/ceilf.c new file mode 100644 index 000000000..f8b44c9d1 --- /dev/null +++ b/test/mathc/ceilf.c @@ -0,0 +1,33 @@ +#include "smack.h" +#include + +// @expect verified +// @flag --bit-precise + +int main(void) { + float NaN = 0.0f / 0.0f; + float Inf = 1.0f / 0.0f; + float negInf = -1.0f / 0.0f; + + assert(ceilf(2.1f) == 3.0f); + + float val = __VERIFIER_nondet_float(); + + if (!__isnanf(val) && !__isinff(val) && !__iszerof(val)) { + assert(ceilf(val) >= val); + assert(ceilf(val) <= val + 1); + } + + assert(ceilf(0.0f) == 0.0f); + assert(ceilf(-0.0f) == -0.0f); + int isNeg = __signbitf(ceilf(-0.0f)); + assert(isNeg); + + assert(ceilf(Inf) == Inf); + assert(ceilf(negInf) == negInf); + + assert(__isnanf(ceilf(NaN))); + + return 0; +} + diff --git a/test/mathc/ceilf_fail.c b/test/mathc/ceilf_fail.c new file mode 100644 index 000000000..28512dd57 --- /dev/null +++ b/test/mathc/ceilf_fail.c @@ -0,0 +1,31 @@ +#include "smack.h" +#include + +// @expect error +// @flag --bit-precise + +int main(void) { + float NaN = 0.0f / 0.0f; + float Inf = 1.0f / 0.0f; + float negInf = -1.0f / 0.0f; + + float val = __VERIFIER_nondet_float(); + + if (!__isnanf(val) && !__isinff(val) && !__iszerof(val)) { + assert(ceilf(val) >= val); + assert(ceilf(val) <= val + 0.5); + } + + assert(ceilf(0.0f) == 0.0f); + assert(ceilf(-0.0f) == -0.0f); + int isNeg = __signbitf(ceilf(-0.0f)); + assert(isNeg); + + assert(ceilf(Inf) == Inf); + assert(ceilf(negInf) == negInf); + + assert(__isnanf(ceilf(NaN))); + + return 0; +} + diff --git a/test/mathc/ceill.c b/test/mathc/ceill.c new file mode 100644 index 000000000..cab2964d0 --- /dev/null +++ b/test/mathc/ceill.c @@ -0,0 +1,32 @@ +#include "smack.h" +#include + +// @expect verified + +int main(void) { + long double NaN = 0.0l / 0.0l; + long double Inf = 1.0l / 0.0l; + long double negInf = -1.0l / 0.0l; + + assert(ceill(2.1l) == 3.0l); + + long double val = __VERIFIER_nondet_long_double(); + + if (!__isnanl(val) && !__isinfl(val) && !__iszerol(val)) { + assert(ceill(val) >= val); + assert(ceill(val) <= val + 1); + } + + assert(ceill(0.0l) == 0.0l); + assert(ceill(-0.0l) == -0.0l); + int isNeg = __signbitl(ceill(-0.0l)); + assert(isNeg); + + assert(ceill(Inf) == Inf); + assert(ceill(negInf) == negInf); + + assert(__isnanl(ceill(NaN))); + + return 0; +} + diff --git a/test/mathc/ceill_fail.c b/test/mathc/ceill_fail.c new file mode 100644 index 000000000..ef36130f7 --- /dev/null +++ b/test/mathc/ceill_fail.c @@ -0,0 +1,30 @@ +#include "smack.h" +#include + +// @expect error + +int main(void) { + long double NaN = 0.0l / 0.0l; + long double Inf = 1.0l / 0.0l; + long double negInf = -1.0l / 0.0l; + + long double val = __VERIFIER_nondet_long_double(); + + if (!__isnanl(val) && !__isinfl(val) && !__iszerol(val)) { + assert(ceill(val) >= val); + assert(ceill(val) <= val + 0.5); + } + + assert(ceill(0.0l) == 0.0l); + assert(ceill(-0.0l) == -0.0l); + int isNeg = __signbitl(ceill(-0.0l)); + assert(isNeg); + + assert(ceill(Inf) == Inf); + assert(ceill(negInf) == negInf); + + assert(__isnanl(ceill(NaN))); + + return 0; +} + diff --git a/test/mathc/config.yml b/test/mathc/config.yml new file mode 100644 index 000000000..8e56f81b0 --- /dev/null +++ b/test/mathc/config.yml @@ -0,0 +1,2 @@ +skip: true +flags: [--float] diff --git a/test/mathc/copysign.c b/test/mathc/copysign.c new file mode 100644 index 000000000..0a57c79e8 --- /dev/null +++ b/test/mathc/copysign.c @@ -0,0 +1,34 @@ +#include "smack.h" +#include + +// @expect verified +// @flag --bit-precise + +int main(void) { + double NaN = 0.0 / 0.0; + double Inf = 1.0 / 0.0; + double negInf = -1.0 / 0.0; + + double x = __VERIFIER_nondet_double(); + double y = __VERIFIER_nondet_double(); + + if (!__isnan(x) && !__isinf(x) && !__iszero(x)) { + if (!__isnan(y) && !__isinf(y) && !__iszero(y)) { + double val = copysign(x, y); + if (__signbit(x) - __signbit(y)) { + assert(val == -x); + } else { + assert(val == x); + } + } + } + + int isNeg; + + if (!__isnan(y)) { + double val = copysign(NaN, y); + assert(__isnan(val)); + } + + return 0; +} diff --git a/test/mathc/copysign_fail.c b/test/mathc/copysign_fail.c new file mode 100644 index 000000000..f96995931 --- /dev/null +++ b/test/mathc/copysign_fail.c @@ -0,0 +1,34 @@ +#include "smack.h" +#include + +// @expect error +// @flag --bit-precise + +int main(void) { + double NaN = 0.0 / 0.0; + double Inf = 1.0 / 0.0; + double negInf = -1.0 / 0.0; + + double x = __VERIFIER_nondet_double(); + double y = __VERIFIER_nondet_double(); + + if (!__isnan(x) && !__isinf(x) && !__iszero(x)) { + if (!__isnan(y) && !__isinf(y) && !__iszero(y)) { + double val = copysign(x, y); + if (__signbit(x) - __signbit(y)) { + assert(val == x); + } else { + assert(val == x); + } + } + } + + int isNeg; + + if (!__isnan(y)) { + double val = copysign(NaN, y); + assert(__isnan(val)); + } + + return 0; +} diff --git a/test/mathc/copysignf.c b/test/mathc/copysignf.c new file mode 100644 index 000000000..be01c7f9a --- /dev/null +++ b/test/mathc/copysignf.c @@ -0,0 +1,34 @@ +#include "smack.h" +#include + +// @expect verified +// @flag --bit-precise + +int main(void) { + float NaN = 0.0f / 0.0f; + float Inf = 1.0f / 0.0f; + float negInf = -1.0f / 0.0f; + + float x = __VERIFIER_nondet_float(); + float y = __VERIFIER_nondet_float(); + + if (!__isnanf(x) && !__isinff(x) && !__iszerof(x)) { + if (!__isnanf(y) && !__isinff(y) && !__iszerof(y)) { + float val = copysignf(x, y); + if (__signbitf(x) - __signbitf(y)) { + assert(val == -x); + } else { + assert(val == x); + } + } + } + + int isNeg; + + if (!__isnanf(y)) { + float val = copysignf(NaN, y); + assert(__isnanf(val)); + } + + return 0; +} diff --git a/test/mathc/copysignf_fail.c b/test/mathc/copysignf_fail.c new file mode 100644 index 000000000..87b445799 --- /dev/null +++ b/test/mathc/copysignf_fail.c @@ -0,0 +1,34 @@ +#include "smack.h" +#include + +// @expect error +// @flag --bit-precise + +int main(void) { + float NaN = 0.0f / 0.0f; + float Inf = 1.0f / 0.0f; + float negInf = -1.0f / 0.0f; + + float x = __VERIFIER_nondet_float(); + float y = __VERIFIER_nondet_float(); + + if (!__isnanf(x) && !__isinff(x) && !__iszerof(x)) { + if (!__isnanf(y) && !__isinff(y) && !__iszerof(y)) { + float val = copysignf(x, y); + if (__signbitf(x) - __signbitf(y)) { + assert(val == -x); + } else { + assert(val == -x); + } + } + } + + int isNeg; + + if (!__isnanf(y)) { + float val = copysignf(NaN, y); + assert(__isnanf(val)); + } + + return 0; +} diff --git a/test/mathc/copysignl.c b/test/mathc/copysignl.c new file mode 100644 index 000000000..d62bc27dc --- /dev/null +++ b/test/mathc/copysignl.c @@ -0,0 +1,33 @@ +#include "smack.h" +#include + +// @expect verified + +int main(void) { + long double NaN = 0.0l / 0.0l; + long double Inf = 1.0l / 0.0l; + long double negInf = -1.0l / 0.0l; + + long double x = __VERIFIER_nondet_long_double(); + long double y = __VERIFIER_nondet_long_double(); + + if (!__isnanl(x) && !__isinfl(x) && !__iszerol(x)) { + if (!__isnanl(y) && !__isinfl(y) && !__iszerol(y)) { + long double val = copysignl(x, y); + if (__signbitl(x) - __signbitl(y)) { + assert(val == -x); + } else { + assert(val == x); + } + } + } + + int isNeg; + + if (!__isnanl(y)) { + long double val = copysignl(NaN, y); + assert(__isnanl(val)); + } + + return 0; +} diff --git a/test/mathc/copysignl_fail.c b/test/mathc/copysignl_fail.c new file mode 100644 index 000000000..c0c060a30 --- /dev/null +++ b/test/mathc/copysignl_fail.c @@ -0,0 +1,33 @@ +#include "smack.h" +#include + +// @expect error + +int main(void) { + long double NaN = 0.0l / 0.0l; + long double Inf = 1.0l / 0.0l; + long double negInf = -1.0l / 0.0l; + + long double x = __VERIFIER_nondet_long_double(); + long double y = __VERIFIER_nondet_long_double(); + + if (!__isnanl(x) && !__isinfl(x) && !__iszerol(x)) { + if (!__isnanl(y) && !__isinfl(y) && !__iszerol(y)) { + long double val = copysignl(x, y); + if (__signbitl(x) - __signbitl(y)) { + assert(val == -x); + } else { + assert(val == -x); + } + } + } + + int isNeg; + + if (!__isnanl(y)) { + long double val = copysignl(NaN, y); + assert(__isnanl(val)); + } + + return 0; +} diff --git a/test/mathc/fabs.c b/test/mathc/fabs.c new file mode 100644 index 000000000..2e990e771 --- /dev/null +++ b/test/mathc/fabs.c @@ -0,0 +1,33 @@ +#include "smack.h" +#include + +// @expect verified +// @flag --bit-precise + +int main(void) { + double NaN = 0.0 / 0.0; + double Inf = 1.0 / 0.0; + double negInf = -1.0 / 0.0; + + double val = __VERIFIER_nondet_double(); + + if (!__isnan(val) && !__isinf(val) && !__iszero(val)) { + if (val > 0) { + assert(fabs(val) == val); + } else { + assert(fabs(val) == -val); + } + } + + assert(fabs(0.0) == 0.0); + assert(fabs(-0.0) == 0.0); + int isNeg = __signbit(fabs(-0.0)); + assert(!isNeg); + + assert(fabs(Inf) == Inf); + assert(fabs(negInf) == Inf); + + assert(__isnan(fabs(NaN))); + + return 0; +} diff --git a/test/mathc/fabs_fail.c b/test/mathc/fabs_fail.c new file mode 100644 index 000000000..fa81d5da5 --- /dev/null +++ b/test/mathc/fabs_fail.c @@ -0,0 +1,33 @@ +#include "smack.h" +#include + +// @expect error +// @flag --bit-precise + +int main(void) { + double NaN = 0.0 / 0.0; + double Inf = 1.0 / 0.0; + double negInf = -1.0 / 0.0; + + double val = __VERIFIER_nondet_double(); + + if (!__isnan(val) && !__isinf(val) && !__iszero(val)) { + if (val > 0) { + assert(fabs(val) == -val); + } else { + assert(fabs(val) == -val); + } + } + + assert(fabs(0.0) == 0.0); + assert(fabs(-0.0) == 0.0); + int isNeg = __signbit(fabs(-0.0)); + assert(!isNeg); + + assert(fabs(Inf) == Inf); + assert(fabs(negInf) == Inf); + + assert(__isnan(fabs(NaN))); + + return 0; +} diff --git a/test/mathc/fabsf.c b/test/mathc/fabsf.c new file mode 100644 index 000000000..c32b22272 --- /dev/null +++ b/test/mathc/fabsf.c @@ -0,0 +1,33 @@ +#include "smack.h" +#include + +// @expect verified +// @flag --bit-precise + +int main(void) { + float NaN = 0.0f / 0.0f; + float Inf = 1.0f / 0.0f; + float negInf = -1.0f / 0.0f; + + float val = __VERIFIER_nondet_float(); + + if (!__isnanf(val) && !__isinff(val) && !__iszerof(val)) { + if (val > 0) { + assert(fabsf(val) == val); + } else { + assert(fabsf(val) == -val); + } + } + + assert(fabsf(0.0f) == 0.0f); + assert(fabsf(-0.0f) == 0.0f); + int isNeg = __signbitf(fabsf(-0.0f)); + assert(!isNeg); + + assert(fabsf(Inf) == Inf); + assert(fabsf(negInf) == Inf); + + assert(__isnanf(fabsf(NaN))); + + return 0; +} diff --git a/test/mathc/fabsf_fail.c b/test/mathc/fabsf_fail.c new file mode 100644 index 000000000..2af8561b8 --- /dev/null +++ b/test/mathc/fabsf_fail.c @@ -0,0 +1,33 @@ +#include "smack.h" +#include + +// @expect error +// @flag --bit-precise + +int main(void) { + float NaN = 0.0f / 0.0f; + float Inf = 1.0f / 0.0f; + float negInf = -1.0f / 0.0f; + + float val = __VERIFIER_nondet_float(); + + if (!__isnanf(val) && !__isinff(val) && !__iszerof(val)) { + if (val > 0) { + assert(fabsf(val) == val); + } else { + assert(fabsf(val) == val); + } + } + + assert(fabsf(0.0f) == 0.0f); + assert(fabsf(-0.0f) == 0.0f); + int isNeg = __signbitf(fabsf(-0.0f)); + assert(!isNeg); + + assert(fabsf(Inf) == Inf); + assert(fabsf(negInf) == Inf); + + assert(__isnanf(fabsf(NaN))); + + return 0; +} diff --git a/test/mathc/fabsl.c b/test/mathc/fabsl.c new file mode 100644 index 000000000..105f5cd76 --- /dev/null +++ b/test/mathc/fabsl.c @@ -0,0 +1,32 @@ +#include "smack.h" +#include + +// @expect verified + +int main(void) { + long double NaN = 0.0l / 0.0l; + long double Inf = 1.0l / 0.0l; + long double negInf = -1.0l / 0.0l; + + long double val = __VERIFIER_nondet_long_double(); + + if (!__isnanl(val) && !__isinfl(val) && !__iszerol(val)) { + if (val > 0) { + assert(fabsl(val) == val); + } else { + assert(fabsl(val) == -val); + } + } + + assert(fabsl(0.0l) == 0.0l); + assert(fabsl(-0.0l) == 0.0l); + int isNeg = __signbitl(fabsl(-0.0l)); + assert(!isNeg); + + assert(fabsl(Inf) == Inf); + assert(fabsl(negInf) == Inf); + + assert(__isnanl(fabsl(NaN))); + + return 0; +} diff --git a/test/mathc/fabsl_fail.c b/test/mathc/fabsl_fail.c new file mode 100644 index 000000000..fea3d6fe1 --- /dev/null +++ b/test/mathc/fabsl_fail.c @@ -0,0 +1,32 @@ +#include "smack.h" +#include + +// @expect error + +int main(void) { + long double NaN = 0.0l / 0.0l; + long double Inf = 1.0l / 0.0l; + long double negInf = -1.0l / 0.0l; + + long double val = __VERIFIER_nondet_long_double(); + + if (!__isnanl(val) && !__isinfl(val) && !__iszerol(val)) { + if (val > 0) { + assert(fabsl(val) == val); + } else { + assert(fabsl(val) == val); + } + } + + assert(fabsl(0.0l) == 0.0l); + assert(fabsl(-0.0l) == 0.0l); + int isNeg = __signbitl(fabsl(-0.0l)); + assert(!isNeg); + + assert(fabsl(Inf) == Inf); + assert(fabsl(negInf) == Inf); + + assert(__isnanl(fabsl(NaN))); + + return 0; +} diff --git a/test/mathc/fdim.c b/test/mathc/fdim.c new file mode 100644 index 000000000..7ab9824b8 --- /dev/null +++ b/test/mathc/fdim.c @@ -0,0 +1,38 @@ +#include "smack.h" +#include +#include + +// @expect verified + +int main(void) { + double NaN = 0.0 / 0.0; + double Inf = 1.0 / 0.0; + double negInf = -1.0 / 0.0; + + double x = __VERIFIER_nondet_double(); + double y = __VERIFIER_nondet_double(); + + if (!__isnan(x) && !__isinf(x)) { + if (!__isnan(y) && !__isinf(y)) { + double dim = fdim(x, y); + if (x > y) { + assert(dim == x - y); + } else { + assert(dim == 0.0); + } + } + } + + if (!__isnan(x)) { + assert(fdim(x, Inf) == 0.0); + } + + if (!__isnan(y) && y < 0) { + assert(fdim(Inf, y) == Inf); + } + + assert(__isnan(fdim(x, NaN))); + assert(__isnan(fdim(NaN, y))); + + return 0; +} diff --git a/test/mathc/fdim_fail.c b/test/mathc/fdim_fail.c new file mode 100644 index 000000000..aa33bc2eb --- /dev/null +++ b/test/mathc/fdim_fail.c @@ -0,0 +1,38 @@ +#include "smack.h" +#include +#include + +// @expect error + +int main(void) { + double NaN = 0.0 / 0.0; + double Inf = 1.0 / 0.0; + double negInf = -1.0 / 0.0; + + double x = __VERIFIER_nondet_double(); + double y = __VERIFIER_nondet_double(); + + if (!__isnan(x) && !__isinf(x)) { + if (!__isnan(y) && !__isinf(y)) { + double dim = fdim(x, y); + if (x > y) { + assert(dim == y - x); + } else { + assert(dim == 0.0); + } + } + } + + if (!__isnan(x)) { + assert(fdim(x, Inf) == 0.0); + } + + if (!__isnan(y) && y < 0) { + assert(fdim(Inf, y) == Inf); + } + + assert(__isnan(fdim(x, NaN))); + assert(__isnan(fdim(NaN, y))); + + return 0; +} diff --git a/test/mathc/fdimf.c b/test/mathc/fdimf.c new file mode 100644 index 000000000..9041fd81a --- /dev/null +++ b/test/mathc/fdimf.c @@ -0,0 +1,38 @@ +#include "smack.h" +#include +#include + +// @expect verified + +int main(void) { + float NaN = 0.0f / 0.0f; + float Inf = 1.0f / 0.0f; + float negInf = -1.0f / 0.0f; + + float x = __VERIFIER_nondet_float(); + float y = __VERIFIER_nondet_float(); + + if (!__isnanf(x) && !__isinff(x)) { + if (!__isnanf(y) && !__isinff(y)) { + float dim = fdimf(x, y); + if (x > y) { + assert(dim == x - y); + } else { + assert(dim == 0.0f); + } + } + } + + if (!__isnanf(x)) { + assert(fdimf(x, Inf) == 0.0f); + } + + if (!__isnanf(y) && y < 0) { + assert(fdimf(Inf, y) == Inf); + } + + assert(__isnanf(fdimf(x, NaN))); + assert(__isnanf(fdimf(NaN, y))); + + return 0; +} diff --git a/test/mathc/fdimf_fail.c b/test/mathc/fdimf_fail.c new file mode 100644 index 000000000..cb9eb5577 --- /dev/null +++ b/test/mathc/fdimf_fail.c @@ -0,0 +1,38 @@ +#include "smack.h" +#include +#include + +// @expect error + +int main(void) { + float NaN = 0.0f / 0.0f; + float Inf = 1.0f / 0.0f; + float negInf = -1.0f / 0.0f; + + float x = __VERIFIER_nondet_float(); + float y = __VERIFIER_nondet_float(); + + if (!__isnanf(x) && !__isinff(x)) { + if (!__isnanf(y) && !__isinff(y)) { + float dim = fdimf(x, y); + if (x > y) { + assert(dim == x - y); + } else { + assert(dim < 0.0f); + } + } + } + + if (!__isnanf(x)) { + assert(fdimf(x, Inf) == 0.0f); + } + + if (!__isnanf(y) && y < 0) { + assert(fdimf(Inf, y) == Inf); + } + + assert(__isnanf(fdimf(x, NaN))); + assert(__isnanf(fdimf(NaN, y))); + + return 0; +} diff --git a/test/mathc/fdiml.c b/test/mathc/fdiml.c new file mode 100644 index 000000000..eda28e28a --- /dev/null +++ b/test/mathc/fdiml.c @@ -0,0 +1,38 @@ +#include "smack.h" +#include +#include + +// @expect verified + +int main(void) { + long double NaN = 0.0l / 0.0l; + long double Inf = 1.0l / 0.0l; + long double negInf = -1.0l / 0.0l; + + long double x = __VERIFIER_nondet_long_double(); + long double y = __VERIFIER_nondet_long_double(); + + if (!__isnanl(x) && !__isinfl(x)) { + if (!__isnanl(y) && !__isinfl(y)) { + long double dim = fdiml(x, y); + if (x > y) { + assert(dim == x - y); + } else { + assert(dim == 0.0l); + } + } + } + + if (!__isnanl(x)) { + assert(fdiml(x, Inf) == 0.0l); + } + + if (!__isnanl(y) && y < 0) { + assert(fdiml(Inf, y) == Inf); + } + + assert(__isnanl(fdiml(x, NaN))); + assert(__isnanl(fdiml(NaN, y))); + + return 0; +} diff --git a/test/mathc/fdiml_fail.c b/test/mathc/fdiml_fail.c new file mode 100644 index 000000000..ec9ed636e --- /dev/null +++ b/test/mathc/fdiml_fail.c @@ -0,0 +1,38 @@ +#include "smack.h" +#include +#include + +// @expect error + +int main(void) { + long double NaN = 0.0l / 0.0l; + long double Inf = 1.0l / 0.0l; + long double negInf = -1.0l / 0.0l; + + long double x = __VERIFIER_nondet_long_double(); + long double y = __VERIFIER_nondet_long_double(); + + if (!__isnanl(x) && !__isinfl(x)) { + if (!__isnanl(y) && !__isinfl(y)) { + long double dim = fdiml(x, y); + if (x > y) { + assert(dim == x - y); + } else { + assert(dim < 0.0l); + } + } + } + + if (!__isnanl(x)) { + assert(fdiml(x, Inf) == 0.0l); + } + + if (!__isnanl(y) && y < 0) { + assert(fdiml(Inf, y) == Inf); + } + + assert(__isnanl(fdiml(x, NaN))); + assert(__isnanl(fdiml(NaN, y))); + + return 0; +} diff --git a/test/mathc/floor.c b/test/mathc/floor.c new file mode 100644 index 000000000..170a74c45 --- /dev/null +++ b/test/mathc/floor.c @@ -0,0 +1,33 @@ +#include "smack.h" +#include + +// @expect verified +// @flag --bit-precise + +int main(void) { + double NaN = 0.0 / 0.0; + double Inf = 1.0 / 0.0; + double negInf = -1.0 / 0.0; + + assert(floor(2.9) == 2.0); + + double val = __VERIFIER_nondet_double(); + + if (!__isnan(val) && !__isinf(val) && !__iszero(val)) { + assert(floor(val) <= val); + assert(floor(val) >= val - 1); + } + + assert(floor(0.0) == 0.0); + assert(floor(-0.0) == -0.0); + int isNeg = __signbit(floor(-0.0)); + assert(isNeg); + + assert(floor(Inf) == Inf); + assert(floor(negInf) == negInf); + + assert(__isnan(floor(NaN))); + + return 0; +} + diff --git a/test/mathc/floor_fail.c b/test/mathc/floor_fail.c new file mode 100644 index 000000000..f458c1bc8 --- /dev/null +++ b/test/mathc/floor_fail.c @@ -0,0 +1,31 @@ +#include "smack.h" +#include + +// @expect error +// @flag --bit-precise + +int main(void) { + double NaN = 0.0 / 0.0; + double Inf = 1.0 / 0.0; + double negInf = -1.0 / 0.0; + + double val = __VERIFIER_nondet_double(); + + if (!__isnan(val) && !__isinf(val) && !__iszero(val)) { + assert(floor(val) < val); + assert(floor(val) >= val - 1); + } + + assert(floor(0.0) == 0.0); + assert(floor(-0.0) == -0.0); + int isNeg = __signbit(floor(-0.0)); + assert(isNeg); + + assert(floor(Inf) == Inf); + assert(floor(negInf) == negInf); + + assert(__isnan(floor(NaN))); + + return 0; +} + diff --git a/test/mathc/floorf.c b/test/mathc/floorf.c new file mode 100644 index 000000000..990947ad3 --- /dev/null +++ b/test/mathc/floorf.c @@ -0,0 +1,33 @@ +#include "smack.h" +#include + +// @expect verified +// @flag --bit-precise + +int main(void) { + float NaN = 0.0f / 0.0f; + float Inf = 1.0f / 0.0f; + float negInf = -1.0f / 0.0f; + + assert(floorf(2.9f) == 2.0f); + + float val = __VERIFIER_nondet_float(); + + if (!__isnanf(val) && !__isinff(val) && !__iszerof(val)) { + assert(floorf(val) <= val); + assert(floorf(val) >= val - 1); + } + + assert(floorf(0.0f) == 0.0f); + assert(floorf(-0.0f) == -0.0f); + int isNeg = __signbitf(floorf(-0.0f)); + assert(isNeg); + + assert(floorf(Inf) == Inf); + assert(floorf(negInf) == negInf); + + assert(__isnanf(floorf(NaN))); + + return 0; +} + diff --git a/test/mathc/floorf_fail.c b/test/mathc/floorf_fail.c new file mode 100644 index 000000000..799e1fe44 --- /dev/null +++ b/test/mathc/floorf_fail.c @@ -0,0 +1,31 @@ +#include "smack.h" +#include + +// @expect error +// @flag --bit-precise + +int main(void) { + float NaN = 0.0f / 0.0f; + float Inf = 1.0f / 0.0f; + float negInf = -1.0f / 0.0f; + + float val = __VERIFIER_nondet_float(); + + if (!__isnanf(val) && !__isinff(val) && !__iszerof(val)) { + assert(floorf(val) <= val); + assert(floorf(val) > val - 1); + } + + assert(floorf(0.0f) == 0.0f); + assert(floorf(-0.0f) == -0.0f); + int isNeg = __signbitf(floorf(-0.0f)); + assert(isNeg); + + assert(floorf(Inf) == Inf); + assert(floorf(negInf) == negInf); + + assert(__isnanf(floorf(NaN))); + + return 0; +} + diff --git a/test/mathc/floorl.c b/test/mathc/floorl.c new file mode 100644 index 000000000..a04bf7ad4 --- /dev/null +++ b/test/mathc/floorl.c @@ -0,0 +1,32 @@ +#include "smack.h" +#include + +// @expect verified + +int main(void) { + long double NaN = 0.0l / 0.0l; + long double Inf = 1.0l / 0.0l; + long double negInf = -1.0l / 0.0l; + + assert(floorl(2.9l) == 2.0l); + + long double val = __VERIFIER_nondet_long_double(); + + if (!__isnanl(val) && !__isinfl(val) && !__iszerol(val)) { + assert(floorl(val) <= val); + assert(floorl(val) >= val - 1); + } + + assert(floorl(0.0l) == 0.0l); + assert(floorl(-0.0l) == -0.0l); + int isNeg = __signbitl(floorl(-0.0l)); + assert(isNeg); + + assert(floorl(Inf) == Inf); + assert(floorl(negInf) == negInf); + + assert(__isnanl(floorl(NaN))); + + return 0; +} + diff --git a/test/mathc/floorl_fail.c b/test/mathc/floorl_fail.c new file mode 100644 index 000000000..d7d06e9c2 --- /dev/null +++ b/test/mathc/floorl_fail.c @@ -0,0 +1,30 @@ +#include "smack.h" +#include + +// @expect error + +int main(void) { + long double NaN = 0.0l / 0.0l; + long double Inf = 1.0l / 0.0l; + long double negInf = -1.0l / 0.0l; + + long double val = __VERIFIER_nondet_long_double(); + + if (!__isnanl(val) && !__isinfl(val) && !__iszerol(val)) { + assert(floorl(val) <= val); + assert(floorl(val) > val - 1); + } + + assert(floorl(0.0l) == 0.0l); + assert(floorl(-0.0l) == -0.0l); + int isNeg = __signbitl(floorl(-0.0l)); + assert(isNeg); + + assert(floorl(Inf) == Inf); + assert(floorl(negInf) == negInf); + + assert(__isnanl(floorl(NaN))); + + return 0; +} + diff --git a/test/mathc/fmax.c b/test/mathc/fmax.c new file mode 100644 index 000000000..613f179cc --- /dev/null +++ b/test/mathc/fmax.c @@ -0,0 +1,40 @@ +#include "smack.h" +#include + +// @expect verified + +int main(void) { + double NaN = 0.0 / 0.0; + double Inf = 1.0 / 0.0; + double negInf = -1.0 / 0.0; + + double x = __VERIFIER_nondet_double(); + double y = __VERIFIER_nondet_double(); + + if (!__isnan(x) && !__isinf(x) && !__iszero(x)) { + if (!__isnan(y) && !__isinf(y) && !__iszero(y)) { + double maxVal = fmax(x, y); + if (x > y) { + assert(maxVal == x); + } else { + assert(maxVal == y); + } + } + } + + if (!__isnan(y)) { + assert(fmax(Inf, y) == Inf); + assert(fmax(negInf, y) == y); + assert(fmax(NaN, y) == y); + } + + if (!__isnan(x)) { + assert(fmax(x, Inf) == Inf); + assert(fmax(x, negInf) == x); + assert(fmax(x, NaN) == x); + } + + assert(__isnan(fmax(NaN, NaN))); + + return 0; +} diff --git a/test/mathc/fmax_fail.c b/test/mathc/fmax_fail.c new file mode 100644 index 000000000..55d434b41 --- /dev/null +++ b/test/mathc/fmax_fail.c @@ -0,0 +1,40 @@ +#include "smack.h" +#include + +// @expect error + +int main(void) { + double NaN = 0.0 / 0.0; + double Inf = 1.0 / 0.0; + double negInf = -1.0 / 0.0; + + double x = __VERIFIER_nondet_double(); + double y = __VERIFIER_nondet_double(); + + if (!__isnan(x) && !__isinf(x) && !__iszero(x)) { + if (!__isnan(y) && !__isinf(y) && !__iszero(y)) { + double maxVal = fmax(x, y); + if (x > y) { + assert(maxVal == y); + } else { + assert(maxVal == x); + } + } + } + + if (!__isnan(y)) { + assert(fmax(Inf, y) == Inf); + assert(fmax(negInf, y) == y); + assert(fmax(NaN, y) == y); + } + + if (!__isnan(x)) { + assert(fmax(x, Inf) == Inf); + assert(fmax(x, negInf) == x); + assert(fmax(x, NaN) == x); + } + + assert(__isnan(fmax(NaN, NaN))); + + return 0; +} diff --git a/test/mathc/fmaxf.c b/test/mathc/fmaxf.c new file mode 100644 index 000000000..9aac65a9a --- /dev/null +++ b/test/mathc/fmaxf.c @@ -0,0 +1,40 @@ +#include "smack.h" +#include + +// @expect verified + +int main(void) { + float NaN = 0.0f / 0.0f; + float Inf = 1.0f / 0.0f; + float negInf = -1.0f / 0.0f; + + float x = __VERIFIER_nondet_float(); + float y = __VERIFIER_nondet_float(); + + if (!__isnanf(x) && !__isinff(x) && !__iszerof(x)) { + if (!__isnanf(y) && !__isinff(y) && !__iszerof(y)) { + float maxVal = fmaxf(x, y); + if (x > y) { + assert(maxVal == x); + } else { + assert(maxVal == y); + } + } + } + + if (!__isnanf(y)) { + assert(fmaxf(Inf, y) == Inf); + assert(fmaxf(negInf, y) == y); + assert(fmaxf(NaN, y) == y); + } + + if (!__isnanf(x)) { + assert(fmaxf(x, Inf) == Inf); + assert(fmaxf(x, negInf) == x); + assert(fmaxf(x, NaN) == x); + } + + assert(__isnanf(fmaxf(NaN, NaN))); + + return 0; +} diff --git a/test/mathc/fmaxf_fail.c b/test/mathc/fmaxf_fail.c new file mode 100644 index 000000000..a10a2a80b --- /dev/null +++ b/test/mathc/fmaxf_fail.c @@ -0,0 +1,40 @@ +#include "smack.h" +#include + +// @expect error + +int main(void) { + float NaN = 0.0f / 0.0f; + float Inf = 1.0f / 0.0f; + float negInf = -1.0f / 0.0f; + + float x = __VERIFIER_nondet_float(); + float y = __VERIFIER_nondet_float(); + + if (!__isnanf(x) && !__isinff(x) && !__iszerof(x)) { + if (!__isnanf(y) && !__isinff(y) && !__iszerof(y)) { + float maxVal = fmaxf(x, y); + if (x > y) { + assert(maxVal == y); + } else { + assert(maxVal == x); + } + } + } + + if (!__isnanf(y)) { + assert(fmaxf(Inf, y) == Inf); + assert(fmaxf(negInf, y) == y); + assert(fmaxf(NaN, y) == y); + } + + if (!__isnanf(x)) { + assert(fmaxf(x, Inf) == Inf); + assert(fmaxf(x, negInf) == x); + assert(fmaxf(x, NaN) == x); + } + + assert(__isnanf(fmaxf(NaN, NaN))); + + return 0; +} diff --git a/test/mathc/fmaxl.c b/test/mathc/fmaxl.c new file mode 100644 index 000000000..46332655d --- /dev/null +++ b/test/mathc/fmaxl.c @@ -0,0 +1,40 @@ +#include "smack.h" +#include + +// @expect verified + +int main(void) { + long double NaN = 0.0l / 0.0l; + long double Inf = 1.0l / 0.0l; + long double negInf = -1.0l / 0.0l; + + long double x = __VERIFIER_nondet_long_double(); + long double y = __VERIFIER_nondet_long_double(); + + if (!__isnanl(x) && !__isinfl(x) && !__iszerol(x)) { + if (!__isnanl(y) && !__isinfl(y) && !__iszerol(y)) { + long double maxVal = fmaxl(x, y); + if (x > y) { + assert(maxVal == x); + } else { + assert(maxVal == y); + } + } + } + + if (!__isnanl(y)) { + assert(fmaxl(Inf, y) == Inf); + assert(fmaxl(negInf, y) == y); + assert(fmaxl(NaN, y) == y); + } + + if (!__isnanl(x)) { + assert(fmaxl(x, Inf) == Inf); + assert(fmaxl(x, negInf) == x); + assert(fmaxl(x, NaN) == x); + } + + assert(__isnanl(fmaxl(NaN, NaN))); + + return 0; +} diff --git a/test/mathc/fmaxl_fail.c b/test/mathc/fmaxl_fail.c new file mode 100644 index 000000000..ed3807bce --- /dev/null +++ b/test/mathc/fmaxl_fail.c @@ -0,0 +1,40 @@ +#include "smack.h" +#include + +// @expect error + +int main(void) { + long double NaN = 0.0l / 0.0l; + long double Inf = 1.0l / 0.0l; + long double negInf = -1.0l / 0.0l; + + long double x = __VERIFIER_nondet_long_double(); + long double y = __VERIFIER_nondet_long_double(); + + if (!__isnanl(x) && !__isinfl(x) && !__iszerol(x)) { + if (!__isnanl(y) && !__isinfl(y) && !__iszerol(y)) { + long double maxVal = fmaxl(x, y); + if (x > y) { + assert(maxVal == y); + } else { + assert(maxVal == x); + } + } + } + + if (!__isnanl(y)) { + assert(fmaxl(Inf, y) == Inf); + assert(fmaxl(negInf, y) == y); + assert(fmaxl(NaN, y) == y); + } + + if (!__isnanl(x)) { + assert(fmaxl(x, Inf) == Inf); + assert(fmaxl(x, negInf) == x); + assert(fmaxl(x, NaN) == x); + } + + assert(__isnanl(fmaxl(NaN, NaN))); + + return 0; +} diff --git a/test/mathc/fmin.c b/test/mathc/fmin.c new file mode 100644 index 000000000..835dca030 --- /dev/null +++ b/test/mathc/fmin.c @@ -0,0 +1,40 @@ +#include "smack.h" +#include + +// @expect verified + +int main(void) { + double NaN = 0.0 / 0.0; + double Inf = 1.0 / 0.0; + double negInf = -1.0 / 0.0; + + double x = __VERIFIER_nondet_double(); + double y = __VERIFIER_nondet_double(); + + if (!__isnan(x) && !__isinf(x) && !__iszero(x)) { + if (!__isnan(y) && !__isinf(y) && !__iszero(y)) { + double minVal = fmin(x, y); + if (x < y) { + assert(minVal == x); + } else { + assert(minVal == y); + } + } + } + + if (!__isnan(y)) { + assert(fmin(Inf, y) == y); + assert(fmin(negInf, y) == negInf); + assert(fmin(NaN, y) == y); + } + + if (!__isnan(x)) { + assert(fmin(x, Inf) == x); + assert(fmin(x, negInf) == negInf); + assert(fmin(x, NaN) == x); + } + + assert(__isnan(fmin(NaN, NaN))); + + return 0; +} diff --git a/test/mathc/fmin_fail.c b/test/mathc/fmin_fail.c new file mode 100644 index 000000000..6f0c0b376 --- /dev/null +++ b/test/mathc/fmin_fail.c @@ -0,0 +1,40 @@ +#include "smack.h" +#include + +// @expect error + +int main(void) { + double NaN = 0.0 / 0.0; + double Inf = 1.0 / 0.0; + double negInf = -1.0 / 0.0; + + double x = __VERIFIER_nondet_double(); + double y = __VERIFIER_nondet_double(); + + if (!__isnan(x) && !__isinf(x) && !__iszero(x)) { + if (!__isnan(y) && !__isinf(y) && !__iszero(y)) { + double minVal = fmin(x, y); + if (x < y) { + assert(minVal == y); + } else { + assert(minVal == x); + } + } + } + + if (!__isnan(y)) { + assert(fmin(Inf, y) == y); + assert(fmin(negInf, y) == negInf); + assert(fmin(NaN, y) == y); + } + + if (!__isnan(x)) { + assert(fmin(x, Inf) == x); + assert(fmin(x, negInf) == negInf); + assert(fmin(x, NaN) == x); + } + + assert(__isnan(fmin(NaN, NaN))); + + return 0; +} diff --git a/test/mathc/fminf.c b/test/mathc/fminf.c new file mode 100644 index 000000000..ef8c38e5b --- /dev/null +++ b/test/mathc/fminf.c @@ -0,0 +1,40 @@ +#include "smack.h" +#include + +// @expect verified + +int main(void) { + float NaN = 0.0f / 0.0f; + float Inf = 1.0f / 0.0f; + float negInf = -1.0f / 0.0f; + + float x = __VERIFIER_nondet_float(); + float y = __VERIFIER_nondet_float(); + + if (!__isnanf(x) && !__isinff(x) && !__iszerof(x)) { + if (!__isnanf(y) && !__isinff(y) && !__iszerof(y)) { + float minVal = fminf(x, y); + if (x < y) { + assert(minVal == x); + } else { + assert(minVal == y); + } + } + } + + if (!__isnanf(y)) { + assert(fminf(Inf, y) == y); + assert(fminf(negInf, y) == negInf); + assert(fminf(NaN, y) == y); + } + + if (!__isnanf(x)) { + assert(fminf(x, Inf) == x); + assert(fminf(x, negInf) == negInf); + assert(fminf(x, NaN) == x); + } + + assert(__isnanf(fminf(NaN, NaN))); + + return 0; +} diff --git a/test/mathc/fminf_fail.c b/test/mathc/fminf_fail.c new file mode 100644 index 000000000..6ccd4d5f6 --- /dev/null +++ b/test/mathc/fminf_fail.c @@ -0,0 +1,40 @@ +#include "smack.h" +#include + +// @expect error + +int main(void) { + float NaN = 0.0f / 0.0f; + float Inf = 1.0f / 0.0f; + float negInf = -1.0f / 0.0f; + + float x = __VERIFIER_nondet_float(); + float y = __VERIFIER_nondet_float(); + + if (!__isnanf(x) && !__isinff(x) && !__iszerof(x)) { + if (!__isnanf(y) && !__isinff(y) && !__iszerof(y)) { + float minVal = fminf(x, y); + if (x < y) { + assert(minVal == y); + } else { + assert(minVal == x); + } + } + } + + if (!__isnanf(y)) { + assert(fminf(Inf, y) == y); + assert(fminf(negInf, y) == negInf); + assert(fminf(NaN, y) == y); + } + + if (!__isnanf(x)) { + assert(fminf(x, Inf) == x); + assert(fminf(x, negInf) == negInf); + assert(fminf(x, NaN) == x); + } + + assert(__isnanf(fminf(NaN, NaN))); + + return 0; +} diff --git a/test/mathc/fminl.c b/test/mathc/fminl.c new file mode 100644 index 000000000..a5f81f334 --- /dev/null +++ b/test/mathc/fminl.c @@ -0,0 +1,40 @@ +#include "smack.h" +#include + +// @expect verified + +int main(void) { + long double NaN = 0.0l / 0.0l; + long double Inf = 1.0l / 0.0l; + long double negInf = -1.0l / 0.0l; + + long double x = __VERIFIER_nondet_long_double(); + long double y = __VERIFIER_nondet_long_double(); + + if (!__isnanl(x) && !__isinfl(x) && !__iszerol(x)) { + if (!__isnanl(y) && !__isinfl(y) && !__iszerol(y)) { + long double minVal = fminl(x, y); + if (x < y) { + assert(minVal == x); + } else { + assert(minVal == y); + } + } + } + + if (!__isnanl(y)) { + assert(fminl(Inf, y) == y); + assert(fminl(negInf, y) == negInf); + assert(fminl(NaN, y) == y); + } + + if (!__isnanl(x)) { + assert(fminl(x, Inf) == x); + assert(fminl(x, negInf) == negInf); + assert(fminl(x, NaN) == x); + } + + assert(__isnanl(fminl(NaN, NaN))); + + return 0; +} diff --git a/test/mathc/fminl_fail.c b/test/mathc/fminl_fail.c new file mode 100644 index 000000000..733f0e5f1 --- /dev/null +++ b/test/mathc/fminl_fail.c @@ -0,0 +1,40 @@ +#include "smack.h" +#include + +// @expect error + +int main(void) { + long double NaN = 0.0l / 0.0l; + long double Inf = 1.0l / 0.0l; + long double negInf = -1.0l / 0.0l; + + long double x = __VERIFIER_nondet_long_double(); + long double y = __VERIFIER_nondet_long_double(); + + if (!__isnanl(x) && !__isinfl(x) && !__iszerol(x)) { + if (!__isnanl(y) && !__isinfl(y) && !__iszerol(y)) { + long double minVal = fminl(x, y); + if (x < y) { + assert(minVal == y); + } else { + assert(minVal == x); + } + } + } + + if (!__isnanl(y)) { + assert(fminl(Inf, y) == y); + assert(fminl(negInf, y) == negInf); + assert(fminl(NaN, y) == y); + } + + if (!__isnanl(x)) { + assert(fminl(x, Inf) == x); + assert(fminl(x, negInf) == negInf); + assert(fminl(x, NaN) == x); + } + + assert(__isnanl(fminl(NaN, NaN))); + + return 0; +} diff --git a/test/mathc/fmod.c b/test/mathc/fmod.c new file mode 100644 index 000000000..1c19c2bf5 --- /dev/null +++ b/test/mathc/fmod.c @@ -0,0 +1,47 @@ +#include "smack.h" +#include + +// @expect verified +// @flag --bit-precise + +int main(void) { + double NaN = 0.0 / 0.0; + double Inf = 1.0 / 0.0; + double negInf = -1.0 / 0.0; + + double x = 2.0; + double y = -8.5; + + double a = 5.1; + double b = -3.0; + double c = fmod(a, b); + assert(fabs(c - 2.1) < 1e-8); + + if (!__isnan(y)) { + assert(__isnan(fmod(Inf, y))); + assert(__isnan(fmod(negInf, y))); + } + + if (!__isnan(x)) { + assert(__isnan(fmod(x, 0.0))); + assert(__isnan(fmod(x, -0.0))); + } + + + if (!__isnan(x) && !__isinf(x)) { + assert(fmod(x, Inf) == x); + assert(fmod(x, negInf) == x); + } + + if (!__isnan(y) && !__iszero(y)) { + assert(fmod(0.0, y) == 0.0); + assert(fmod(-0.0, y) == -0.0); + int isNeg = __signbit(fmod(-0.0, y)); + assert(isNeg); + } + + assert(__isnan(fmod(NaN, y))); + assert(__isnan(fmod(x, NaN))); + + return 0; +} diff --git a/test/mathc/fmod_fail.c b/test/mathc/fmod_fail.c new file mode 100644 index 000000000..651456d8c --- /dev/null +++ b/test/mathc/fmod_fail.c @@ -0,0 +1,47 @@ +#include "smack.h" +#include + +// @expect error +// @flag --bit-precise + +int main(void) { + double NaN = 0.0 / 0.0; + double Inf = 1.0 / 0.0; + double negInf = -1.0 / 0.0; + + double x = 2.0; + double y = -8.5; + + double a = 5.1; + double b = -3.0; + double c = fmod(a, b); + assert(fabs(c - 2.1) == 0.0); + + if (!__isnan(y)) { + assert(__isnan(fmod(Inf, y))); + assert(__isnan(fmod(negInf, y))); + } + + if (!__isnan(x)) { + assert(__isnan(fmod(x, 0.0))); + assert(__isnan(fmod(x, -0.0))); + } + + + if (!__isnan(x) && !__isinf(x)) { + assert(fmod(x, Inf) == x); + assert(fmod(x, negInf) == x); + } + + if (!__isnan(y) && !__iszero(y)) { + assert(fmod(0.0, y) == 0.0); + assert(fmod(-0.0, y) == -0.0); + int isNeg = __signbit(fmod(-0.0, y)); + assert(isNeg); + } + + assert(__isnan(fmod(NaN, y))); + assert(__isnan(fmod(x, NaN))); + + return 0; +} diff --git a/test/mathc/fmodf.c b/test/mathc/fmodf.c new file mode 100644 index 000000000..e5f6152e2 --- /dev/null +++ b/test/mathc/fmodf.c @@ -0,0 +1,47 @@ +#include "smack.h" +#include + +// @expect verified +// @flag --bit-precise + +int main(void) { + float NaN = 0.0f / 0.0f; + float Inf = 1.0f / 0.0f; + float negInf = -1.0f / 0.0f; + + float x = 2.0f; + float y = -8.5; + + float a = 5.1; + float b = -3.0f; + float c = fmodf(a, b); + assert(fabsf(c - 2.1) < 1e-8); + + if (!__isnanf(y)) { + assert(__isnanf(fmodf(Inf, y))); + assert(__isnanf(fmodf(negInf, y))); + } + + if (!__isnanf(x)) { + assert(__isnanf(fmodf(x, 0.0f))); + assert(__isnanf(fmodf(x, -0.0f))); + } + + + if (!__isnanf(x) && !__isinff(x)) { + assert(fmodf(x, Inf) == x); + assert(fmodf(x, negInf) == x); + } + + if (!__isnanf(y) && !__iszerof(y)) { + assert(fmodf(0.0f, y) == 0.0f); + assert(fmodf(-0.0f, y) == -0.0f); + int isNeg = __signbitf(fmodf(-0.0f, y)); + assert(isNeg); + } + + assert(__isnanf(fmodf(NaN, y))); + assert(__isnanf(fmodf(x, NaN))); + + return 0; +} diff --git a/test/mathc/fmodf_fail.c b/test/mathc/fmodf_fail.c new file mode 100644 index 000000000..3d54eb422 --- /dev/null +++ b/test/mathc/fmodf_fail.c @@ -0,0 +1,47 @@ +#include "smack.h" +#include + +// @expect error +// @flag --bit-precise + +int main(void) { + float NaN = 0.0f / 0.0f; + float Inf = 1.0f / 0.0f; + float negInf = -1.0f / 0.0f; + + float x = 2.0f; + float y = -8.5; + + float a = 5.1; + float b = -3.0f; + float c = fmodf(a, b); + assert(fabsf(c - 2.1) == 0.0f); + + if (!__isnanf(y)) { + assert(__isnanf(fmodf(Inf, y))); + assert(__isnanf(fmodf(negInf, y))); + } + + if (!__isnanf(x)) { + assert(__isnanf(fmodf(x, 0.0f))); + assert(__isnanf(fmodf(x, -0.0f))); + } + + + if (!__isnanf(x) && !__isinff(x)) { + assert(fmodf(x, Inf) == x); + assert(fmodf(x, negInf) == x); + } + + if (!__isnanf(y) && !__iszerof(y)) { + assert(fmodf(0.0f, y) == 0.0f); + assert(fmodf(-0.0f, y) == -0.0f); + int isNeg = __signbitf(fmodf(-0.0f, y)); + assert(isNeg); + } + + assert(__isnanf(fmodf(NaN, y))); + assert(__isnanf(fmodf(x, NaN))); + + return 0; +} diff --git a/test/mathc/fmodl.c b/test/mathc/fmodl.c new file mode 100644 index 000000000..be028d4fa --- /dev/null +++ b/test/mathc/fmodl.c @@ -0,0 +1,46 @@ +#include "smack.h" +#include + +// @expect verified + +int main(void) { + long double NaN = 0.0l / 0.0l; + long double Inf = 1.0l / 0.0l; + long double negInf = -1.0l / 0.0l; + + long double x = 2.0l; + long double y = -8.5; + + long double a = 5.1; + long double b = -3.0l; + long double c = fmodl(a, b); + assert(fabsl(c - 2.1) < 1e-8); + + if (!__isnanl(y)) { + assert(__isnanl(fmodl(Inf, y))); + assert(__isnanl(fmodl(negInf, y))); + } + + if (!__isnanl(x)) { + assert(__isnanl(fmodl(x, 0.0l))); + assert(__isnanl(fmodl(x, -0.0l))); + } + + + if (!__isnanl(x) && !__isinfl(x)) { + assert(fmodl(x, Inf) == x); + assert(fmodl(x, negInf) == x); + } + + if (!__isnanl(y) && !__iszerol(y)) { + assert(fmodl(0.0l, y) == 0.0l); + assert(fmodl(-0.0l, y) == -0.0l); + int isNeg = __signbitl(fmodl(-0.0l, y)); + assert(isNeg); + } + + assert(__isnanl(fmodl(NaN, y))); + assert(__isnanl(fmodl(x, NaN))); + + return 0; +} diff --git a/test/mathc/fmodl_fail.c b/test/mathc/fmodl_fail.c new file mode 100644 index 000000000..bbcd891d2 --- /dev/null +++ b/test/mathc/fmodl_fail.c @@ -0,0 +1,46 @@ +#include "smack.h" +#include + +// @expect error + +int main(void) { + long double NaN = 0.0l / 0.0l; + long double Inf = 1.0l / 0.0l; + long double negInf = -1.0l / 0.0l; + + long double x = 2.0l; + long double y = -8.5; + + long double a = 5.1; + long double b = -3.0l; + long double c = fmodl(a, b); + assert(fabsl(c - 2.1) == 0.0l); + + if (!__isnanl(y)) { + assert(__isnanl(fmodl(Inf, y))); + assert(__isnanl(fmodl(negInf, y))); + } + + if (!__isnanl(x)) { + assert(__isnanl(fmodl(x, 0.0l))); + assert(__isnanl(fmodl(x, -0.0l))); + } + + + if (!__isnanl(x) && !__isinfl(x)) { + assert(fmodl(x, Inf) == x); + assert(fmodl(x, negInf) == x); + } + + if (!__isnanl(y) && !__iszerol(y)) { + assert(fmodl(0.0l, y) == 0.0l); + assert(fmodl(-0.0l, y) == -0.0l); + int isNeg = __signbitl(fmodl(-0.0l, y)); + assert(isNeg); + } + + assert(__isnanl(fmodl(NaN, y))); + assert(__isnanl(fmodl(x, NaN))); + + return 0; +} diff --git a/test/mathc/issue_198.c b/test/mathc/issue_198.c new file mode 100644 index 000000000..692f21baa --- /dev/null +++ b/test/mathc/issue_198.c @@ -0,0 +1,11 @@ +#include smack.h" +#include + +// @expect verified + +int main(void) { + assert(remainder(5.1f, 3) == -0x1.ccccdp-1); + assert(remainder(5.1f, -3) == -0x1.ccccdp-1); + assert(remainder(-5.1f, -3) == 0x1.ccccdp-1); + assert(remainder(-5.1f, 3) == 0x1.ccccdp-1); +} diff --git a/test/mathc/issue_198_fail.c b/test/mathc/issue_198_fail.c new file mode 100644 index 000000000..b5ff69b3d --- /dev/null +++ b/test/mathc/issue_198_fail.c @@ -0,0 +1,11 @@ +#include smack.h" +#include + +// @expect error + +int main(void) { + assert(remainder(5.1f, 3) == 0x1.ccccdp-1); + assert(remainder(5.1f, -3) == -0x1.ccccdp-1); + assert(remainder(-5.1f, -3) == 0x1.ccccdp-1); + assert(remainder(-5.1f, 3) == 0x1.ccccdp-1); +} diff --git a/test/mathc/issue_244.c b/test/mathc/issue_244.c new file mode 100644 index 000000000..4703226dd --- /dev/null +++ b/test/mathc/issue_244.c @@ -0,0 +1,10 @@ +#include "smack.h" +#include + +// @expect verified +// @flag --bit-precise + +int main(void) +{ + assert(!__signbit(remainder(0.0, 1.0))); +} diff --git a/test/mathc/issue_244_fail.c b/test/mathc/issue_244_fail.c new file mode 100644 index 000000000..284f4b843 --- /dev/null +++ b/test/mathc/issue_244_fail.c @@ -0,0 +1,10 @@ +#include "smack.h" +#include + +// @expect error +// @flag --bit-precise + +int main(void) +{ + assert(__signbit(remainder(0.0, 1.0))); +} diff --git a/test/mathc/lrint.c b/test/mathc/lrint.c new file mode 100644 index 000000000..8ba258a4b --- /dev/null +++ b/test/mathc/lrint.c @@ -0,0 +1,47 @@ +#include "smack.h" +#include +#include + +// @expect verified +// @flag --bit-precise + +int main(void) { + double NaN = 0.0 / 0.0; + double Inf = 1.0 / 0.0; + double negInf = -1.0 / 0.0; + + double a = -2.5; + double b = -2.4999999999; + double c = -2.5000000001; + double d = 8.3; + + fesetround(FE_TONEAREST); + assert(lrint(a) == -2); + assert(lrint(b) == -2); + assert(lrint(c) == -3); + assert(lrint(d) == 8); + + fesetround(FE_UPWARD); + assert(lrint(a) == -2); + assert(lrint(b) == -2); + assert(lrint(c) == -2); + assert(lrint(d) == 9); + + fesetround(FE_DOWNWARD); + assert(lrint(a) == -3); + assert(lrint(b) == -3); + assert(lrint(c) == -3); + assert(lrint(d) == 8); + + fesetround(FE_TOWARDZERO); + assert(lrint(a) == -2); + assert(lrint(b) == -2); + assert(lrint(c) == -2); + assert(lrint(d) == 8); + + assert(lrint(0.0) == 0); + assert(lrint(-0.0) == 0); + + return 0; +} + diff --git a/test/mathc/lrint_fail.c b/test/mathc/lrint_fail.c new file mode 100644 index 000000000..2d673c92d --- /dev/null +++ b/test/mathc/lrint_fail.c @@ -0,0 +1,47 @@ +#include "smack.h" +#include +#include + +// @expect error +// @flag --bit-precise + +int main(void) { + double NaN = 0.0 / 0.0; + double Inf = 1.0 / 0.0; + double negInf = -1.0 / 0.0; + + double a = -2.5; + double b = -2.4999999999; + double c = -2.5000000001; + double d = 8.3; + + fesetround(FE_TONEAREST); + assert(lrint(a) == 2); + assert(lrint(b) == -2); + assert(lrint(c) == -3); + assert(lrint(d) == 8); + + fesetround(FE_UPWARD); + assert(lrint(a) == -2); + assert(lrint(b) == -2); + assert(lrint(c) == -2); + assert(lrint(d) == 9); + + fesetround(FE_DOWNWARD); + assert(lrint(a) == -3); + assert(lrint(b) == -3); + assert(lrint(c) == -3); + assert(lrint(d) == 8); + + fesetround(FE_TOWARDZERO); + assert(lrint(a) == -2); + assert(lrint(b) == -2); + assert(lrint(c) == -2); + assert(lrint(d) == 8); + + assert(lrint(0.0) == 0); + assert(lrint(-0.0) == 0); + + return 0; +} + diff --git a/test/mathc/lrintf.c b/test/mathc/lrintf.c new file mode 100644 index 000000000..02525fec6 --- /dev/null +++ b/test/mathc/lrintf.c @@ -0,0 +1,47 @@ +#include "smack.h" +#include +#include + +// @expect verified +// @flag --bit-precise + +int main(void) { + float NaN = 0.0f / 0.0f; + float Inf = 1.0f / 0.0f; + float negInf = -1.0f / 0.0f; + + float a = -2.5f; + float b = -2.4999999999f; + float c = -2.5000000001f; + float d = 8.3f; + + fesetround(FE_TONEAREST); + assert(lrintf(a) == -2); + assert(lrintf(b) == -2); + assert(lrintf(c) == -3); + assert(lrintf(d) == 8); + + fesetround(FE_UPWARD); + assert(lrintf(a) == -2); + assert(lrintf(b) == -2); + assert(lrintf(c) == -2); + assert(lrintf(d) == 9); + + fesetround(FE_DOWNWARD); + assert(lrintf(a) == -3); + assert(lrintf(b) == -3); + assert(lrintf(c) == -3); + assert(lrintf(d) == 8); + + fesetround(FE_TOWARDZERO); + assert(lrintf(a) == -2); + assert(lrintf(b) == -2); + assert(lrintf(c) == -2); + assert(lrintf(d) == 8); + + assert(lrintf(0.0f) == 0); + assert(lrintf(-0.0f) == 0); + + return 0; +} + diff --git a/test/mathc/lrintf_fail.c b/test/mathc/lrintf_fail.c new file mode 100644 index 000000000..de757de6a --- /dev/null +++ b/test/mathc/lrintf_fail.c @@ -0,0 +1,47 @@ +#include "smack.h" +#include +#include + +// @expect error +// @flag --bit-precise + +int main(void) { + float NaN = 0.0f / 0.0f; + float Inf = 1.0f / 0.0f; + float negInf = -1.0f / 0.0f; + + float a = -2.5f; + float b = -2.4999999999f; + float c = -2.5000000001f; + float d = 8.3f; + + fesetround(FE_TONEAREST); + assert(lrintf(a) == -2); + assert(lrintf(b) == -2); + assert(lrintf(c) == -3); + assert(lrintf(d) == 8); + + fesetround(FE_UPWARD); + assert(lrintf(a) == -2); + assert(lrintf(b) == -1); + assert(lrintf(c) == -2); + assert(lrintf(d) == 9); + + fesetround(FE_DOWNWARD); + assert(lrintf(a) == -3); + assert(lrintf(b) == -3); + assert(lrintf(c) == -3); + assert(lrintf(d) == 8); + + fesetround(FE_TOWARDZERO); + assert(lrintf(a) == -2); + assert(lrintf(b) == -2); + assert(lrintf(c) == -2); + assert(lrintf(d) == 8); + + assert(lrintf(0.0f) == 0); + assert(lrintf(-0.0f) == 0); + + return 0; +} + diff --git a/test/mathc/lrintl.c b/test/mathc/lrintl.c new file mode 100644 index 000000000..3e8d2324f --- /dev/null +++ b/test/mathc/lrintl.c @@ -0,0 +1,46 @@ +#include "smack.h" +#include +#include + +// @expect verified + +int main(void) { + long double NaN = 0.0l / 0.0l; + long double Inf = 1.0l / 0.0l; + long double negInf = -1.0l / 0.0l; + + long double a = -2.5l; + long double b = -2.4999999999l; + long double c = -2.5000000001l; + long double d = 8.3l; + + fesetround(FE_TONEAREST); + assert(lrintl(a) == -2); + assert(lrintl(b) == -2); + assert(lrintl(c) == -3); + assert(lrintl(d) == 8); + + fesetround(FE_UPWARD); + assert(lrintl(a) == -2); + assert(lrintl(b) == -2); + assert(lrintl(c) == -2); + assert(lrintl(d) == 9); + + fesetround(FE_DOWNWARD); + assert(lrintl(a) == -3); + assert(lrintl(b) == -3); + assert(lrintl(c) == -3); + assert(lrintl(d) == 8); + + fesetround(FE_TOWARDZERO); + assert(lrintl(a) == -2); + assert(lrintl(b) == -2); + assert(lrintl(c) == -2); + assert(lrintl(d) == 8); + + assert(lrintl(0.0l) == 0); + assert(lrintl(-0.0l) == 0); + + return 0; +} + diff --git a/test/mathc/lrintl_fail.c b/test/mathc/lrintl_fail.c new file mode 100644 index 000000000..6c6882a2d --- /dev/null +++ b/test/mathc/lrintl_fail.c @@ -0,0 +1,46 @@ +#include "smack.h" +#include +#include + +// @expect error + +int main(void) { + long double NaN = 0.0l / 0.0l; + long double Inf = 1.0l / 0.0l; + long double negInf = -1.0l / 0.0l; + + long double a = -2.5l; + long double b = -2.4999999999l; + long double c = -2.5000000001l; + long double d = 8.3l; + + fesetround(FE_TONEAREST); + assert(lrintl(a) == -2); + assert(lrintl(b) == -2); + assert(lrintl(c) == -3); + assert(lrintl(d) == 8); + + fesetround(FE_UPWARD); + assert(lrintl(a) == -2); + assert(lrintl(b) == -1); + assert(lrintl(c) == -2); + assert(lrintl(d) == 9); + + fesetround(FE_DOWNWARD); + assert(lrintl(a) == -3); + assert(lrintl(b) == -3); + assert(lrintl(c) == -3); + assert(lrintl(d) == 8); + + fesetround(FE_TOWARDZERO); + assert(lrintl(a) == -2); + assert(lrintl(b) == -2); + assert(lrintl(c) == -2); + assert(lrintl(d) == 8); + + assert(lrintl(0.0l) == 0); + assert(lrintl(-0.0l) == 0); + + return 0; +} + diff --git a/test/mathc/lround.c b/test/mathc/lround.c new file mode 100644 index 000000000..fcdc3897b --- /dev/null +++ b/test/mathc/lround.c @@ -0,0 +1,29 @@ +#include "smack.h" +#include + +// @expect verified +// @flag --bit-precise + +int main(void) { + double NaN = 0.0 / 0.0; + double Inf = 1.0 / 0.0; + double negInf = -1.0 / 0.0; + + double a = -1.5; + double b = -1.49999999999999999; + double c = 3.5; + double d = 2.0; + + assert(lround(a) == -2); + assert(lround(b) == -1); + assert(lround(c) == 4); + assert(lround(d) == 2); + + assert(lround(0.0) == 0); + assert(lround(-0.0) == 0); + int isNeg = __signbit(lround(-0.0)); + assert(isNeg); + + return 0; +} + diff --git a/test/mathc/lround_fail.c b/test/mathc/lround_fail.c new file mode 100644 index 000000000..798b1e27f --- /dev/null +++ b/test/mathc/lround_fail.c @@ -0,0 +1,29 @@ +#include "smack.h" +#include + +// @expect error +// @flag --bit-precise + +int main(void) { + double NaN = 0.0 / 0.0; + double Inf = 1.0 / 0.0; + double negInf = -1.0 / 0.0; + + double a = -1.5; + double b = -1.49999999999999999; + double c = 3.5; + double d = 2.0; + + assert(lround(a) == 2); + assert(lround(b) == -1); + assert(lround(c) == 4); + assert(lround(d) == 2); + + assert(lround(0.0) == 0); + assert(lround(-0.0) == 0); + int isNeg = __signbit(lround(-0.0)); + assert(isNeg); + + return 0; +} + diff --git a/test/mathc/lroundf.c b/test/mathc/lroundf.c new file mode 100644 index 000000000..cfaf48a67 --- /dev/null +++ b/test/mathc/lroundf.c @@ -0,0 +1,29 @@ +#include "smack.h" +#include + +// @expect verified +// @flag --bit-precise + +int main(void) { + float NaN = 0.0f / 0.0f; + float Inf = 1.0f / 0.0f; + float negInf = -1.0f / 0.0f; + + float a = -1.5f; + float b = -1.49999999999999999f; + float c = 3.5f; + float d = 2.0f; + + assert(lroundf(a) == -2); + assert(lroundf(b) == -1); + assert(lroundf(c) == 4); + assert(lroundf(d) == 2); + + assert(lroundf(0.0f) == 0); + assert(lroundf(-0.0f) == 0); + int isNeg = __signbitf(lroundf(-0.0f)); + assert(isNeg); + + return 0; +} + diff --git a/test/mathc/lroundf_fail.c b/test/mathc/lroundf_fail.c new file mode 100644 index 000000000..591d7cac0 --- /dev/null +++ b/test/mathc/lroundf_fail.c @@ -0,0 +1,29 @@ +#include "smack.h" +#include + +// @expect error +// @flag --bit-precise + +int main(void) { + float NaN = 0.0f / 0.0f; + float Inf = 1.0f / 0.0f; + float negInf = -1.0f / 0.0f; + + float a = -1.5f; + float b = -1.49999999999999999f; + float c = 3.5f; + float d = 2.0f; + + assert(lroundf(a) == -2); + assert(lroundf(b) == 1); + assert(lroundf(c) == 4); + assert(lroundf(d) == 2); + + assert(lroundf(0.0f) == 0); + assert(lroundf(-0.0f) == 0); + int isNeg = __signbitf(lroundf(-0.0f)); + assert(isNeg); + + return 0; +} + diff --git a/test/mathc/lroundl.c b/test/mathc/lroundl.c new file mode 100644 index 000000000..d301f688c --- /dev/null +++ b/test/mathc/lroundl.c @@ -0,0 +1,28 @@ +#include "smack.h" +#include + +// @expect verified + +int main(void) { + long double NaN = 0.0l / 0.0l; + long double Inf = 1.0l / 0.0l; + long double negInf = -1.0l / 0.0l; + + long double a = -1.5l; + long double b = -1.49999999999999999l; + long double c = 3.5l; + long double d = 2.0l; + + assert(lroundl(a) == -2); + assert(lroundl(b) == -1); + assert(lroundl(c) == 4); + assert(lroundl(d) == 2); + + assert(lroundl(0.0l) == 0); + assert(lroundl(-0.0l) == 0); + int isNeg = __signbitl(lroundl(-0.0l)); + assert(isNeg); + + return 0; +} + diff --git a/test/mathc/lroundl_fail.c b/test/mathc/lroundl_fail.c new file mode 100644 index 000000000..e5f86bcc8 --- /dev/null +++ b/test/mathc/lroundl_fail.c @@ -0,0 +1,28 @@ +#include "smack.h" +#include + +// @expect error + +int main(void) { + long double NaN = 0.0l / 0.0l; + long double Inf = 1.0l / 0.0l; + long double negInf = -1.0l / 0.0l; + + long double a = -1.5l; + long double b = -1.49999999999999999l; + long double c = 3.5l; + long double d = 2.0l; + + assert(lroundl(a) == -2); + assert(lroundl(b) == 1); + assert(lroundl(c) == 4); + assert(lroundl(d) == 2); + + assert(lroundl(0.0l) == 0); + assert(lroundl(-0.0l) == 0); + int isNeg = __signbitl(lroundl(-0.0l)); + assert(isNeg); + + return 0; +} + diff --git a/test/mathc/modf.c b/test/mathc/modf.c new file mode 100644 index 000000000..b4ee8d698 --- /dev/null +++ b/test/mathc/modf.c @@ -0,0 +1,43 @@ +#include "smack.h" +#include +#include + +// @expect verified +// @flag --bit-precise + +int main(void) { + double NaN = 0.0 / 0.0; + double Inf = 1.0 / 0.0; + double negInf = -1.0 / 0.0; + + double x = __VERIFIER_nondet_double(); + double fPart, iPart; + + if (!__isnan(x) && !__isinf(x) && !__iszero(x)) { + fPart = modf(x, &iPart); + if (x < 0) { + assert(x <= iPart); + assert(x <= fPart); + } else { + assert(x >= iPart); + assert(x >= fPart); + } + } + + fPart = modf(0.0, &iPart); + assert(iPart == 0.0 && fPart == 0.0); + + fPart = modf(-0.0, &iPart); + assert(iPart == -0.0 && fPart == -0.0); + + fPart = modf(Inf, &iPart); + assert(iPart == Inf && fPart == 0.0); + + fPart = modf(negInf, &iPart); + assert(iPart == negInf && fPart == -0.0); + + fPart = modf(NaN, &iPart); + assert(__isnan(iPart) && __isnan(fPart)); + + return 0; +} diff --git a/test/mathc/modf_fail.c b/test/mathc/modf_fail.c new file mode 100644 index 000000000..95733cc5f --- /dev/null +++ b/test/mathc/modf_fail.c @@ -0,0 +1,43 @@ +#include "smack.h" +#include +#include + +// @expect error +// @flag --bit-precise + +int main(void) { + double NaN = 0.0 / 0.0; + double Inf = 1.0 / 0.0; + double negInf = -1.0 / 0.0; + + double x = __VERIFIER_nondet_double(); + double fPart, iPart; + + if (!__isnan(x) && !__isinf(x) && !__iszero(x)) { + fPart = modf(x, &iPart); + if (x < 0) { + assert(x < iPart); + assert(x < fPart); + } else { + assert(x >= iPart); + assert(x >= fPart); + } + } + + fPart = modf(0.0, &iPart); + assert(iPart == 0.0 && fPart == 0.0); + + fPart = modf(-0.0, &iPart); + assert(iPart == -0.0 && fPart == -0.0); + + fPart = modf(Inf, &iPart); + assert(iPart == Inf && fPart == 0.0); + + fPart = modf(negInf, &iPart); + assert(iPart == negInf && fPart == -0.0); + + fPart = modf(NaN, &iPart); + assert(__isnan(iPart) && __isnan(fPart)); + + return 0; +} diff --git a/test/mathc/modff.c b/test/mathc/modff.c new file mode 100644 index 000000000..251417bac --- /dev/null +++ b/test/mathc/modff.c @@ -0,0 +1,43 @@ +#include "smack.h" +#include +#include + +// @expect verified +// @flag --bit-precise + +int main(void) { + float NaN = 0.0f / 0.0f; + float Inf = 1.0f / 0.0f; + float negInf = -1.0f / 0.0f; + + float x = __VERIFIER_nondet_float(); + float fPart, iPart; + + if (!__isnanf(x) && !__isinff(x) && !__iszerof(x)) { + fPart = modff(x, &iPart); + if (x < 0) { + assert(x <= iPart); + assert(x <= fPart); + } else { + assert(x >= iPart); + assert(x >= fPart); + } + } + + fPart = modff(0.0f, &iPart); + assert(iPart == 0.0f && fPart == 0.0f); + + fPart = modff(-0.0f, &iPart); + assert(iPart == -0.0f && fPart == -0.0f); + + fPart = modff(Inf, &iPart); + assert(iPart == Inf && fPart == 0.0f); + + fPart = modff(negInf, &iPart); + assert(iPart == negInf && fPart == -0.0f); + + fPart = modff(NaN, &iPart); + assert(__isnanf(iPart) && __isnanf(fPart)); + + return 0; +} diff --git a/test/mathc/modff_fail.c b/test/mathc/modff_fail.c new file mode 100644 index 000000000..432882754 --- /dev/null +++ b/test/mathc/modff_fail.c @@ -0,0 +1,43 @@ +#include "smack.h" +#include +#include + +// @expect error +// @flag --bit-precise + +int main(void) { + float NaN = 0.0f / 0.0f; + float Inf = 1.0f / 0.0f; + float negInf = -1.0f / 0.0f; + + float x = __VERIFIER_nondet_float(); + float fPart, iPart; + + if (!__isnanf(x) && !__isinff(x) && !__iszerof(x)) { + fPart = modff(x, &iPart); + if (x < 0) { + assert(x <= iPart); + assert(x <= fPart); + } else { + assert(x > iPart); + assert(x > fPart); + } + } + + fPart = modff(0.0f, &iPart); + assert(iPart == 0.0f && fPart == 0.0f); + + fPart = modff(-0.0f, &iPart); + assert(iPart == -0.0f && fPart == -0.0f); + + fPart = modff(Inf, &iPart); + assert(iPart == Inf && fPart == 0.0f); + + fPart = modff(negInf, &iPart); + assert(iPart == negInf && fPart == -0.0f); + + fPart = modff(NaN, &iPart); + assert(__isnanf(iPart) && __isnanf(fPart)); + + return 0; +} diff --git a/test/mathc/modfl.c b/test/mathc/modfl.c new file mode 100644 index 000000000..b79a96278 --- /dev/null +++ b/test/mathc/modfl.c @@ -0,0 +1,42 @@ +#include "smack.h" +#include +#include + +// @expect verified + +int main(void) { + long double NaN = 0.0l / 0.0l; + long double Inf = 1.0l / 0.0l; + long double negInf = -1.0l / 0.0l; + + long double x = __VERIFIER_nondet_long_double(); + long double fPart, iPart; + + if (!__isnanl(x) && !__isinfl(x) && !__iszerol(x)) { + fPart = modfl(x, &iPart); + if (x < 0) { + assert(x <= iPart); + assert(x <= fPart); + } else { + assert(x >= iPart); + assert(x >= fPart); + } + } + + fPart = modfl(0.0l, &iPart); + assert(iPart == 0.0l && fPart == 0.0l); + + fPart = modfl(-0.0l, &iPart); + assert(iPart == -0.0l && fPart == -0.0l); + + fPart = modfl(Inf, &iPart); + assert(iPart == Inf && fPart == 0.0l); + + fPart = modfl(negInf, &iPart); + assert(iPart == negInf && fPart == -0.0l); + + fPart = modfl(NaN, &iPart); + assert(__isnanl(iPart) && __isnanl(fPart)); + + return 0; +} diff --git a/test/mathc/modfl_fail.c b/test/mathc/modfl_fail.c new file mode 100644 index 000000000..7cb23d474 --- /dev/null +++ b/test/mathc/modfl_fail.c @@ -0,0 +1,42 @@ +#include "smack.h" +#include +#include + +// @expect error + +int main(void) { + long double NaN = 0.0l / 0.0l; + long double Inf = 1.0l / 0.0l; + long double negInf = -1.0l / 0.0l; + + long double x = __VERIFIER_nondet_long_double(); + long double fPart, iPart; + + if (!__isnanl(x) && !__isinfl(x) && !__iszerol(x)) { + fPart = modfl(x, &iPart); + if (x < 0) { + assert(x <= iPart); + assert(x <= fPart); + } else { + assert(x > iPart); + assert(x > fPart); + } + } + + fPart = modfl(0.0l, &iPart); + assert(iPart == 0.0l && fPart == 0.0l); + + fPart = modfl(-0.0l, &iPart); + assert(iPart == -0.0l && fPart == -0.0l); + + fPart = modfl(Inf, &iPart); + assert(iPart == Inf && fPart == 0.0l); + + fPart = modfl(negInf, &iPart); + assert(iPart == negInf && fPart == -0.0l); + + fPart = modfl(NaN, &iPart); + assert(__isnanl(iPart) && __isnanl(fPart)); + + return 0; +} diff --git a/test/mathc/nearbyint.c b/test/mathc/nearbyint.c new file mode 100644 index 000000000..7e4abf769 --- /dev/null +++ b/test/mathc/nearbyint.c @@ -0,0 +1,54 @@ +#include "smack.h" +#include +#include + +// @expect verified +// @flag --bit-precise + +int main(void) { + double NaN = 0.0 / 0.0; + double Inf = 1.0 / 0.0; + double negInf = -1.0 / 0.0; + + double a = -3.5; + double b = -3.4999999999; + double c = -3.5000000001; + double d = 7.3; + + fesetround(FE_TONEAREST); + assert(nearbyint(a) == -4.0); + assert(nearbyint(b) == -3.0); + assert(nearbyint(c) == -4.0); + assert(nearbyint(d) == 7.0); + + fesetround(FE_UPWARD); + assert(nearbyint(a) == -3.0); + assert(nearbyint(b) == -3.0); + assert(nearbyint(c) == -3.0); + assert(nearbyint(d) == 8.0); + + fesetround(FE_DOWNWARD); + assert(nearbyint(a) == -4.0); + assert(nearbyint(b) == -4.0); + assert(nearbyint(c) == -4.0); + assert(nearbyint(d) == 7.0); + + fesetround(FE_TOWARDZERO); + assert(nearbyint(a) == -3.0); + assert(nearbyint(b) == -3.0); + assert(nearbyint(c) == -3.0); + assert(nearbyint(d) == 7.0); + + assert(nearbyint(0.0) == 0.0); + assert(nearbyint(-0.0) == -0.0); + int isNeg = __signbit(nearbyint(-0.0)); + assert(isNeg); + + assert(nearbyint(Inf) == Inf); + assert(nearbyint(negInf) == negInf); + + assert(__isnan(nearbyint(NaN))); + + return 0; +} + diff --git a/test/mathc/nearbyint_fail.c b/test/mathc/nearbyint_fail.c new file mode 100644 index 000000000..cf441e29e --- /dev/null +++ b/test/mathc/nearbyint_fail.c @@ -0,0 +1,54 @@ +#include "smack.h" +#include +#include + +// @expect error +// @flag --bit-precise + +int main(void) { + double NaN = 0.0 / 0.0; + double Inf = 1.0 / 0.0; + double negInf = -1.0 / 0.0; + + double a = -3.5; + double b = -3.4999999999; + double c = -3.5000000001; + double d = 7.3; + + fesetround(FE_TONEAREST); + assert(nearbyint(a) == -3.0); + assert(nearbyint(b) == -3.0); + assert(nearbyint(c) == -4.0); + assert(nearbyint(d) == 7.0); + + fesetround(FE_UPWARD); + assert(nearbyint(a) == -3.0); + assert(nearbyint(b) == -3.0); + assert(nearbyint(c) == -3.0); + assert(nearbyint(d) == 8.0); + + fesetround(FE_DOWNWARD); + assert(nearbyint(a) == -4.0); + assert(nearbyint(b) == -4.0); + assert(nearbyint(c) == -4.0); + assert(nearbyint(d) == 7.0); + + fesetround(FE_TOWARDZERO); + assert(nearbyint(a) == -3.0); + assert(nearbyint(b) == -3.0); + assert(nearbyint(c) == -3.0); + assert(nearbyint(d) == 7.0); + + assert(nearbyint(0.0) == 0.0); + assert(nearbyint(-0.0) == -0.0); + int isNeg = __signbit(nearbyint(-0.0)); + assert(isNeg); + + assert(nearbyint(Inf) == Inf); + assert(nearbyint(negInf) == negInf); + + assert(__isnan(nearbyint(NaN))); + + return 0; +} + diff --git a/test/mathc/nearbyintf.c b/test/mathc/nearbyintf.c new file mode 100644 index 000000000..836ff666d --- /dev/null +++ b/test/mathc/nearbyintf.c @@ -0,0 +1,54 @@ +#include "smack.h" +#include +#include + +// @expect verified +// @flag --bit-precise + +int main(void) { + float NaN = 0.0f / 0.0f; + float Inf = 1.0f / 0.0f; + float negInf = -1.0f / 0.0f; + + float a = -3.5f; + float b = -3.4999999999f; + float c = -3.5000000001f; + float d = 7.3f; + + fesetround(FE_TONEAREST); + assert(nearbyintf(a) == -4.0f); + assert(nearbyintf(b) == -3.0f); + assert(nearbyintf(c) == -4.0f); + assert(nearbyintf(d) == 7.0f); + + fesetround(FE_UPWARD); + assert(nearbyintf(a) == -3.0f); + assert(nearbyintf(b) == -3.0f); + assert(nearbyintf(c) == -3.0f); + assert(nearbyintf(d) == 8.0f); + + fesetround(FE_DOWNWARD); + assert(nearbyintf(a) == -4.0f); + assert(nearbyintf(b) == -4.0f); + assert(nearbyintf(c) == -4.0f); + assert(nearbyintf(d) == 7.0f); + + fesetround(FE_TOWARDZERO); + assert(nearbyintf(a) == -3.0f); + assert(nearbyintf(b) == -3.0f); + assert(nearbyintf(c) == -3.0f); + assert(nearbyintf(d) == 7.0f); + + assert(nearbyintf(0.0f) == 0.0f); + assert(nearbyintf(-0.0f) == -0.0f); + int isNeg = __signbitf(nearbyintf(-0.0f)); + assert(isNeg); + + assert(nearbyintf(Inf) == Inf); + assert(nearbyintf(negInf) == negInf); + + assert(__isnanf(nearbyintf(NaN))); + + return 0; +} + diff --git a/test/mathc/nearbyintf_fail.c b/test/mathc/nearbyintf_fail.c new file mode 100644 index 000000000..7984e8fc0 --- /dev/null +++ b/test/mathc/nearbyintf_fail.c @@ -0,0 +1,54 @@ +#include "smack.h" +#include +#include + +// @expect error +// @flag --bit-precise + +int main(void) { + float NaN = 0.0f / 0.0f; + float Inf = 1.0f / 0.0f; + float negInf = -1.0f / 0.0f; + + float a = -3.5f; + float b = -3.4999999999f; + float c = -3.5000000001f; + float d = 7.3f; + + fesetround(FE_TONEAREST); + assert(nearbyintf(a) == -4.0f); + assert(nearbyintf(b) == -3.0f); + assert(nearbyintf(c) == -4.0f); + assert(nearbyintf(d) == 7.0f); + + fesetround(FE_UPWARD); + assert(nearbyintf(a) == -3.0f); + assert(nearbyintf(b) == -2.0f); + assert(nearbyintf(c) == -3.0f); + assert(nearbyintf(d) == 8.0f); + + fesetround(FE_DOWNWARD); + assert(nearbyintf(a) == -4.0f); + assert(nearbyintf(b) == -4.0f); + assert(nearbyintf(c) == -4.0f); + assert(nearbyintf(d) == 7.0f); + + fesetround(FE_TOWARDZERO); + assert(nearbyintf(a) == -3.0f); + assert(nearbyintf(b) == -3.0f); + assert(nearbyintf(c) == -3.0f); + assert(nearbyintf(d) == 7.0f); + + assert(nearbyintf(0.0f) == 0.0f); + assert(nearbyintf(-0.0f) == -0.0f); + int isNeg = __signbitf(nearbyintf(-0.0f)); + assert(isNeg); + + assert(nearbyintf(Inf) == Inf); + assert(nearbyintf(negInf) == negInf); + + assert(__isnanf(nearbyintf(NaN))); + + return 0; +} + diff --git a/test/mathc/nearbyintl.c b/test/mathc/nearbyintl.c new file mode 100644 index 000000000..c947e9d25 --- /dev/null +++ b/test/mathc/nearbyintl.c @@ -0,0 +1,53 @@ +#include "smack.h" +#include +#include + +// @expect verified + +int main(void) { + long double NaN = 0.0l / 0.0l; + long double Inf = 1.0l / 0.0l; + long double negInf = -1.0l / 0.0l; + + long double a = -3.5l; + long double b = -3.4999999999l; + long double c = -3.5000000001l; + long double d = 7.3l; + + fesetround(FE_TONEAREST); + assert(nearbyintl(a) == -4.0l); + assert(nearbyintl(b) == -3.0l); + assert(nearbyintl(c) == -4.0l); + assert(nearbyintl(d) == 7.0l); + + fesetround(FE_UPWARD); + assert(nearbyintl(a) == -3.0l); + assert(nearbyintl(b) == -3.0l); + assert(nearbyintl(c) == -3.0l); + assert(nearbyintl(d) == 8.0l); + + fesetround(FE_DOWNWARD); + assert(nearbyintl(a) == -4.0l); + assert(nearbyintl(b) == -4.0l); + assert(nearbyintl(c) == -4.0l); + assert(nearbyintl(d) == 7.0l); + + fesetround(FE_TOWARDZERO); + assert(nearbyintl(a) == -3.0l); + assert(nearbyintl(b) == -3.0l); + assert(nearbyintl(c) == -3.0l); + assert(nearbyintl(d) == 7.0l); + + assert(nearbyintl(0.0l) == 0.0l); + assert(nearbyintl(-0.0l) == -0.0l); + int isNeg = __signbitl(nearbyintl(-0.0l)); + assert(isNeg); + + assert(nearbyintl(Inf) == Inf); + assert(nearbyintl(negInf) == negInf); + + assert(__isnanl(nearbyintl(NaN))); + + return 0; +} + diff --git a/test/mathc/nearbyintl_fail.c b/test/mathc/nearbyintl_fail.c new file mode 100644 index 000000000..6feca401e --- /dev/null +++ b/test/mathc/nearbyintl_fail.c @@ -0,0 +1,53 @@ +#include "smack.h" +#include +#include + +// @expect error + +int main(void) { + long double NaN = 0.0l / 0.0l; + long double Inf = 1.0l / 0.0l; + long double negInf = -1.0l / 0.0l; + + long double a = -3.5l; + long double b = -3.4999999999l; + long double c = -3.5000000001l; + long double d = 7.3l; + + fesetround(FE_TONEAREST); + assert(nearbyintl(a) == -4.0l); + assert(nearbyintl(b) == -3.0l); + assert(nearbyintl(c) == -4.0l); + assert(nearbyintl(d) == 7.0l); + + fesetround(FE_UPWARD); + assert(nearbyintl(a) == -3.0l); + assert(nearbyintl(b) == -2.0l); + assert(nearbyintl(c) == -3.0l); + assert(nearbyintl(d) == 8.0l); + + fesetround(FE_DOWNWARD); + assert(nearbyintl(a) == -4.0l); + assert(nearbyintl(b) == -4.0l); + assert(nearbyintl(c) == -4.0l); + assert(nearbyintl(d) == 7.0l); + + fesetround(FE_TOWARDZERO); + assert(nearbyintl(a) == -3.0l); + assert(nearbyintl(b) == -3.0l); + assert(nearbyintl(c) == -3.0l); + assert(nearbyintl(d) == 7.0l); + + assert(nearbyintl(0.0l) == 0.0l); + assert(nearbyintl(-0.0l) == -0.0l); + int isNeg = __signbitl(nearbyintl(-0.0l)); + assert(isNeg); + + assert(nearbyintl(Inf) == Inf); + assert(nearbyintl(negInf) == negInf); + + assert(__isnanl(nearbyintl(NaN))); + + return 0; +} + diff --git a/test/mathc/remainder.c b/test/mathc/remainder.c new file mode 100644 index 000000000..2ac1b5e91 --- /dev/null +++ b/test/mathc/remainder.c @@ -0,0 +1,32 @@ +#include "smack.h" +#include + +// @expect verified + +int main(void) { + double NaN = 0.0 / 0.0; + double Inf = 1.0 / 0.0; + double negInf = -1.0 / 0.0; + + assert(remainder(2, 4) == 2); + assert(remainder(2.00000001, 4) == -1.99999999); + assert(remainder(1.99999999, 4) == 1.99999999); + + double x = __VERIFIER_nondet_double(); + double y = __VERIFIER_nondet_double(); + + if (!__isnan(y)) { + assert(__isnan(remainder(Inf, y))); + assert(__isnan(remainder(negInf, y))); + } + + if (!__isnan(x)) { + assert(__isnan(remainder(x, 0.0))); + assert(__isnan(remainder(x, -0.0))); + } + + assert(__isnan(remainder(NaN, y))); + assert(__isnan(remainder(x, NaN))); + + return 0; +} diff --git a/test/mathc/remainder_fail.c b/test/mathc/remainder_fail.c new file mode 100644 index 000000000..8cc96f277 --- /dev/null +++ b/test/mathc/remainder_fail.c @@ -0,0 +1,32 @@ +#include "smack.h" +#include + +// @expect error + +int main(void) { + double NaN = 0.0 / 0.0; + double Inf = 1.0 / 0.0; + double negInf = -1.0 / 0.0; + + assert(remainder(2, 4) == 2); + assert(remainder(2.00000001, 4) == 2.00000001; + assert(remainder(1.99999999, 4) == 1.99999999); + + double x = __VERIFIER_nondet_double(); + double y = __VERIFIER_nondet_double(); + + if (!__isnan(y)) { + assert(__isnan(remainder(Inf, y))); + assert(__isnan(remainder(negInf, y))); + } + + if (!__isnan(x)) { + assert(__isnan(remainder(x, 0.0))); + assert(__isnan(remainder(x, -0.0))); + } + + assert(__isnan(remainder(NaN, y))); + assert(__isnan(remainder(x, NaN))); + + return 0; +} diff --git a/test/mathc/remainderf.c b/test/mathc/remainderf.c new file mode 100644 index 000000000..61347c7e2 --- /dev/null +++ b/test/mathc/remainderf.c @@ -0,0 +1,32 @@ +#include "smack.h" +#include + +// @expect verified + +int main(void) { + float NaN = 0.0f / 0.0f; + float Inf = 1.0f / 0.0f; + float negInf = -1.0f / 0.0f; + + assert(remainderf(2.0f, 4.0f) == 2); + assert(remainderf(2.00000001f, 4) == -1.99999999f); + assert(remainderf(1.99999999f, 4) == 1.99999999f); + + float x = __VERIFIER_nondet_float(); + float y = __VERIFIER_nondet_float(); + + if (!__isnanf(y)) { + assert(__isnanf(remainderf(Inf, y))); + assert(__isnanf(remainderf(negInf, y))); + } + + if (!__isnanf(x)) { + assert(__isnanf(remainderf(x, 0.0f))); + assert(__isnanf(remainderf(x, -0.0f))); + } + + assert(__isnanf(remainderf(NaN, y))); + assert(__isnanf(remainderf(x, NaN))); + + return 0; +} diff --git a/test/mathc/remainderf_fail.c b/test/mathc/remainderf_fail.c new file mode 100644 index 000000000..b0bedc68a --- /dev/null +++ b/test/mathc/remainderf_fail.c @@ -0,0 +1,32 @@ +#include "smack.h" +#include + +// @expect error + +int main(void) { + float NaN = 0.0f / 0.0f; + float Inf = 1.0f / 0.0f; + float negInf = -1.0f / 0.0f; + + assert(remainderf(2.0f, 4.0f) == 2); + assert(remainderf(2.00000001f, 4) == -1.99999999f); + assert(remainderf(1.99999999f, 4) == -2.00000001f); + + float x = __VERIFIER_nondet_float(); + float y = __VERIFIER_nondet_float(); + + if (!__isnanf(y)) { + assert(__isnanf(remainderf(Inf, y))); + assert(__isnanf(remainderf(negInf, y))); + } + + if (!__isnanf(x)) { + assert(__isnanf(remainderf(x, 0.0f))); + assert(__isnanf(remainderf(x, -0.0f))); + } + + assert(__isnanf(remainderf(NaN, y))); + assert(__isnanf(remainderf(x, NaN))); + + return 0; +} diff --git a/test/mathc/remainderl.c b/test/mathc/remainderl.c new file mode 100644 index 000000000..7f2a20d5a --- /dev/null +++ b/test/mathc/remainderl.c @@ -0,0 +1,32 @@ +#include "smack.h" +#include + +// @expect verified + +int main(void) { + long double NaN = 0.0l / 0.0l; + long double Inf = 1.0l / 0.0l; + long double negInf = -1.0l / 0.0l; + + assert(remainderl(2.0l, 4.0l) == 2); + assert(remainderl(2.00000001l, 4) == -1.99999999l); + assert(remainderl(1.99999999l, 4) == 1.99999999l); + + long double x = __VERIFIER_nondet_long_double(); + long double y = __VERIFIER_nondet_long_double(); + + if (!__isnanl(y)) { + assert(__isnanl(remainderl(Inf, y))); + assert(__isnanl(remainderl(negInf, y))); + } + + if (!__isnanl(x)) { + assert(__isnanl(remainderl(x, 0.0l))); + assert(__isnanl(remainderl(x, -0.0l))); + } + + assert(__isnanl(remainderl(NaN, y))); + assert(__isnanl(remainderl(x, NaN))); + + return 0; +} diff --git a/test/mathc/remainderl_fail.c b/test/mathc/remainderl_fail.c new file mode 100644 index 000000000..6c5c4ba6e --- /dev/null +++ b/test/mathc/remainderl_fail.c @@ -0,0 +1,32 @@ +#include "smack.h" +#include + +// @expect error + +int main(void) { + long double NaN = 0.0l / 0.0l; + long double Inf = 1.0l / 0.0l; + long double negInf = -1.0l / 0.0l; + + assert(remainderl(2.0l, 4.0l) == 2); + assert(remainderl(2.00000001l, 4) == -1.99999999l); + assert(remainderl(1.99999999l, 4) == -2.00000001l); + + long double x = __VERIFIER_nondet_long_double(); + long double y = __VERIFIER_nondet_long_double(); + + if (!__isnanl(y)) { + assert(__isnanl(remainderl(Inf, y))); + assert(__isnanl(remainderl(negInf, y))); + } + + if (!__isnanl(x)) { + assert(__isnanl(remainderl(x, 0.0l))); + assert(__isnanl(remainderl(x, -0.0l))); + } + + assert(__isnanl(remainderl(NaN, y))); + assert(__isnanl(remainderl(x, NaN))); + + return 0; +} diff --git a/test/mathc/rint.c b/test/mathc/rint.c new file mode 100644 index 000000000..2534e8f58 --- /dev/null +++ b/test/mathc/rint.c @@ -0,0 +1,54 @@ +#include "smack.h" +#include +#include + +// @expect verified +// @flag --bit-precise + +int main(void) { + double NaN = 0.0 / 0.0; + double Inf = 1.0 / 0.0; + double negInf = -1.0 / 0.0; + + double a = -4.5; + double b = -4.4999999999; + double c = -4.5000000001; + double d = 5.3; + + fesetround(FE_TONEAREST); + assert(rint(a) == -4.0); + assert(rint(b) == -4.0); + assert(rint(c) == -5.0); + assert(rint(d) == 5.0); + + fesetround(FE_UPWARD); + assert(rint(a) == -4.0); + assert(rint(b) == -4.0); + assert(rint(c) == -4.0); + assert(rint(d) == 6.0); + + fesetround(FE_DOWNWARD); + assert(rint(a) == -5.0); + assert(rint(b) == -5.0); + assert(rint(c) == -5.0); + assert(rint(d) == 5.0); + + fesetround(FE_TOWARDZERO); + assert(rint(a) == -4.0); + assert(rint(b) == -4.0); + assert(rint(c) == -4.0); + assert(rint(d) == 5.0); + + assert(rint(0.0) == 0.0); + assert(rint(-0.0) == -0.0); + int isNeg = __signbit(rint(-0.0)); + assert(isNeg); + + assert(rint(Inf) == Inf); + assert(rint(negInf) == negInf); + + assert(__isnan(rint(NaN))); + + return 0; +} + diff --git a/test/mathc/rint_fail.c b/test/mathc/rint_fail.c new file mode 100644 index 000000000..d5ab4e936 --- /dev/null +++ b/test/mathc/rint_fail.c @@ -0,0 +1,54 @@ +#include "smack.h" +#include +#include + +// @expect error +// @flag --bit-precise + +int main(void) { + double NaN = 0.0 / 0.0; + double Inf = 1.0 / 0.0; + double negInf = -1.0 / 0.0; + + double a = -4.5; + double b = -4.4999999999; + double c = -4.5000000001; + double d = 5.3; + + fesetround(FE_TONEAREST); + assert(rint(a) == 4.0); + assert(rint(b) == -4.0); + assert(rint(c) == -5.0); + assert(rint(d) == 5.0); + + fesetround(FE_UPWARD); + assert(rint(a) == -4.0); + assert(rint(b) == -4.0); + assert(rint(c) == -4.0); + assert(rint(d) == 6.0); + + fesetround(FE_DOWNWARD); + assert(rint(a) == -5.0); + assert(rint(b) == -5.0); + assert(rint(c) == -5.0); + assert(rint(d) == 5.0); + + fesetround(FE_TOWARDZERO); + assert(rint(a) == -4.0); + assert(rint(b) == -4.0); + assert(rint(c) == -4.0); + assert(rint(d) == 5.0); + + assert(rint(0.0) == 0.0); + assert(rint(-0.0) == -0.0); + int isNeg = __signbit(rint(-0.0)); + assert(isNeg); + + assert(rint(Inf) == Inf); + assert(rint(negInf) == negInf); + + assert(__isnan(rint(NaN))); + + return 0; +} + diff --git a/test/mathc/rintf.c b/test/mathc/rintf.c new file mode 100644 index 000000000..81185d377 --- /dev/null +++ b/test/mathc/rintf.c @@ -0,0 +1,54 @@ +#include "smack.h" +#include +#include + +// @expect verified +// @flag --bit-precise + +int main(void) { + float NaN = 0.0f / 0.0f; + float Inf = 1.0f / 0.0f; + float negInf = -1.0f / 0.0f; + + float a = -4.5f; + float b = -4.4999999999f; + float c = -4.5000000001f; + float d = 5.3f; + + fesetround(FE_TONEAREST); + assert(rintf(a) == -4.0f); + assert(rintf(b) == -4.0f); + assert(rintf(c) == -5.0f); + assert(rintf(d) == 5.0f); + + fesetround(FE_UPWARD); + assert(rintf(a) == -4.0f); + assert(rintf(b) == -4.0f); + assert(rintf(c) == -4.0f); + assert(rintf(d) == 6.0f); + + fesetround(FE_DOWNWARD); + assert(rintf(a) == -5.0f); + assert(rintf(b) == -5.0f); + assert(rintf(c) == -5.0f); + assert(rintf(d) == 5.0f); + + fesetround(FE_TOWARDZERO); + assert(rintf(a) == -4.0f); + assert(rintf(b) == -4.0f); + assert(rintf(c) == -4.0f); + assert(rintf(d) == 5.0f); + + assert(rintf(0.0f) == 0.0f); + assert(rintf(-0.0f) == -0.0f); + int isNeg = __signbitf(rintf(-0.0f)); + assert(isNeg); + + assert(rintf(Inf) == Inf); + assert(rintf(negInf) == negInf); + + assert(__isnanf(rintf(NaN))); + + return 0; +} + diff --git a/test/mathc/rintf_fail.c b/test/mathc/rintf_fail.c new file mode 100644 index 000000000..7fe99fd4e --- /dev/null +++ b/test/mathc/rintf_fail.c @@ -0,0 +1,54 @@ +#include "smack.h" +#include +#include + +// @expect error +// @flag --bit-precise + +int main(void) { + float NaN = 0.0f / 0.0f; + float Inf = 1.0f / 0.0f; + float negInf = -1.0f / 0.0f; + + float a = -4.5f; + float b = -4.4999999999f; + float c = -4.5000000001f; + float d = 5.3f; + + fesetround(FE_TONEAREST); + assert(rintf(a) == -4.0f); + assert(rintf(b) == -4.0f); + assert(rintf(c) == -5.0f); + assert(rintf(d) == 5.0f); + + fesetround(FE_UPWARD); + assert(rintf(a) == -4.0f); + assert(rintf(b) == -3.0f); + assert(rintf(c) == -4.0f); + assert(rintf(d) == 6.0f); + + fesetround(FE_DOWNWARD); + assert(rintf(a) == -5.0f); + assert(rintf(b) == -5.0f); + assert(rintf(c) == -5.0f); + assert(rintf(d) == 5.0f); + + fesetround(FE_TOWARDZERO); + assert(rintf(a) == -4.0f); + assert(rintf(b) == -4.0f); + assert(rintf(c) == -4.0f); + assert(rintf(d) == 5.0f); + + assert(rintf(0.0f) == 0.0f); + assert(rintf(-0.0f) == -0.0f); + int isNeg = __signbitf(rintf(-0.0f)); + assert(isNeg); + + assert(rintf(Inf) == Inf); + assert(rintf(negInf) == negInf); + + assert(__isnanf(rintf(NaN))); + + return 0; +} + diff --git a/test/mathc/rintl.c b/test/mathc/rintl.c new file mode 100644 index 000000000..870b853cf --- /dev/null +++ b/test/mathc/rintl.c @@ -0,0 +1,53 @@ +#include "smack.h" +#include +#include + +// @expect verified + +int main(void) { + long double NaN = 0.0l / 0.0l; + long double Inf = 1.0l / 0.0l; + long double negInf = -1.0l / 0.0l; + + long double a = -4.5l; + long double b = -4.4999999999l; + long double c = -4.5000000001l; + long double d = 5.3l; + + fesetround(FE_TONEAREST); + assert(rintl(a) == -4.0l); + assert(rintl(b) == -4.0l); + assert(rintl(c) == -5.0l); + assert(rintl(d) == 5.0l); + + fesetround(FE_UPWARD); + assert(rintl(a) == -4.0l); + assert(rintl(b) == -4.0l); + assert(rintl(c) == -4.0l); + assert(rintl(d) == 6.0l); + + fesetround(FE_DOWNWARD); + assert(rintl(a) == -5.0l); + assert(rintl(b) == -5.0l); + assert(rintl(c) == -5.0l); + assert(rintl(d) == 5.0l); + + fesetround(FE_TOWARDZERO); + assert(rintl(a) == -4.0l); + assert(rintl(b) == -4.0l); + assert(rintl(c) == -4.0l); + assert(rintl(d) == 5.0l); + + assert(rintl(0.0l) == 0.0l); + assert(rintl(-0.0l) == -0.0l); + int isNeg = __signbitl(rintl(-0.0l)); + assert(isNeg); + + assert(rintl(Inf) == Inf); + assert(rintl(negInf) == negInf); + + assert(__isnanl(rintl(NaN))); + + return 0; +} + diff --git a/test/mathc/rintl_fail.c b/test/mathc/rintl_fail.c new file mode 100644 index 000000000..1004ac4bd --- /dev/null +++ b/test/mathc/rintl_fail.c @@ -0,0 +1,53 @@ +#include "smack.h" +#include +#include + +// @expect error + +int main(void) { + long double NaN = 0.0l / 0.0l; + long double Inf = 1.0l / 0.0l; + long double negInf = -1.0l / 0.0l; + + long double a = -4.5l; + long double b = -4.4999999999l; + long double c = -4.5000000001l; + long double d = 5.3l; + + fesetround(FE_TONEAREST); + assert(rintl(a) == -4.0l); + assert(rintl(b) == -4.0l); + assert(rintl(c) == -5.0l); + assert(rintl(d) == 5.0l); + + fesetround(FE_UPWARD); + assert(rintl(a) == -4.0l); + assert(rintl(b) == -3.0l); + assert(rintl(c) == -4.0l); + assert(rintl(d) == 6.0l); + + fesetround(FE_DOWNWARD); + assert(rintl(a) == -5.0l); + assert(rintl(b) == -5.0l); + assert(rintl(c) == -5.0l); + assert(rintl(d) == 5.0l); + + fesetround(FE_TOWARDZERO); + assert(rintl(a) == -4.0l); + assert(rintl(b) == -4.0l); + assert(rintl(c) == -4.0l); + assert(rintl(d) == 5.0l); + + assert(rintl(0.0l) == 0.0l); + assert(rintl(-0.0l) == -0.0l); + int isNeg = __signbitl(rintl(-0.0l)); + assert(isNeg); + + assert(rintl(Inf) == Inf); + assert(rintl(negInf) == negInf); + + assert(__isnanl(rintl(NaN))); + + return 0; +} + diff --git a/test/mathc/round.c b/test/mathc/round.c new file mode 100644 index 000000000..6753e050b --- /dev/null +++ b/test/mathc/round.c @@ -0,0 +1,31 @@ +#include "smack.h" +#include + +// @expect verified +// @flag --bit-precise + +int main(void) { + double NaN = 0.0 / 0.0; + double Inf = 1.0 / 0.0; + double negInf = -1.0 / 0.0; + + double val = __VERIFIER_nondet_double(); + + if (!__isnan(val) && !__isinf(val) && !__iszero(val)) { + double rval = round(val); + assert(rval == floor(val) || rval == ceil(val)); + } + + assert(round(0.0) == 0.0); + assert(round(-0.0) == -0.0); + int isNeg = __signbit(round(-0.0)); + assert(isNeg); + + assert(round(Inf) == Inf); + assert(round(negInf) == negInf); + + assert(__isnan(round(NaN))); + + return 0; +} + diff --git a/test/mathc/round_fail.c b/test/mathc/round_fail.c new file mode 100644 index 000000000..aaad7f85a --- /dev/null +++ b/test/mathc/round_fail.c @@ -0,0 +1,31 @@ +#include "smack.h" +#include + +// @expect error +// @flag --bit-precise + +int main(void) { + double NaN = 0.0 / 0.0; + double Inf = 1.0 / 0.0; + double negInf = -1.0 / 0.0; + + double val = __VERIFIER_nondet_double(); + + if (!__isnan(val) && !__isinf(val) && !__iszero(val)) { + double rval = round(val); + assert(rval == floor(val) || rval == ceil(val)); + } + + assert(round(0.0) < 0.0); + assert(round(-0.0) == -0.0); + int isNeg = __signbit(round(-0.0)); + assert(isNeg); + + assert(round(Inf) == Inf); + assert(round(negInf) == negInf); + + assert(__isnan(round(NaN))); + + return 0; +} + diff --git a/test/mathc/roundf.c b/test/mathc/roundf.c new file mode 100644 index 000000000..5e427c4fe --- /dev/null +++ b/test/mathc/roundf.c @@ -0,0 +1,31 @@ +#include "smack.h" +#include + +// @expect verified +// @flag --bit-precise + +int main(void) { + float NaN = 0.0f / 0.0f; + float Inf = 1.0f / 0.0f; + float negInf = -1.0f / 0.0f; + + float val = __VERIFIER_nondet_float(); + + if (!__isnanf(val) && !__isinff(val) && !__iszerof(val)) { + float rval = roundf(val); + assert(rval == floorf(val) || rval == ceilf(val)); + } + + assert(roundf(0.0f) == 0.0f); + assert(roundf(-0.0f) == -0.0f); + int isNeg = __signbitf(roundf(-0.0f)); + assert(isNeg); + + assert(roundf(Inf) == Inf); + assert(roundf(negInf) == negInf); + + assert(__isnanf(roundf(NaN))); + + return 0; +} + diff --git a/test/mathc/roundf_fail.c b/test/mathc/roundf_fail.c new file mode 100644 index 000000000..7fa86de5b --- /dev/null +++ b/test/mathc/roundf_fail.c @@ -0,0 +1,31 @@ +#include "smack.h" +#include + +// @expect error +// @flag --bit-precise + +int main(void) { + float NaN = 0.0f / 0.0f; + float Inf = 1.0f / 0.0f; + float negInf = -1.0f / 0.0f; + + float val = __VERIFIER_nondet_float(); + + if (!__isnanf(val) && !__isinff(val) && !__iszerof(val)) { + float rval = roundf(val); + assert(rval == floorf(val) || rval == ceilf(val)); + } + + assert(roundf(0.0f) == 0.0f); + assert(roundf(-0.0f) > -0.0f); + int isNeg = __signbitf(roundf(-0.0f)); + assert(isNeg); + + assert(roundf(Inf) == Inf); + assert(roundf(negInf) == negInf); + + assert(__isnanf(roundf(NaN))); + + return 0; +} + diff --git a/test/mathc/roundl.c b/test/mathc/roundl.c new file mode 100644 index 000000000..038d65b64 --- /dev/null +++ b/test/mathc/roundl.c @@ -0,0 +1,30 @@ +#include "smack.h" +#include + +// @expect verified + +int main(void) { + long double NaN = 0.0l / 0.0l; + long double Inf = 1.0l / 0.0l; + long double negInf = -1.0l / 0.0l; + + long double val = __VERIFIER_nondet_long_double(); + + if (!__isnanl(val) && !__isinfl(val) && !__iszerol(val)) { + long double rval = roundl(val); + assert(rval == floorl(val) || rval == ceill(val)); + } + + assert(roundl(0.0l) == 0.0l); + assert(roundl(-0.0l) == -0.0l); + int isNeg = __signbitl(roundl(-0.0l)); + assert(isNeg); + + assert(roundl(Inf) == Inf); + assert(roundl(negInf) == negInf); + + assert(__isnanl(roundl(NaN))); + + return 0; +} + diff --git a/test/mathc/roundl_fail.c b/test/mathc/roundl_fail.c new file mode 100644 index 000000000..06172174c --- /dev/null +++ b/test/mathc/roundl_fail.c @@ -0,0 +1,30 @@ +#include "smack.h" +#include + +// @expect error + +int main(void) { + long double NaN = 0.0l / 0.0l; + long double Inf = 1.0l / 0.0l; + long double negInf = -1.0l / 0.0l; + + long double val = __VERIFIER_nondet_long_double(); + + if (!__isnanl(val) && !__isinfl(val) && !__iszerol(val)) { + long double rval = roundl(val); + assert(rval == floorl(val) || rval == ceill(val)); + } + + assert(roundl(0.0l) == 0.0l); + assert(roundl(-0.0l) > -0.0l); + int isNeg = __signbitl(roundl(-0.0l)); + assert(isNeg); + + assert(roundl(Inf) == Inf); + assert(roundl(negInf) == negInf); + + assert(__isnanl(roundl(NaN))); + + return 0; +} + diff --git a/test/mathc/sqrt.c b/test/mathc/sqrt.c new file mode 100644 index 000000000..89d3a81e8 --- /dev/null +++ b/test/mathc/sqrt.c @@ -0,0 +1,30 @@ +#include "smack.h" +#include + +// @expect verified +// @flag --bit-precise + +int main(void) { + double NaN = 0.0 / 0.0; + double Inf = 1.0 / 0.0; + double negInf = -1.0 / 0.0; + + double a = 4.0; + double b = 4.0 / 9.0; + double c = -1.0; + assert(fabs(2.0 - sqrt(a)) < 1e-8); + assert(fabs(2.0 / 3.0 - sqrt(b)) < 1e-8); + assert(__isnan(sqrt(c))); + + assert(sqrt(0.0) == 0.0); + assert(sqrt(-0.0) == -0.0); + int isNeg = __signbit(sqrt(-0.0)); + assert(isNeg); + + assert(sqrt(Inf) == Inf); + assert(__isnan(sqrt(negInf))); + + assert(__isnan(sqrt(NaN))); + + return 0; +} diff --git a/test/mathc/sqrt_fail.c b/test/mathc/sqrt_fail.c new file mode 100644 index 000000000..4cb46720b --- /dev/null +++ b/test/mathc/sqrt_fail.c @@ -0,0 +1,30 @@ +#include "smack.h" +#include + +// @expect error +// @flag --bit-precise + +int main(void) { + double NaN = 0.0 / 0.0; + double Inf = 1.0 / 0.0; + double negInf = -1.0 / 0.0; + + double a = 4.0; + double b = 4.0 / 9.0; + double c = -1.0; + assert(fabs(2.0 - sqrt(a)) < 1e-8); + assert(fabs(2.0 / 3.0 - sqrt(b)) < 1e-8); + assert(!__isnan(sqrt(c))); + + assert(sqrt(0.0) == 0.0); + assert(sqrt(-0.0) == -0.0); + int isNeg = __signbit(sqrt(-0.0)); + assert(isNeg); + + assert(sqrt(Inf) == Inf); + assert(__isnan(sqrt(negInf))); + + assert(__isnan(sqrt(NaN))); + + return 0; +} diff --git a/test/mathc/sqrtf.c b/test/mathc/sqrtf.c new file mode 100644 index 000000000..7b2f01d96 --- /dev/null +++ b/test/mathc/sqrtf.c @@ -0,0 +1,30 @@ +#include "smack.h" +#include + +// @expect verified +// @flag --bit-precise + +int main(void) { + float NaN = 0.0f / 0.0f; + float Inf = 1.0f / 0.0f; + float negInf = -1.0f / 0.0f; + + float a = 4.0f; + float b = 4.0f / 9.0f; + float c = -1.0f; + assert(fabsf(2.0f - sqrtf(a)) < 1e-8); + assert(fabsf(2.0f / 3.0f - sqrtf(b)) < 1e-8); + assert(__isnanf(sqrtf(c))); + + assert(sqrtf(0.0f) == 0.0f); + assert(sqrtf(-0.0f) == -0.0f); + int isNeg = __signbitf(sqrtf(-0.0f)); + assert(isNeg); + + assert(sqrtf(Inf) == Inf); + assert(__isnanf(sqrtf(negInf))); + + assert(__isnanf(sqrtf(NaN))); + + return 0; +} diff --git a/test/mathc/sqrtf_fail.c b/test/mathc/sqrtf_fail.c new file mode 100644 index 000000000..17c6c7700 --- /dev/null +++ b/test/mathc/sqrtf_fail.c @@ -0,0 +1,30 @@ +#include "smack.h" +#include + +// @expect error +// @flag --bit-precise + +int main(void) { + float NaN = 0.0f / 0.0f; + float Inf = 1.0f / 0.0f; + float negInf = -1.0f / 0.0f; + + float a = 4.0f; + float b = 4.0f / 9.0f; + float c = -1.0f; + assert(fabsf(2.0f - sqrtf(a)) < 1e-8); + assert(fabsf(2.0f / 3.0f - sqrtf(b)) < 1e-8); + assert(__isnanf(sqrtf(c))); + + assert(sqrtf(0.0f) == 0.0f); + assert(sqrtf(-0.0f) == -0.0f); + int isNeg = __signbitf(sqrtf(-0.0f)); + assert(!isNeg); + + assert(sqrtf(Inf) == Inf); + assert(__isnanf(sqrtf(negInf))); + + assert(__isnanf(sqrtf(NaN))); + + return 0; +} diff --git a/test/mathc/sqrtl.c b/test/mathc/sqrtl.c new file mode 100644 index 000000000..d90dd226d --- /dev/null +++ b/test/mathc/sqrtl.c @@ -0,0 +1,29 @@ +#include "smack.h" +#include + +// @expect verified + +int main(void) { + long double NaN = 0.0l / 0.0l; + long double Inf = 1.0l / 0.0l; + long double negInf = -1.0l / 0.0l; + + long double a = 4.0l; + long double b = 4.0l / 9.0l; + long double c = -1.0l; + assert(fabsl(2.0l - sqrtl(a)) < 1e-8); + assert(fabsl(2.0l / 3.0l - sqrtl(b)) < 1e-8); + assert(__isnanl(sqrtl(c))); + + assert(sqrtl(0.0l) == 0.0l); + assert(sqrtl(-0.0l) == -0.0l); + int isNeg = __signbitl(sqrtl(-0.0l)); + assert(isNeg); + + assert(sqrtl(Inf) == Inf); + assert(__isnanl(sqrtl(negInf))); + + assert(__isnanl(sqrtl(NaN))); + + return 0; +} diff --git a/test/mathc/sqrtl_fail.c b/test/mathc/sqrtl_fail.c new file mode 100644 index 000000000..444d331b3 --- /dev/null +++ b/test/mathc/sqrtl_fail.c @@ -0,0 +1,29 @@ +#include "smack.h" +#include + +// @expect error + +int main(void) { + long double NaN = 0.0l / 0.0l; + long double Inf = 1.0l / 0.0l; + long double negInf = -1.0l / 0.0l; + + long double a = 4.0l; + long double b = 4.0l / 9.0l; + long double c = -1.0l; + assert(fabsl(2.0l - sqrtl(a)) < 1e-8); + assert(fabsl(2.0l / 3.0l - sqrtl(b)) < 1e-8); + assert(__isnanl(sqrtl(c))); + + assert(sqrtl(0.0l) == 0.0l); + assert(sqrtl(-0.0l) == -0.0l); + int isNeg = __signbitl(sqrtl(-0.0l)); + assert(!isNeg); + + assert(sqrtl(Inf) == Inf); + assert(__isnanl(sqrtl(negInf))); + + assert(__isnanl(sqrtl(NaN))); + + return 0; +} diff --git a/test/mathc/trunc.c b/test/mathc/trunc.c new file mode 100644 index 000000000..394270e1c --- /dev/null +++ b/test/mathc/trunc.c @@ -0,0 +1,34 @@ +#include "smack.h" +#include + +// @expect verified +// @flag --bit-precise + +int main(void) { + double NaN = 0.0 / 0.0; + double Inf = 1.0 / 0.0; + double negInf = -1.0 / 0.0; + + double val = __VERIFIER_nondet_double(); + + if (!__isnan(val) && !__isinf(val) && !__iszero(val)) { + if (val > 0) { + assert(trunc(val) <= val); + } else { + assert(trunc(val) >= val); + } + } + + assert(trunc(0.0) == 0.0); + assert(trunc(-0.0) == -0.0); + int isNeg = __signbit(trunc(-0.0)); + assert(isNeg); + + assert(trunc(Inf) == Inf); + assert(trunc(negInf) == negInf); + + assert(__isnan(trunc(NaN))); + + return 0; +} + diff --git a/test/mathc/trunc_fail.c b/test/mathc/trunc_fail.c new file mode 100644 index 000000000..b9ea11a25 --- /dev/null +++ b/test/mathc/trunc_fail.c @@ -0,0 +1,34 @@ +#include "smack.h" +#include + +// @expect error +// @flag --bit-precise + +int main(void) { + double NaN = 0.0 / 0.0; + double Inf = 1.0 / 0.0; + double negInf = -1.0 / 0.0; + + double val = __VERIFIER_nondet_double(); + + if (!__isnan(val) && !__isinf(val) && !__iszero(val)) { + if (val > 0) { + assert(trunc(val) <= val); + } else { + assert(trunc(val) >= val); + } + } + + assert(trunc(0.0) == 0.0); + assert(trunc(-0.0) == -0.0); + int isNeg = __signbit(trunc(-0.0)); + assert(isNeg); + + assert(trunc(Inf) == Inf); + assert(trunc(negInf) != negInf); + + assert(__isnan(trunc(NaN))); + + return 0; +} + diff --git a/test/mathc/truncf.c b/test/mathc/truncf.c new file mode 100644 index 000000000..ffec69511 --- /dev/null +++ b/test/mathc/truncf.c @@ -0,0 +1,34 @@ +#include "smack.h" +#include + +// @expect verified +// @flag --bit-precise + +int main(void) { + float NaN = 0.0f / 0.0f; + float Inf = 1.0f / 0.0f; + float negInf = -1.0f / 0.0f; + + float val = __VERIFIER_nondet_float(); + + if (!__isnanf(val) && !__isinff(val) && !__iszerof(val)) { + if (val > 0) { + assert(truncf(val) <= val); + } else { + assert(truncf(val) >= val); + } + } + + assert(truncf(0.0f) == 0.0f); + assert(truncf(-0.0f) == -0.0f); + int isNeg = __signbitf(truncf(-0.0f)); + assert(isNeg); + + assert(truncf(Inf) == Inf); + assert(truncf(negInf) == negInf); + + assert(__isnanf(truncf(NaN))); + + return 0; +} + diff --git a/test/mathc/truncf_fail.c b/test/mathc/truncf_fail.c new file mode 100644 index 000000000..d88bcf975 --- /dev/null +++ b/test/mathc/truncf_fail.c @@ -0,0 +1,34 @@ +#include "smack.h" +#include + +// @expect error +// @flag --bit-precise + +int main(void) { + float NaN = 0.0f / 0.0f; + float Inf = 1.0f / 0.0f; + float negInf = -1.0f / 0.0f; + + float val = __VERIFIER_nondet_float(); + + if (!__isnanf(val) && !__isinff(val) && !__iszerof(val)) { + if (val > 0) { + assert(truncf(val) <= val); + } else { + assert(truncf(val) >= val); + } + } + + assert(truncf(0.0f) == 0.0f); + assert(truncf(-0.0f) == -0.0f); + int isNeg = __signbitf(truncf(-0.0f)); + assert(isNeg); + + assert(truncf(Inf) == Inf); + assert(truncf(negInf) == negInf); + + assert(!__isnanf(truncf(NaN))); + + return 0; +} + diff --git a/test/mathc/truncl.c b/test/mathc/truncl.c new file mode 100644 index 000000000..0f80c1f6f --- /dev/null +++ b/test/mathc/truncl.c @@ -0,0 +1,33 @@ +#include "smack.h" +#include + +// @expect verified + +int main(void) { + long double NaN = 0.0l / 0.0l; + long double Inf = 1.0l / 0.0l; + long double negInf = -1.0l / 0.0l; + + long double val = __VERIFIER_nondet_long_double(); + + if (!__isnanl(val) && !__isinfl(val) && !__iszerol(val)) { + if (val > 0) { + assert(truncl(val) <= val); + } else { + assert(truncl(val) >= val); + } + } + + assert(truncl(0.0l) == 0.0l); + assert(truncl(-0.0l) == -0.0l); + int isNeg = __signbitl(truncl(-0.0l)); + assert(isNeg); + + assert(truncl(Inf) == Inf); + assert(truncl(negInf) == negInf); + + assert(__isnanl(truncl(NaN))); + + return 0; +} + diff --git a/test/mathc/truncl_fail.c b/test/mathc/truncl_fail.c new file mode 100644 index 000000000..82460dbc9 --- /dev/null +++ b/test/mathc/truncl_fail.c @@ -0,0 +1,33 @@ +#include "smack.h" +#include + +// @expect error + +int main(void) { + long double NaN = 0.0l / 0.0l; + long double Inf = 1.0l / 0.0l; + long double negInf = -1.0l / 0.0l; + + long double val = __VERIFIER_nondet_long_double(); + + if (!__isnanl(val) && !__isinfl(val) && !__iszerol(val)) { + if (val > 0) { + assert(truncl(val) <= val); + } else { + assert(truncl(val) >= val); + } + } + + assert(truncl(0.0l) == 0.0l); + assert(truncl(-0.0l) == -0.0l); + int isNeg = __signbitl(truncl(-0.0l)); + assert(isNeg); + + assert(truncl(Inf) == Inf); + assert(truncl(negInf) == negInf); + + assert(!__isnanl(truncl(NaN))); + + return 0; +} + diff --git a/test/pthread/cond.c b/test/pthread/cond.c index 5c463acd5..2e0f73d77 100644 --- a/test/pthread/cond.c +++ b/test/pthread/cond.c @@ -1,11 +1,11 @@ +#include +#include + // Generally tests pthread_cond_wait, pthread_cond_signal, // pthread_cond_init // @expect verified -#include -#include - pthread_cond_t cond; pthread_mutex_t lock; int thread1Done = 0; @@ -18,18 +18,20 @@ void *j1(void *arg) { pthread_cond_signal(&cond); pthread_mutex_unlock(&lock); pthread_exit(0); + return 0; } void *j2(void *arg) { pthread_mutex_lock(&lock); while(!thread1Done) pthread_cond_wait(&cond, &lock); - assert(count==1); + assert(count == 1); pthread_mutex_unlock(&lock); pthread_exit(0); + return 0; } -int main() { +int main(void) { pthread_t t1, t2; pthread_cond_init(&cond, 0); pthread_mutex_init(&lock, 0); @@ -40,3 +42,4 @@ int main() { pthread_join(t2, 0); return 0; } + diff --git a/test/pthread/cond_fail.c b/test/pthread/cond_fail.c index 40b974d72..ca5c82941 100644 --- a/test/pthread/cond_fail.c +++ b/test/pthread/cond_fail.c @@ -1,11 +1,11 @@ +#include +#include + // Generally tests pthread_cond_wait, pthread_cond_signal, // pthread_cond_init // @expect error -#include -#include - pthread_cond_t cond; pthread_mutex_t lock; int thread1Done = 0; @@ -18,18 +18,19 @@ void *j1(void *arg) { pthread_cond_signal(&cond); pthread_mutex_unlock(&lock); pthread_exit(0); + return 0; } void *j2(void *arg) { pthread_mutex_lock(&lock); - //while(!thread1Done) - pthread_cond_wait(&cond, &lock); - assert(count==1); + pthread_cond_wait(&cond, &lock); + assert(count == 1); pthread_mutex_unlock(&lock); pthread_exit(0); + return 0; } -int main() { +int main(void) { pthread_t t1, t2; pthread_cond_init(&cond, 0); pthread_mutex_init(&lock, 0); @@ -40,3 +41,4 @@ int main() { pthread_join(t2, 0); return 0; } + diff --git a/test/pthread/equal.c b/test/pthread/equal.c index a4ffeb5ca..159f23884 100644 --- a/test/pthread/equal.c +++ b/test/pthread/equal.c @@ -1,17 +1,20 @@ -// Tests pthread_equal() -// @expect verified - #include #include +// Tests pthread_equal() +// @expect verified + pthread_t worker; void *t1(void *arg){ - __VERIFIER_assert(pthread_equal(pthread_self(),worker)); + assert(pthread_equal(pthread_self(),worker)); + return 0; } -int main() { +int main(void) { pthread_create(&worker,0,0,0); pthread_join(worker,0); - __VERIFIER_assert(!pthread_equal(pthread_self(),worker)); + assert(!pthread_equal(pthread_self(),worker)); + return 0; } + diff --git a/test/pthread/equal2.c b/test/pthread/equal2.c index d983a4131..c93aaf8e2 100644 --- a/test/pthread/equal2.c +++ b/test/pthread/equal2.c @@ -1,8 +1,9 @@ -// Tests pthread_equal() -// @expect verified #include #include +// Tests pthread_equal() +// @expect verified + pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; pthread_t aggregator; @@ -16,9 +17,10 @@ void *t1(void *arg) { x++; pthread_mutex_unlock(&lock); } + return 0; } -int main() { +int main(void) { pthread_t tid1, tid2; pthread_create(&aggregator, 0, t1, 0); @@ -32,3 +34,4 @@ int main() { pthread_join(tid2, 0); assert(x == 4); } + diff --git a/test/pthread/join.c b/test/pthread/join.c index cb267f6b8..e3f039333 100644 --- a/test/pthread/join.c +++ b/test/pthread/join.c @@ -1,19 +1,18 @@ -// Shows pthread_join effectively blocks until child thread done - -// @expect verified - #include #include +// Shows pthread_join effectively blocks until child thread done +// @expect verified + int x = 1; void *t1(void *arg) { x++; pthread_exit(0); + return 0; } -int main() { - +int main(void) { pthread_t t; pthread_create(&t, 0, t1, 0); @@ -22,3 +21,4 @@ int main() { assert(x == 3); return 0; } + diff --git a/test/pthread/join_fail.c b/test/pthread/join_fail.c index d37eed867..abc1bc751 100644 --- a/test/pthread/join_fail.c +++ b/test/pthread/join_fail.c @@ -1,19 +1,18 @@ -// Shows join.c fails when parent doesn't wait for child before x++ call - -// @expect error - #include #include +// Shows join.c fails when parent doesn't wait for child before x++ call +// @expect error + int x = 1; void *t1(void *arg) { x++; pthread_exit(0); + return 0; } -int main() { - +int main(void) { pthread_t t; pthread_create(&t, 0, t1, 0); @@ -22,3 +21,4 @@ int main() { assert(x == 3); return 0; } + diff --git a/test/pthread/join_return.c b/test/pthread/join_return.c index cefff945f..e136b00d7 100644 --- a/test/pthread/join_return.c +++ b/test/pthread/join_return.c @@ -1,13 +1,13 @@ +#include +#include +#include + // Tests join & return in general - would fail if join doesn't block. // Also tests that exit and join successfully store/load a return value // and that return values work when pointers. // @expect verified -#include -#include -#include - int x = 1; typedef struct pair{ @@ -21,9 +21,10 @@ void *t1(void *arg) { retptr->x = 3; retptr->y = 4; pthread_exit(retptr); + return 0; } -int main() { +int main(void) { pthread_t t; pair* ret; @@ -35,3 +36,4 @@ int main() { free(ret); return 0; } + diff --git a/test/pthread/join_return2.c b/test/pthread/join_return2.c index bc0f8a1fb..7cf371778 100644 --- a/test/pthread/join_return2.c +++ b/test/pthread/join_return2.c @@ -1,28 +1,26 @@ +#include +#include + // Ensures return values from multiple threads can be // held simultaneously. - - // @expect verified -#include -#include - int x = 1; void *t1(void *arg) { x++; pthread_exit((void*)5); + return 0; } void *t2(void *arg) { x++; pthread_exit((void*)6); + return 0; } -int main() { - +int main(void) { pthread_t tid1, tid2; - int a; void *ret1, *ret2; @@ -34,3 +32,4 @@ int main() { assert((int)ret2 == 6); return 0; } + diff --git a/test/pthread/join_return2_fail.c b/test/pthread/join_return2_fail.c index d2d5437a6..8e28fcd6b 100644 --- a/test/pthread/join_return2_fail.c +++ b/test/pthread/join_return2_fail.c @@ -1,28 +1,26 @@ +#include +#include + // Ensures return values from multiple threads can be // held simultaneously. - - // @expect error -#include -#include - int x = 1; void *t1(void *arg) { x++; pthread_exit((void*)5); + return 0; } void *t2(void *arg) { x++; pthread_exit((void*)6); + return 0; } -int main() { - +int main(void) { pthread_t tid1, tid2; - int a; void *ret1, *ret2; @@ -34,3 +32,4 @@ int main() { assert((int)ret2 == (int)ret1); return 0; } + diff --git a/test/pthread/join_return_fail.c b/test/pthread/join_return_fail.c index ca559fa23..e6d7b4d0c 100644 --- a/test/pthread/join_return_fail.c +++ b/test/pthread/join_return_fail.c @@ -1,13 +1,13 @@ +#include +#include +#include + // Tests join & return in general - would fail if join doesn't block. // Also tests that exit and join successfully store/load a return value // and that return values work when pointers. // @expect error -#include -#include -#include - int x = 1; typedef struct pair{ @@ -21,9 +21,10 @@ void *t1(void *arg) { retptr->x = 2; retptr->y = 4; pthread_exit(&retptr); + return 0; } -int main() { +int main(void) { pthread_t t; pair* ret; @@ -35,3 +36,4 @@ int main() { free(ret); return 0; } + diff --git a/test/pthread/join_self.c b/test/pthread/join_self.c index dc7624bb5..51637a7a3 100644 --- a/test/pthread/join_self.c +++ b/test/pthread/join_self.c @@ -1,10 +1,9 @@ -// Tests deadlock detection when join on self - -// @expect verified - #include #include +// Tests deadlock detection when join on self +// @expect verified + pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; void* t1(void* arg) { @@ -14,16 +13,14 @@ void* t1(void* arg) { int err = pthread_join(self, (void*)&ret); // Should be an EDEADLK error assert(err == 35); - if(err != 35) - assert(0); - pthread_exit((void*)1); return 0; } -int main() { +int main(void) { pthread_t tid1 = __VERIFIER_nondet_int(); int ret; pthread_create(&tid1, 0, t1, &tid1); return 0; } + diff --git a/test/pthread/join_self_fail.c b/test/pthread/join_self_fail.c index f1c1deff3..016d70d39 100644 --- a/test/pthread/join_self_fail.c +++ b/test/pthread/join_self_fail.c @@ -1,10 +1,9 @@ -// Tests deadlock detection when join on self - -// @expect error - #include #include +// Tests deadlock detection when join on self +// @expect error + //////////////////////////////////////////////////////////////// // // Declare alternate functions for pthread_join(), @@ -36,14 +35,11 @@ void* t1(void* arg) { int err = pthread_join2(self, (void*)&ret); // Should be an EDEADLK error assert(err == 35); - if(err != 35) - assert(0); - pthread_exit((void*)1); return 0; } -int main() { +int main(void) { pthread_t tid1 = __VERIFIER_nondet_int(); int ret; pthread_create2(&tid1, 0, t1, &tid1); @@ -89,7 +85,7 @@ int pthread_join2(pthread_t __th, void **__thread_return) { __SMACK_code("assume $pthreadStatus[@][0] == $pthread_stopped;", __th); // Get the thread's return value - void* tmp_thread_return_pointer = (void*)__VERIFIER_nondet_long(); + void* tmp_thread_return_pointer = __VERIFIER_nondet_pointer(); __SMACK_code("@ := $pthreadStatus[@][1];", tmp_thread_return_pointer, __th); *__thread_return = tmp_thread_return_pointer; @@ -143,7 +139,3 @@ int pthread_create2(pthread_t *__restrict __newthread, return 0; } - - - - diff --git a/test/pthread/lock.c b/test/pthread/lock.c index b3d1239b8..3d7a996a5 100644 --- a/test/pthread/lock.c +++ b/test/pthread/lock.c @@ -1,10 +1,9 @@ -// Tests pthread_mutex_init() - -// @expect verified - #include #include +// Tests pthread_mutex_init() +// @expect verified + int z = 1; void *t1(void *arg) { @@ -12,10 +11,10 @@ void *t1(void *arg) { pthread_mutex_lock(lock); z++; pthread_mutex_unlock(lock); + return 0; } -int main() { - +int main(void) { pthread_mutex_t lock; pthread_mutex_init(&lock, 0); assert(lock.lock == UNLOCKED); @@ -29,4 +28,6 @@ int main() { pthread_mutex_unlock(&lock); pthread_join(tid1, 0); assert(z == 3); + return 0; } + diff --git a/test/pthread/lock2.c b/test/pthread/lock2.c index e27afaf35..f9b7851c3 100644 --- a/test/pthread/lock2.c +++ b/test/pthread/lock2.c @@ -1,10 +1,9 @@ -// Tests PTHREAD_MUTEX_INITIALIZER macro - -// @expect verified - #include #include +// Tests PTHREAD_MUTEX_INITIALIZER macro +// @expect verified + pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; int x = 1; @@ -13,10 +12,10 @@ void *t1(void *arg) { pthread_mutex_lock(&lock); x++; pthread_mutex_unlock(&lock); + return 0; } -int main() { - +int main(void) { pthread_t tid1, tid2; assert(lock.lock == UNLOCKED); assert(lock.init == INITIALIZED); @@ -29,4 +28,6 @@ int main() { pthread_join(tid1, 0); pthread_join(tid2, 0); assert(x == 4); + return 0; } + diff --git a/test/pthread/lock2_fail.c b/test/pthread/lock2_fail.c index f44948650..10ee05451 100644 --- a/test/pthread/lock2_fail.c +++ b/test/pthread/lock2_fail.c @@ -1,10 +1,9 @@ -// Tests failure when trying to acquire an owned lock - -// @expect error - #include #include +// Tests failure when trying to acquire an owned lock +// @expect error + pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; int x = 1; @@ -14,10 +13,10 @@ void *t1(void *arg) { pthread_mutex_lock(&lock); x++; pthread_mutex_unlock(&lock); + return 0; } -int main() { - +int main(void) { pthread_t tid1, tid2; pthread_create(&tid1, 0, t1, 0); @@ -28,4 +27,6 @@ int main() { pthread_join(tid1, 0); pthread_join(tid2, 0); assert(x == 4); + return 0; } + diff --git a/test/pthread/lock3.c b/test/pthread/lock3.c index cf809570d..c43694a8c 100644 --- a/test/pthread/lock3.c +++ b/test/pthread/lock3.c @@ -1,10 +1,9 @@ -// Tests with multiple threads - -// @expect verified - #include #include +// Tests with multiple threads +// @expect verified + pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; int x = 1; @@ -13,16 +12,17 @@ void *t1(void *arg) { pthread_mutex_lock(&lock); x++; pthread_mutex_unlock(&lock); + return 0; } void *t2(void *arg) { pthread_mutex_lock(&lock); x++; pthread_mutex_unlock(&lock); + return 0; } -int main() { - +int main(void) { pthread_t tid1, tid2; assert(lock.lock == UNLOCKED); assert(lock.init == INITIALIZED); @@ -35,4 +35,6 @@ int main() { pthread_join(tid1, 0); pthread_join(tid2, 0); assert(x == 4); + return 0; } + diff --git a/test/pthread/lock3_fail.c b/test/pthread/lock3_fail.c index 702b2703b..6d0c56306 100644 --- a/test/pthread/lock3_fail.c +++ b/test/pthread/lock3_fail.c @@ -1,10 +1,9 @@ -// Tests with multiple threads - -// @expect error - #include #include +// Tests with multiple threads +// @expect error + pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; int x = 1; @@ -13,14 +12,15 @@ void *t1(void *arg) { pthread_mutex_lock(&lock); x++; pthread_mutex_unlock(&lock); + return 0; } void *t2(void *arg) { x++; + return 0; } -int main() { - +int main(void) { pthread_t tid1, tid2; pthread_create(&tid1, 0, t1, 0); @@ -31,4 +31,6 @@ int main() { pthread_join(tid1, 0); pthread_join(tid2, 0); assert(x == 4); + return 0; } + diff --git a/test/pthread/lock4.c b/test/pthread/lock4.c index 22f040326..f5eab4aaa 100644 --- a/test/pthread/lock4.c +++ b/test/pthread/lock4.c @@ -1,10 +1,9 @@ -// Tests that using mutex fails after being destroyed - -// @expect verified - #include #include +// Tests that using mutex fails after being destroyed +// @expect verified + pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; int x = 1; @@ -13,10 +12,10 @@ void *t1(void *arg) { pthread_mutex_lock(&lock); x++; pthread_mutex_unlock(&lock); + return 0; } -int main() { - +int main(void) { pthread_t tid1; assert(lock.lock == UNLOCKED); assert(lock.init == INITIALIZED); @@ -27,4 +26,6 @@ int main() { pthread_mutex_unlock(&lock); pthread_join(tid1, 0); assert(x == 3); + return 0; } + diff --git a/test/pthread/lock4_fail.c b/test/pthread/lock4_fail.c index eba78b386..e30ffec73 100644 --- a/test/pthread/lock4_fail.c +++ b/test/pthread/lock4_fail.c @@ -1,10 +1,9 @@ -// Tests that using mutex fails after being destroyed - -// @expect error - #include #include +// Tests that using mutex fails after being destroyed +// @expect error + pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; int x = 1; @@ -13,10 +12,10 @@ void *t1(void *arg) { pthread_mutex_lock(&lock); x++; pthread_mutex_unlock(&lock); + return 0; } -int main() { - +int main(void) { pthread_t tid1; pthread_create(&tid1, 0, t1, 0); @@ -27,3 +26,4 @@ int main() { pthread_join(tid1, 0); assert(x == 3); } + diff --git a/test/pthread/lock5.c b/test/pthread/lock5.c index 0706f9514..9a3834a12 100644 --- a/test/pthread/lock5.c +++ b/test/pthread/lock5.c @@ -1,14 +1,14 @@ -// Tests that uninitialized mutex fails on use - -// @expect verified - #include #include -int main() { +// Tests that uninitialized mutex fails on use +// @expect verified + +int main(void) { pthread_mutex_t lock; pthread_mutex_init(&lock, 0); pthread_mutex_lock(&lock); pthread_mutex_unlock(&lock); return 0; } + diff --git a/test/pthread/lock5_fail.c b/test/pthread/lock5_fail.c index 313c1f79f..bc18dda54 100644 --- a/test/pthread/lock5_fail.c +++ b/test/pthread/lock5_fail.c @@ -1,13 +1,13 @@ -// Tests that uninitialized mutex fails on use - -// @expect error - #include #include -int main() { +// Tests that uninitialized mutex fails on use +// @expect error + +int main(void) { pthread_mutex_t lock; pthread_mutex_lock(&lock); pthread_mutex_unlock(&lock); return 0; } + diff --git a/test/pthread/lock_fail.c b/test/pthread/lock_fail.c index fc54488e7..46523b6ad 100644 --- a/test/pthread/lock_fail.c +++ b/test/pthread/lock_fail.c @@ -1,10 +1,9 @@ -// Tests failure on use of uninitialized mutex - -// @expect error - #include #include +// Tests failure on use of uninitialized mutex +// @expect error + int z = 1; void *t1(void *arg) { @@ -12,12 +11,11 @@ void *t1(void *arg) { pthread_mutex_lock(lock); z++; pthread_mutex_unlock(lock); + return 0; } -int main() { - +int main(void) { pthread_mutex_t lock; - pthread_t tid1; pthread_create(&tid1, 0, t1, &lock); @@ -26,4 +24,6 @@ int main() { pthread_mutex_unlock(&lock); pthread_join(tid1, 0); assert(z == 3); + return 0; } + diff --git a/test/pthread/lockattr.c b/test/pthread/lockattr.c index fa540017f..40c5f2e5c 100644 --- a/test/pthread/lockattr.c +++ b/test/pthread/lockattr.c @@ -1,17 +1,17 @@ +#include +#include + // Uses error handling from error checking mutex // to avoid what would otherwise be deadlock or permitted error // @expect verified -#include -#include - pthread_mutex_t lock; pthread_mutexattr_t lockattr; int x; void* t1(void *arg) { - int err = __SMACK_nondet(); + int err = __VERIFIER_nondet_int(); pthread_mutex_lock(&lock); err = pthread_mutex_lock(&lock); // Should be an EDEADLK error @@ -21,23 +21,25 @@ void* t1(void *arg) { err = pthread_mutex_unlock(&lock); // Should be an EPERM error assert(1 == err); + return 0; } -int main() { +int main(void) { x = 0; lock.attr.type = PTHREAD_MUTEX_ERRORCHECK; int err = pthread_mutex_lock(&lock); // Should be an EINVAL error - assert(err = 22); - err = 0; + assert(err == 22); err = pthread_mutex_unlock(&lock); // Should be an EINVAL error - assert(err = 22); + assert(err == 22); pthread_mutexattr_init(&lockattr); pthread_mutexattr_settype(&lockattr, PTHREAD_MUTEX_ERRORCHECK); pthread_mutex_init(&lock, &lockattr); pthread_t t; pthread_create(&t, 0, t1, 0); pthread_join(t, 0); - assert(x==1); + assert(x == 1); + return 0; } + diff --git a/test/pthread_extras/config.yml b/test/pthread_extras/config.yml index 055610e53..e9e657118 100644 --- a/test/pthread_extras/config.yml +++ b/test/pthread_extras/config.yml @@ -1,5 +1,5 @@ verifiers: [corral] memory: [no-reuse-impls] -time-limit: 800 +time-limit: 900 flags: [--pthread, --context-bound=2, --verifier-options=/trackAllVars] skip: ok diff --git a/test/pthread_extras/stack_true-unreach-call.c b/test/pthread_extras/stack_true-unreach-call.c index ef06838ac..151b687d6 100644 --- a/test/pthread_extras/stack_true-unreach-call.c +++ b/test/pthread_extras/stack_true-unreach-call.c @@ -3,7 +3,7 @@ #include // @expect verified -// @flag -x=svcomp +// @flag --unroll=6 #define TRUE (1) #define FALSE (0) diff --git a/test/reach/regtest.py b/test/reach/regtest.py index 8d02cde8a..fb516f534 100755 --- a/test/reach/regtest.py +++ b/test/reach/regtest.py @@ -1,4 +1,4 @@ -#! /usr/bin/env python +#! /usr/bin/env python2 import subprocess import re @@ -75,4 +75,3 @@ def runtests(): print '\nPASSED count: ', passed print 'FAILED count: ', failed - diff --git a/test/regtest.py b/test/regtest.py index 374f587c5..9562627d5 100755 --- a/test/regtest.py +++ b/test/regtest.py @@ -1,4 +1,4 @@ -#! /usr/bin/env python +#! /usr/bin/env python2 from os import path from multiprocessing.pool import ThreadPool diff --git a/test/simd/add.c b/test/simd/add.c new file mode 100644 index 000000000..e7fc77b06 --- /dev/null +++ b/test/simd/add.c @@ -0,0 +1,13 @@ +#include +#include + +// @expect verified + +int main(void) { + __m128i a = _mm_set_epi64x(1,2); + __m128i b = _mm_set_epi64x(10,10); + __m128i c = _mm_add_epi64(a,b); + assert(c[0] == 12); + assert(c[1] == 11); + return 0; +} diff --git a/test/simd/add_fail.c b/test/simd/add_fail.c new file mode 100644 index 000000000..7da0fdd73 --- /dev/null +++ b/test/simd/add_fail.c @@ -0,0 +1,12 @@ +#include +#include + +// @expect error + +int main(void) { + __m128i a = _mm_set_epi64x(1,2); + __m128i b = _mm_set_epi64x(10,10); + __m128i c = _mm_add_epi64(a,b); + assert(c[0] != 12); + return 0; +} diff --git a/test/simd/cast.c b/test/simd/cast.c new file mode 100644 index 000000000..036df0a61 --- /dev/null +++ b/test/simd/cast.c @@ -0,0 +1,11 @@ +#include +#include + +// @expect verified + +int main(void) { + long long a = 42; + __m64 b = (__m64) a; + assert(b[0] == 42); + return 0; +} diff --git a/test/simd/cast_fail.c b/test/simd/cast_fail.c new file mode 100644 index 000000000..f2544019e --- /dev/null +++ b/test/simd/cast_fail.c @@ -0,0 +1,11 @@ +#include +#include + +// @expect error + +int main(void) { + long long a = 42; + __m64 b = (__m64) a; + assert(b[0] == 41); + return 0; +} diff --git a/test/simd/config.yml b/test/simd/config.yml new file mode 100644 index 000000000..6bcab82d8 --- /dev/null +++ b/test/simd/config.yml @@ -0,0 +1 @@ +verifiers: [boogie] diff --git a/test/simd/constant.c b/test/simd/constant.c new file mode 100644 index 000000000..03477a5d8 --- /dev/null +++ b/test/simd/constant.c @@ -0,0 +1,10 @@ +#include +#include + +// @expect verified + +int main(void) { + __m128i v = {0xff,0xff}; + assert(v[0] == 0xff); + return 0; +} diff --git a/test/simd/constant_fail.c b/test/simd/constant_fail.c new file mode 100644 index 000000000..1b6cdee6e --- /dev/null +++ b/test/simd/constant_fail.c @@ -0,0 +1,10 @@ +#include +#include + +// @expect error + +int main(void) { + __m128i v = {0xff,0xff}; + assert(v[0] == 0xfe); + return 0; +} diff --git a/test/simd/shuffle.c b/test/simd/shuffle.c new file mode 100644 index 000000000..2cf4187f8 --- /dev/null +++ b/test/simd/shuffle.c @@ -0,0 +1,17 @@ +#include +#include + +// @expect verified + +int main() { + __m128i A = _mm_set_epi32(13,12,11,10); + __m128i B = _mm_set_epi32(23,22,21,20); + + A = _mm_shuffle_epi32(A,2*1 + 3*4 + 2*16 + 3*64); + B = _mm_shuffle_epi32(B,2*1 + 3*4 + 2*16 + 3*64); + + __m128i C = _mm_blend_epi32(A,B,0xf0); + + assert(_mm_extract_epi32(C,0) != 0); + return 0; +} diff --git a/test/simd/shuffle_fail.c b/test/simd/shuffle_fail.c new file mode 100644 index 000000000..0bfb9d913 --- /dev/null +++ b/test/simd/shuffle_fail.c @@ -0,0 +1,17 @@ +#include +#include + +// @expect error + +int main() { + __m128i A = _mm_set_epi32(13,12,11,10); + __m128i B = _mm_set_epi32(23,22,21,20); + + A = _mm_shuffle_epi32(A,2*1 + 3*4 + 2*16 + 3*64); + B = _mm_shuffle_epi32(B,2*1 + 3*4 + 2*16 + 3*64); + + __m128i C = _mm_blend_epi32(A,B,0xf0); + + assert(_mm_extract_epi32(C,0) == 0); + return 0; +} diff --git a/test/strings/config.yml b/test/strings/config.yml new file mode 100644 index 000000000..cab6957e4 --- /dev/null +++ b/test/strings/config.yml @@ -0,0 +1,2 @@ +skip: ok +flags: [--strings, --unroll=13] diff --git a/test/strings/strcat.c b/test/strings/strcat.c new file mode 100644 index 000000000..31d5b53e0 --- /dev/null +++ b/test/strings/strcat.c @@ -0,0 +1,14 @@ +#include +#include "smack.h" + +// @expect verified + +int main(void) { + char brick[10]; + strcpy(brick,"bl"); + char *glue = "ue"; + char *modernart = strcat(brick,glue); + + assert(strcmp(modernart,"blue") == 0); + return 0; +} diff --git a/test/strings/strcat_fail.c b/test/strings/strcat_fail.c new file mode 100644 index 000000000..47a2fcf85 --- /dev/null +++ b/test/strings/strcat_fail.c @@ -0,0 +1,14 @@ +#include +#include "smack.h" + +// @expect error + +int main(void) { + char brick[4]; + strcpy(brick,"bl"); + char *glue = "u!"; + char *modernart = strcat(brick,glue); + + assert(strcmp(modernart,"blue") == 0); + return 0; +} diff --git a/test/strings/strcat_overflow.c b/test/strings/strcat_overflow.c new file mode 100644 index 000000000..41f9689d0 --- /dev/null +++ b/test/strings/strcat_overflow.c @@ -0,0 +1,15 @@ +#include +#include "smack.h" + +// @flag --memory-safety +// @expect error + +int main(void) { + char notLong[3] = "So"; + char *moreText = ".."; + char *overflowed = strcat(notLong,moreText); + + assert(strcmp(overflowed,"So..") == 0); + return 0; +} + diff --git a/test/strings/strchr.c b/test/strings/strchr.c new file mode 100644 index 000000000..9026bd9c8 --- /dev/null +++ b/test/strings/strchr.c @@ -0,0 +1,12 @@ +#include +#include "smack.h" + +// @expect verified + +int main(void) { + char *sentence = "a..b"; + char *withoutFirstWord = strchr(sentence,'.'); + + assert(strcmp(withoutFirstWord,"..b") == 0); + return 0; +} diff --git a/test/strings/strchr_fail.c b/test/strings/strchr_fail.c new file mode 100644 index 000000000..92e8a4e58 --- /dev/null +++ b/test/strings/strchr_fail.c @@ -0,0 +1,12 @@ +#include +#include "smack.h" + +// @expect error + +int main(void) { + char *notAWebAddress = "word"; + char *dotToEnd = strchr(notAWebAddress,'.'); + + assert(dotToEnd != 0); + return 0; +} diff --git a/test/strings/strcmp.c b/test/strings/strcmp.c new file mode 100644 index 000000000..aec6302f6 --- /dev/null +++ b/test/strings/strcmp.c @@ -0,0 +1,13 @@ +#include +#include "smack.h" + +// @expect verified + +int main(void) { + char *smaller = "AAAA"; + char *bigger = "aaaa"; + int comparison = strcmp(smaller,bigger); + + assert(comparison < 0); + return 0; +} diff --git a/test/strings/strcmp_fail.c b/test/strings/strcmp_fail.c new file mode 100644 index 000000000..adfc67818 --- /dev/null +++ b/test/strings/strcmp_fail.c @@ -0,0 +1,13 @@ +#include +#include "smack.h" + +// @expect error + +int main(void) { + char *alpha = "alph"; + char *zeta = "zeta"; + int comparison = strcmp(alpha,zeta); + + assert(comparison == 0); + return 0; +} diff --git a/test/strings/strcpy.c b/test/strings/strcpy.c new file mode 100644 index 000000000..e9357eb82 --- /dev/null +++ b/test/strings/strcpy.c @@ -0,0 +1,15 @@ +#include +#include "smack.h" + +// @expect verified + +int main(void) { + const char *word = "Roof"; + char container[5]; + + strcpy(container,word); + assert(strlen(container) == 4); + assert(strcmp(container,word) == 0); + return 0; +} + diff --git a/test/strings/strcpy_fail.c b/test/strings/strcpy_fail.c new file mode 100644 index 000000000..335080964 --- /dev/null +++ b/test/strings/strcpy_fail.c @@ -0,0 +1,14 @@ +#include +#include "smack.h" + +// @expect error + +int main(void) { + const char *word = "made"; + char container[5]; + + strcpy(container,word); + assert(strcmp(container,"made") != 0); + return 0; +} + diff --git a/test/strings/strcpy_overflow.c b/test/strings/strcpy_overflow.c new file mode 100644 index 000000000..a2cd28d26 --- /dev/null +++ b/test/strings/strcpy_overflow.c @@ -0,0 +1,13 @@ +#include +#include "smack.h" + +// @flag --memory-safety +// @expect error + +int main(void) { + const char *sentence = "long"; + char container[2]; + strcpy(container,sentence); // buffer overflow! + return 0; +} + diff --git a/test/strings/strcspn.c b/test/strings/strcspn.c new file mode 100644 index 000000000..41beb6d89 --- /dev/null +++ b/test/strings/strcspn.c @@ -0,0 +1,12 @@ +#include +#include "smack.h" + +// @expect verified + +int main(void) { + char *string = "ffef"; + size_t firstE = strcspn(string,"e"); + + assert(firstE == 2); + return 0; +} diff --git a/test/strings/strcspn_fail.c b/test/strings/strcspn_fail.c new file mode 100644 index 000000000..2e3d2e593 --- /dev/null +++ b/test/strings/strcspn_fail.c @@ -0,0 +1,12 @@ +#include +#include "smack.h" + +// @expect error + +int main(void) { + char *string = "ffff"; + size_t firstE = strcspn(string,"f"); + + assert(firstE == 5); + return 0; +} diff --git a/test/strings/strlen.c b/test/strings/strlen.c new file mode 100644 index 000000000..4a80029cf --- /dev/null +++ b/test/strings/strlen.c @@ -0,0 +1,12 @@ +#include +#include +#include "smack.h" + +// @expect verified + +int main(void) { + char word[] = "Hi!!"; + + assert(strlen(word) == 4); + return 0; +} diff --git a/test/strings/strlen_fail.c b/test/strings/strlen_fail.c new file mode 100644 index 000000000..bb2579876 --- /dev/null +++ b/test/strings/strlen_fail.c @@ -0,0 +1,12 @@ +#include +#include +#include "smack.h" + +// @expect error + +int main(void) { + char word[] = "Hi"; + + assert(strlen(word) == 4); + return 0; +} diff --git a/test/strings/strncat.c b/test/strings/strncat.c new file mode 100644 index 000000000..6a8bedbc2 --- /dev/null +++ b/test/strings/strncat.c @@ -0,0 +1,15 @@ +#include +#include "smack.h" + +// @expect verified + +int main(void) { + char dish[40]; + strcpy(dish,"R"); + + char *milk = "ice"; + strncat(dish,milk,2); + + assert(strcmp(dish,"Ric") == 0); + return 0; +} diff --git a/test/strings/strncat_fail.c b/test/strings/strncat_fail.c new file mode 100644 index 000000000..f94228d9f --- /dev/null +++ b/test/strings/strncat_fail.c @@ -0,0 +1,15 @@ +#include +#include "smack.h" + +// @expect error + +int main(void) { + char dish[30]; + strcpy(dish,"R"); + + char *milk = "ice"; + strncat(dish,milk,2); + + assert(strcmp(dish,"Rice") == 0); + return 0; +} diff --git a/test/strings/strncmp.c b/test/strings/strncmp.c new file mode 100644 index 000000000..d8ab49225 --- /dev/null +++ b/test/strings/strncmp.c @@ -0,0 +1,13 @@ +#include +#include "smack.h" + +// @expect verified + +int main(void) { + char *str1 = "aaAA"; + char *str2 = "aaBB"; + + assert(strncmp(str1,str2,2) == 0); + assert(strncmp(str1,str2,3) < 0); + return 0; +} diff --git a/test/strings/strncmp_fail.c b/test/strings/strncmp_fail.c new file mode 100644 index 000000000..962fbc4b0 --- /dev/null +++ b/test/strings/strncmp_fail.c @@ -0,0 +1,12 @@ +#include +#include "smack.h" + +// @expect error + +int main(void) { + char *str1 = "aaAA"; + char *str2 = "aBBB"; + + assert(strncmp(str1,str2,2) == 0); + return 0; +} diff --git a/test/strings/strncmp_toolong.c b/test/strings/strncmp_toolong.c new file mode 100644 index 000000000..eaa0046ce --- /dev/null +++ b/test/strings/strncmp_toolong.c @@ -0,0 +1,13 @@ +#include +#include "smack.h" + +// @expect verified + +int main(void) { + char *shorty = "go"; + char *otherShorty = "go"; + int comparison = strncmp(shorty, otherShorty, 5); + + assert(comparison == 0); + return 0; +} diff --git a/test/strings/strpbrk.c b/test/strings/strpbrk.c new file mode 100644 index 000000000..699dd2e97 --- /dev/null +++ b/test/strings/strpbrk.c @@ -0,0 +1,12 @@ +#include +#include "smack.h" + +// @expect verified + +int main(void) { + char *letters = "abcd"; + char *fromFirstBorC = strpbrk(letters,"cb"); + + assert(strcmp(fromFirstBorC,"bcd") == 0); + return 0; +} diff --git a/test/strings/strpbrk_fail.c b/test/strings/strpbrk_fail.c new file mode 100644 index 000000000..b029e0c59 --- /dev/null +++ b/test/strings/strpbrk_fail.c @@ -0,0 +1,12 @@ +#include +#include "smack.h" + +// @expect error + +int main(void) { + char *letters = "efgh"; + char *fromFirstBorC = strpbrk(letters,"bc"); + + assert(fromFirstBorC != 0); + return 0; +} diff --git a/test/strings/strrchr.c b/test/strings/strrchr.c new file mode 100644 index 000000000..edfad22e3 --- /dev/null +++ b/test/strings/strrchr.c @@ -0,0 +1,12 @@ +#include +#include "smack.h" + +// @expect verified + +int main(void) { + char *website = "a..b"; + char *dotCom = strrchr(website,'.'); + + assert(strcmp(dotCom,".b") == 0); + return 0; +} diff --git a/test/strings/strrchr_fail.c b/test/strings/strrchr_fail.c new file mode 100644 index 000000000..9e6b9bac9 --- /dev/null +++ b/test/strings/strrchr_fail.c @@ -0,0 +1,12 @@ +#include +#include "smack.h" + +// @expect error + +int main(void) { + char *website = "a..b"; + char dotCom = strrchr(website,'.'); + + assert(strcmp(dotCom,"..b") == 0); + return 0; +} diff --git a/test/strings/strspn.c b/test/strings/strspn.c new file mode 100644 index 000000000..4a5d5ffcd --- /dev/null +++ b/test/strings/strspn.c @@ -0,0 +1,14 @@ +#include +#include "smack.h" + +// @expect verified + +int main(void) { + char *field = "bbab"; + size_t firstNonB = strspn(field,"b"); + size_t end = strspn(field,"ab"); + + assert(firstNonB == 2); + assert(end == strlen(field)); + return 0; +} diff --git a/test/strings/strspn_fail.c b/test/strings/strspn_fail.c new file mode 100644 index 000000000..0a1bdad33 --- /dev/null +++ b/test/strings/strspn_fail.c @@ -0,0 +1,12 @@ +#include +#include "smack.h" + +// @expect error + +int main(void) { + char *field = "bbcb"; + size_t end = strspn(field,"ab"); + + assert(end == strlen(field)); + return 0; +} diff --git a/test/strings/strstr.c b/test/strings/strstr.c new file mode 100644 index 000000000..373f486c5 --- /dev/null +++ b/test/strings/strstr.c @@ -0,0 +1,13 @@ +#include +#include "smack.h" + +// @expect verified + +int main(void) { + char *large = "wxyz"; + char *small = "xy"; + char *firstOccurrenceOfXY = strstr(large,small); + + assert(strcmp(firstOccurrenceOfXY,"xyz") == 0); + return 0; +} diff --git a/test/strings/strstr_fail.c b/test/strings/strstr_fail.c new file mode 100644 index 000000000..85c42a6f4 --- /dev/null +++ b/test/strings/strstr_fail.c @@ -0,0 +1,13 @@ +#include +#include "smack.h" + +// @expect error + +int main(void) { + char *large = "lmno"; + char *small = "xy"; + char *firstOccurrenceOfXY = strstr(large,small); + + assert(firstOccurrenceOfXY != 0); + return 0; +} diff --git a/test/strings/strtok.c b/test/strings/strtok.c new file mode 100644 index 000000000..18c844645 --- /dev/null +++ b/test/strings/strtok.c @@ -0,0 +1,16 @@ +#include +#include "smack.h" + +// @expect verified + +int main(void) { + char *string = "a-b"; + char *delim = "-"; + char *firstTok = strtok(string,delim); + char *nextTok = strtok(NULL,delim); + + assert(strcmp(firstTok,"a") == 0); + assert(strcmp(nextTok,"b") == 0); + return 0; + +} diff --git a/test/strings/strtok_fail.c b/test/strings/strtok_fail.c new file mode 100644 index 000000000..42ec58e98 --- /dev/null +++ b/test/strings/strtok_fail.c @@ -0,0 +1,15 @@ +#include +#include "smack.h" + +// @expect error + +int main(void) { + char *string = "a--"; + char *delim = "-"; + char *firstTok = strtok(string,delim); + char *nextTok = strtok(NULL,delim); + + assert(strcmp(firstTok,"a") == 0); + assert(strcmp(nextTok,"b") == 0); + return 0; +} diff --git a/tools/llvm2bpl/llvm2bpl.cpp b/tools/llvm2bpl/llvm2bpl.cpp index 61f564be7..c169a7590 100644 --- a/tools/llvm2bpl/llvm2bpl.cpp +++ b/tools/llvm2bpl/llvm2bpl.cpp @@ -39,8 +39,9 @@ #include "smack/VerifierCodeMetadata.h" #include "smack/SimplifyLibCalls.h" #include "smack/MemorySafetyChecker.h" -#include "smack/SignedIntegerOverflowChecker.h" -#include "smack/SplitAggregateLoadStore.h" +#include "smack/IntegerOverflowChecker.h" +#include "smack/SplitAggregateValue.h" +#include "smack/NormalizeLoops.h" static llvm::cl::opt InputFilename(llvm::cl::Positional, llvm::cl::desc(""), @@ -62,18 +63,10 @@ static llvm::cl::opt DefaultDataLayout("default-data-layout", llvm::cl::desc("data layout string to use if not specified by module"), llvm::cl::init(""), llvm::cl::value_desc("layout-string")); -static llvm::cl::opt -SignedIntegerOverflow("signed-integer-overflow", llvm::cl::desc("Enable signed integer overflow checks"), - llvm::cl::init(false)); - static llvm::cl::opt Modular("modular", llvm::cl::desc("Enable contracts-based modular deductive verification"), llvm::cl::init(false)); -static llvm::cl::opt -SplitStructs("split-aggregate-values", llvm::cl::desc("Split load/store instructions of LLVM aggregate types"), - llvm::cl::init(false)); - std::string filenamePrefix(const std::string &str) { return str.substr(0, str.find_last_of(".")); } @@ -165,7 +158,8 @@ int main(int argc, char **argv) { pass_manager.add(llvm::createLoopUnrollPass(32767)); } - pass_manager.add(new llvm::StructRet()); + //pass_manager.add(new llvm::StructRet()); + pass_manager.add(new smack::NormalizeLoops()); pass_manager.add(new llvm::SimplifyEV()); pass_manager.add(new llvm::SimplifyIV()); pass_manager.add(new smack::ExtractContracts()); @@ -178,16 +172,13 @@ int main(int argc, char **argv) { pass_manager.add(new llvm::MergeArrayGEP()); // pass_manager.add(new smack::SimplifyLibCalls()); pass_manager.add(new llvm::Devirtualize()); - - if (SplitStructs) - pass_manager.add(new smack::SplitAggregateLoadStore()); + pass_manager.add(new smack::SplitAggregateValue()); if (smack::SmackOptions::MemorySafety) { pass_manager.add(new smack::MemorySafetyChecker()); } - if (SignedIntegerOverflow) - pass_manager.add(new smack::SignedIntegerOverflowChecker()); + pass_manager.add(new smack::IntegerOverflowChecker()); if(smack::SmackOptions::AddTiming){